forked from OSchip/llvm-project
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; } llvm-svn: 44509
This commit is contained in:
parent
c48023bd5b
commit
5bcdf24a50
|
@ -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<FunctionDecl>(D) || isa<FileVarDecl>(D)) {
|
||||
return LValue::MakeAddr(CGM.GetAddrOfGlobalDecl(D));
|
||||
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
return LValue::MakeAddr(CGM.GetAddrOfFunctionDecl(FD, false));
|
||||
} else if (const FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
|
||||
return LValue::MakeAddr(CGM.GetAddrOfFileVarDecl(FVD, false));
|
||||
}
|
||||
assert(0 && "Unimp declref");
|
||||
//an invalid LValue, but the assert will
|
||||
|
|
|
@ -59,42 +59,7 @@ void CodeGenFunction::GenerateCode(const FunctionDecl *FD) {
|
|||
SourceLocation()));
|
||||
|
||||
CurFuncDecl = FD;
|
||||
llvm::Constant *CurFnC = CGM.GetAddrOfGlobalDecl(FD);
|
||||
if (!(CurFn = dyn_cast<llvm::Function>(CurFnC))) {
|
||||
// If CurFnC is not a constant, it must be a bitcast of another function.
|
||||
llvm::ConstantExpr *CurFnCE = cast<llvm::ConstantExpr>(CurFnC);
|
||||
assert(CurFnCE->getOpcode() == llvm::Instruction::BitCast &&
|
||||
"Unexpected name collision");
|
||||
llvm::Function *OtherFunc = cast<llvm::Function>(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<llvm::PointerType>(CurFnC->getType());
|
||||
const llvm::FunctionType *FTy =
|
||||
cast<llvm::FunctionType>(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<llvm::Function>(CGM.GetAddrOfFunctionDecl(FD, true));
|
||||
assert(CurFn->isDeclaration() && "Function already has body?");
|
||||
|
||||
// TODO: Set up linkage and many other things. Note, this is a simple
|
||||
|
|
|
@ -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<ValueDecl>(D)->getType();
|
||||
const llvm::Type *Ty = getTypes().ConvertType(ASTTy);
|
||||
if (isa<FunctionDecl>(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<llvm::FunctionType>(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<llvm::FunctionType>(Ty);
|
||||
return Entry = new llvm::Function(FTy, llvm::Function::ExternalLinkage,
|
||||
D->getName(), &getModule());
|
||||
}
|
||||
|
||||
assert(isa<FileVarDecl>(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<llvm::GlobalVariable>(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<llvm::GlobalVariable>(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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
Loading…
Reference in New Issue