diff options
author | John McCall <rjmccall@apple.com> | 2011-09-21 08:08:30 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-09-21 08:08:30 +0000 |
commit | cbc038a6c3fcb45439473a70d0284916d47d900e (patch) | |
tree | 068e2cd6328fb13ba95832e950d6bc6a8e0e2c7e /clang/lib/CodeGen | |
parent | 3b4de99158766ca7f41d7f6baafbd9b94a81e0a5 (diff) | |
download | bcm5719-llvm-cbc038a6c3fcb45439473a70d0284916d47d900e.tar.gz bcm5719-llvm-cbc038a6c3fcb45439473a70d0284916d47d900e.zip |
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.
llvm-svn: 140241
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 32 | ||||
-rw-r--r-- | clang/lib/CodeGen/TargetInfo.cpp | 17 | ||||
-rw-r--r-- | clang/lib/CodeGen/TargetInfo.h | 35 |
3 files changed, 82 insertions, 2 deletions
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index f4c552b0850..62be62b79ed 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -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 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee, 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:: diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 434e202f2e9..bad8a1d928a 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -98,6 +98,14 @@ unsigned TargetCodeGenInfo::getSizeOfUnwindException() const { 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 @@ public: 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 { diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index 22e6eb8383b..8f90c7bdd92 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -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 @@ namespace clang { 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; }; } |