summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/CodeGenModule.cpp
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2009-05-05 06:16:31 +0000
committerChris Lattner <sabre@nondot.org>2009-05-05 06:16:31 +0000
commit36797ab2513a1e31304b703f3771fb143c0da1e1 (patch)
tree0a73541a4e73a7f34e35bb199d9bd5b6cfdd750b /clang/lib/CodeGen/CodeGenModule.cpp
parent448a2285218486b87a819ffa0488e3908ca50107 (diff)
downloadbcm5719-llvm-36797ab2513a1e31304b703f3771fb143c0da1e1.tar.gz
bcm5719-llvm-36797ab2513a1e31304b703f3771fb143c0da1e1.zip
When defining a function whose type has no prototype, make an effort
to go back and clean up existing uses of the bitcasted function. This is not just an optimization: it is required for correctness to get always inline functions to work, see testcases in function-attributes.c. llvm-svn: 70971
Diffstat (limited to 'clang/lib/CodeGen/CodeGenModule.cpp')
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp85
1 files changed, 79 insertions, 6 deletions
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 48e1a1e2ec4..08f2b27bea5 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -851,6 +851,69 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
}
}
+/// ReplaceUsesOfNonProtoTypeWithRealFunction - This function is called when we
+/// implement a function with no prototype, e.g. "int foo() {}". If there are
+/// existing call uses of the old function in the module, this adjusts them to
+/// call the new function directly.
+///
+/// This is not just a cleanup: the always_inline pass requires direct calls to
+/// functions to be able to inline them. If there is a bitcast in the way, it
+/// won't inline them. Instcombine normally deletes these calls, but it isn't
+/// run at -O0.
+static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
+ llvm::Function *NewFn) {
+ // If we're redefining a global as a function, don't transform it.
+ llvm::Function *OldFn = dyn_cast<llvm::Function>(Old);
+ if (OldFn == 0) return;
+
+ const llvm::Type *NewRetTy = NewFn->getReturnType();
+ llvm::SmallVector<llvm::Value*, 4> ArgList;
+
+ for (llvm::Value::use_iterator UI = OldFn->use_begin(), E = OldFn->use_end();
+ UI != E; ) {
+ // TODO: Do invokes ever occur in C code? If so, we should handle them too.
+ llvm::CallInst *CI = dyn_cast<llvm::CallInst>(*UI++);
+ if (!CI) continue;
+
+ // If the return types don't match exactly, and if the call isn't dead, then
+ // we can't transform this call.
+ if (CI->getType() != NewRetTy && !CI->use_empty())
+ continue;
+
+ // If the function was passed too few arguments, don't transform. If extra
+ // arguments were passed, we silently drop them. If any of the types
+ // mismatch, we don't transform.
+ unsigned ArgNo = 0;
+ bool DontTransform = false;
+ for (llvm::Function::arg_iterator AI = NewFn->arg_begin(),
+ E = NewFn->arg_end(); AI != E; ++AI, ++ArgNo) {
+ if (CI->getNumOperands()-1 == ArgNo ||
+ CI->getOperand(ArgNo+1)->getType() != AI->getType()) {
+ DontTransform = true;
+ break;
+ }
+ }
+ if (DontTransform)
+ continue;
+
+ // Okay, we can transform this. Create the new call instruction and copy
+ // over the required information.
+ ArgList.append(CI->op_begin()+1, CI->op_begin()+1+ArgNo);
+ llvm::CallInst *NewCall = llvm::CallInst::Create(NewFn, ArgList.begin(),
+ ArgList.end(), "", CI);
+ ArgList.clear();
+ if (NewCall->getType() != llvm::Type::VoidTy)
+ NewCall->takeName(CI);
+ NewCall->setCallingConv(CI->getCallingConv());
+ NewCall->setAttributes(CI->getAttributes());
+
+ // Finally, remove the old call, replacing any uses with the new one.
+ if (!CI->use_empty())
+ CI->replaceAllUsesWith(NewCall);
+ CI->eraseFromParent();
+ }
+}
+
void CodeGenModule::EmitGlobalFunctionDefinition(const FunctionDecl *D) {
const llvm::FunctionType *Ty;
@@ -886,8 +949,10 @@ void CodeGenModule::EmitGlobalFunctionDefinition(const FunctionDecl *D) {
if (cast<llvm::GlobalValue>(Entry)->getType()->getElementType() != Ty) {
+ llvm::GlobalValue *OldFn = cast<llvm::GlobalValue>(Entry);
+
// If the types mismatch then we have to rewrite the definition.
- assert(cast<llvm::GlobalValue>(Entry)->isDeclaration() &&
+ assert(OldFn->isDeclaration() &&
"Shouldn't replace non-declaration");
// F is the Function* for the one with the wrong type, we must make a new
@@ -900,15 +965,23 @@ void CodeGenModule::EmitGlobalFunctionDefinition(const FunctionDecl *D) {
// correct type, RAUW, then steal the name.
GlobalDeclMap.erase(getMangledName(D));
llvm::Function *NewFn = cast<llvm::Function>(GetAddrOfFunction(D, Ty));
- NewFn->takeName(cast<llvm::GlobalValue>(Entry));
+ NewFn->takeName(OldFn);
+
+ // If this is an implementation of a function without a prototype, try to
+ // replace any existing uses of the function (which may be calls) with uses
+ // of the new function
+ if (D->getType()->isFunctionNoProtoType())
+ ReplaceUsesOfNonProtoTypeWithRealFunction(OldFn, NewFn);
// Replace uses of F with the Function we will endow with a body.
- llvm::Constant *NewPtrForOldDecl =
- llvm::ConstantExpr::getBitCast(NewFn, Entry->getType());
- Entry->replaceAllUsesWith(NewPtrForOldDecl);
+ if (!Entry->use_empty()) {
+ llvm::Constant *NewPtrForOldDecl =
+ llvm::ConstantExpr::getBitCast(NewFn, Entry->getType());
+ Entry->replaceAllUsesWith(NewPtrForOldDecl);
+ }
// Ok, delete the old function now, which is dead.
- cast<llvm::GlobalValue>(Entry)->eraseFromParent();
+ OldFn->eraseFromParent();
Entry = NewFn;
}
OpenPOWER on IntegriCloud