From: Chris Lattner Date: Sun, 2 Dec 2007 06:27:33 +0000 (+0000) Subject: implement codegen for functions whose function body type don't match X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=58c3f9ec11cbe852a518bf2f83af46f938b7b852;p=clang implement codegen for functions whose function body type don't match their prototype. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44506 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/CodeGen/CodeGenFunction.cpp b/CodeGen/CodeGenFunction.cpp index 0da5fcdaaa..190da77b2b 100644 --- a/CodeGen/CodeGenFunction.cpp +++ b/CodeGen/CodeGenFunction.cpp @@ -58,8 +58,42 @@ void CodeGenFunction::GenerateCode(const FunctionDecl *FD) { getContext().getTypeSize(getContext().getPointerType(getContext().VoidTy), SourceLocation())); - CurFn = cast(CGM.GetAddrOfGlobalDecl(FD)); CurFuncDecl = FD; + llvm::Constant *CurFnC = CGM.GetAddrOfGlobalDecl(FD); + if (!(CurFn = dyn_cast(CurFnC))) { + // If CurFnC is not a constant, it must be a bitcast of another function. + llvm::ConstantExpr *CurFnCE = cast(CurFnC); + assert(CurFnCE->getOpcode() == llvm::Instruction::BitCast && + "Unexpected name collision"); + llvm::Function *OtherFunc = cast(CurFnCE->getOperand(0)); + + // 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. + const llvm::PointerType *PTy = cast(CurFnC->getType()); + const llvm::FunctionType *FTy = + cast(PTy->getElementType()); + CurFn = new llvm::Function(FTy, llvm::Function::ExternalLinkage, "", + &CGM.getModule()); + CurFn->takeName(OtherFunc); + + // Replace uses of OtherFunc with the Function we will endow with a body. + llvm::Constant *NewPtrForOldDecl = + llvm::ConstantExpr::getBitCast(CurFn, OtherFunc->getType()); + OtherFunc->replaceAllUsesWith(NewPtrForOldDecl); + + // Make sure the GlobalDecl map for FD is up-to-date. + CGM.ChangeGlobalDeclMap(FD, CurFn); + + // FIXME: Update the globaldeclmap for the previous decl of this name. We + // really want a way to walk all of these, but we don't have it yet. This + // is incredibly slow! + CGM.ReplaceMapValuesWith(OtherFunc, NewPtrForOldDecl); + + // Ok, delete the old function now, which is dead. + assert(OtherFunc->isDeclaration() && "Shouldn't replace non-declaration"); + OtherFunc->eraseFromParent(); + } assert(CurFn->isDeclaration() && "Function already has body?"); diff --git a/CodeGen/CodeGenModule.cpp b/CodeGen/CodeGenModule.cpp index b76d5e35ee..51f758c542 100644 --- a/CodeGen/CodeGenModule.cpp +++ b/CodeGen/CodeGenModule.cpp @@ -31,6 +31,18 @@ CodeGenModule::CodeGenModule(ASTContext &C, const LangOptions &LO, : Context(C), Features(LO), TheModule(M), TheTargetData(TD), Diags(diags), Types(C, M, TD), MemCpyFn(0), CFConstantStringClassRef(0) {} + +/// ReplaceMapValuesWith - This is a really slow and bad function that +/// searches for any entries in GlobalDeclMap that point to OldVal, changing +/// them to point to NewVal. This is badbadbad, FIXME! +void CodeGenModule::ReplaceMapValuesWith(llvm::Constant *OldVal, + llvm::Constant *NewVal) { + for (llvm::DenseMap::iterator + I = GlobalDeclMap.begin(), E = GlobalDeclMap.end(); I != E; ++I) + if (I->second == OldVal) I->second = NewVal; +} + + llvm::Constant *CodeGenModule::GetAddrOfGlobalDecl(const ValueDecl *D) { // See if it is already in the map. llvm::Constant *&Entry = GlobalDeclMap[D]; diff --git a/CodeGen/CodeGenModule.h b/CodeGen/CodeGenModule.h index c4867c0bfa..dd4c006a12 100644 --- a/CodeGen/CodeGenModule.h +++ b/CodeGen/CodeGenModule.h @@ -68,6 +68,15 @@ public: llvm::Constant *GetAddrOfGlobalDecl(const ValueDecl *D); + void ChangeGlobalDeclMap(const Decl *Decl, llvm::Constant *NewVal) { + GlobalDeclMap[Decl] = NewVal; + } + + /// ReplaceMapValuesWith - This is a really slow and bad function that + /// searches for any entries in GlobalDeclMap that point to OldVal, changing + /// them to point to NewVal. This is badbadbad, FIXME! + void ReplaceMapValuesWith(llvm::Constant *OldVal, llvm::Constant *NewVal); + /// getBuiltinLibFunction - Given a builtin id for a function like /// "__builtin_fabsf", return a Function* for "fabsf". /// diff --git a/test/CodeGen/functions.c b/test/CodeGen/functions.c new file mode 100644 index 0000000000..09cb9786da --- /dev/null +++ b/test/CodeGen/functions.c @@ -0,0 +1,11 @@ +// RUN: clang %s -emit-llvm +int g(); + +int foo(int i) { + return g(i); +} + +int g(int i) { + return g(i); +} +