[lanai] Add Lanai backend to clang driver.

Changes to clang to add Lanai backend. Adds a new target, ABI and toolchain.

General Lanai backend discussion on llvm-dev thread "[RFC] Lanai backend" (http://lists.llvm.org/pipermail/llvm-dev/2016-February/095118.html).

Differential Revision: http://reviews.llvm.org/D17002

llvm-svn: 264655
This commit is contained in:
Jacques Pienaar 2016-03-28 21:02:54 +00:00
parent 83c3bd3e59
commit d964cc22d1
12 changed files with 420 additions and 0 deletions

View File

@ -5950,6 +5950,111 @@ const Builtin::Info HexagonTargetInfo::BuiltinInfo[] = {
#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<CPUKind>(Name)
.Case("v11", CK_V11)
.Default(CK_NONE);
return CPU != CK_NONE;
}
bool hasFeature(StringRef Feature) const override {
return llvm::StringSwitch<bool>(Feature).Case("lanai", true).Default(false);
}
ArrayRef<const char *> getGCCRegNames() const override;
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::VoidPtrBuiltinVaList;
}
ArrayRef<Builtin::Info> 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<const char *> 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<TargetInfo::GCCRegAlias> 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 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
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);

View File

@ -6582,6 +6582,78 @@ Address HexagonABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
/*AllowHigherAlign*/ true);
}
//===----------------------------------------------------------------------===//
// 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<EnumType>())
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 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
}
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:

View File

@ -2459,6 +2459,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
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;

View File

@ -874,6 +874,14 @@ private:
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;

View File

@ -1619,6 +1619,13 @@ static std::string getR600TargetGPU(const ArgList &Args) {
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 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T,
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 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args,
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 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
AddX86TargetArgs(Args, CmdArgs);
break;
case llvm::Triple::lanai:
AddLanaiTargetArgs(Args, CmdArgs);
break;
case llvm::Triple::hexagon:
AddHexagonTargetArgs(Args, CmdArgs);
break;

View File

@ -82,6 +82,8 @@ private:
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;

View File

@ -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) {}

View File

@ -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)

View File

@ -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"

View File

@ -0,0 +1,2 @@
// RUN: %clang -target lanai-unknown-unknown -v 2> %t
// RUN: grep 'Target: lanai-unknown-unknown' %t

View File

@ -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<int> void Switch();
template<> void Switch<4>();
template<> void Switch<8>();
template<> void Switch<16>();
void check_pointer_size() {
// CHECK: SwitchILi4
Switch<sizeof(void*)>();
// CHECK: SwitchILi8
Switch<sizeof(long long)>();
// CHECK: SwitchILi4
Switch<sizeof(va_list)>();
}

View File

@ -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
//