From 9ed63f8b87b1f7d074d21cc1210fd28d93291bea Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Thu, 6 Sep 2012 17:37:28 +0000 Subject: [PATCH] Use custom ABIInfo for le32/PNaCl argument codegen This patch uses a new ABIInfo implementation specific to the le32 target, rather than falling back to DefaultABIInfo. Its behavior is basically the same, but it also allows the regparm argument attribute. It also includes basic tests for argument codegen and attributes. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163333 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/TargetInfo.cpp | 86 +++++++++++++++++++++++++++++++++++ test/CodeGen/le32-arguments.c | 61 +++++++++++++++++++++++++ test/CodeGen/le32-regparm.c | 41 +++++++++++++++++ 3 files changed, 188 insertions(+) create mode 100644 test/CodeGen/le32-arguments.c create mode 100644 test/CodeGen/le32-regparm.c diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index bbffc9ea92..909a6e858b 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -389,6 +389,90 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const { ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } +//===----------------------------------------------------------------------===// +// le32/PNaCl bitcode ABI Implementation +//===----------------------------------------------------------------------===// + +class PNaClABIInfo : public ABIInfo { + public: + PNaClABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {} + + ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType RetTy, unsigned &FreeRegs) const; + + virtual void computeInfo(CGFunctionInfo &FI) const; + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; +}; + +class PNaClTargetCodeGenInfo : public TargetCodeGenInfo { + public: + PNaClTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) + : TargetCodeGenInfo(new PNaClABIInfo(CGT)) {} +}; + +void PNaClABIInfo::computeInfo(CGFunctionInfo &FI) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + + unsigned FreeRegs = FI.getHasRegParm() ? FI.getRegParm() : 0; + + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) + it->info = classifyArgumentType(it->type, FreeRegs); + } + +llvm::Value *PNaClABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + return 0; +} + +ABIArgInfo PNaClABIInfo::classifyArgumentType(QualType Ty, + unsigned &FreeRegs) const { + if (isAggregateTypeForABI(Ty)) { + // Records with non trivial destructors/constructors should not be passed + // by value. + FreeRegs = 0; + if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) + return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + + return ABIArgInfo::getIndirect(0); + } + + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs()) + Ty = EnumTy->getDecl()->getIntegerType(); + + ABIArgInfo BaseInfo = (Ty->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + + // Regparm regs hold 32 bits. + unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32; + if (SizeInRegs == 0) return BaseInfo; + if (SizeInRegs > FreeRegs) { + FreeRegs = 0; + return BaseInfo; + } + FreeRegs -= SizeInRegs; + return BaseInfo.isDirect() ? + ABIArgInfo::getDirectInReg(BaseInfo.getCoerceToType()) : + ABIArgInfo::getExtendInReg(BaseInfo.getCoerceToType()); +} + +ABIArgInfo PNaClABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isVoidType()) + return ABIArgInfo::getIgnore(); + + if (isAggregateTypeForABI(RetTy)) + return ABIArgInfo::getIndirect(0); + + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = RetTy->getAs()) + RetTy = EnumTy->getDecl()->getIntegerType(); + + return (RetTy->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); +} + /// UseX86_MMXType - Return true if this is an MMX type that should use the /// special x86_mmx type. bool UseX86_MMXType(llvm::Type *IRType) { @@ -3768,6 +3852,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { default: return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo(Types)); + case llvm::Triple::le32: + return *(TheTargetCodeGenInfo = new PNaClTargetCodeGenInfo(Types)); case llvm::Triple::mips: case llvm::Triple::mipsel: return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, true)); diff --git a/test/CodeGen/le32-arguments.c b/test/CodeGen/le32-arguments.c new file mode 100644 index 0000000000..2cbbc0fbea --- /dev/null +++ b/test/CodeGen/le32-arguments.c @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 -triple le32-unknown-nacl %s -emit-llvm -o - | FileCheck %s + +// Basic argument/attribute tests for le32/PNaCl + +// CHECK: define void @f0(i32 %i, i32 %j, double %k) +void f0(int i, long j, double k) {} + +typedef struct { + int aa; + int bb; +} s1; +// Structs should be passed byval and not split up +// CHECK: define void @f1(%struct.s1* byval %i) +void f1(s1 i) {} + +typedef struct { + int cc; +} s2; +// Structs should be returned sret and not simplified by the frontend +// CHECK: define void @f2(%struct.s2* noalias sret %agg.result) +s2 f2() { + s2 foo; + return foo; +} + +// CHECK: define void @f3(i64 %i) +void f3(long long i) {} + +// i8/i16 should be signext, i32 and higher should not +// CHECK: define void @f4(i8 signext %a, i16 signext %b) +void f4(char a, short b) {} + +// CHECK: define void @f5(i8 zeroext %a, i16 zeroext %b) +void f5(unsigned char a, unsigned short b) {} + + +enum my_enum { + ENUM1, + ENUM2, + ENUM3, +}; +// Enums should be treated as the underlying i32 +// CHECK: define void @f6(i32 %a) +void f6(enum my_enum a) {} + +union simple_union { + int a; + char b; +}; +// Unions should be passed as byval structs +// CHECK: define void @f7(%union.simple_union* byval %s) +void f7(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 @f8(%struct.bitfield1* byval %bf1) +void f8(bitfield1 bf1) {} diff --git a/test/CodeGen/le32-regparm.c b/test/CodeGen/le32-regparm.c new file mode 100644 index 0000000000..6ab5a11106 --- /dev/null +++ b/test/CodeGen/le32-regparm.c @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -triple le32-unknown-nacl %s -emit-llvm -o - | FileCheck %s + +#define FASTCALL __attribute__((regparm(2))) + +typedef struct { + int aaa; + double bbbb; + int ccc[200]; +} foo; + +// 2 inreg arguments are supported. +void FASTCALL f1(int i, int j, int k); +// CHECK: define void @f1(i32 inreg %i, i32 inreg %j, i32 %k) +void f1(int i, int j, int k) { } + +// inreg structs are not supported. +// CHECK: define void @f2(%struct.foo* inreg %a) +void __attribute__((regparm(1))) f2(foo* a) {} + +// Only the first 2 arguments can be passed inreg, and the first +// non-integral type consumes remaining available registers. +// CHECK: define void @f3(%struct.foo* byval %a, i32 %b) +void __attribute__((regparm(2))) f3(foo a, int b) {} + +// Only 64 total bits are supported +// CHECK: define void @f4(i64 inreg %g, i32 %h) +void __attribute__((regparm(2))) f4(long long g, int h) {} + +typedef void (*FType)(int, int) __attribute ((regparm (2))); +FType bar; +extern void FASTCALL reduced(char b, double c, foo* d, double e, int f); + +int +main(void) { + // The presence of double c means that foo* d is not passed inreg. This + // behavior is different from current x86-32 behavior + // CHECK: call void @reduced(i8 signext inreg 0, {{.*}} %struct.foo* null + reduced(0, 0.0, 0, 0.0, 0); + // CHECK: call void {{.*}}(i32 inreg 1, i32 inreg 2) + bar(1,2); +} -- 2.40.0