[llvm-commits] [dragonegg] r138663 - in /dragonegg/trunk: include/dragonegg/Internals.h include/dragonegg/Types.h src/Backend.cpp src/Convert.cpp src/Types.cpp

Duncan Sands baldrick at free.fr
Fri Aug 26 14:29:18 PDT 2011


Author: baldrick
Date: Fri Aug 26 16:29:18 2011
New Revision: 138663

URL: http://llvm.org/viewvc/llvm-project?rev=138663&view=rev
Log:
Be more careful about making functions varargs.  Use gcc's predicate to
determine whether a function type is varargs.  As a result, functions
with no arguments (eg: void foo() in C; void foo(...) in C++) are no
longer considered varargs.  This fixes PR10713 which showed that such
functions must not be considered varargs when called.  On the other hand
there is still the problem of K&R style function declarations, and Fortran
which likes to declare functions with arguments that are completely different
to the arguments declared in the function type (previously these Fortran
problems were worked around by declaring most functions to be varargs).
Deal with these by tweaking the existing logic, which was close to be able
to handle them already.

Modified:
    dragonegg/trunk/include/dragonegg/Internals.h
    dragonegg/trunk/include/dragonegg/Types.h
    dragonegg/trunk/src/Backend.cpp
    dragonegg/trunk/src/Convert.cpp
    dragonegg/trunk/src/Types.cpp

Modified: dragonegg/trunk/include/dragonegg/Internals.h
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/include/dragonegg/Internals.h?rev=138663&r1=138662&r2=138663&view=diff
==============================================================================
--- dragonegg/trunk/include/dragonegg/Internals.h (original)
+++ dragonegg/trunk/include/dragonegg/Internals.h Fri Aug 26 16:29:18 2011
@@ -95,15 +95,11 @@
 /// definitions are equivalent).
 extern bool flag_odr;
 
-/// flag_vararg_requires_arguments - Do not consider functions with no arguments
-/// to take a variable number of arguments (...).  If set then a function like
-/// "T foo() {}" will be treated like "T foo(void) {}" and not "T foo(...) {}".
-extern bool flag_vararg_requires_arguments;
-
-/// flag_force_vararg_prototypes - Force prototypes to take a variable number of
-/// arguments (...).  This is helpful if the language front-end sometimes emits
-/// calls where the call arguments do not match the callee function declaration.
-extern bool flag_force_vararg_prototypes;
+/// flag_functions_from_args - Construct function prototypes from the argument
+/// list, ignoring the function type.  This is helpful if the language front-end
+/// sometimes creates functions and/or calls where the arguments do not match
+/// the arguments given in the function type.
+extern bool flag_functions_from_args;
 
 /// AttributeUsedGlobals - The list of globals that are marked attribute(used).
 extern SmallSetVector<Constant *,32> AttributeUsedGlobals;

Modified: dragonegg/trunk/include/dragonegg/Types.h
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/include/dragonegg/Types.h?rev=138663&r1=138662&r2=138663&view=diff
==============================================================================
--- dragonegg/trunk/include/dragonegg/Types.h (original)
+++ dragonegg/trunk/include/dragonegg/Types.h Fri Aug 26 16:29:18 2011
@@ -94,8 +94,10 @@
 /// ConvertArgListToFnType - Given a DECL_ARGUMENTS list on an GCC tree,
 /// return the LLVM type corresponding to the function.  This is useful for
 /// turning "T foo(...)" functions into "T foo(void)" functions.
-llvm::FunctionType *ConvertArgListToFnType(tree_node *type, tree_node *arglist,
+llvm::FunctionType *ConvertArgListToFnType(tree_node *type,
+                                           ArrayRef<tree_node *> arglist,
                                            tree_node *static_chain,
+                                           bool KNRPromotion,
                                            llvm::CallingConv::ID &CC,
                                            llvm::AttrListPtr &PAL);
 

Modified: dragonegg/trunk/src/Backend.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/src/Backend.cpp?rev=138663&r1=138662&r2=138663&view=diff
==============================================================================
--- dragonegg/trunk/src/Backend.cpp (original)
+++ dragonegg/trunk/src/Backend.cpp Fri Aug 26 16:29:18 2011
@@ -464,15 +464,11 @@
 /// definitions are equivalent).
 bool flag_odr;
 
-/// flag_vararg_requires_arguments - Do not consider functions with no arguments
-/// to take a variable number of arguments (...).  If set then a function like
-/// "T foo() {}" will be treated like "T foo(void) {}" and not "T foo(...) {}".
-bool flag_vararg_requires_arguments;
-
-/// flag_force_vararg_prototypes - Force prototypes to take a variable number of
-/// arguments (...).  This is helpful if the language front-end sometimes emits
-/// calls where the call arguments do not match the callee function declaration.
-bool flag_force_vararg_prototypes;
+/// flag_functions_from_args - Construct function prototypes from the argument
+/// list, ignoring the function type.  This is helpful if the language front-end
+/// sometimes creates functions and/or calls where the arguments do not match
+/// the arguments given in the function type.
+bool flag_functions_from_args;
 
 /// InstallLanguageSettings - Do any language-specific back-end configuration.
 static void InstallLanguageSettings() {
@@ -485,15 +481,14 @@
     flag_default_initialize_globals = false; // Uninitialized means what it says
     flag_odr = true; // Ada obeys the one-definition-rule
   } else if (LanguageName == "GNU C") {
-    flag_vararg_requires_arguments = true; // "T foo() {}" -> "T foo(void) {}"
   } else if (LanguageName == "GNU C++") {
     flag_odr = true; // C++ obeys the one-definition-rule
   } else if (LanguageName == "GNU Fortran") {
-    flag_force_vararg_prototypes = true;
+    flag_functions_from_args = true;
   } else if (LanguageName == "GNU GIMPLE") { // LTO gold plugin
+  } else if (LanguageName == "GNU Go") {
   } else if (LanguageName == "GNU Java") {
   } else if (LanguageName == "GNU Objective-C") {
-    flag_vararg_requires_arguments = true; // "T foo() {}" -> "T foo(void) {}"
   } else if (LanguageName == "GNU Objective-C++") {
     flag_odr = true; // Objective C++ obeys the one-definition-rule
   }

Modified: dragonegg/trunk/src/Convert.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/src/Convert.cpp?rev=138663&r1=138662&r2=138663&view=diff
==============================================================================
--- dragonegg/trunk/src/Convert.cpp (original)
+++ dragonegg/trunk/src/Convert.cpp Fri Aug 26 16:29:18 2011
@@ -495,36 +495,21 @@
   CallingConv::ID CallingConv;
   AttrListPtr PAL;
 
-  bool getFunctionTypeFromArgList = false;
-
-  // If the function has no arguments and is varargs (...), turn it into a
-  // non-varargs function by scanning the param list for the function.  This
-  // allows C functions declared as "T foo() {}" to be treated like
-  // "T foo(void) {}" and allows us to handle functions with K&R-style
-  // definitions correctly.
-  //
-  // Note that we only do this in C/Objective-C.  Doing this in C++ for
-  // functions explicitly declared as taking (...) is bad.
-  if (TYPE_ARG_TYPES(TREE_TYPE(FnDecl)) == 0 && flag_vararg_requires_arguments)
-    getFunctionTypeFromArgList = true;
-
-  // When forcing vararg prototypes ensure that the function only gets a varargs
-  // part if it was originally declared varargs.
-  if (flag_force_vararg_prototypes) {
-    tree Args = TYPE_ARG_TYPES(TREE_TYPE(FnDecl));
-    while (Args && TREE_VALUE(Args) != void_type_node)
-      Args = TREE_CHAIN(Args);
-    if (Args != 0)
-      getFunctionTypeFromArgList = true;
-  }
-
-  if (getFunctionTypeFromArgList)
-    FTy = ConvertArgListToFnType(TREE_TYPE(FnDecl), DECL_ARGUMENTS(FnDecl),
-                                 static_chain, CallingConv, PAL);
-  else
+  // If this is a K&R-style function: with a type that takes no arguments but
+  // with arguments none the less, then calculate the LLVM type from the list
+  // of arguments.
+  if (flag_functions_from_args || (TYPE_ARG_TYPES(TREE_TYPE(FnDecl)) == 0 &&
+                                   DECL_ARGUMENTS(FnDecl))) {
+    SmallVector<tree, 8> Args;
+    for (tree Arg = DECL_ARGUMENTS(FnDecl); Arg; Arg = TREE_CHAIN(Arg))
+      Args.push_back(Arg);
+    FTy = ConvertArgListToFnType(TREE_TYPE(FnDecl), Args, static_chain,
+                                 !flag_functions_from_args, CallingConv, PAL);
+  } else {
     // Otherwise, just get the type from the function itself.
     FTy = ConvertFunctionType(TREE_TYPE(FnDecl), FnDecl, static_chain,
                               CallingConv, PAL);
+  }
 
   // If we've already seen this function and created a prototype, and if the
   // proto has the right LLVM type, just use it.
@@ -2840,34 +2825,9 @@
     Client.clear();
   }
 
-  // Compile stuff like:
-  //   %tmp = call float (...)* bitcast (float ()* @foo to float (...)*)( )
-  // to:
-  //   %tmp = call float @foo( )
-  // This commonly occurs due to C "implicit ..." semantics.
-  if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Callee)) {
-    if (CallOperands.empty() && CE->getOpcode() == Instruction::BitCast) {
-      Constant *RealCallee = CE->getOperand(0);
-      assert(RealCallee->getType()->isPointerTy() &&
-             "Bitcast to ptr not from ptr?");
-      PointerType *RealPT = cast<PointerType>(RealCallee->getType());
-      if (FunctionType *RealFT =
-          dyn_cast<FunctionType>(RealPT->getElementType())) {
-        PointerType *ActualPT = cast<PointerType>(Callee->getType());
-        FunctionType *ActualFT =
-          cast<FunctionType>(ActualPT->getElementType());
-        if (RealFT->getReturnType() == ActualFT->getReturnType() &&
-            RealFT->getNumParams() == 0)
-          Callee = RealCallee;
-      }
-    }
-  }
-
   // Unlike LLVM, GCC does not require that call statements provide a value for
   // every function argument (it passes rubbish for arguments with no value).
   // To get the same effect we pass 'undef' for any unspecified arguments.
-  PFTy = cast<PointerType>(Callee->getType());
-  FTy = cast<FunctionType>(PFTy->getElementType());
   if (CallOperands.size() < FTy->getNumParams())
     for (unsigned i = CallOperands.size(), e = FTy->getNumParams(); i != e; ++i)
       CallOperands.push_back(UndefValue::get(FTy->getParamType(i)));
@@ -8467,8 +8427,23 @@
   CallingConv::ID CallingConv;
   AttrListPtr PAL;
 
-  Type *Ty = ConvertFunctionType(function_type, fndecl, gimple_call_chain(stmt),
-                                 CallingConv, PAL);
+  Type *Ty;
+  // If this is a K&R-style function: with a type that takes no arguments but
+  // with arguments none the less, then calculate the LLVM type from the list
+  // of arguments.
+  if (flag_functions_from_args || (TYPE_ARG_TYPES(function_type) == 0 &&
+                                   gimple_call_num_args(stmt) > 0)) {
+    tree *FirstArgAddr = gimple_call_num_args(stmt) > 0 ?
+      gimple_call_arg_ptr(stmt, 0) : NULL;
+    Ty = ConvertArgListToFnType(function_type,
+                                ArrayRef<tree>(FirstArgAddr,
+                                               gimple_call_num_args(stmt)),
+                                gimple_call_chain(stmt),
+                                !flag_functions_from_args, CallingConv, PAL);
+  } else {
+    Ty = ConvertFunctionType(function_type, fndecl, gimple_call_chain(stmt),
+                             CallingConv, PAL);
+  }
 
   // If this is a direct call to a function using a static chain then we need
   // to ensure the function type is the one just calculated: it has an extra

Modified: dragonegg/trunk/src/Types.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/src/Types.cpp?rev=138663&r1=138662&r2=138663&view=diff
==============================================================================
--- dragonegg/trunk/src/Types.cpp (original)
+++ dragonegg/trunk/src/Types.cpp Fri Aug 26 16:29:18 2011
@@ -650,14 +650,15 @@
 /// for the function.  This method takes the DECL_ARGUMENTS list (Args), and
 /// fills in Result with the argument types for the function.  It returns the
 /// specified result type for the function.
-FunctionType *ConvertArgListToFnType(tree type, tree Args, tree static_chain,
+FunctionType *ConvertArgListToFnType(tree type, ArrayRef<tree> Args,
+                                     tree static_chain, bool KNRPromotion,
                                      CallingConv::ID &CallingConv,
                                      AttrListPtr &PAL) {
   tree ReturnType = TREE_TYPE(type);
   SmallVector<Type*, 8> ArgTys;
   Type *RetTy(Type::getVoidTy(Context));
 
-  FunctionTypeConversion Client(RetTy, ArgTys, CallingConv, true /*K&R*/);
+  FunctionTypeConversion Client(RetTy, ArgTys, CallingConv, KNRPromotion);
   DefaultABI ABIConverter(Client);
 
 #ifdef TARGET_ADJUST_LLVM_CC
@@ -695,8 +696,8 @@
                                              Attribute::Nest));
   }
 
-  for (; Args && TREE_TYPE(Args) != void_type_node; Args = TREE_CHAIN(Args)) {
-    tree ArgTy = TREE_TYPE(Args);
+  for (ArrayRef<tree>::iterator I = Args.begin(), E = Args.end(); I != E; ++I) {
+    tree ArgTy = TREE_TYPE(*I);
 
     // Determine if there are any attributes for this param.
     Attributes PAttributes = Attribute::None;
@@ -719,7 +720,6 @@
                                   AttrListPtr &PAL) {
   Type *RetTy = Type::getVoidTy(Context);
   SmallVector<Type*, 8> ArgTypes;
-  bool isVarArg = false;
   FunctionTypeConversion Client(RetTy, ArgTypes, CallingConv, false/*not K&R*/);
   DefaultABI ABIConverter(Client);
 
@@ -886,13 +886,6 @@
   if (HasByVal)
     FnAttributes &= ~(Attribute::ReadNone | Attribute::ReadOnly);
 
-  if (flag_force_vararg_prototypes)
-    // If forcing prototypes to be varargs, make all function types varargs
-    // except those for builtin functions.
-    isVarArg = decl ? !DECL_BUILT_IN(decl) : true;
-  else
-    // If the argument list ends with a void type node, it isn't vararg.
-    isVarArg = (Args == 0);
   assert(RetTy && "Return type not specified!");
 
   if (FnAttributes != Attribute::None)
@@ -900,7 +893,7 @@
 
   // Finally, make the function type and result attributes.
   PAL = AttrListPtr::get(Attrs.begin(), Attrs.end());
-  return FunctionType::get(RetTy, ArgTypes, isVarArg);
+  return FunctionType::get(RetTy, ArgTypes, stdarg_p(type));
 }
 
 static Type *ConvertPointerTypeRecursive(tree type) {





More information about the llvm-commits mailing list