[cfe-commits] r140241 - in /cfe/trunk: lib/CodeGen/CGExpr.cpp lib/CodeGen/TargetInfo.cpp lib/CodeGen/TargetInfo.h test/CodeGen/builtin-expect.c test/CodeGen/functions.c test/CodeGen/kr-call.c test/CodeGen/microsoft-call-conv.c test/CodeGen/mrtd.c test/CodeGen/stdcall-fastcall.c

John McCall rjmccall at apple.com
Wed Sep 21 01:08:30 PDT 2011


Author: rjmccall
Date: Wed Sep 21 03:08:30 2011
New Revision: 140241

URL: http://llvm.org/viewvc/llvm-project?rev=140241&view=rev
Log:
ANSI C requires that a call to an unprototyped function type succeed
if the definition has a non-variadic prototype with compatible
parameters.  Therefore, the default rule for such calls must be to
use a non-variadic convention.  Achieve this by casting the callee to
the function type with which it is required to be compatible, unless
the target specifically opts out and insists that unprototyped calls
should use the variadic rules.  The only case of that I'm aware of is
the x86-64 convention, which passes arguments the same way in both
cases but also sets a small amount of extra information;  here we seek
to maintain compatibility with GCC, which does set this when calling
an unprototyped function.

Addresses PR10810 and PR10713.


Modified:
    cfe/trunk/lib/CodeGen/CGExpr.cpp
    cfe/trunk/lib/CodeGen/TargetInfo.cpp
    cfe/trunk/lib/CodeGen/TargetInfo.h
    cfe/trunk/test/CodeGen/builtin-expect.c
    cfe/trunk/test/CodeGen/functions.c
    cfe/trunk/test/CodeGen/kr-call.c
    cfe/trunk/test/CodeGen/microsoft-call-conv.c
    cfe/trunk/test/CodeGen/mrtd.c
    cfe/trunk/test/CodeGen/stdcall-fastcall.c

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=140241&r1=140240&r2=140241&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Wed Sep 21 03:08:30 2011
@@ -18,6 +18,7 @@
 #include "CGDebugInfo.h"
 #include "CGRecordLayout.h"
 #include "CGObjCRuntime.h"
+#include "TargetInfo.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/Frontend/CodeGenOptions.h"
@@ -2414,8 +2415,35 @@
   CallArgList Args;
   EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), ArgBeg, ArgEnd);
 
-  return EmitCall(CGM.getTypes().getFunctionInfo(Args, FnType),
-                  Callee, ReturnValue, Args, TargetDecl);
+  const CGFunctionInfo &FnInfo = CGM.getTypes().getFunctionInfo(Args, FnType);
+
+  // C99 6.5.2.2p6:
+  //   If the expression that denotes the called function has a type
+  //   that does not include a prototype, [the default argument
+  //   promotions are performed]. If the number of arguments does not
+  //   equal the number of parameters, the behavior is undefined. If
+  //   the function is defined with a type that includes a prototype,
+  //   and either the prototype ends with an ellipsis (, ...) or the
+  //   types of the arguments after promotion are not compatible with
+  //   the types of the parameters, the behavior is undefined. If the
+  //   function is defined with a type that does not include a
+  //   prototype, and the types of the arguments after promotion are
+  //   not compatible with those of the parameters after promotion,
+  //   the behavior is undefined [except in some trivial cases].
+  // That is, in the general case, we should assume that a call
+  // through an unprototyped function type works like a *non-variadic*
+  // call.  The way we make this work is to cast to the exact type
+  // of the promoted arguments.
+  if (isa<FunctionNoProtoType>(FnType) &&
+      !getTargetHooks().isNoProtoCallVariadic(FnType->getCallConv())) {
+    assert(cast<llvm::FunctionType>(Callee->getType()->getContainedType(0))
+             ->isVarArg());
+    llvm::Type *CalleeTy = getTypes().GetFunctionType(FnInfo, false);
+    CalleeTy = CalleeTy->getPointerTo();
+    Callee = Builder.CreateBitCast(Callee, CalleeTy, "callee.knr.cast");
+  }
+
+  return EmitCall(FnInfo, Callee, ReturnValue, Args, TargetDecl);
 }
 
 LValue CodeGenFunction::

Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=140241&r1=140240&r2=140241&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Wed Sep 21 03:08:30 2011
@@ -98,6 +98,14 @@
   return 32;
 }
 
+bool TargetCodeGenInfo::isNoProtoCallVariadic(CallingConv CC) const {
+  // The following conventions are known to require this to be false:
+  //   x86_stdcall
+  //   MIPS
+  // For everything else, we just prefer false unless we opt out.
+  return false;
+}
+
 static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays);
 
 /// isEmptyField - Return true iff a the field is "empty", that is it
@@ -959,6 +967,15 @@
     return X86AdjustInlineAsmType(CGF, Constraint, Ty);
   }
 
+  bool isNoProtoCallVariadic(CallingConv CC) const {
+    // The default CC on x86-64 sets %al to the number of SSA
+    // registers used, and GCC sets this when calling an unprototyped
+    // function, so we override the default behavior.
+    if (CC == CC_Default || CC == CC_C) return true;
+
+    return TargetCodeGenInfo::isNoProtoCallVariadic(CC);
+  }
+
 };
 
 class WinX86_64TargetCodeGenInfo : public TargetCodeGenInfo {

Modified: cfe/trunk/lib/CodeGen/TargetInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.h?rev=140241&r1=140240&r2=140241&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.h (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.h Wed Sep 21 03:08:30 2011
@@ -16,6 +16,7 @@
 #define CLANG_CODEGEN_TARGETINFO_H
 
 #include "clang/Basic/LLVM.h"
+#include "clang/AST/Type.h"
 #include "llvm/ADT/StringRef.h"
 
 namespace llvm {
@@ -126,6 +127,40 @@
     virtual StringRef getARCRetainAutoreleasedReturnValueMarker() const {
       return "";
     }
+
+    /// Determine whether a call to an unprototyped functions under
+    /// the given calling convention should use the variadic
+    /// convention or the non-variadic convention.
+    ///
+    /// There's a good reason to make a platform's variadic calling
+    /// convention be different from its non-variadic calling
+    /// convention: the non-variadic arguments can be passed in
+    /// registers (better for performance), and the variadic arguments
+    /// can be passed on the stack (also better for performance).  If
+    /// this is done, however, unprototyped functions *must* use the
+    /// non-variadic convention, because C99 states that a call
+    /// through an unprototyped function type must succeed if the
+    /// function was defined with a non-variadic prototype with
+    /// compatible parameters.  Therefore, splitting the conventions
+    /// makes it impossible to call a variadic function through an
+    /// unprototyped type.  Since function prototypes came out in the
+    /// late 1970s, this is probably an acceptable trade-off.
+    /// Nonetheless, not all platforms are willing to make it, and in
+    /// particularly x86-64 bends over backwards to make the
+    /// conventions compatible.
+    ///
+    /// The default is false.  This is correct whenever:
+    ///   - the conventions are exactly the same, because it does not
+    ///     matter and the resulting IR will be somewhat prettier in
+    ///     certain cases; or
+    ///   - the conventions are substantively different in how they pass
+    ///     arguments, because in this case using the variadic convention
+    ///     will lead to C99 violations.
+    /// It is not necessarily correct when arguments are passed in the
+    /// same way and some out-of-band information is passed for the
+    /// benefit of variadic callees, as is the case for x86-64.
+    /// In this case the ABI should be consulted.
+    virtual bool isNoProtoCallVariadic(CallingConv CC) const;
   };
 }
 

Modified: cfe/trunk/test/CodeGen/builtin-expect.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/builtin-expect.c?rev=140241&r1=140240&r2=140241&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/builtin-expect.c (original)
+++ cfe/trunk/test/CodeGen/builtin-expect.c Wed Sep 21 03:08:30 2011
@@ -18,7 +18,7 @@
 }
 
 // CHECK: call void @isigprocmask()
-// CHECK: [[C:%.*]] = call i64 (...)* @bar()
+// CHECK: [[C:%.*]] = call i64 bitcast (i64 (...)* @bar to i64 ()*)()
 
 
 // CHECK: @test1

Modified: cfe/trunk/test/CodeGen/functions.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/functions.c?rev=140241&r1=140240&r2=140241&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/functions.c (original)
+++ cfe/trunk/test/CodeGen/functions.c Wed Sep 21 03:08:30 2011
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - -verify | FileCheck %s
+// RUN: %clang_cc1 %s -triple i386-unknown-unknown -emit-llvm -o - -verify | FileCheck %s
 
 int g();
 
@@ -24,7 +24,7 @@
 
 void f1();
 void f2(void) {
-// CHECK: call void @f1()
+// CHECK: call void bitcast (void ()* @f1 to void (i32, i32, i32)*)(i32 1, i32 2, i32 3)
   f1(1, 2, 3);
 }
 // CHECK: define void @f1()

Modified: cfe/trunk/test/CodeGen/kr-call.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/kr-call.c?rev=140241&r1=140240&r2=140241&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/kr-call.c (original)
+++ cfe/trunk/test/CodeGen/kr-call.c Wed Sep 21 03:08:30 2011
@@ -2,11 +2,10 @@
 
 // Test that we don't crash.  The s390x-unknown-linux target happens
 // to need to set a sext argument attribute on this call, and we need
-// to make sure that rewriting it correctly drops that attribute when
-// also dropping the spurious argument.
+// to make sure that rewriting it correctly keeps that attribute.
 void test0_helper();
 void test0() {
-  // CHECK: call void @test0_helper()
+  // CHECK: call void bitcast (void ()* @test0_helper to void (i32)*)(i32 signext 1)
   test0_helper(1);
 }
 void test0_helper() {}

Modified: cfe/trunk/test/CodeGen/microsoft-call-conv.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/microsoft-call-conv.c?rev=140241&r1=140240&r2=140241&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/microsoft-call-conv.c (original)
+++ cfe/trunk/test/CodeGen/microsoft-call-conv.c Wed Sep 21 03:08:30 2011
@@ -46,5 +46,5 @@
 void __stdcall f7(foo) int foo; {}
 void f8(void) {
   f7(0);
-  // CHECK: call x86_stdcallcc void (...)* bitcast
+  // CHECK: call x86_stdcallcc void @f7(i32 0)
 }

Modified: cfe/trunk/test/CodeGen/mrtd.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/mrtd.c?rev=140241&r1=140240&r2=140241&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/mrtd.c (original)
+++ cfe/trunk/test/CodeGen/mrtd.c Wed Sep 21 03:08:30 2011
@@ -4,7 +4,7 @@
 
 // CHECK: define x86_stdcallcc void @foo(i32 %arg) nounwind
 void foo(int arg) {
-// CHECK: call x86_stdcallcc i32 (...)* @bar(i32
+// CHECK: call x86_stdcallcc i32 bitcast (i32 (...)* @bar to i32 (i32)*)(
   bar(arg);
 // CHECK: call x86_stdcallcc void @baz(i32
   baz(arg);

Modified: cfe/trunk/test/CodeGen/stdcall-fastcall.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/stdcall-fastcall.c?rev=140241&r1=140240&r2=140241&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/stdcall-fastcall.c (original)
+++ cfe/trunk/test/CodeGen/stdcall-fastcall.c Wed Sep 21 03:08:30 2011
@@ -46,5 +46,5 @@
 void __attribute((stdcall)) f7(foo) int foo; {}
 void f8(void) {
   f7(0);
-  // CHECK: call x86_stdcallcc void (...)* bitcast
+  // CHECK: call x86_stdcallcc void @f7(i32 0)
 }





More information about the cfe-commits mailing list