From: Daniel Dunbar Date: Thu, 19 Feb 2009 07:15:39 +0000 (+0000) Subject: Don't emit K&R unprototyped function definitions as varargs. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d5d31801fc87239436fa349c89dce7797cf13537;p=clang Don't emit K&R unprototyped function definitions as varargs. - clang/x86-64 - too many reg saves git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65032 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 17662ef340..ae472f01ce 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -773,8 +773,10 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { } llvm::GlobalValue * -CodeGenModule::EmitForwardFunctionDefinition(const FunctionDecl *D) { - const llvm::Type *Ty = getTypes().ConvertType(D->getType()); +CodeGenModule::EmitForwardFunctionDefinition(const FunctionDecl *D, + const llvm::Type *Ty) { + if (!Ty) + Ty = getTypes().ConvertType(D->getType()); llvm::Function *F = llvm::Function::Create(cast(Ty), llvm::Function::ExternalLinkage, getMangledName(D), @@ -791,28 +793,40 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(const FunctionDecl *D) { // Lookup the entry, lazily creating it if necessary. llvm::GlobalValue *&Entry = GlobalDeclMap[getMangledName(D)]; if (!Entry) - Entry = EmitForwardFunctionDefinition(D); + Entry = EmitForwardFunctionDefinition(D, 0); return llvm::ConstantExpr::getBitCast(Entry, PTy); } void CodeGenModule::EmitGlobalFunctionDefinition(const FunctionDecl *D) { + const llvm::FunctionType *Ty = + cast(getTypes().ConvertType(D->getType())); + + // As a special case, make sure that definitions of K&R function + // "type foo()" aren't declared as varargs (which forces the backend + // to do unnecessary work). + if (Ty->isVarArg() && Ty->getNumParams() == 0 && Ty->isVarArg()) + Ty = llvm::FunctionType::get(Ty->getReturnType(), + std::vector(), + false); + llvm::GlobalValue *&Entry = GlobalDeclMap[getMangledName(D)]; if (!Entry) { - Entry = EmitForwardFunctionDefinition(D); + Entry = EmitForwardFunctionDefinition(D, Ty); } else { // If the types mismatch then we have to rewrite the definition. - const llvm::Type *Ty = getTypes().ConvertType(D->getType()); if (Entry->getType() != llvm::PointerType::getUnqual(Ty)) { - // Otherwise, we have a definition after a prototype with the wrong type. - // F is the Function* for the one with the wrong type, we must make a new - // Function* and update everything that used F (a declaration) with the new - // Function* (which will be a definition). + // Otherwise, we have a definition after a prototype with the + // wrong type. F is the Function* for the one with the wrong + // type, we must make a new Function* and update everything that + // used F (a declaration) with the new Function* (which will be + // a definition). // - // This happens if there is a prototype for a function (e.g. "int f()") and - // then a definition of a different type (e.g. "int f(int x)"). Start by - // making a new function of the correct type, RAUW, then steal the name. - llvm::GlobalValue *NewFn = EmitForwardFunctionDefinition(D); + // This happens if there is a prototype for a function + // (e.g. "int f()") and then a definition of a different type + // (e.g. "int f(int x)"). Start by making a new function of the + // correct type, RAUW, then steal the name. + llvm::GlobalValue *NewFn = EmitForwardFunctionDefinition(D, Ty); NewFn->takeName(Entry); // Replace uses of F with the Function we will endow with a body. diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index b7d3aa9f38..3f1aeb80be 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -322,7 +322,16 @@ private: void EmitGlobal(const ValueDecl *D); void EmitGlobalDefinition(const ValueDecl *D); - llvm::GlobalValue *EmitForwardFunctionDefinition(const FunctionDecl *D); + + /// EmitForwardFunctionDefinition - Create a new function for the + /// given decl and set attributes as appropriate. + /// + /// \arg Ty - If non-null the LLVM function type to use for the + /// decl; it is the callers responsibility to make sure this is + /// compatible with the correct type. + llvm::GlobalValue *EmitForwardFunctionDefinition(const FunctionDecl *D, + const llvm::Type *Ty); + void EmitGlobalFunctionDefinition(const FunctionDecl *D); void EmitGlobalVarDefinition(const VarDecl *D); void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D); diff --git a/test/CodeGen/functions.c b/test/CodeGen/functions.c index 83da64704b..ad918263c5 100644 --- a/test/CodeGen/functions.c +++ b/test/CodeGen/functions.c @@ -1,4 +1,5 @@ -// RUN: clang %s -emit-llvm -o - +// RUN: clang %s -emit-llvm -o %t && + int g(); int foo(int i) { @@ -17,3 +18,14 @@ void test3(T f) { int a(int); int a() {return 1;} + +// RUN: grep 'define void @f0()' %t && +void f0() {} + +void f1(); +// RUN: grep 'call void (...)\* bitcast (void ()\* @f1' %t && +void f2(void) { + f1(1, 2, 3); +} +// RUN: grep 'define void @f1()' %t +void f1() {}