aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/CodeGen/TargetInfo.cpp86
-rw-r--r--test/CodeGen/le32-arguments.c61
-rw-r--r--test/CodeGen/le32-regparm.c41
3 files changed, 188 insertions, 0 deletions
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<EnumType>())
+ 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<EnumType>())
+ 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);
+}