]> granicus.if.org Git - clang/commitdiff
Don't emit K&R unprototyped function definitions as varargs.
authorDaniel Dunbar <daniel@zuster.org>
Thu, 19 Feb 2009 07:15:39 +0000 (07:15 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Thu, 19 Feb 2009 07:15:39 +0000 (07:15 +0000)
 - <rdar://problem/6584606> clang/x86-64 - too many reg saves

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65032 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
test/CodeGen/functions.c

index 17662ef340e422dbaa961158b688e21855beedc1..ae472f01ce62190d89dacc1d83c6b00a814c6130 100644 (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.
index b7d3aa9f38eff0e610a2106edd8fcae605112cf7..3f1aeb80be10c6e7abcca74d0c9b44e14098b900 100644 (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);
index 83da64704bb622f8daf7ec35a5d4e72978dcd1e9..ad918263c5fdb07a81ecff9747e5d40dbf74cb66 100644 (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() {}