From: Chris Lattner Date: Sat, 13 Jun 2009 00:26:38 +0000 (+0000) Subject: Fix PR4372, another case where non-prototyped functions can prevent X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5db7ae59bb0115ccc420ff1d688abc8706559b57;p=clang Fix PR4372, another case where non-prototyped functions can prevent always_inline from working. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73273 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index b10b9c2d9d..4037f32ac1 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -682,10 +682,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // location that we would like to return into. QualType RetTy = CallInfo.getReturnType(); const ABIArgInfo &RetAI = CallInfo.getReturnInfo(); - if (CGM.ReturnTypeUsesSret(CallInfo)) { - // Create a temporary alloca to hold the result of the call. :( + + + // If the call returns a temporary with struct return, create a temporary + // alloca to hold the result. + if (CGM.ReturnTypeUsesSret(CallInfo)) Args.push_back(CreateTempAlloca(ConvertTypeForMem(RetTy))); - } assert(CallInfo.arg_size() == CallArgs.size() && "Mismatch between function signature & arguments."); @@ -747,6 +749,35 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, break; } } + + // If the callee is a bitcast of a function to a varargs pointer to function + // type, check to see if we can remove the bitcast. This handles some cases + // with unprototyped functions. + if (llvm::ConstantExpr *CE = dyn_cast(Callee)) + if (llvm::Function *CalleeF = dyn_cast(CE->getOperand(0))) { + const llvm::PointerType *CurPT=cast(Callee->getType()); + const llvm::FunctionType *CurFT = + cast(CurPT->getElementType()); + const llvm::FunctionType *ActualFT = CalleeF->getFunctionType(); + + if (CE->getOpcode() == llvm::Instruction::BitCast && + ActualFT->getReturnType() == CurFT->getReturnType() && + ActualFT->getNumParams() == CurFT->getNumParams()) { + bool ArgsMatch = true; + for (unsigned i = 0, e = ActualFT->getNumParams(); i != e; ++i) + if (ActualFT->getParamType(i) != CurFT->getParamType(i)) { + ArgsMatch = false; + break; + } + + // Strip the cast if we can get away with it. This is a nice cleanup, + // but also allows us to inline the function at -O0 if it is marked + // always_inline. + if (ArgsMatch) + Callee = CalleeF; + } + } + llvm::BasicBlock *InvokeDest = getInvokeDest(); CodeGen::AttributeListType AttributeList; @@ -765,7 +796,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, } CS.setAttributes(Attrs); - if (const llvm::Function *F = dyn_cast(Callee->stripPointerCasts())) + if (const llvm::Function *F = + dyn_cast(Callee->stripPointerCasts())) CS.setCallingConv(F->getCallingConv()); // If the call doesn't return, finish the basic block and clear the diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index c52e6bd0c5..eb0db61115 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -1156,10 +1156,9 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) { } } - if (const CXXOperatorCallExpr *CE = dyn_cast(E)) { + if (const CXXOperatorCallExpr *CE = dyn_cast(E)) if (const CXXMethodDecl *MD = dyn_cast_or_null(TargetDecl)) return EmitCXXOperatorMemberCallExpr(CE, MD); - } llvm::Value *Callee = EmitScalarExpr(E->getCallee()); return EmitCall(Callee, E->getCallee()->getType(), diff --git a/test/CodeGen/always_inline.c b/test/CodeGen/always_inline.c index cb32e3b621..c12b45404d 100644 --- a/test/CodeGen/always_inline.c +++ b/test/CodeGen/always_inline.c @@ -1,5 +1,6 @@ // RUN: clang -emit-llvm -S -o %t %s && -// RUN: grep '@f0' %t | count 0 && +// RUN: not grep '@f0' %t && +// RUN: not grep 'call ' %t && // RUN: clang -mllvm -disable-llvm-optzns -emit-llvm -S -o %t %s && // RUN: grep '@f0' %t | count 2 @@ -11,3 +12,9 @@ static int __attribute__((always_inline)) f0() { int f1() { return f0(); } + +// PR4372 +inline int f2() __attribute__((always_inline)); +int f2() { return 7; } +int f3(void) { return f2(); } +