Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -135,6 +135,8 @@ Group, DocName<"AARCH64">; def m_amdgpu_Features_Group : OptionGroup<"">, Group, DocName<"AMDGPU">; +def m_arc_Features_Group : OptionGroup<"">, + Group, DocName<"ARC">; def m_arm_Features_Group : OptionGroup<"">, Group, DocName<"ARM">; def m_hexagon_Features_Group : OptionGroup<"">, @@ -2644,6 +2646,10 @@ def _write_user_dependencies : Flag<["--"], "write-user-dependencies">, Alias; def _ : Joined<["--"], "">, Flags<[Unsupported]>; +// ARC feature flags. +def mrf16 : Flag<["-"], "mrf16">, Group, + HelpText<"Enable 16-entry register file (ARC only). Defines the __ARC_RF16__ preprocessor macro.">; + // Hexagon feature flags. def mieee_rnd_near : Flag<["-"], "mieee-rnd-near">, Group; Index: lib/Basic/CMakeLists.txt =================================================================== --- lib/Basic/CMakeLists.txt +++ lib/Basic/CMakeLists.txt @@ -71,6 +71,7 @@ Targets.cpp Targets/AArch64.cpp Targets/AMDGPU.cpp + Targets/ARC.cpp Targets/ARM.cpp Targets/AVR.cpp Targets/BPF.cpp Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -16,6 +16,7 @@ #include "Targets/AArch64.h" #include "Targets/AMDGPU.h" +#include "Targets/ARC.h" #include "Targets/ARM.h" #include "Targets/AVR.h" #include "Targets/BPF.h" @@ -124,6 +125,9 @@ default: return nullptr; + case llvm::Triple::arc: + return new ARCTargetInfo(Triple, Opts); + case llvm::Triple::xcore: return new XCoreTargetInfo(Triple, Opts); Index: lib/Basic/Targets/ARC.h =================================================================== --- lib/Basic/Targets/ARC.h +++ lib/Basic/Targets/ARC.h @@ -0,0 +1,85 @@ +//===--- ARC.h - Declare ARC target feature support -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares ARC TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_ARC_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_ARC_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY ARCTargetInfo : public TargetInfo { +public: + ARCTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + NoAsmVariants = true; + LongLongAlign = 32; + SuitableAlign = 32; + DoubleAlign = LongDoubleAlign = 32; + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + UseZeroLengthBitfieldAlignment = true; + resetDataLayout("e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-" + "i32:32:32-f32:32:32-i64:32-f64:32-a:0:32-n32"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef getTargetBuiltins() const override { return None; } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + const char *getClobbers() const override { return ""; } + + ArrayRef getGCCRegNames() const override { + static const char *const GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "gp", "sp", "fp", "ilink1", "r30", "blink"}; + return llvm::makeArrayRef(GCCRegNames); + } + + ArrayRef getGCCRegAliases() const override { + return None; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + return false; + } + + bool isValidFeatureName(StringRef Feature) const override; + + bool hasFeature(StringRef Feature) const override; + + bool handleTargetFeatures(std::vector &Features, + DiagnosticsEngine &Diags) override; + +private: + // Target cpu features. + bool IsRF16Enabled = false; +}; + +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_ARC_H Index: lib/Basic/Targets/ARC.cpp =================================================================== --- lib/Basic/Targets/ARC.cpp +++ lib/Basic/Targets/ARC.cpp @@ -0,0 +1,65 @@ +//===--- ARC.cpp - Implement ARC target feature support -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements ARC TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "ARC.h" +#include "clang/Basic/MacroBuilder.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +namespace arc { +namespace macro { + constexpr llvm::StringLiteral arch("__arc__"); + constexpr llvm::StringLiteral rf16("__ARC_RF16__"); +} // namespace macro + +namespace feature { + constexpr llvm::StringLiteral rf16("rf16"); +} // namespace feature +} + +void ARCTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro(arc::macro::arch); + if (IsRF16Enabled) + Builder.defineMacro(arc::macro::rf16); +} + +bool ARCTargetInfo::isValidFeatureName(StringRef Feature) const { + return llvm::StringSwitch(Feature) + .Case(arc::feature::rf16, true) + .Default(false); +} + +bool ARCTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch(Feature) + .Case(arc::feature::rf16, IsRF16Enabled) + .Default(false); +} + +bool ARCTargetInfo::handleTargetFeatures(std::vector &Features, + DiagnosticsEngine &Diags) { + for (llvm::StringRef feature : Features) { + bool enable = llvm::StringSwitch(feature) + .StartsWith("+", true) + .StartsWith("-", false) + .Default(false); + + if (feature.endswith(arc::feature::rf16)) + IsRF16Enabled = enable; + else + return false; + } + return true; +} \ No newline at end of file Index: lib/CodeGen/TargetInfo.cpp =================================================================== --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -8209,7 +8209,139 @@ return false; } +// ARC ABI implementation. +namespace { +class ARCABIInfo : public DefaultABIInfo { +public: + using DefaultABIInfo::DefaultABIInfo; + +private: + Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, + QualType Ty) const override; + + void updateState(const ABIArgInfo &Info, QualType Ty, CCState &State) const { + if (!State.FreeRegs) + return; + if (Info.isIndirect() && Info.getInReg()) + State.FreeRegs--; + else if (Info.isDirect() && Info.getInReg()) { + unsigned sz = (getContext().getTypeSize(Ty) + 31) / 32; + if (sz < State.FreeRegs) + State.FreeRegs -= sz; + else + State.FreeRegs = 0; + } + } + + void computeInfo(CGFunctionInfo &FI) const override { + CCState State(FI.getCallingConvention()); + // ARC uses 8 registers to pass arguments (4 for reduced register set). + State.FreeRegs = getTarget().hasFeature("rf16") ? 4 : 8; + + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + updateState(FI.getReturnInfo(), FI.getReturnType(), State); + for (auto &I : FI.arguments()) { + I.info = classifyArgumentType(I.type, State.FreeRegs); + updateState(I.info, I.type, State); + } + } + + ABIArgInfo getIndirectByRef(QualType Ty, bool HasFreeRegs) const; + ABIArgInfo getIndirectByValue(QualType Ty) const; + ABIArgInfo classifyArgumentType(QualType Ty, uint8_t FreeRegs) const; + ABIArgInfo classifyReturnType(QualType RetTy) const; +}; + +class ARCTargetCodeGenInfo : public TargetCodeGenInfo { +public: + ARCTargetCodeGenInfo(CodeGenTypes &CGT) + : TargetCodeGenInfo(new ARCABIInfo(CGT)) {} +}; + + +ABIArgInfo ARCABIInfo::getIndirectByRef(QualType Ty, bool HasFreeRegs) const { + return HasFreeRegs ? getNaturalAlignIndirectInReg(Ty) : + getNaturalAlignIndirect(Ty, false); +} + +ABIArgInfo ARCABIInfo::getIndirectByValue(QualType Ty) const { + // Compute the byval alignment. + const unsigned MinABIStackAlignInBytes = 4; + unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8; + return ABIArgInfo::getIndirect(CharUnits::fromQuantity(4), /*ByVal=*/true, + TypeAlign > MinABIStackAlignInBytes); +} + +Address ARCABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, + QualType Ty) const { + return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, + getContext().getTypeInfoInChars(Ty), + CharUnits::fromQuantity(4), true); +} + +ABIArgInfo ARCABIInfo::classifyArgumentType(QualType Ty, + uint8_t FreeRegs) const { + // Handle the generic C++ ABI. + const RecordType *RT = Ty->getAs(); + if (RT) { + CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()); + if (RAA == CGCXXABI::RAA_Indirect) + return getIndirectByRef(Ty, FreeRegs > 0); + + if (RAA == CGCXXABI::RAA_DirectInMemory) + return getIndirectByValue(Ty); + } + + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs()) + Ty = EnumTy->getDecl()->getIntegerType(); + + auto SizeInRegs = llvm::alignTo(getContext().getTypeSize(Ty), 32) / 32; + + if (isAggregateTypeForABI(Ty) || SizeInRegs > 1) { + const RecordType *RT = Ty->getAs(); + // Structures with flexible arrays are always indirect. + if (RT && RT->getDecl()->hasFlexibleArrayMember()) + return getIndirectByValue(Ty); + + // Ignore empty structs/unions. + if (isEmptyRecord(getContext(), Ty, true)) + return ABIArgInfo::getIgnore(); + + llvm::LLVMContext &LLVMContext = getVMContext(); + + llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext); + SmallVector Elements(SizeInRegs, Int32); + llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements); + + return FreeRegs >= SizeInRegs ? + ABIArgInfo::getDirectInReg(Result) : + ABIArgInfo::getDirect(Result); + } + + return Ty->isPromotableIntegerType() ? + (FreeRegs >= SizeInRegs ? ABIArgInfo::getExtendInReg(Ty) : + ABIArgInfo::getExtend(Ty)) : + (FreeRegs >= SizeInRegs ? ABIArgInfo::getDirectInReg() : + ABIArgInfo::getDirect()); +} + +ABIArgInfo ARCABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isAnyComplexType()) + return ABIArgInfo::getDirectInReg(); + + // Arguments of size > 4 registers are indirect. + auto RetSize = llvm::alignTo(getContext().getTypeSize(RetTy), 32) / 32; + if (RetSize > 4) + return getIndirectByRef(RetTy, /*HasFreeRegs*/ true); + + return DefaultABIInfo::classifyReturnType(RetTy); +} + +} // End anonymous namespace. + //===----------------------------------------------------------------------===// // XCore ABI Implementation //===----------------------------------------------------------------------===// @@ -9230,6 +9362,8 @@ return SetCGInfo(new SparcV9TargetCodeGenInfo(Types)); case llvm::Triple::xcore: return SetCGInfo(new XCoreTargetCodeGenInfo(Types)); + case llvm::Triple::arc: + return SetCGInfo(new ARCTargetCodeGenInfo(Types)); case llvm::Triple::spir: case llvm::Triple::spir64: return SetCGInfo(new SPIRTargetCodeGenInfo(Types)); Index: lib/Driver/CMakeLists.txt =================================================================== --- lib/Driver/CMakeLists.txt +++ lib/Driver/CMakeLists.txt @@ -21,6 +21,7 @@ SanitizerArgs.cpp Tool.cpp ToolChain.cpp + ToolChains/Arch/ARC.cpp ToolChains/Arch/AArch64.cpp ToolChains/Arch/ARM.cpp ToolChains/Arch/Mips.cpp Index: lib/Driver/ToolChains/Arch/ARC.h =================================================================== --- lib/Driver/ToolChains/Arch/ARC.h +++ lib/Driver/ToolChains/Arch/ARC.h @@ -0,0 +1,35 @@ +//===--- ARC.h - ARC ToolChain Implementations ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARC_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARC_H + +#include + +namespace llvm { + class StringRef; + namespace opt { + class ArgList; + } +} + +namespace clang { +namespace driver { +namespace tools { +namespace arc { + +void getARCTargetFeatures(const llvm::opt::ArgList &Args, + std::vector &Features); + +} // end namespace arc +} // end namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARC_H Index: lib/Driver/ToolChains/Arch/ARC.cpp =================================================================== --- lib/Driver/ToolChains/Arch/ARC.cpp +++ lib/Driver/ToolChains/Arch/ARC.cpp @@ -0,0 +1,25 @@ +//===----------- ARC.cpp - ARC ToolChain Implementations --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ARC.h" +#include "ToolChains/CommonArgs.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::tools; + +// ARC target features. +void arc::getARCTargetFeatures(const llvm::opt::ArgList &Args, + std::vector &Features) { + handleTargetFeaturesGroup(Args, Features, + options::OPT_m_arc_Features_Group); +} + Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -9,6 +9,7 @@ #include "Clang.h" #include "Arch/AArch64.h" +#include "Arch/ARC.h" #include "Arch/ARM.h" #include "Arch/Mips.h" #include "Arch/PPC.h" @@ -363,6 +364,10 @@ case llvm::Triple::amdgcn: amdgpu::getAMDGPUTargetFeatures(D, Args, Features); break; + + case llvm::Triple::arc: + arc::getARCTargetFeatures(Args, Features); + break; } // Find the last of each feature. Index: test/CodeGen/arc/arguments.c =================================================================== --- test/CodeGen/arc/arguments.c +++ test/CodeGen/arc/arguments.c @@ -0,0 +1,135 @@ +// RUN: %clang_cc1 -triple arc-unknown-unknown %s -emit-llvm -o - \ +// RUN: | FileCheck %s + +// Basic argument tests for ARC. + +// CHECK: define void @f0(i32 inreg %i, i32 inreg %j, i32 inreg %k.coerce0, i32 inreg %k.coerce1) +void f0(int i, long j, long long k) {} + +typedef struct { + int aa; + int bb; +} s1; +// CHECK: define void @f1(i32 inreg %i.coerce0, i32 inreg %i.coerce1) +void f1(s1 i) {} + +typedef struct { + char aa; char bb; char cc; char dd; +} cs1; +// CHECK: define void @cf1(i32 inreg %i.coerce) +void cf1(cs1 i) {} + +typedef struct { + int cc; +} s2; +// CHECK: define void @f2(%struct.s2* noalias sret %agg.result) +s2 f2() { + s2 foo; + return foo; +} + +typedef struct { + int cc; + int dd; +} s3; +// CHECK: define void @f3(%struct.s3* noalias sret %agg.result) +s3 f3() { + s3 foo; + return foo; +} + +// CHECK: define void @f4(i32 inreg %i.coerce0, i32 inreg %i.coerce1) +void f4(long long i) {} + +// CHECK: define void @f5(i8 inreg signext %a, i16 inreg signext %b) +void f5(signed char a, short b) {} + +// CHECK: define void @f6(i8 inreg zeroext %a, i16 inreg zeroext %b) +void f6(unsigned char a, unsigned short b) {} + +enum my_enum { + ENUM1, + ENUM2, + ENUM3, +}; +// Enums should be treated as the underlying i32. +// CHECK: define void @f7(i32 inreg %a) +void f7(enum my_enum a) {} + +enum my_big_enum { + ENUM4 = 0xFFFFFFFFFFFFFFFF, +}; +// Big enums should be treated as the underlying i64. +// CHECK: define void @f8(i32 inreg %a.coerce0, i32 inreg %a.coerce1) +void f8(enum my_big_enum a) {} + +union simple_union { + int a; + char b; +}; +// Unions should be passed inreg. +// CHECK: define void @f9(i32 inreg %s.coerce) +void f9(union simple_union s) {} + +typedef struct { + int b4 : 4; + int b3 : 3; + int b8 : 8; +} bitfield1; +// Bitfields should be passed inreg. +// CHECK: define void @f10(i32 inreg %bf1.coerce) +void f10(bitfield1 bf1) {} + +// CHECK: define inreg { float, float } @cplx1(float inreg %r) +_Complex float cplx1(float r) { + return r + 2.0fi; +} + +// CHECK: define inreg { double, double } @cplx2(i32 inreg %r.coerce0, i32 inreg %r.coerce1) +_Complex double cplx2(double r) { + return r + 2.0i; +} + +// CHECK: define inreg { i32, i32 } @cplx3(i32 inreg %r) +_Complex int cplx3(int r) { + return r + 2i; +} + +// CHECK: define inreg { i64, i64 } @cplx4(i32 inreg %r.coerce0, i32 inreg %r.coerce1) +_Complex long long cplx4(long long r) { + return r + 2i; +} + +// CHECK: define inreg { i8, i8 } @cplx6(i8 inreg signext %r) +_Complex signed char cplx6(signed char r) { + return r + 2i; +} + +// CHECK: define inreg { i16, i16 } @cplx7(i16 inreg signext %r) +_Complex short cplx7(short r) { + return r + 2i; +} + +typedef struct { + int aa; int bb; +} s8; + +typedef struct { + int aa; int bb; int cc; int dd; +} s16; + +// Use 16-byte struct 2 times, gets 8 registers. +void st2(s16 a, s16 b) {} +// CHECK: define void @st2(i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %a.coerce2, i32 inreg %a.coerce3, i32 inreg %b.coerce0, i32 inreg %b.coerce1, i32 inreg %b.coerce2, i32 inreg %b.coerce3) + +// Use 8-byte struct 3 times, gets 8 registers, 1 byval struct argument. +void st3(s16 a, s16 b, s16 c) {} +// CHECK: define void @st3(i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %a.coerce2, i32 inreg %a.coerce3, i32 inreg %b.coerce0, i32 inreg %b.coerce1, i32 inreg %b.coerce2, i32 inreg %b.coerce3, i32 %c.coerce0, i32 %c.coerce1, i32 %c.coerce2, i32 %c.coerce3) + +// 1 sret + 1 i32 + 2*(i32 coerce) + 4*(i32 coerce) + 1 byval +s16 st4(int x, s8 a, s16 b, s16 c) { return b; } +// CHECK: define void @st4(%struct.s16* noalias sret %agg.result, i32 inreg %x, i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %b.coerce0, i32 inreg %b.coerce1, i32 inreg %b.coerce2, i32 inreg %b.coerce3, i32 %c.coerce0, i32 %c.coerce1, i32 %c.coerce2, i32 %c.coerce3) + +// 1 sret + 2*(i32 coerce) + 4*(i32 coerce) + 4*(i32 coerce) +s16 st5(s8 a, s16 b, s16 c) { return b; } +// CHECK: define void @st5(%struct.s16* noalias sret %agg.result, i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %b.coerce0, i32 inreg %b.coerce1, i32 inreg %b.coerce2, i32 inreg %b.coerce3, i32 %c.coerce0, i32 %c.coerce1, i32 %c.coerce2, i32 %c.coerce3) Index: test/CodeGen/arc/struct-align.c =================================================================== --- test/CodeGen/arc/struct-align.c +++ test/CodeGen/arc/struct-align.c @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -triple arc-unknown-unknown %s -emit-llvm -o - \ +// RUN: | FileCheck %s + +// 64-bit fields need only be 32-bit aligned for arc. + +typedef struct { + int aa; + double bb; +} s1; + +// CHECK: define i32 @f1 +// CHECK: ret i32 12 +int f1() { + return sizeof(s1); +} + +typedef struct { + int aa; + long long bb; +} s2; +// CHECK: define i32 @f2 +// CHECK: ret i32 12 +int f2() { + return sizeof(s2); +} + Index: test/CodeGen/target-data.c =================================================================== --- test/CodeGen/target-data.c +++ test/CodeGen/target-data.c @@ -151,6 +151,10 @@ // RUN: %s | FileCheck %s -check-prefix=ARM-GNU // ARM-GNU: target datalayout = "e-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" +// RUN: %clang_cc1 -triple arc-unknown-unknown -o - -emit-llvm %s | \ +// RUN: FileCheck %s -check-prefix=ARC +// ARC: target datalayout = "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-f32:32:32-i64:32-f64:32-a:0:32-n32" + // RUN: %clang_cc1 -triple hexagon-unknown -o - -emit-llvm %s | \ // RUN: FileCheck %s -check-prefix=HEXAGON // HEXAGON: target datalayout = "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048" Index: test/Driver/arc-target-features.c =================================================================== --- test/Driver/arc-target-features.c +++ test/Driver/arc-target-features.c @@ -0,0 +1,5 @@ +// REQUIRES: arc-registered-target + +// RUN: %clang -target arc-unknown-unknown -### -S %s -mrf16 2>&1 | FileCheck %s -check-prefix=CHECK-RF16 +// CHECK-RF16: "-target-feature" "+rf16" +// CHECK: #define __ARC_RF16__