Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -5851,6 +5851,114 @@ #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 Builtin::Info BuiltinInfo[]; + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char *const GCCRegNames[]; + bool SoftFloat; + + public: + LanaiTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { + // Description string has to be kept in sync with backend. + DataLayoutString = + "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; + default: + 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); + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + ArrayRef getGCCRegNames() const override; + ArrayRef getGCCRegAliases() const override; + + 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[]; @@ -7543,6 +7651,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: lib/CodeGen/TargetInfo.cpp =================================================================== --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -19,6 +19,7 @@ #include "CodeGenFunction.h" #include "clang/AST/RecordLayout.h" #include "clang/CodeGen/CGFunctionInfo.h" +#include "clang/Driver/DriverDiagnostic.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" @@ -6488,6 +6489,107 @@ } //===----------------------------------------------------------------------===// +// Lanai ABI Implementation +//===----------------------------------------------------------------------===// + +class LanaiABIInfo : public DefaultABIInfo { + enum Class { Integer, Float }; + + Class classify(QualType Ty) const; + +public: + LanaiABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} + + static bool isRegisterSize(unsigned Size) { + return (Size == 8 || Size == 16 || Size == 32); + } + + 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; +}; + +LanaiABIInfo::Class LanaiABIInfo::classify(QualType Ty) const { + const Type *T = isSingleElementStruct(Ty, getContext()); + if (T == nullptr) + T = Ty.getTypePtr(); + + if (const BuiltinType *BT = T->getAs()) { + BuiltinType::Kind K = BT->getKind(); + if (K == BuiltinType::Float || K == BuiltinType::Double) + return Float; + } + return Integer; +} + +bool LanaiABIInfo::shouldUseInReg(QualType Ty, CCState &State) const { + Class C = classify(Ty); + if (C == Float) + return false; + + unsigned Size = getContext().getTypeSize(Ty); + unsigned SizeInRegs = (Size + 31) / 32; + + 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 EnumType *EnumTy = Ty->getAs()) + Ty = EnumTy->getDecl()->getIntegerType(); + + bool InReg = shouldUseInReg(Ty, State); + if (Ty->isPromotableIntegerType()) { + if (InReg) { + return ABIArgInfo::getDirectInReg(); + } + return ABIArgInfo::getExtend(); + } + if (InReg) + return ABIArgInfo::getDirectInReg(); + + return ABIArgInfo::getDirect(); +} + +namespace { +class LanaiTargetCodeGenInfo : public TargetCodeGenInfo { +public: + LanaiTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) + : TargetCodeGenInfo(new LanaiABIInfo(CGT)) {} +}; +} + +//===----------------------------------------------------------------------===// // AMDGPU ABI Implementation //===----------------------------------------------------------------------===// @@ -7600,6 +7702,16 @@ } case llvm::Triple::hexagon: return *(TheTargetCodeGenInfo = new HexagonTargetCodeGenInfo(Types)); + case llvm::Triple::lanai: + // Allow compiling with mregparm unset (NumRegisterParameters is 0) or + // mregparm=4. + if (CodeGenOpts.NumRegisterParameters == 0 || + CodeGenOpts.NumRegisterParameters == 4) { + return *(TheTargetCodeGenInfo = new LanaiTargetCodeGenInfo(Types)); + } else { + getDiags().Report(diag::err_drv_unsupported_opt_for_target) << "-mregparm" + << "lanai"; + } case llvm::Triple::r600: return *(TheTargetCodeGenInfo = new AMDGPUTargetCodeGenInfo(Types)); case llvm::Triple::amdgcn: Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ lib/Driver/Driver.cpp @@ -2344,6 +2344,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: lib/Driver/ToolChains.h =================================================================== --- lib/Driver/ToolChains.h +++ lib/Driver/ToolChains.h @@ -867,6 +867,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: lib/Driver/Tools.h =================================================================== --- lib/Driver/Tools.h +++ 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: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -1555,6 +1555,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(); @@ -1772,6 +1779,9 @@ return "hexagon" + toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str(); + case llvm::Triple::lanai: + return getLanaiTargetCPU(Args); + case llvm::Triple::systemz: return getSystemZTargetCPU(Args); @@ -2081,6 +2091,16 @@ 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)); + } +} + void Clang::AddWebAssemblyTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Default to "hidden" visibility. @@ -4093,6 +4113,10 @@ AddX86TargetArgs(Args, CmdArgs); break; + case llvm::Triple::lanai: + AddLanaiTargetArgs(Args, CmdArgs); + break; + case llvm::Triple::hexagon: AddHexagonTargetArgs(Args, CmdArgs); break; Index: test/CodeGen/lanai-arguments.c =================================================================== --- test/CodeGen/lanai-arguments.c +++ test/CodeGen/lanai-arguments.c @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 -triple wasm32-unknown-unknown %s -emit-llvm -o - \ +// RUN: | FileCheck %s -check-prefix=LANAI + +// Basic argument/attribute tests for Lanai. + +// LANAI: define void @f0(i32 %i, i32 %j, i64 %k) +void f0(int i, long j, long long k) {} + +typedef struct { + int aa; + int bb; +} s1; +// LANAI: define void @f1(%struct.s1* byval align 4 %i) +void f1(s1 i) {} + +typedef struct { + int cc; +} s2; +// LANAI: define i32 @f2() +s2 f2() { + s2 foo; + return foo; +} + +typedef struct { + int cc; + int dd; +} s3; +// LANAI: define void @f3(%struct.s3* noalias sret %agg.result) +s3 f3() { + s3 foo; + return foo; +} + +// LANAI: define void @f4(i64 %i) +void f4(long long i) {} + +// LANAI: define void @f5(i8 signext %a, i16 signext %b) +void f5(char a, short b) {} + +// LANAI: define void @f6(i8 zeroext %a, i16 zeroext %b) +void f6(unsigned char a, unsigned short b) {} + +enum my_enum { + ENUM1, + ENUM2, + ENUM3, +}; +// Enums should be treated as the underlying i32. +// LANAI: define void @f7(i32 %a) +void f7(enum my_enum a) {} + +enum my_big_enum { + ENUM4 = 0xFFFFFFFFFFFFFFFF, +}; +// Big enums should be treated as the underlying i64. +// LANAI: define void @f8(i64 %a) +void f8(enum my_big_enum a) {} + +union simple_union { + int a; + char b; +}; +// Unions should be passed as byval structs. +// LANAI: 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. +// LANAI: define void @f10(%struct.bitfield1* byval align 4 %bf1) +void f10(bitfield1 bf1) {} Index: test/CodeGen/lanai-regparm.c =================================================================== --- test/CodeGen/lanai-regparm.c +++ 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: test/CodeGen/target-data.c =================================================================== --- test/CodeGen/target-data.c +++ 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: test/Driver/lanai-toolchain.c =================================================================== --- test/Driver/lanai-toolchain.c +++ 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: test/Driver/lanai-unknown-unknown.cpp =================================================================== --- test/Driver/lanai-unknown-unknown.cpp +++ 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: test/Preprocessor/init.c =================================================================== --- test/Preprocessor/init.c +++ test/Preprocessor/init.c @@ -8412,6 +8412,9 @@ // RUN: %clang_cc1 -triple arm-linux-androideabi -E -dM < /dev/null | FileCheck -check-prefix ANDROID %s // ANDROID: __ANDROID__ 1 // +// RUN: %clang_cc1 -triple lanai-unknown-unknown -E -dM < /dev/null | FileCheck -check-prefix LANAI %s +// LANAI: __lanai__ 1 +// // RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-unknown-freebsd < /dev/null | FileCheck -check-prefix PPC64-FREEBSD %s // PPC64-FREEBSD-NOT: #define __LONG_DOUBLE_128__ 1 //