mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-03 00:20:40 +03:00
Refactoring: Move IR global declaration & definition to IrGlobal
This commit is contained in:
parent
a74601f91d
commit
a765bf8901
7 changed files with 144 additions and 115 deletions
|
@ -278,57 +278,13 @@ public:
|
|||
"manifest constant being codegen'd!");
|
||||
assert(!irs->dcomputetarget);
|
||||
|
||||
IrGlobal *irGlobal = getIrGlobal(decl);
|
||||
LLGlobalVariable *gvar = llvm::cast<LLGlobalVariable>(irGlobal->value);
|
||||
assert(gvar && "DtoResolveVariable should have created value");
|
||||
|
||||
if (global.params.vtls && gvar->isThreadLocal() &&
|
||||
!(decl->storage_class & STCtemp)) {
|
||||
const char *p = decl->loc.toChars();
|
||||
message("%s: `%s` is thread local", p, decl->toChars());
|
||||
}
|
||||
|
||||
// Check if we are defining or just declaring the global in this module.
|
||||
// If we reach here during codegen of an available_externally function,
|
||||
// new variable declarations should stay external and therefore must not
|
||||
// have an initializer.
|
||||
if (!(decl->storage_class & STCextern) && !decl->inNonRoot()) {
|
||||
// Build the initializer. Might use irGlobal->value!
|
||||
LLConstant *initVal =
|
||||
DtoConstInitializer(decl->loc, decl->type, decl->_init);
|
||||
bool define = !(decl->storage_class & STCextern) && !decl->inNonRoot();
|
||||
|
||||
// Cache it.
|
||||
assert(!irGlobal->constInit);
|
||||
irGlobal->constInit = initVal;
|
||||
|
||||
// Set the initializer, swapping out the variable if the types do not
|
||||
// match.
|
||||
irGlobal->value = irs->setGlobalVarInitializer(gvar, initVal);
|
||||
|
||||
// Finalize linkage & DLL storage class.
|
||||
const auto lwc = DtoLinkage(decl);
|
||||
setLinkage(lwc, gvar);
|
||||
if (gvar->hasDLLImportStorageClass()) {
|
||||
gvar->setDLLStorageClass(LLGlobalValue::DLLExportStorageClass);
|
||||
}
|
||||
|
||||
// Hide non-exported symbols
|
||||
if (opts::defaultToHiddenVisibility && !decl->isExport()) {
|
||||
gvar->setVisibility(LLGlobalValue::HiddenVisibility);
|
||||
}
|
||||
|
||||
// Also set up the debug info.
|
||||
irs->DBuilder.EmitGlobalVariable(gvar, decl);
|
||||
}
|
||||
|
||||
// If this global is used from a naked function, we need to create an
|
||||
// artificial "use" for it, or it could be removed by the optimizer if
|
||||
// the only reference to it is in inline asm.
|
||||
if (irGlobal->nakedUse) {
|
||||
irs->usedArray.push_back(gvar);
|
||||
}
|
||||
|
||||
IF_LOG Logger::cout() << *gvar << '\n';
|
||||
getIrGlobal(decl)->getValue(define);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -131,10 +131,12 @@ bool IRState::emitArrayBoundsChecks() {
|
|||
return t->ty == Tfunction && ((TypeFunction *)t)->trust == TRUST::safe;
|
||||
}
|
||||
|
||||
LLConstant *IRState::setGlobalVarInitializer(LLGlobalVariable *&globalVar,
|
||||
LLConstant *initializer) {
|
||||
LLConstant *
|
||||
IRState::setGlobalVarInitializer(LLGlobalVariable *&globalVar,
|
||||
LLConstant *initializer,
|
||||
Dsymbol *symbolForLinkageAndVisibility) {
|
||||
if (initializer->getType() == globalVar->getType()->getContainedType(0)) {
|
||||
globalVar->setInitializer(initializer);
|
||||
defineGlobal(globalVar, initializer, symbolForLinkageAndVisibility);
|
||||
return globalVar;
|
||||
}
|
||||
|
||||
|
@ -142,7 +144,7 @@ LLConstant *IRState::setGlobalVarInitializer(LLGlobalVariable *&globalVar,
|
|||
// It inherits most properties from the existing globalVar.
|
||||
auto globalHelperVar = new LLGlobalVariable(
|
||||
module, initializer->getType(), globalVar->isConstant(),
|
||||
globalVar->getLinkage(), initializer, "", nullptr,
|
||||
globalVar->getLinkage(), nullptr, "", nullptr,
|
||||
globalVar->getThreadLocalMode());
|
||||
globalHelperVar->setAlignment(LLMaybeAlign(globalVar->getAlignment()));
|
||||
globalHelperVar->setComdat(globalVar->getComdat());
|
||||
|
@ -150,6 +152,8 @@ LLConstant *IRState::setGlobalVarInitializer(LLGlobalVariable *&globalVar,
|
|||
globalHelperVar->setSection(globalVar->getSection());
|
||||
globalHelperVar->takeName(globalVar);
|
||||
|
||||
defineGlobal(globalHelperVar, initializer, symbolForLinkageAndVisibility);
|
||||
|
||||
// Replace all existing uses of globalVar by the bitcast pointer.
|
||||
auto castHelperVar = DtoBitCast(globalHelperVar, globalVar->getType());
|
||||
globalVar->replaceAllUsesWith(castHelperVar);
|
||||
|
|
|
@ -229,8 +229,10 @@ public:
|
|||
// Returns either the specified globalVar if the types match, or the bitcast
|
||||
// pointer replacing globalVar (and resets globalVar to the new helper
|
||||
// global).
|
||||
llvm::Constant *setGlobalVarInitializer(llvm::GlobalVariable *&globalVar,
|
||||
llvm::Constant *initializer);
|
||||
llvm::Constant *
|
||||
setGlobalVarInitializer(llvm::GlobalVariable *&globalVar,
|
||||
llvm::Constant *initializer,
|
||||
Dsymbol *symbolForLinkageAndVisibility);
|
||||
|
||||
// To be called when finalizing the IR module in order to perform a second
|
||||
// replacement pass for global variables replaced (and registered) by
|
||||
|
|
|
@ -861,67 +861,12 @@ void DtoResolveVariable(VarDeclaration *vd) {
|
|||
}
|
||||
vd->ir->setDeclared();
|
||||
|
||||
getIrGlobal(vd, true);
|
||||
|
||||
IF_LOG {
|
||||
if (vd->parent) {
|
||||
Logger::println("parent: %s (%s)", vd->parent->toChars(),
|
||||
vd->parent->kind());
|
||||
} else {
|
||||
Logger::println("parent: null");
|
||||
}
|
||||
}
|
||||
|
||||
// If a const/immutable value has a proper initializer (not "= void"),
|
||||
// it cannot be assigned again in a static constructor. Thus, we can
|
||||
// emit it as read-only data.
|
||||
// We also do so for forward-declared (extern) globals, just like clang.
|
||||
const bool isLLConst = (vd->isConst() || vd->isImmutable()) &&
|
||||
((vd->_init && !vd->_init->isVoidInitializer()) ||
|
||||
(vd->storage_class & STCextern));
|
||||
auto irGlobal = getIrGlobal(vd, true);
|
||||
irGlobal->getValue();
|
||||
|
||||
assert(!vd->ir->isInitialized());
|
||||
if (gIR->dmodule) {
|
||||
vd->ir->setInitialized();
|
||||
}
|
||||
const auto irMangle = getIRMangledName(vd);
|
||||
|
||||
// Since the type of a global must exactly match the type of its
|
||||
// initializer, we cannot know the type until after we have emitted the
|
||||
// latter (e.g. in case of unions, …). However, it is legal for the
|
||||
// initializer to refer to the address of the variable. Thus, we first
|
||||
// create a global with the generic type (note the assignment to
|
||||
// vd->ir->irGlobal->value!), and in case we also do an initializer
|
||||
// with a different type later, swap it out and replace any existing
|
||||
// uses with bitcasts to the previous type.
|
||||
|
||||
llvm::GlobalVariable *gvar =
|
||||
declareGlobal(vd->loc, gIR->module, DtoMemType(vd->type), irMangle,
|
||||
isLLConst, vd->isThreadlocal());
|
||||
if (vd->llvmInternal == LLVMextern_weak)
|
||||
gvar->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
|
||||
|
||||
auto varIr = getIrGlobal(vd);
|
||||
varIr->value = gvar;
|
||||
|
||||
// Set the alignment (it is important not to use type->alignsize because
|
||||
// VarDeclarations can have an align() attribute independent of the type
|
||||
// as well).
|
||||
gvar->setAlignment(LLMaybeAlign(DtoAlignment(vd)));
|
||||
|
||||
// Windows: initialize DLL storage class with `dllimport` for `export`ed
|
||||
// symbols
|
||||
if (global.params.isWindows && vd->isExport()) {
|
||||
gvar->setDLLStorageClass(LLGlobalValue::DLLImportStorageClass);
|
||||
}
|
||||
|
||||
applyVarDeclUDAs(vd, gvar);
|
||||
if (varIr->dynamicCompileConst) {
|
||||
addDynamicCompiledVar(gIR, varIr);
|
||||
}
|
||||
|
||||
IF_LOG Logger::cout() << *gvar << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
|
|
@ -407,7 +407,7 @@ public:
|
|||
|
||||
p->setStructLiteralConstant(se, globalVar);
|
||||
llvm::Constant *constValue = toConstElem(se);
|
||||
constValue = p->setGlobalVarInitializer(globalVar, constValue);
|
||||
constValue = p->setGlobalVarInitializer(globalVar, constValue, nullptr);
|
||||
p->setStructLiteralConstant(se, constValue);
|
||||
|
||||
result = constValue;
|
||||
|
@ -604,7 +604,7 @@ public:
|
|||
|
||||
llvm::Constant *constValue =
|
||||
getIrAggr(origClass)->createInitializerConstant(varInits);
|
||||
constValue = p->setGlobalVarInitializer(globalVar, constValue);
|
||||
constValue = p->setGlobalVarInitializer(globalVar, constValue, nullptr);
|
||||
p->setStructLiteralConstant(value, constValue);
|
||||
|
||||
result = constValue;
|
||||
|
|
121
ir/irvar.cpp
121
ir/irvar.cpp
|
@ -10,12 +10,131 @@
|
|||
#include "ir/irvar.h"
|
||||
|
||||
#include "dmd/declaration.h"
|
||||
#include "dmd/errors.h"
|
||||
#include "dmd/init.h"
|
||||
#include "gen/dynamiccompile.h"
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/llvm.h"
|
||||
#include "gen/llvmhelpers.h"
|
||||
#include "gen/logger.h"
|
||||
#include "gen/mangling.h"
|
||||
#include "gen/pragma.h"
|
||||
#include "gen/uda.h"
|
||||
#include "ir/irdsymbol.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LLValue *IrGlobal::getValue(bool define) {
|
||||
if (!value) {
|
||||
declare();
|
||||
}
|
||||
|
||||
if (define && !(V->storage_class & STCextern)) {
|
||||
auto gvar = llvm::dyn_cast<LLGlobalVariable>(value);
|
||||
const bool isDefined = !gvar // bitcast pointer to a helper global
|
||||
|| gvar->hasInitializer();
|
||||
if (!isDefined)
|
||||
this->define();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void IrGlobal::declare() {
|
||||
Logger::println("Declaring global: %s", V->toChars());
|
||||
LOG_SCOPE
|
||||
|
||||
IF_LOG {
|
||||
if (V->parent) {
|
||||
Logger::println("parent: %s (%s)", V->parent->toChars(),
|
||||
V->parent->kind());
|
||||
} else {
|
||||
Logger::println("parent: null");
|
||||
}
|
||||
}
|
||||
|
||||
assert(!value);
|
||||
|
||||
// If a const/immutable value has a proper initializer (not "= void"),
|
||||
// it cannot be assigned again in a static constructor. Thus, we can
|
||||
// emit it as read-only data.
|
||||
// We also do so for forward-declared (extern) globals, just like clang.
|
||||
const bool isLLConst = (V->isConst() || V->isImmutable()) &&
|
||||
((V->_init && !V->_init->isVoidInitializer()) ||
|
||||
(V->storage_class & STCextern));
|
||||
|
||||
const auto irMangle = getIRMangledName(V);
|
||||
|
||||
// Since the type of a global must exactly match the type of its
|
||||
// initializer, we cannot know the type until after we have emitted the
|
||||
// latter (e.g. in case of unions, …). However, it is legal for the
|
||||
// initializer to refer to the address of the variable. Thus, we first
|
||||
// create a global with the generic type (note the assignment to
|
||||
// vd->ir->irGlobal->value!), and in case we also do an initializer
|
||||
// with a different type later, swap it out and replace any existing
|
||||
// uses with bitcasts to the previous type.
|
||||
|
||||
LLGlobalVariable *gvar =
|
||||
declareGlobal(V->loc, gIR->module, DtoMemType(V->type), irMangle,
|
||||
isLLConst, V->isThreadlocal());
|
||||
value = gvar;
|
||||
|
||||
if (V->llvmInternal == LLVMextern_weak)
|
||||
gvar->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
|
||||
|
||||
// Set the alignment (it is important not to use type->alignsize because
|
||||
// VarDeclarations can have an align() attribute independent of the type
|
||||
// as well).
|
||||
gvar->setAlignment(LLMaybeAlign(DtoAlignment(V)));
|
||||
|
||||
// Windows: initialize DLL storage class with `dllimport` for `export`ed
|
||||
// symbols
|
||||
if (global.params.isWindows && V->isExport()) {
|
||||
gvar->setDLLStorageClass(LLGlobalValue::DLLImportStorageClass);
|
||||
}
|
||||
|
||||
applyVarDeclUDAs(V, gvar);
|
||||
|
||||
if (dynamicCompileConst)
|
||||
addDynamicCompiledVar(gIR, this);
|
||||
|
||||
IF_LOG Logger::cout() << *gvar << '\n';
|
||||
}
|
||||
|
||||
void IrGlobal::define() {
|
||||
Logger::println("Defining global: %s", V->toChars());
|
||||
LOG_SCOPE
|
||||
|
||||
if (global.params.vtls && V->isThreadlocal() &&
|
||||
!(V->storage_class & STCtemp)) {
|
||||
message("%s: `%s` is thread local", V->loc.toChars(), V->toChars());
|
||||
}
|
||||
|
||||
LLConstant *initVal = DtoConstInitializer(V->loc, V->type, V->_init);
|
||||
|
||||
// Set the initializer, swapping out the variable if the types do not
|
||||
// match.
|
||||
auto gvar = llvm::cast<LLGlobalVariable>(value);
|
||||
value = gIR->setGlobalVarInitializer(gvar, initVal, V);
|
||||
|
||||
// Finalize DLL storage class.
|
||||
if (gvar->hasDLLImportStorageClass()) {
|
||||
gvar->setDLLStorageClass(LLGlobalValue::DLLExportStorageClass);
|
||||
}
|
||||
|
||||
// If this global is used from a naked function, we need to create an
|
||||
// artificial "use" for it, or it could be removed by the optimizer if
|
||||
// the only reference to it is in inline asm.
|
||||
if (nakedUse) {
|
||||
gIR->usedArray.push_back(gvar);
|
||||
}
|
||||
|
||||
// Also set up the debug info.
|
||||
gIR->DBuilder.EmitGlobalVariable(gvar, V);
|
||||
|
||||
IF_LOG Logger::cout() << *gvar << '\n';
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IrVar *getIrVar(VarDeclaration *decl) {
|
||||
|
|
|
@ -34,12 +34,15 @@ struct IrVar {
|
|||
struct IrGlobal : IrVar {
|
||||
explicit IrGlobal(VarDeclaration *v) : IrVar(v) {}
|
||||
|
||||
llvm::Constant *constInit = nullptr;
|
||||
|
||||
// This var is used by a naked function.
|
||||
bool nakedUse = false;
|
||||
|
||||
llvm::Value *getValue(bool define = false);
|
||||
llvm::Type *getType() { return value->getType()->getContainedType(0); }
|
||||
|
||||
private:
|
||||
void declare();
|
||||
void define();
|
||||
};
|
||||
|
||||
// represents a local variable variable
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue