From: Rafael Espindola Date: Wed, 24 Oct 2012 01:58:58 +0000 (+0000) Subject: Add inreg markers with the x86_fastcallcc calling convention. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b6932692234eba2472ef85a38434496e9342fd38;p=clang Add inreg markers with the x86_fastcallcc calling convention. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166537 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 6a929a17cc..534c8f685d 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -528,8 +528,10 @@ class X86_32ABIInfo : public ABIInfo { Class classify(QualType Ty) const; ABIArgInfo classifyReturnType(QualType RetTy, unsigned callingConvention) const; - ABIArgInfo classifyArgumentType(QualType RetTy, unsigned &FreeRegs) const; - bool shouldUseInReg(QualType Ty, unsigned &FreeRegs) const; + ABIArgInfo classifyArgumentType(QualType RetTy, unsigned &FreeRegs, + bool IsFastCall) const; + bool shouldUseInReg(QualType Ty, unsigned &FreeRegs, + bool IsFastCall) const; public: @@ -804,12 +806,14 @@ X86_32ABIInfo::Class X86_32ABIInfo::classify(QualType Ty) const { return Integer; } -bool X86_32ABIInfo::shouldUseInReg(QualType Ty, unsigned &FreeRegs) const { +bool X86_32ABIInfo::shouldUseInReg(QualType Ty, unsigned &FreeRegs, + bool IsFastCall) const { Class C = classify(Ty); if (C == Float) return false; - unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32; + unsigned Size = getContext().getTypeSize(Ty); + unsigned SizeInRegs = (Size + 31) / 32; if (SizeInRegs == 0) return false; @@ -820,11 +824,29 @@ bool X86_32ABIInfo::shouldUseInReg(QualType Ty, unsigned &FreeRegs) const { } FreeRegs -= SizeInRegs; + + if (IsFastCall) { + if (Size > 32) + return false; + + if (Ty->isIntegralOrEnumerationType()) + return true; + + if (Ty->isPointerType()) + return true; + + if (Ty->isReferenceType()) + return true; + + return false; + } + return true; } ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, - unsigned &FreeRegs) const { + unsigned &FreeRegs, + bool IsFastCall) const { // FIXME: Set alignment on indirect arguments. if (isAggregateTypeForABI(Ty)) { // Structures with flexible arrays are always indirect. @@ -842,7 +864,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); - if (shouldUseInReg(Ty, FreeRegs)) { + if (shouldUseInReg(Ty, FreeRegs, IsFastCall)) { unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32; llvm::LLVMContext &LLVMContext = getVMContext(); llvm::Type *Int32 = llvm::Type::getInt32Ty(LLVMContext); @@ -892,7 +914,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); - bool InReg = shouldUseInReg(Ty, FreeRegs); + bool InReg = shouldUseInReg(Ty, FreeRegs, IsFastCall); if (Ty->isPromotableIntegerType()) { if (InReg) @@ -908,8 +930,15 @@ void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const { FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), FI.getCallingConvention()); - unsigned FreeRegs = FI.getHasRegParm() ? FI.getRegParm() : - DefaultNumRegisterParameters; + unsigned CC = FI.getCallingConvention(); + bool IsFastCall = CC == llvm::CallingConv::X86_FastCall; + unsigned FreeRegs; + if (IsFastCall) + FreeRegs = 2; + else if (FI.getHasRegParm()) + FreeRegs = FI.getRegParm(); + else + FreeRegs = DefaultNumRegisterParameters; // If the return value is indirect, then the hidden argument is consuming one // integer register. @@ -923,7 +952,7 @@ void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const { for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) - it->info = classifyArgumentType(it->type, FreeRegs); + it->info = classifyArgumentType(it->type, FreeRegs, IsFastCall); } llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, diff --git a/test/CodeGen/attributes.c b/test/CodeGen/attributes.c index e971a79347..00688dc72b 100644 --- a/test/CodeGen/attributes.c +++ b/test/CodeGen/attributes.c @@ -80,7 +80,7 @@ void t21(void) { fptr(10); } // CHECK: [[FPTRVAR:%[a-z0-9]+]] = load void (i32)** @fptr -// CHECK-NEXT: call x86_fastcallcc void [[FPTRVAR]](i32 10) +// CHECK-NEXT: call x86_fastcallcc void [[FPTRVAR]](i32 inreg 10) // PR9356: We might want to err on this, but for now at least make sure we diff --git a/test/CodeGen/stdcall-fastcall.c b/test/CodeGen/stdcall-fastcall.c index 2832e91123..dac2a3a142 100644 --- a/test/CodeGen/stdcall-fastcall.c +++ b/test/CodeGen/stdcall-fastcall.c @@ -48,3 +48,99 @@ void f8(void) { f7(0); // CHECK: call x86_stdcallcc void @f7(i32 0) } + +void __attribute__((fastcall)) foo1(int y); +void bar1(int y) { + // CHECK: define void @bar1 + // CHECK: call x86_fastcallcc void @foo1(i32 inreg % + foo1(y); +} + +struct S1 { + int x; +}; +void __attribute__((fastcall)) foo2(struct S1 y); +void bar2(struct S1 y) { + // CHECK: define void @bar2 + // CHECK: call x86_fastcallcc void @foo2(i32 % + foo2(y); +} + +void __attribute__((fastcall)) foo3(int *y); +void bar3(int *y) { + // CHECK: define void @bar3 + // CHECK: call x86_fastcallcc void @foo3(i32* inreg % + foo3(y); +} + +enum Enum {Eval}; +void __attribute__((fastcall)) foo4(enum Enum y); +void bar4(enum Enum y) { + // CHECK: define void @bar4 + // CHECK: call x86_fastcallcc void @foo4(i32 inreg % + foo4(y); +} + +struct S2 { + int x1; + double x2; + double x3; +}; +void __attribute__((fastcall)) foo5(struct S2 y); +void bar5(struct S2 y) { + // CHECK: define void @bar5 + // CHECK: call x86_fastcallcc void @foo5(%struct.S2* byval align 4 % + foo5(y); +} + +void __attribute__((fastcall)) foo6(long long y); +void bar6(long long y) { + // CHECK: define void @bar6 + // CHECK: call x86_fastcallcc void @foo6(i64 % + foo6(y); +} + +void __attribute__((fastcall)) foo7(int a, struct S1 b, int c); +void bar7(int a, struct S1 b, int c) { + // CHECK: define void @bar7 + // CHECK: call x86_fastcallcc void @foo7(i32 inreg %{{.*}}, i32 %{{.*}}, i32 %{{.*}} + foo7(a, b, c); +} + +void __attribute__((fastcall)) foo8(struct S1 a, int b); +void bar8(struct S1 a, int b) { + // CHECK: define void @bar8 + // CHECK: call x86_fastcallcc void @foo8(i32 %{{.*}}, i32 inreg % + foo8(a, b); +} + +void __attribute__((fastcall)) foo9(struct S2 a, int b); +void bar9(struct S2 a, int b) { + // CHECK: define void @bar9 + // CHECK: call x86_fastcallcc void @foo9(%struct.S2* byval align 4 %{{.*}}, i32 % + foo9(a, b); +} + +void __attribute__((fastcall)) foo10(float y, int x); +void bar10(float y, int x) { + // CHECK: define void @bar10 + // CHECK: call x86_fastcallcc void @foo10(float %{{.*}}, i32 inreg % + foo10(y, x); +} + +void __attribute__((fastcall)) foo11(double y, int x); +void bar11(double y, int x) { + // CHECK: define void @bar11 + // CHECK: call x86_fastcallcc void @foo11(double %{{.*}}, i32 inreg % + foo11(y, x); +} + +struct S3 { + float x; +}; +void __attribute__((fastcall)) foo12(struct S3 y, int x); +void bar12(struct S3 y, int x) { + // CHECK: define void @bar12 + // CHECK: call x86_fastcallcc void @foo12(float %{{.*}}, i32 inreg % + foo12(y, x); +} diff --git a/test/CodeGenCXX/fastcall.cpp b/test/CodeGenCXX/fastcall.cpp new file mode 100644 index 0000000000..c0a9106672 --- /dev/null +++ b/test/CodeGenCXX/fastcall.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck %s + +void __attribute__((fastcall)) foo1(int &y); +void bar1(int &y) { + // CHECK: define void @_Z4bar1Ri + // CHECK: call x86_fastcallcc void @_Z4foo1Ri(i32* inreg % + foo1(y); +} + +struct S1 { + int x; + S1(const S1 &y); +}; + +void __attribute__((fastcall)) foo2(S1 a, int b); +void bar2(S1 a, int b) { + // CHECK: define void @_Z4bar22S1i + // CHECK: call x86_fastcallcc void @_Z4foo22S1i(%struct.S1* inreg %{{.*}}, i32 inreg % + foo2(a, b); +}