Don't emit K&R unprototyped function definitions as varargs.

- <rdar://problem/6584606> clang/x86-64 - too many reg saves

llvm-svn: 65032
This commit is contained in:
Daniel Dunbar 2009-02-19 07:15:39 +00:00
parent 5c275a94fb
commit f0acf7bd4c
3 changed files with 50 additions and 15 deletions

View File

@ -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<llvm::FunctionType>(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<llvm::FunctionType>(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<const llvm::Type*>(),
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.

View File

@ -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);

View File

@ -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() {}