Index: cfe/trunk/lib/Basic/Targets.cpp =================================================================== --- cfe/trunk/lib/Basic/Targets.cpp +++ cfe/trunk/lib/Basic/Targets.cpp @@ -5950,6 +5950,111 @@ #include "clang/Basic/BuiltinsHexagon.def" }; +class LanaiTargetInfo : public TargetInfo { + // Class for Lanai (32-bit). + // The CPU profiles supported by the Lanai backend + enum CPUKind { + CK_NONE, + CK_V11, + } CPU; + + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char *const GCCRegNames[]; + +public: + LanaiTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { + // Description string has to be kept in sync with backend. + resetDataLayout("E" // Big endian + "-m:e" // ELF name manging + "-p:32:32" // 32 bit pointers, 32 bit aligned + "-i64:64" // 64 bit integers, 64 bit aligned + "-a:0:32" // 32 bit alignment of objects of aggregate type + "-n32" // 32 bit native integer width + "-S64" // 64 bit natural stack alignment + ); + + // Setting RegParmMax equal to what mregparm was set to in the old + // toolchain + RegParmMax = 4; + + // Set the default CPU to V11 + CPU = CK_V11; + + // Temporary approach to make everything at least word-aligned and allow for + // safely casting between pointers with different alignment requirements. + // TODO: Remove this when there are no more cast align warnings on the + // firmware. + MinGlobalAlign = 32; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + // Define __lanai__ when building for target lanai. + Builder.defineMacro("__lanai__"); + + // Set define for the CPU specified. + switch (CPU) { + case CK_V11: + Builder.defineMacro("__LANAI_V11__"); + break; + case CK_NONE: + llvm_unreachable("Unhandled target CPU"); + } + } + + bool setCPU(const std::string &Name) override { + CPU = llvm::StringSwitch(Name) + .Case("v11", CK_V11) + .Default(CK_NONE); + + return CPU != CK_NONE; + } + + bool hasFeature(StringRef Feature) const override { + return llvm::StringSwitch(Feature).Case("lanai", true).Default(false); + } + + ArrayRef getGCCRegNames() const override; + + ArrayRef getGCCRegAliases() const override; + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + ArrayRef getTargetBuiltins() const override { return None; } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + return false; + } + + const char *getClobbers() const override { return ""; } +}; + +const char *const LanaiTargetInfo::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", "r26", "r27", "r28", "r29", "r30", "r31"}; + +ArrayRef LanaiTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +const TargetInfo::GCCRegAlias LanaiTargetInfo::GCCRegAliases[] = { + {{"pc"}, "r2"}, + {{"sp"}, "r4"}, + {{"fp"}, "r5"}, + {{"rv"}, "r8"}, + {{"rr1"}, "r10"}, + {{"rr2"}, "r11"}, + {{"rca"}, "r15"}, +}; + +ArrayRef LanaiTargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(GCCRegAliases); +} + // Shared base class for SPARC v8 (32-bit) and SPARC v9 (64-bit). class SparcTargetInfo : public TargetInfo { static const TargetInfo::GCCRegAlias GCCRegAliases[]; @@ -7672,6 +7777,9 @@ case llvm::Triple::hexagon: return new HexagonTargetInfo(Triple); + case llvm::Triple::lanai: + return new LanaiTargetInfo(Triple); + case llvm::Triple::aarch64: if (Triple.isOSDarwin()) return new DarwinAArch64TargetInfo(Triple); Index: cfe/trunk/lib/CodeGen/TargetInfo.cpp =================================================================== --- cfe/trunk/lib/CodeGen/TargetInfo.cpp +++ cfe/trunk/lib/CodeGen/TargetInfo.cpp @@ -6583,6 +6583,78 @@ } //===----------------------------------------------------------------------===// +// Lanai ABI Implementation +//===----------------------------------------------------------------------===// + +class LanaiABIInfo : public DefaultABIInfo { +public: + LanaiABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} + + bool shouldUseInReg(QualType Ty, CCState &State) const; + + void computeInfo(CGFunctionInfo &FI) const override { + CCState State(FI.getCallingConvention()); + // Lanai uses 4 registers to pass arguments unless the function has the + // regparm attribute set. + if (FI.getHasRegParm()) { + State.FreeRegs = FI.getRegParm(); + } else { + State.FreeRegs = 4; + } + + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + for (auto &I : FI.arguments()) + I.info = classifyArgumentType(I.type, State); + } + + ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const; +}; + +bool LanaiABIInfo::shouldUseInReg(QualType Ty, CCState &State) const { + unsigned Size = getContext().getTypeSize(Ty); + unsigned SizeInRegs = llvm::alignTo(Size, 32U) / 32U; + + if (SizeInRegs == 0) + return false; + + if (SizeInRegs > State.FreeRegs) { + State.FreeRegs = 0; + return false; + } + + State.FreeRegs -= SizeInRegs; + + return true; +} + +ABIArgInfo LanaiABIInfo::classifyArgumentType(QualType Ty, + CCState &State) const { + if (isAggregateTypeForABI(Ty)) + return getNaturalAlignIndirect(Ty); + + // Treat an enum type as its underlying type. + if (const auto *EnumTy = Ty->getAs()) + Ty = EnumTy->getDecl()->getIntegerType(); + + if (shouldUseInReg(Ty, State)) + return ABIArgInfo::getDirectInReg(); + + if (Ty->isPromotableIntegerType()) + return ABIArgInfo::getExtend(); + + return ABIArgInfo::getDirect(); +} + +namespace { +class LanaiTargetCodeGenInfo : public TargetCodeGenInfo { +public: + LanaiTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) + : TargetCodeGenInfo(new LanaiABIInfo(CGT)) {} +}; +} + +//===----------------------------------------------------------------------===// // AMDGPU ABI Implementation //===----------------------------------------------------------------------===// @@ -7740,6 +7812,8 @@ } case llvm::Triple::hexagon: return *(TheTargetCodeGenInfo = new HexagonTargetCodeGenInfo(Types)); + case llvm::Triple::lanai: + return *(TheTargetCodeGenInfo = new LanaiTargetCodeGenInfo(Types)); case llvm::Triple::r600: return *(TheTargetCodeGenInfo = new AMDGPUTargetCodeGenInfo(Types)); case llvm::Triple::amdgcn: Index: cfe/trunk/lib/Driver/Driver.cpp =================================================================== --- cfe/trunk/lib/Driver/Driver.cpp +++ cfe/trunk/lib/Driver/Driver.cpp @@ -2459,6 +2459,9 @@ case llvm::Triple::hexagon: TC = new toolchains::HexagonToolChain(*this, Target, Args); break; + case llvm::Triple::lanai: + TC = new toolchains::LanaiToolChain(*this, Target, Args); + break; case llvm::Triple::xcore: TC = new toolchains::XCoreToolChain(*this, Target, Args); break; Index: cfe/trunk/lib/Driver/ToolChains.h =================================================================== --- cfe/trunk/lib/Driver/ToolChains.h +++ cfe/trunk/lib/Driver/ToolChains.h @@ -874,6 +874,14 @@ std::string LibSuffix; }; +class LLVM_LIBRARY_VISIBILITY LanaiToolChain : public Generic_ELF { +public: + LanaiToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : Generic_ELF(D, Triple, Args) {} + bool IsIntegratedAssemblerDefault() const override { return true; } +}; + class LLVM_LIBRARY_VISIBILITY HexagonToolChain : public Linux { protected: GCCVersion GCCLibAndIncVersion; Index: cfe/trunk/lib/Driver/Tools.h =================================================================== --- cfe/trunk/lib/Driver/Tools.h +++ cfe/trunk/lib/Driver/Tools.h @@ -82,6 +82,8 @@ llvm::opt::ArgStringList &CmdArgs) const; void AddHexagonTargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; + void AddLanaiTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; void AddWebAssemblyTargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; Index: cfe/trunk/lib/Driver/Tools.cpp =================================================================== --- cfe/trunk/lib/Driver/Tools.cpp +++ cfe/trunk/lib/Driver/Tools.cpp @@ -1619,6 +1619,13 @@ return ""; } +static std::string getLanaiTargetCPU(const ArgList &Args) { + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { + return A->getValue(); + } + return ""; +} + void Clang::AddSparcTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); @@ -1836,6 +1843,9 @@ return "hexagon" + toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str(); + case llvm::Triple::lanai: + return getLanaiTargetCPU(Args); + case llvm::Triple::systemz: return getSystemZTargetCPU(Args); @@ -2145,6 +2155,29 @@ CmdArgs.push_back("-machine-sink-split=0"); } +void Clang::AddLanaiTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { + StringRef CPUName = A->getValue(); + + CmdArgs.push_back("-target-cpu"); + CmdArgs.push_back(Args.MakeArgString(CPUName)); + } + if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) { + StringRef Value = A->getValue(); + // Only support mregparm=4 to support old usage. Report error for all other + // cases. + int Mregparm; + if (Value.getAsInteger(10, Mregparm)) { + if (Mregparm != 4) { + getToolChain().getDriver().Diag( + diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; + } + } + } +} + void Clang::AddWebAssemblyTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Default to "hidden" visibility. @@ -4176,6 +4209,10 @@ AddX86TargetArgs(Args, CmdArgs); break; + case llvm::Triple::lanai: + AddLanaiTargetArgs(Args, CmdArgs); + break; + case llvm::Triple::hexagon: AddHexagonTargetArgs(Args, CmdArgs); break; Index: cfe/trunk/test/CodeGen/lanai-arguments.c =================================================================== --- cfe/trunk/test/CodeGen/lanai-arguments.c +++ cfe/trunk/test/CodeGen/lanai-arguments.c @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 -triple lanai-unknown-unknown %s -emit-llvm -o - \ +// RUN: | FileCheck %s + +// Basic argument/attribute tests for Lanai. + +// CHECK: define void @f0(i32 inreg %i, i32 inreg %j, i64 inreg %k) +void f0(int i, long j, long long k) {} + +typedef struct { + int aa; + int bb; +} s1; +// CHECK: define void @f1(%struct.s1* byval align 4 %i) +void f1(s1 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(i64 inreg %i) +void f4(long long i) {} + +// CHECK: define void @f5(i8 inreg %a, i16 inreg %b) +void f5(char a, short b) {} + +// CHECK: define void @f6(i8 inreg %a, i16 inreg %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(i64 inreg %a) +void f8(enum my_big_enum a) {} + +union simple_union { + int a; + char b; +}; +// Unions should be passed as byval structs. +// CHECK: define void @f9(%union.simple_union* byval align 4 %s) +void f9(union simple_union s) {} + +typedef struct { + int b4 : 4; + int b3 : 3; + int b8 : 8; +} bitfield1; +// Bitfields should be passed as byval structs. +// CHECK: define void @f10(%struct.bitfield1* byval align 4 %bf1) +void f10(bitfield1 bf1) {} Index: cfe/trunk/test/CodeGen/lanai-regparm.c =================================================================== --- cfe/trunk/test/CodeGen/lanai-regparm.c +++ cfe/trunk/test/CodeGen/lanai-regparm.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple lanai-unknown-unknown -mregparm 4 %s -emit-llvm -o - | FileCheck %s + +void f1(int a, int b, int c, int d, + int e, int f, int g, int h); + +void f2(int a, int b) __attribute((regparm(0))); + +void f0() { +// CHECK: call void @f1(i32 inreg 1, i32 inreg 2, i32 inreg 3, i32 inreg 4, +// CHECK: i32 5, i32 6, i32 7, i32 8) + f1(1, 2, 3, 4, 5, 6, 7, 8); +// CHECK: call void @f2(i32 1, i32 2) + f2(1, 2); +} + +// CHECK: declare void @f1(i32 inreg, i32 inreg, i32 inreg, i32 inreg, +// CHECK: i32, i32, i32, i32) +// CHECK: declare void @f2(i32, i32) Index: cfe/trunk/test/CodeGen/target-data.c =================================================================== --- cfe/trunk/test/CodeGen/target-data.c +++ cfe/trunk/test/CodeGen/target-data.c @@ -86,6 +86,10 @@ // RUN: FileCheck %s -check-prefix=WEBASSEMBLY64 // WEBASSEMBLY64: target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128" +// RUN: %clang_cc1 -triple lanai-unknown-unknown -o - -emit-llvm %s | \ +// RUN: FileCheck %s -check-prefix=LANAI +// LANAI: target datalayout = "E-m:e-p:32:32-i64:64-a:0:32-n32-S64" + // RUN: %clang_cc1 -triple powerpc-unknown -o - -emit-llvm %s | \ // RUN: FileCheck %s -check-prefix=PPC // PPC: target datalayout = "E-m:e-p:32:32-i64:64-n32" Index: cfe/trunk/test/Driver/lanai-toolchain.c =================================================================== --- cfe/trunk/test/Driver/lanai-toolchain.c +++ cfe/trunk/test/Driver/lanai-toolchain.c @@ -0,0 +1,2 @@ +// RUN: %clang -target lanai-unknown-unknown -v 2> %t +// RUN: grep 'Target: lanai-unknown-unknown' %t Index: cfe/trunk/test/Driver/lanai-unknown-unknown.cpp =================================================================== --- cfe/trunk/test/Driver/lanai-unknown-unknown.cpp +++ cfe/trunk/test/Driver/lanai-unknown-unknown.cpp @@ -0,0 +1,86 @@ +// RUN: %clang -target lanai-unknown-unknown -### %s -emit-llvm-only -c 2>&1 \ +// RUN: | FileCheck %s -check-prefix=ECHO +// RUN: %clang -target lanai-unknown-unknown %s -emit-llvm -S -o - \ +// RUN: | FileCheck %s + +// ECHO: {{.*}} "-cc1" {{.*}}lanai-unknown-unknown.c + +typedef __builtin_va_list va_list; +typedef __SIZE_TYPE__ size_t; +typedef __PTRDIFF_TYPE__ ptrdiff_t; + +extern "C" { + +// CHECK: @align_c = global i32 1 +int align_c = __alignof(char); + +// CHECK: @align_s = global i32 2 +int align_s = __alignof(short); + +// CHECK: @align_i = global i32 4 +int align_i = __alignof(int); + +// CHECK: @align_l = global i32 4 +int align_l = __alignof(long); + +// CHECK: @align_ll = global i32 8 +int align_ll = __alignof(long long); + +// CHECK: @align_p = global i32 4 +int align_p = __alignof(void*); + +// CHECK: @align_vl = global i32 4 +int align_vl = __alignof(va_list); + +// Check types + +// CHECK: signext i8 @check_char() +char check_char() { return 0; } + +// CHECK: signext i16 @check_short() +short check_short() { return 0; } + +// CHECK: i32 @check_int() +int check_int() { return 0; } + +// CHECK: i32 @check_long() +long check_long() { return 0; } + +// CHECK: i64 @check_longlong() +long long check_longlong() { return 0; } + +// CHECK: zeroext i8 @check_uchar() +unsigned char check_uchar() { return 0; } + +// CHECK: zeroext i16 @check_ushort() +unsigned short check_ushort() { return 0; } + +// CHECK: i32 @check_uint() +unsigned int check_uint() { return 0; } + +// CHECK: i32 @check_ulong() +unsigned long check_ulong() { return 0; } + +// CHECK: i64 @check_ulonglong() +unsigned long long check_ulonglong() { return 0; } + +// CHECK: i32 @check_size_t() +size_t check_size_t() { return 0; } + +} + +template void Switch(); +template<> void Switch<4>(); +template<> void Switch<8>(); +template<> void Switch<16>(); + +void check_pointer_size() { + // CHECK: SwitchILi4 + Switch(); + + // CHECK: SwitchILi8 + Switch(); + + // CHECK: SwitchILi4 + Switch(); +} Index: cfe/trunk/test/Preprocessor/init.c =================================================================== --- cfe/trunk/test/Preprocessor/init.c +++ cfe/trunk/test/Preprocessor/init.c @@ -8414,6 +8414,9 @@ // RUN: %clang_cc1 -triple arm-linux-androideabi -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix ANDROID %s // ANDROID:#define __ANDROID__ 1 // +// RUN: %clang_cc1 -triple lanai-unknown-unknown -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix LANAI %s +// LANAI: #define __lanai__ 1 +// // RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-unknown-freebsd < /dev/null | FileCheck -match-full-lines -check-prefix PPC64-FREEBSD %s // PPC64-FREEBSD-NOT: #define __LONG_DOUBLE_128__ 1 //