diff options
Diffstat (limited to 'lib/CodeGen/CGDecl.cpp')
-rw-r--r-- | lib/CodeGen/CGDecl.cpp | 145 |
1 files changed, 84 insertions, 61 deletions
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index d6d6696894..7cd02d8d86 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -169,7 +169,24 @@ static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D, return ContextName + Separator + D.getNameAsString(); } -llvm::GlobalVariable * +/// We wanted to make a variable of one type, but the variable already +/// exists with another. Is that type good enough? +/// +/// The problem we're working around here is that giving a global +/// variable an initializer can require changing its type in some +/// convoluted circumstances. +static bool isExistingVarAdequate(CodeGenModule &CGM, + llvm::Type *existing, llvm::Type *desired) { + // Equality makes for a good fast path. + if (existing == desired) return true; + + // Otherwise, just require them to have the same size. + return (CGM.getTargetData().getTypeStoreSize(existing) + == CGM.getTargetData().getTypeStoreSize(desired)); +} + + +llvm::Constant * CodeGenFunction::CreateStaticVarDecl(const VarDecl &D, const char *Separator, llvm::GlobalValue::LinkageTypes Linkage) { @@ -184,20 +201,27 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D, Name = GetStaticDeclName(*this, D, Separator); llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty); + unsigned addrspace = CGM.getContext().getTargetAddressSpace(Ty); // In C++, there are strange possibilities here involving the // double-emission of constructors and destructors. if (CGM.getLangOpts().CPlusPlus) { llvm::GlobalValue *value = CGM.getModule().getNamedValue(Name); - if (value && isa<llvm::GlobalVariable>(value) && - value->getType() == - LTy->getPointerTo(CGM.getContext().getTargetAddressSpace(Ty))) - return cast<llvm::GlobalVariable>(value); + if (value && isa<llvm::GlobalVariable>(value)) { + // Check that the type is compatible with the type we want. The + // simple equality check isn't good enough because initializers + // can force the changing of a type (e.g. with unions). + if (value->getType()->getAddressSpace() == addrspace && + isExistingVarAdequate(CGM, value->getType()->getElementType(), LTy)) + return llvm::ConstantExpr::getBitCast(value, + LTy->getPointerTo(addrspace)); + } if (value) { CGM.Error(D.getLocation(), - "problem emitting static variable: already present as " - "different kind of symbol"); + "problem emitting static variable '" + Name + + "': already present as different kind of symbol"); + // Fall through and implicitly give it a uniqued name. } } @@ -207,7 +231,7 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D, Ty.isConstant(getContext()), Linkage, CGM.EmitNullConstant(D.getType()), Name, 0, D.isThreadSpecified(), - CGM.getContext().getTargetAddressSpace(Ty)); + addrspace); GV->setAlignment(getContext().getDeclAlign(&D).getQuantity()); if (Linkage != llvm::GlobalValue::InternalLinkage) GV->setVisibility(CurFn->getVisibility()); @@ -222,80 +246,85 @@ static bool hasNontrivialDestruction(QualType T) { return RD && !RD->hasTrivialDestructor(); } -/// AddInitializerToStaticVarDecl - Add the initializer for 'D' to the -/// global variable that has already been created for it. If the initializer -/// has a different type than GV does, this may free GV and return a different -/// one. Otherwise it just returns GV. -llvm::GlobalVariable * +/// AddInitializerToStaticVarDecl - Add the initializer for 'D' to +/// the global variable that has already been created for it. If +/// the initializer has a different type than GV does, this may +/// force the underlying variable to change. Otherwise it just +/// returns it. +/// +/// The argument must be a (potentially casted) global variable, +/// and the result will be one, too. +llvm::Constant * CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, - llvm::GlobalVariable *GV) { - llvm::Constant *Init = CGM.EmitConstantInit(D, this); + llvm::Constant *addr) { + llvm::Constant *init = CGM.EmitConstantInit(D, this); + + llvm::GlobalVariable *var = + cast<llvm::GlobalVariable>(addr->stripPointerCasts()); // If constant emission failed, then this should be a C++ static // initializer. - if (!Init) { + if (!init) { if (!getContext().getLangOpts().CPlusPlus) CGM.ErrorUnsupported(D.getInit(), "constant l-value expression"); else if (Builder.GetInsertBlock()) { // Since we have a static initializer, this global variable can't // be constant. - GV->setConstant(false); + var->setConstant(false); - EmitCXXGuardedInit(D, GV, /*PerformInit*/true); + EmitCXXGuardedInit(D, addr, /*PerformInit*/true); } - return GV; + return addr; } // The initializer may differ in type from the global. Rewrite // the global to match the initializer. (We have to do this // because some types, like unions, can't be completely represented // in the LLVM type system.) - if (GV->getType()->getElementType() != Init->getType()) { - llvm::GlobalVariable *OldGV = GV; - - GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), - OldGV->isConstant(), - OldGV->getLinkage(), Init, "", - /*InsertBefore*/ OldGV, - D.isThreadSpecified(), - CGM.getContext().getTargetAddressSpace(D.getType())); - GV->setVisibility(OldGV->getVisibility()); + if (var->getType()->getElementType() != init->getType()) { + llvm::GlobalVariable *newVar + = new llvm::GlobalVariable(CGM.getModule(), init->getType(), + var->isConstant(), + var->getLinkage(), init, "", + /*InsertBefore*/ var, + D.isThreadSpecified(), + var->getType()->getAddressSpace()); + newVar->setVisibility(var->getVisibility()); // Steal the name of the old global - GV->takeName(OldGV); + newVar->takeName(var); // Replace all uses of the old global with the new global - llvm::Constant *NewPtrForOldDecl = - llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); - OldGV->replaceAllUsesWith(NewPtrForOldDecl); + addr = llvm::ConstantExpr::getBitCast(newVar, addr->getType()); + var->replaceAllUsesWith(addr); // Erase the old global, since it is no longer used. - OldGV->eraseFromParent(); + var->eraseFromParent(); + var = newVar; } - GV->setConstant(CGM.isTypeConstant(D.getType(), true)); - GV->setInitializer(Init); + var->setConstant(CGM.isTypeConstant(D.getType(), true)); + var->setInitializer(init); if (hasNontrivialDestruction(D.getType())) { // We have a constant initializer, but a nontrivial destructor. We still // need to perform a guarded "initialization" in order to register the // destructor. - EmitCXXGuardedInit(D, GV, /*PerformInit*/false); + EmitCXXGuardedInit(D, addr, /*PerformInit*/false); } - return GV; + return addr; } void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, llvm::GlobalValue::LinkageTypes Linkage) { - llvm::Value *&DMEntry = LocalDeclMap[&D]; - assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); - llvm::GlobalVariable *GV = CreateStaticVarDecl(D, ".", Linkage); + llvm::Constant *addr = CreateStaticVarDecl(D, ".", Linkage); // Store into LocalDeclMap before generating initializer to handle // circular references. - DMEntry = GV; + assert(!LocalDeclMap.count(&D) && "Decl already exists in localdeclmap!"); + LocalDeclMap[&D] = addr; // We can't have a VLA here, but we can have a pointer to a VLA, // even though that doesn't really make any sense. @@ -305,40 +334,34 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, // Local static block variables must be treated as globals as they may be // referenced in their RHS initializer block-literal expresion. - CGM.setStaticLocalDeclAddress(&D, GV); + CGM.setStaticLocalDeclAddress(&D, addr); // If this value has an initializer, emit it. + // This can leave us with a casted pointer. if (D.getInit()) - GV = AddInitializerToStaticVarDecl(D, GV); + addr = AddInitializerToStaticVarDecl(D, addr); - GV->setAlignment(getContext().getDeclAlign(&D).getQuantity()); + llvm::GlobalVariable *var = + cast<llvm::GlobalVariable>(addr->stripPointerCasts()); + var->setAlignment(getContext().getDeclAlign(&D).getQuantity()); if (D.hasAttr<AnnotateAttr>()) - CGM.AddGlobalAnnotations(&D, GV); + CGM.AddGlobalAnnotations(&D, var); if (const SectionAttr *SA = D.getAttr<SectionAttr>()) - GV->setSection(SA->getName()); + var->setSection(SA->getName()); if (D.hasAttr<UsedAttr>()) - CGM.AddUsedGlobal(GV); - - // We may have to cast the constant because of the initializer - // mismatch above. - // - // FIXME: It is really dangerous to store this in the map; if anyone - // RAUW's the GV uses of this constant will be invalid. - llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(D.getType()); - llvm::Type *LPtrTy = - LTy->getPointerTo(CGM.getContext().getTargetAddressSpace(D.getType())); - llvm::Constant *CastedVal = llvm::ConstantExpr::getBitCast(GV, LPtrTy); - DMEntry = CastedVal; - CGM.setStaticLocalDeclAddress(&D, CastedVal); + CGM.AddUsedGlobal(var); + + LocalDeclMap[&D] = addr; + CGM.setStaticLocalDeclAddress(&D, addr); // Emit global variable debug descriptor for static vars. CGDebugInfo *DI = getDebugInfo(); if (DI) { DI->setLocation(D.getLocation()); - DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(GV), &D); + DI->EmitGlobalVariable(var, &D); } } |