mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-11 04:06:20 +00:00
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. llvm-svn: 161022
This commit is contained in:
parent
3865c6e670
commit
06b2b4a7c9
@ -74,31 +74,42 @@ namespace clang {
|
|||||||
unsigned UIntData;
|
unsigned UIntData;
|
||||||
bool BoolData0;
|
bool BoolData0;
|
||||||
bool BoolData1;
|
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)
|
llvm::Type* P)
|
||||||
: TheKind(K), TypeData(TD), PaddingType(P), UIntData(UI), BoolData0(B0),
|
: TheKind(K), TypeData(TD), PaddingType(P), UIntData(UI), BoolData0(B0),
|
||||||
BoolData1(B1) {}
|
BoolData1(B1), InReg(IR) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {}
|
ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {}
|
||||||
|
|
||||||
static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0,
|
static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0,
|
||||||
llvm::Type *Padding = 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) {
|
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() {
|
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
|
static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true
|
||||||
, bool Realign = false) {
|
, 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() {
|
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; }
|
Kind getKind() const { return TheKind; }
|
||||||
@ -132,6 +143,11 @@ namespace clang {
|
|||||||
TypeData = T;
|
TypeData = T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool getInReg() const {
|
||||||
|
assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!");
|
||||||
|
return InReg;
|
||||||
|
}
|
||||||
|
|
||||||
// Indirect accessors
|
// Indirect accessors
|
||||||
unsigned getIndirectAlign() const {
|
unsigned getIndirectAlign() const {
|
||||||
assert(TheKind == Indirect && "Invalid kind!");
|
assert(TheKind == Indirect && "Invalid kind!");
|
||||||
|
@ -983,14 +983,18 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
|
|||||||
case ABIArgInfo::Ignore:
|
case ABIArgInfo::Ignore:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ABIArgInfo::Indirect:
|
case ABIArgInfo::Indirect: {
|
||||||
PAL.push_back(llvm::AttributeWithIndex::get(Index,
|
llvm::Attributes SRETAttrs = llvm::Attribute::StructRet;
|
||||||
llvm::Attribute::StructRet));
|
if (RetAI.getInReg())
|
||||||
|
SRETAttrs |= llvm::Attribute::InReg;
|
||||||
|
PAL.push_back(llvm::AttributeWithIndex::get(Index, SRETAttrs));
|
||||||
|
|
||||||
++Index;
|
++Index;
|
||||||
// sret disables readnone and readonly
|
// sret disables readnone and readonly
|
||||||
FuncAttrs &= ~(llvm::Attribute::ReadOnly |
|
FuncAttrs &= ~(llvm::Attribute::ReadOnly |
|
||||||
llvm::Attribute::ReadNone);
|
llvm::Attribute::ReadNone);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ABIArgInfo::Expand:
|
case ABIArgInfo::Expand:
|
||||||
llvm_unreachable("Invalid ABI kind for return argument");
|
llvm_unreachable("Invalid ABI kind for return argument");
|
||||||
@ -999,14 +1003,6 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
|
|||||||
if (RetAttrs)
|
if (RetAttrs)
|
||||||
PAL.push_back(llvm::AttributeWithIndex::get(0, 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(),
|
for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
|
||||||
ie = FI.arg_end(); it != ie; ++it) {
|
ie = FI.arg_end(); it != ie; ++it) {
|
||||||
QualType ParamType = it->type;
|
QualType ParamType = it->type;
|
||||||
@ -1024,22 +1020,22 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
|
|||||||
Attrs |= llvm::Attribute::ZExt;
|
Attrs |= llvm::Attribute::ZExt;
|
||||||
// FALL THROUGH
|
// FALL THROUGH
|
||||||
case ABIArgInfo::Direct:
|
case ABIArgInfo::Direct:
|
||||||
if (RegParm > 0 &&
|
if (AI.getInReg())
|
||||||
(ParamType->isIntegerType() || ParamType->isPointerType() ||
|
|
||||||
ParamType->isReferenceType())) {
|
|
||||||
RegParm -=
|
|
||||||
(Context.getTypeSize(ParamType) + PointerWidth - 1) / PointerWidth;
|
|
||||||
if (RegParm >= 0)
|
|
||||||
Attrs |= llvm::Attribute::InReg;
|
Attrs |= llvm::Attribute::InReg;
|
||||||
}
|
|
||||||
// FIXME: handle sseregparm someday...
|
// FIXME: handle sseregparm someday...
|
||||||
|
|
||||||
// Increment Index if there is padding.
|
// Increment Index if there is padding.
|
||||||
Index += (AI.getPaddingType() != 0);
|
Index += (AI.getPaddingType() != 0);
|
||||||
|
|
||||||
if (llvm::StructType *STy =
|
if (llvm::StructType *STy =
|
||||||
dyn_cast<llvm::StructType>(AI.getCoerceToType()))
|
dyn_cast<llvm::StructType>(AI.getCoerceToType())) {
|
||||||
Index += STy->getNumElements()-1; // 1 will be added below.
|
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;
|
break;
|
||||||
|
|
||||||
case ABIArgInfo::Indirect:
|
case ABIArgInfo::Indirect:
|
||||||
|
@ -413,12 +413,18 @@ static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
|
|||||||
|
|
||||||
/// X86_32ABIInfo - The X86-32 ABI information.
|
/// X86_32ABIInfo - The X86-32 ABI information.
|
||||||
class X86_32ABIInfo : public ABIInfo {
|
class X86_32ABIInfo : public ABIInfo {
|
||||||
|
enum Class {
|
||||||
|
Integer,
|
||||||
|
Float
|
||||||
|
};
|
||||||
|
|
||||||
static const unsigned MinABIStackAlignInBytes = 4;
|
static const unsigned MinABIStackAlignInBytes = 4;
|
||||||
|
|
||||||
bool IsDarwinVectorABI;
|
bool IsDarwinVectorABI;
|
||||||
bool IsSmallStructInRegABI;
|
bool IsSmallStructInRegABI;
|
||||||
bool IsMMXDisabled;
|
bool IsMMXDisabled;
|
||||||
bool IsWin32FloatStructABI;
|
bool IsWin32FloatStructABI;
|
||||||
|
unsigned DefaultNumRegisterParameters;
|
||||||
|
|
||||||
static bool isRegisterSize(unsigned Size) {
|
static bool isRegisterSize(unsigned Size) {
|
||||||
return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
|
return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
|
||||||
@ -434,8 +440,11 @@ class X86_32ABIInfo : public ABIInfo {
|
|||||||
/// \brief Return the alignment to use for the given type on the stack.
|
/// \brief Return the alignment to use for the given type on the stack.
|
||||||
unsigned getTypeStackAlignInBytes(QualType Ty, unsigned Align) const;
|
unsigned getTypeStackAlignInBytes(QualType Ty, unsigned Align) const;
|
||||||
|
|
||||||
|
Class classify(QualType Ty) const;
|
||||||
ABIArgInfo classifyReturnType(QualType RetTy,
|
ABIArgInfo classifyReturnType(QualType RetTy,
|
||||||
unsigned callingConvention) const;
|
unsigned callingConvention) const;
|
||||||
|
ABIArgInfo classifyArgumentTypeWithReg(QualType RetTy,
|
||||||
|
unsigned &FreeRegs) const;
|
||||||
ABIArgInfo classifyArgumentType(QualType RetTy) const;
|
ABIArgInfo classifyArgumentType(QualType RetTy) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -444,16 +453,18 @@ public:
|
|||||||
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
|
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
|
||||||
CodeGenFunction &CGF) const;
|
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),
|
: ABIInfo(CGT), IsDarwinVectorABI(d), IsSmallStructInRegABI(p),
|
||||||
IsMMXDisabled(m), IsWin32FloatStructABI(w) {}
|
IsMMXDisabled(m), IsWin32FloatStructABI(w),
|
||||||
|
DefaultNumRegisterParameters(r) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class X86_32TargetCodeGenInfo : public TargetCodeGenInfo {
|
class X86_32TargetCodeGenInfo : public TargetCodeGenInfo {
|
||||||
public:
|
public:
|
||||||
X86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT,
|
X86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT,
|
||||||
bool d, bool p, bool m, bool w)
|
bool d, bool p, bool m, bool w, unsigned r)
|
||||||
:TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p, m, w)) {}
|
:TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p, m, w, r)) {}
|
||||||
|
|
||||||
void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
|
void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
|
||||||
CodeGen::CodeGenModule &CGM) const;
|
CodeGen::CodeGenModule &CGM) const;
|
||||||
@ -690,6 +701,57 @@ ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal) const {
|
|||||||
return ABIArgInfo::getIndirect(StackAlign);
|
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 {
|
ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const {
|
||||||
// FIXME: Set alignment on indirect arguments.
|
// FIXME: Set alignment on indirect arguments.
|
||||||
if (isAggregateTypeForABI(Ty)) {
|
if (isAggregateTypeForABI(Ty)) {
|
||||||
@ -754,9 +816,23 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const {
|
|||||||
void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
|
void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
|
||||||
FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
|
FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
|
||||||
FI.getCallingConvention());
|
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();
|
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
|
||||||
it != ie; ++it)
|
it != ie; ++it)
|
||||||
it->info = classifyArgumentType(it->type);
|
it->info = classifyArgumentTypeWithReg(it->type, FreeRegs);
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
|
llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
|
||||||
@ -3735,8 +3811,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
|
|||||||
|
|
||||||
if (Triple.isOSDarwin())
|
if (Triple.isOSDarwin())
|
||||||
return *(TheTargetCodeGenInfo =
|
return *(TheTargetCodeGenInfo =
|
||||||
new X86_32TargetCodeGenInfo(
|
new X86_32TargetCodeGenInfo(Types, true, true, DisableMMX, false,
|
||||||
Types, true, true, DisableMMX, false));
|
CodeGenOpts.NumRegisterParameters));
|
||||||
|
|
||||||
switch (Triple.getOS()) {
|
switch (Triple.getOS()) {
|
||||||
case llvm::Triple::Cygwin:
|
case llvm::Triple::Cygwin:
|
||||||
@ -3746,18 +3822,20 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
|
|||||||
case llvm::Triple::FreeBSD:
|
case llvm::Triple::FreeBSD:
|
||||||
case llvm::Triple::OpenBSD:
|
case llvm::Triple::OpenBSD:
|
||||||
return *(TheTargetCodeGenInfo =
|
return *(TheTargetCodeGenInfo =
|
||||||
new X86_32TargetCodeGenInfo(
|
new X86_32TargetCodeGenInfo(Types, false, true, DisableMMX,
|
||||||
Types, false, true, DisableMMX, false));
|
false,
|
||||||
|
CodeGenOpts.NumRegisterParameters));
|
||||||
|
|
||||||
case llvm::Triple::Win32:
|
case llvm::Triple::Win32:
|
||||||
return *(TheTargetCodeGenInfo =
|
return *(TheTargetCodeGenInfo =
|
||||||
new X86_32TargetCodeGenInfo(
|
new X86_32TargetCodeGenInfo(Types, false, true, DisableMMX, true,
|
||||||
Types, false, true, DisableMMX, true));
|
CodeGenOpts.NumRegisterParameters));
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return *(TheTargetCodeGenInfo =
|
return *(TheTargetCodeGenInfo =
|
||||||
new X86_32TargetCodeGenInfo(
|
new X86_32TargetCodeGenInfo(Types, false, false, DisableMMX,
|
||||||
Types, false, false, DisableMMX, false));
|
false,
|
||||||
|
CodeGenOpts.NumRegisterParameters));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
177
clang/test/CodeGen/regparm-struct.c
Normal file
177
clang/test/CodeGen/regparm-struct.c
Normal file
@ -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);
|
||||||
|
}
|
@ -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 {
|
struct foo {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
__attribute__ ((regparm (3))) foo(T x) {}
|
__attribute__ ((regparm (3))) foo(T x) {}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user