From 9cd4fe4af6d3e8b6dcfce9c2cdefcaafca7eed7c Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 2 Dec 2007 07:09:19 +0000 Subject: [PATCH] Handle global variable definitions which change the type of a definition, such as: extern int x[]; void foo() { x[0] = 1; } int x[10]; void bar() { x[0] = 1; } git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44509 91177308-0d34-0410-b5e6-96231b3b80d8 --- CodeGen/CGExpr.cpp | 6 +- CodeGen/CodeGenFunction.cpp | 37 +--------- CodeGen/CodeGenModule.cpp | 140 ++++++++++++++++++++++++++++-------- CodeGen/CodeGenModule.h | 20 +++--- test/CodeGen/globalinit.c | 6 ++ 5 files changed, 134 insertions(+), 75 deletions(-) diff --git a/CodeGen/CGExpr.cpp b/CodeGen/CGExpr.cpp index 93f3d71eaf..e7bd712f31 100644 --- a/CodeGen/CGExpr.cpp +++ b/CodeGen/CGExpr.cpp @@ -268,8 +268,10 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { llvm::Value *V = LocalDeclMap[D]; assert(V && "BlockVarDecl not entered in LocalDeclMap?"); return LValue::MakeAddr(V); - } else if (isa(D) || isa(D)) { - return LValue::MakeAddr(CGM.GetAddrOfGlobalDecl(D)); + } else if (const FunctionDecl *FD = dyn_cast(D)) { + return LValue::MakeAddr(CGM.GetAddrOfFunctionDecl(FD, false)); + } else if (const FileVarDecl *FVD = dyn_cast(D)) { + return LValue::MakeAddr(CGM.GetAddrOfFileVarDecl(FVD, false)); } assert(0 && "Unimp declref"); //an invalid LValue, but the assert will diff --git a/CodeGen/CodeGenFunction.cpp b/CodeGen/CodeGenFunction.cpp index aa9d2c6054..3ee7d1f0fc 100644 --- a/CodeGen/CodeGenFunction.cpp +++ b/CodeGen/CodeGenFunction.cpp @@ -59,42 +59,7 @@ void CodeGenFunction::GenerateCode(const FunctionDecl *FD) { SourceLocation())); 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(); - } - + CurFn = cast(CGM.GetAddrOfFunctionDecl(FD, true)); assert(CurFn->isDeclaration() && "Function already has body?"); // TODO: Set up linkage and many other things. Note, this is a simple diff --git a/CodeGen/CodeGenModule.cpp b/CodeGen/CodeGenModule.cpp index 7ef4fe19de..727d9fb6d7 100644 --- a/CodeGen/CodeGenModule.cpp +++ b/CodeGen/CodeGenModule.cpp @@ -43,41 +43,123 @@ void CodeGenModule::ReplaceMapValuesWith(llvm::Constant *OldVal, } -llvm::Constant *CodeGenModule::GetAddrOfGlobalDecl(const ValueDecl *D) { - // See if it is already in the map. +llvm::Constant *CodeGenModule::GetAddrOfFunctionDecl(const FunctionDecl *D, + bool isDefinition) { + // See if it is already in the map. If so, just return it. llvm::Constant *&Entry = GlobalDeclMap[D]; if (Entry) return Entry; - QualType ASTTy = cast(D)->getType(); - const llvm::Type *Ty = getTypes().ConvertType(ASTTy); - if (isa(D)) { - // Check to see if the function already exists. - if (llvm::Function *F = getModule().getFunction(D->getName())) { - // If so, make sure it is the correct type. - return Entry = llvm::ConstantExpr::getBitCast(F, - llvm::PointerType::get(Ty)); - } - + const llvm::Type *Ty = getTypes().ConvertType(D->getType()); + + // Check to see if the function already exists. + llvm::Function *F = getModule().getFunction(D->getName()); + const llvm::FunctionType *FTy = cast(Ty); + + // If it doesn't already exist, just create and return an entry. + if (F == 0) { // FIXME: param attributes for sext/zext etc. - const llvm::FunctionType *FTy = cast(Ty); return Entry = new llvm::Function(FTy, llvm::Function::ExternalLinkage, D->getName(), &getModule()); } - assert(isa(D) && "Unknown global decl!"); - - if (llvm::GlobalVariable *GV = getModule().getGlobalVariable(D->getName())) { - // If so, make sure it is the correct type. - return Entry = llvm::ConstantExpr::getBitCast(GV, - llvm::PointerType::get(Ty)); + // If the pointer type matches, just return it. + llvm::Type *PFTy = llvm::PointerType::get(Ty); + if (PFTy == F->getType()) return Entry = F; + // If this isn't a definition, just return it casted to the right type. + if (!isDefinition) + return Entry = llvm::ConstantExpr::getBitCast(F, PFTy); + + // Otherwise, we have a definition after a prototype with the wrong type. + // F is the Function* for the one with the wrong type, we must make a new + // Function* and update everything that used F (a declaration) with the new + // Function* (which will be a definition). + // + // 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. + llvm::Function *NewFn = new llvm::Function(FTy, + llvm::Function::ExternalLinkage, + "", &getModule()); + NewFn->takeName(F); + + // Replace uses of F with the Function we will endow with a body. + llvm::Constant *NewPtrForOldDecl = + llvm::ConstantExpr::getBitCast(NewFn, F->getType()); + F->replaceAllUsesWith(NewPtrForOldDecl); + + // 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! + ReplaceMapValuesWith(F, NewPtrForOldDecl); + + // Ok, delete the old function now, which is dead. + assert(F->isDeclaration() && "Shouldn't replace non-declaration"); + F->eraseFromParent(); + + // Return the new function which has the right type. + return Entry = NewFn; +} + +llvm::Constant *CodeGenModule::GetAddrOfFileVarDecl(const FileVarDecl *D, + bool isDefinition) { + // See if it is already in the map. + llvm::Constant *&Entry = GlobalDeclMap[D]; + if (Entry) return Entry; + + const llvm::Type *Ty = getTypes().ConvertType(D->getType()); + + // Check to see if the global already exists. + llvm::GlobalVariable *GV = getModule().getGlobalVariable(D->getName()); + + // If it doesn't already exist, just create and return an entry. + if (GV == 0) { + return Entry = new llvm::GlobalVariable(Ty, false, + llvm::GlobalValue::ExternalLinkage, + 0, D->getName(), &getModule()); } - return Entry = new llvm::GlobalVariable(Ty, false, - llvm::GlobalValue::ExternalLinkage, - 0, D->getName(), &getModule()); + // If the pointer type matches, just return it. + llvm::Type *PTy = llvm::PointerType::get(Ty); + if (PTy == GV->getType()) return Entry = GV; + + // If this isn't a definition, just return it casted to the right type. + if (!isDefinition) + return Entry = llvm::ConstantExpr::getBitCast(GV, PTy); + + + // Otherwise, we have a definition after a prototype with the wrong type. + // GV is the GlobalVariable* for the one with the wrong type, we must make a + /// new GlobalVariable* and update everything that used GV (a declaration) + // with the new GlobalVariable* (which will be a definition). + // + // This happens if there is a prototype for a global (e.g. "extern int x[];") + // and then a definition of a different type (e.g. "int x[10];"). Start by + // making a new global of the correct type, RAUW, then steal the name. + llvm::GlobalVariable *NewGV = + new llvm::GlobalVariable(Ty, false, llvm::GlobalValue::ExternalLinkage, + 0, D->getName(), &getModule()); + NewGV->takeName(GV); + + // Replace uses of GV with the globalvalue we will endow with a body. + llvm::Constant *NewPtrForOldDecl = + llvm::ConstantExpr::getBitCast(NewGV, GV->getType()); + GV->replaceAllUsesWith(NewPtrForOldDecl); + + // 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! + ReplaceMapValuesWith(GV, NewPtrForOldDecl); + + // Ok, delete the old global now, which is dead. + assert(GV->isDeclaration() && "Shouldn't replace non-declaration"); + GV->eraseFromParent(); + + // Return the new global which has the right type. + return Entry = NewGV; } + void CodeGenModule::EmitFunction(const FunctionDecl *FD) { // If this is not a prototype, emit the body. if (FD->getBody()) @@ -307,14 +389,16 @@ llvm::Constant *CodeGenModule::EmitGlobalInit(const Expr *Expression) { } void CodeGenModule::EmitGlobalVar(const FileVarDecl *D) { - llvm::GlobalVariable *GV = cast(GetAddrOfGlobalDecl(D)); - - // If the storage class is external and there is no initializer, just leave it - // as a declaration. + // If this is just a forward declaration of the variable, don't emit it now, + // allow it to be emitted lazily on its first use. if (D->getStorageClass() == VarDecl::Extern && D->getInit() == 0) return; - - // Otherwise, convert the initializer, or use zero if appropriate. + + // Get the global, forcing it to be a direct reference. + llvm::GlobalVariable *GV = + cast(GetAddrOfFileVarDecl(D, true)); + + // Convert the initializer, or use zero if appropriate. llvm::Constant *Init = 0; if (D->getInit() == 0) { Init = llvm::Constant::getNullValue(GV->getType()->getElementType()); diff --git a/CodeGen/CodeGenModule.h b/CodeGen/CodeGenModule.h index dd4c006a12..027c8303aa 100644 --- a/CodeGen/CodeGenModule.h +++ b/CodeGen/CodeGenModule.h @@ -66,16 +66,11 @@ public: CodeGenTypes &getTypes() { return Types; } Diagnostic &getDiags() const { return Diags; } - llvm::Constant *GetAddrOfGlobalDecl(const ValueDecl *D); + llvm::Constant *GetAddrOfFunctionDecl(const FunctionDecl *D, + bool isDefinition); + llvm::Constant *GetAddrOfFileVarDecl(const FileVarDecl *D, + bool isDefinition); - 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". @@ -92,6 +87,13 @@ public: llvm::Constant *EmitGlobalInit(const Expr *Expression); void PrintStats() {} + +private: + /// 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); + }; } // end namespace CodeGen } // end namespace clang diff --git a/test/CodeGen/globalinit.c b/test/CodeGen/globalinit.c index 7087669cbd..e94027c360 100644 --- a/test/CodeGen/globalinit.c +++ b/test/CodeGen/globalinit.c @@ -2,3 +2,9 @@ int A[10] = { 1,2,3,4,5 }; + +extern int x[]; +void foo() { x[0] = 1; } +int x[10]; +void bar() { x[0] = 1; } + -- 2.40.0