[cfe-commits] r161022 - in /cfe/trunk: lib/CodeGen/ABIInfo.h lib/CodeGen/CGCall.cpp lib/CodeGen/TargetInfo.cpp test/CodeGen/regparm-struct.c test/CodeGenCXX/pr13396.cpp
Rafael Espindola
rafael.espindola at gmail.com
Mon Jul 30 19:44:24 PDT 2012
Author: rafael
Date: Mon Jul 30 21:44:24 2012
New Revision: 161022
URL: http://llvm.org/viewvc/llvm-project?rev=161022&view=rev
Log:
Handle functions with struct arguments or return types and the regparm
attribute. It is a variation of the x86_64 ABI:
* A struct returned indirectly uses the first register argument to pass the
pointer.
* Floats, Doubles and structs containing only one of them are not passed in
registers.
* Other structs are split into registers if they fit on the remaining ones.
Otherwise they are passed in memory.
* When a struct doesn't fit it still consumes the registers.
Added:
cfe/trunk/test/CodeGen/regparm-struct.c
Modified:
cfe/trunk/lib/CodeGen/ABIInfo.h
cfe/trunk/lib/CodeGen/CGCall.cpp
cfe/trunk/lib/CodeGen/TargetInfo.cpp
cfe/trunk/test/CodeGenCXX/pr13396.cpp
Modified: cfe/trunk/lib/CodeGen/ABIInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ABIInfo.h?rev=161022&r1=161021&r2=161022&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ABIInfo.h (original)
+++ cfe/trunk/lib/CodeGen/ABIInfo.h Mon Jul 30 21:44:24 2012
@@ -74,31 +74,42 @@
unsigned UIntData;
bool BoolData0;
bool BoolData1;
+ bool InReg;
- ABIArgInfo(Kind K, llvm::Type *TD, unsigned UI, bool B0, bool B1,
+ ABIArgInfo(Kind K, llvm::Type *TD, unsigned UI, bool B0, bool B1, bool IR,
llvm::Type* P)
: TheKind(K), TypeData(TD), PaddingType(P), UIntData(UI), BoolData0(B0),
- BoolData1(B1) {}
+ BoolData1(B1), InReg(IR) {}
public:
ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {}
static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0,
llvm::Type *Padding = 0) {
- return ABIArgInfo(Direct, T, Offset, false, false, Padding);
+ return ABIArgInfo(Direct, T, Offset, false, false, false, Padding);
+ }
+ static ABIArgInfo getDirectInReg(llvm::Type *T) {
+ return ABIArgInfo(Direct, T, 0, false, false, true, 0);
}
static ABIArgInfo getExtend(llvm::Type *T = 0) {
- return ABIArgInfo(Extend, T, 0, false, false, 0);
+ return ABIArgInfo(Extend, T, 0, false, false, false, 0);
+ }
+ static ABIArgInfo getExtendInReg(llvm::Type *T = 0) {
+ return ABIArgInfo(Extend, T, 0, false, false, true, 0);
}
static ABIArgInfo getIgnore() {
- return ABIArgInfo(Ignore, 0, 0, false, false, 0);
+ return ABIArgInfo(Ignore, 0, 0, false, false, false, 0);
}
static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true
, bool Realign = false) {
- return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, 0);
+ return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, 0);
+ }
+ static ABIArgInfo getIndirectInReg(unsigned Alignment, bool ByVal = true
+ , bool Realign = false) {
+ return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, true, 0);
}
static ABIArgInfo getExpand() {
- return ABIArgInfo(Expand, 0, 0, false, false, 0);
+ return ABIArgInfo(Expand, 0, 0, false, false, false, 0);
}
Kind getKind() const { return TheKind; }
@@ -132,6 +143,11 @@
TypeData = T;
}
+ bool getInReg() const {
+ assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!");
+ return InReg;
+ }
+
// Indirect accessors
unsigned getIndirectAlign() const {
assert(TheKind == Indirect && "Invalid kind!");
Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=161022&r1=161021&r2=161022&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Mon Jul 30 21:44:24 2012
@@ -983,14 +983,18 @@
case ABIArgInfo::Ignore:
break;
- case ABIArgInfo::Indirect:
- PAL.push_back(llvm::AttributeWithIndex::get(Index,
- llvm::Attribute::StructRet));
+ case ABIArgInfo::Indirect: {
+ llvm::Attributes SRETAttrs = llvm::Attribute::StructRet;
+ if (RetAI.getInReg())
+ SRETAttrs |= llvm::Attribute::InReg;
+ PAL.push_back(llvm::AttributeWithIndex::get(Index, SRETAttrs));
+
++Index;
// sret disables readnone and readonly
FuncAttrs &= ~(llvm::Attribute::ReadOnly |
llvm::Attribute::ReadNone);
break;
+ }
case ABIArgInfo::Expand:
llvm_unreachable("Invalid ABI kind for return argument");
@@ -999,14 +1003,6 @@
if (RetAttrs)
PAL.push_back(llvm::AttributeWithIndex::get(0, RetAttrs));
- // FIXME: RegParm should be reduced in case of global register variable.
- signed RegParm;
- if (FI.getHasRegParm())
- RegParm = FI.getRegParm();
- else
- RegParm = CodeGenOpts.NumRegisterParameters;
-
- unsigned PointerWidth = getContext().getTargetInfo().getPointerWidth(0);
for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
ie = FI.arg_end(); it != ie; ++it) {
QualType ParamType = it->type;
@@ -1024,22 +1020,22 @@
Attrs |= llvm::Attribute::ZExt;
// FALL THROUGH
case ABIArgInfo::Direct:
- if (RegParm > 0 &&
- (ParamType->isIntegerType() || ParamType->isPointerType() ||
- ParamType->isReferenceType())) {
- RegParm -=
- (Context.getTypeSize(ParamType) + PointerWidth - 1) / PointerWidth;
- if (RegParm >= 0)
+ if (AI.getInReg())
Attrs |= llvm::Attribute::InReg;
- }
+
// FIXME: handle sseregparm someday...
// Increment Index if there is padding.
Index += (AI.getPaddingType() != 0);
if (llvm::StructType *STy =
- dyn_cast<llvm::StructType>(AI.getCoerceToType()))
- Index += STy->getNumElements()-1; // 1 will be added below.
+ dyn_cast<llvm::StructType>(AI.getCoerceToType())) {
+ unsigned Extra = STy->getNumElements()-1; // 1 will be added below.
+ if (Attrs != llvm::Attribute::None)
+ for (unsigned I = 0; I < Extra; ++I)
+ PAL.push_back(llvm::AttributeWithIndex::get(Index + I, Attrs));
+ Index += Extra;
+ }
break;
case ABIArgInfo::Indirect:
Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=161022&r1=161021&r2=161022&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Mon Jul 30 21:44:24 2012
@@ -413,12 +413,18 @@
/// X86_32ABIInfo - The X86-32 ABI information.
class X86_32ABIInfo : public ABIInfo {
+ enum Class {
+ Integer,
+ Float
+ };
+
static const unsigned MinABIStackAlignInBytes = 4;
bool IsDarwinVectorABI;
bool IsSmallStructInRegABI;
bool IsMMXDisabled;
bool IsWin32FloatStructABI;
+ unsigned DefaultNumRegisterParameters;
static bool isRegisterSize(unsigned Size) {
return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
@@ -434,8 +440,11 @@
/// \brief Return the alignment to use for the given type on the stack.
unsigned getTypeStackAlignInBytes(QualType Ty, unsigned Align) const;
+ Class classify(QualType Ty) const;
ABIArgInfo classifyReturnType(QualType RetTy,
unsigned callingConvention) const;
+ ABIArgInfo classifyArgumentTypeWithReg(QualType RetTy,
+ unsigned &FreeRegs) const;
ABIArgInfo classifyArgumentType(QualType RetTy) const;
public:
@@ -444,16 +453,18 @@
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const;
- X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p, bool m, bool w)
+ X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p, bool m, bool w,
+ unsigned r)
: ABIInfo(CGT), IsDarwinVectorABI(d), IsSmallStructInRegABI(p),
- IsMMXDisabled(m), IsWin32FloatStructABI(w) {}
+ IsMMXDisabled(m), IsWin32FloatStructABI(w),
+ DefaultNumRegisterParameters(r) {}
};
class X86_32TargetCodeGenInfo : public TargetCodeGenInfo {
public:
X86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT,
- bool d, bool p, bool m, bool w)
- :TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p, m, w)) {}
+ bool d, bool p, bool m, bool w, unsigned r)
+ :TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p, m, w, r)) {}
void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &CGM) const;
@@ -690,6 +701,57 @@
return ABIArgInfo::getIndirect(StackAlign);
}
+X86_32ABIInfo::Class X86_32ABIInfo::classify(QualType Ty) const {
+ const Type *T = isSingleElementStruct(Ty, getContext());
+ if (!T)
+ T = Ty.getTypePtr();
+
+ if (const BuiltinType *BT = T->getAs<BuiltinType>()) {
+ BuiltinType::Kind K = BT->getKind();
+ if (K == BuiltinType::Float || K == BuiltinType::Double)
+ return Float;
+ }
+ return Integer;
+}
+
+ABIArgInfo
+X86_32ABIInfo::classifyArgumentTypeWithReg(QualType Ty,
+ unsigned &FreeRegs) const {
+ // Common case first.
+ if (FreeRegs == 0)
+ return classifyArgumentType(Ty);
+
+ Class C = classify(Ty);
+ if (C == Float)
+ return classifyArgumentType(Ty);
+
+ unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32;
+ if (SizeInRegs == 0)
+ return classifyArgumentType(Ty);
+
+ if (SizeInRegs > FreeRegs) {
+ FreeRegs = 0;
+ return classifyArgumentType(Ty);
+ }
+ assert(SizeInRegs >= 1 && SizeInRegs <= 3);
+ FreeRegs -= SizeInRegs;
+
+ // If it is a simple scalar, keep the type so that we produce a cleaner IR.
+ ABIArgInfo Foo = classifyArgumentType(Ty);
+ if (Foo.isDirect() && !Foo.getDirectOffset() && !Foo.getPaddingType())
+ return ABIArgInfo::getDirectInReg(Foo.getCoerceToType());
+ if (Foo.isExtend())
+ return ABIArgInfo::getExtendInReg(Foo.getCoerceToType());
+
+ llvm::LLVMContext &LLVMContext = getVMContext();
+ llvm::Type *Int32 = llvm::Type::getInt32Ty(LLVMContext);
+ SmallVector<llvm::Type*, 3> Elements;
+ for (unsigned I = 0; I < SizeInRegs; ++I)
+ Elements.push_back(Int32);
+ llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
+ return ABIArgInfo::getDirectInReg(Result);
+}
+
ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const {
// FIXME: Set alignment on indirect arguments.
if (isAggregateTypeForABI(Ty)) {
@@ -754,9 +816,23 @@
void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
FI.getCallingConvention());
+
+ unsigned FreeRegs = FI.getHasRegParm() ? FI.getRegParm() :
+ DefaultNumRegisterParameters;
+
+ // If the return value is indirect, then the hidden argument is consuming one
+ // integer register.
+ if (FI.getReturnInfo().isIndirect() && FreeRegs) {
+ --FreeRegs;
+ ABIArgInfo &Old = FI.getReturnInfo();
+ Old = ABIArgInfo::getIndirectInReg(Old.getIndirectAlign(),
+ Old.getIndirectByVal(),
+ Old.getIndirectRealign());
+ }
+
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
it != ie; ++it)
- it->info = classifyArgumentType(it->type);
+ it->info = classifyArgumentTypeWithReg(it->type, FreeRegs);
}
llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
@@ -3735,8 +3811,8 @@
if (Triple.isOSDarwin())
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(
- Types, true, true, DisableMMX, false));
+ new X86_32TargetCodeGenInfo(Types, true, true, DisableMMX, false,
+ CodeGenOpts.NumRegisterParameters));
switch (Triple.getOS()) {
case llvm::Triple::Cygwin:
@@ -3746,18 +3822,20 @@
case llvm::Triple::FreeBSD:
case llvm::Triple::OpenBSD:
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(
- Types, false, true, DisableMMX, false));
+ new X86_32TargetCodeGenInfo(Types, false, true, DisableMMX,
+ false,
+ CodeGenOpts.NumRegisterParameters));
case llvm::Triple::Win32:
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(
- Types, false, true, DisableMMX, true));
+ new X86_32TargetCodeGenInfo(Types, false, true, DisableMMX, true,
+ CodeGenOpts.NumRegisterParameters));
default:
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(
- Types, false, false, DisableMMX, false));
+ new X86_32TargetCodeGenInfo(Types, false, false, DisableMMX,
+ false,
+ CodeGenOpts.NumRegisterParameters));
}
}
Added: cfe/trunk/test/CodeGen/regparm-struct.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/regparm-struct.c?rev=161022&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/regparm-struct.c (added)
+++ cfe/trunk/test/CodeGen/regparm-struct.c Mon Jul 30 21:44:24 2012
@@ -0,0 +1,177 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
+
+__attribute__((regparm(3))) void f1(int a, int b, int c, int d);
+// CHECK: declare void @f1(i32 inreg, i32 inreg, i32 inreg, i32)
+void g1() {
+ f1(41, 42, 43, 44);
+}
+
+struct s1 {
+ int x1;
+};
+__attribute__((regparm(3))) void f2(int a, int b, struct s1 c, int d);
+// CHECK: declare void @f2(i32 inreg, i32 inreg, i32 inreg, i32)
+void g2() {
+ struct s1 x = {43};
+ f2(41, 42, x, 44);
+}
+
+struct s2 {
+ int x1;
+ int x2;
+};
+__attribute__((regparm(3))) void f3(int a, int b, struct s2 c, int d);
+// CHECK: declare void @f3(i32 inreg, i32 inreg, i32, i32, i32)
+void g3() {
+ struct s2 x = {43, 44};
+ f3(41, 42, x, 45);
+}
+__attribute__((regparm(3))) void f4(int a, struct s2 b, int c);
+// CHECK: declare void @f4(i32 inreg, i32 inreg, i32 inreg, i32)
+void g4() {
+ struct s2 x = {42, 43};
+ f4(41, x, 44);
+}
+
+struct s3 {
+ int x1;
+ int x2;
+ int x3;
+};
+__attribute__((regparm(3))) void f5(int a, struct s3 b, int c);
+// CHECK: declare void @f5(i32 inreg, i32, i32, i32, i32)
+void g5() {
+ struct s3 x = {42, 43, 44};
+ f5(41, x, 45);
+}
+__attribute__((regparm(3))) void f6(struct s3 a, int b);
+// CHECK: declare void @f6(i32 inreg, i32 inreg, i32 inreg, i32)
+void g6() {
+ struct s3 x = {41, 42, 43};
+ f6(x, 44);
+}
+
+struct s4 {
+ int x1;
+ int x2;
+ int x3;
+ int x4;
+};
+__attribute__((regparm(3))) void f7(struct s4 a, int b);
+// CHECK: declare void @f7(i32, i32, i32, i32, i32)
+void g7() {
+ struct s4 x = {41, 42, 43, 44};
+ f7(x, 45);
+}
+
+__attribute__((regparm(3))) void f8(float a, int b);
+// CHECK: declare void @f8(float, i32 inreg)
+void g8(void) {
+ f8(41, 42);
+}
+
+struct s5 {
+ float x1;
+};
+__attribute__((regparm(3))) void f9(struct s5 a, int b);
+// CHECK: declare void @f9(float, i32 inreg)
+void g9(void) {
+ struct s5 x = {41};
+ f9(x, 42);
+}
+
+struct s6 {
+ float x1;
+ int x2;
+};
+__attribute__((regparm(3))) void f10(struct s6 a, int b);
+// CHECK: declare void @f10(i32 inreg, i32 inreg, i32 inreg)
+void g10(void) {
+ struct s6 x = {41, 42};
+ f10(x, 43);
+}
+
+struct s7 {
+ float x1;
+ int x2;
+ float x3;
+};
+__attribute__((regparm(3))) void f11(struct s7 a, int b);
+// CHECK: declare void @f11(i32 inreg, i32 inreg, i32 inreg, i32)
+void g11(void) {
+ struct s7 x = {41, 42, 43};
+ f11(x, 44);
+}
+
+struct s8 {
+ float x1;
+ float x2;
+};
+__attribute__((regparm(3))) void f12(struct s8 a, int b);
+// CHECK: declare void @f12(i32 inreg, i32 inreg, i32 inreg)
+void g12(void) {
+ struct s8 x = {41, 42};
+ f12(x, 43);
+}
+
+struct s9 {
+ float x1;
+ float x2;
+ float x3;
+};
+__attribute__((regparm(3))) void f13(struct s9 a, int b);
+// CHECK: declare void @f13(i32 inreg, i32 inreg, i32 inreg, i32)
+void g13(void) {
+ struct s9 x = {41, 42, 43};
+ f13(x, 44);
+}
+
+struct s10 {
+ double x1;
+};
+__attribute__((regparm(3))) void f14(struct s10 a, int b, int c);
+// CHECK: declare void @f14(double, i32 inreg, i32 inreg)
+void g14(void) {
+ struct s10 x = { 41 };
+ f14(x, 42, 43);
+}
+
+struct s11 {
+ double x1;
+ double x2;
+};
+__attribute__((regparm(3))) void f15(struct s11 a, int b);
+// CHECK: declare void @f15(double, double, i32)
+void g15(void) {
+ struct s11 x = { 41, 42 };
+ f15(x, 43);
+}
+
+struct s12 {
+ double x1;
+ float x2;
+};
+__attribute__((regparm(3))) void f16(struct s12 a, int b);
+// CHECK: declare void @f16(i32 inreg, i32 inreg, i32 inreg, i32)
+void g16(void) {
+ struct s12 x = { 41, 42 };
+ f16(x, 43);
+}
+
+__attribute__((regparm(3))) struct s12 f17(int a, int b, int c);
+// CHECK: declare void @f17(%struct.s12* inreg sret, i32 inreg, i32 inreg, i32)
+void g17(void) {
+ f17(41, 42, 43);
+}
+
+struct s13 {
+ struct inner {
+ float x;
+ } y;
+};
+__attribute__((regparm(3))) void f18(struct s13 a, int b, int c, int d);
+// CHECK: declare void @f18(%struct.s13* byval align 4, i32 inreg, i32 inreg, i32 inreg)
+void g18(void) {
+ struct s13 x = {{41}};
+ f18(x, 42, 43, 44);
+}
Modified: cfe/trunk/test/CodeGenCXX/pr13396.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/pr13396.cpp?rev=161022&r1=161021&r2=161022&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/pr13396.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/pr13396.cpp Mon Jul 30 21:44:24 2012
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu %s -emit-llvm -o - | FileCheck %s
struct foo {
template<typename T>
__attribute__ ((regparm (3))) foo(T x) {}
More information about the cfe-commits
mailing list