Skip to content

Commit

Permalink
Cache struct literal constants per compilation unit, not globally (#2992
Browse files Browse the repository at this point in the history
)

Fixes #2990.
  • Loading branch information
kinke committed Feb 15, 2019
1 parent e25c4ee commit 79a22f7
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 21 deletions.
4 changes: 0 additions & 4 deletions dmd/expression.d
Original file line number Diff line number Diff line change
Expand Up @@ -2933,10 +2933,6 @@ extern (C++) final class StructLiteralExp : Expression
// now contain pointers to themselves. While in toElem, contains a pointer
// to the memory used to build the literal for resolving such references.
void* inProgressMemory; // llvm::Value*

// A global variable for taking the address of this struct literal constant,
// if it already exists. Used to resolve self-references.
void* globalVar; // llvm::Constant*
}

bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol
Expand Down
4 changes: 0 additions & 4 deletions dmd/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -361,10 +361,6 @@ class StructLiteralExp : public Expression
// now contain pointers to themselves. While in toElem, contains a pointer
// to the memory used to build the literal for resolving such references.
llvm::Value* inProgressMemory;

// A global variable for taking the address of this struct literal constant,
// if it already exists. Used to resolve self-references.
llvm::Constant *globalVar;
#endif

bool useStaticInit; // if this is true, use the StructDeclaration's init symbol
Expand Down
11 changes: 11 additions & 0 deletions gen/irstate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,17 @@ void IRState::replaceGlobals() {

////////////////////////////////////////////////////////////////////////////////

LLConstant *IRState::getStructLiteralConstant(StructLiteralExp *sle) const {
return static_cast<LLConstant *>(structLiteralConstants.lookup(sle));
}

void IRState::setStructLiteralConstant(StructLiteralExp *sle,
LLConstant *constant) {
structLiteralConstants[sle] = constant;
}

////////////////////////////////////////////////////////////////////////////////

IRBuilder<> *IRBuilderHelper::operator->() {
IRBuilder<> &b = state->scope().builder;
assert(b.GetInsertBlock() != NULL);
Expand Down
13 changes: 13 additions & 0 deletions gen/irstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "gen/objcgen.h"
#include "ir/iraggr.h"
#include "ir/irvar.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/IR/CallSite.h"
#include "llvm/ProfileData/InstrProfReader.h"
Expand Down Expand Up @@ -53,6 +54,7 @@ class Module;
class TypeStruct;
struct BaseClass;
class AnonDeclaration;
class StructLiteralExp;

struct IrFunction;
struct IrModule;
Expand Down Expand Up @@ -111,6 +113,13 @@ struct IRState {
std::vector<std::pair<llvm::GlobalVariable *, llvm::Constant *>>
globalsToReplace;

// Cache of (possibly bitcast) global variables for taking the address of
// struct literal constants. (Also) used to resolve self-references. Must be
// cached per IR module: https://github.com/ldc-developers/ldc/issues/2990
// [The real key type is `StructLiteralExp *`; a fwd class declaration isn't
// enough to use it directly.]
llvm::DenseMap<void *, llvm::Constant *> structLiteralConstants;

public:
IRState(const char *name, llvm::LLVMContext &context);
~IRState();
Expand Down Expand Up @@ -225,6 +234,10 @@ struct IRState {
// setGlobalVarInitializer().
void replaceGlobals();

llvm::Constant *getStructLiteralConstant(StructLiteralExp *sle) const;
void setStructLiteralConstant(StructLiteralExp *sle,
llvm::Constant *constant);

// List of functions with cpu or features attributes overriden by user
std::vector<IrFunction *> targetCpuOrFeaturesOverridden;

Expand Down
27 changes: 14 additions & 13 deletions gen/toconstelem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,10 +413,10 @@ class ToConstElemVisitor : public Visitor {
if (e->e1->op == TOKstructliteral) {
StructLiteralExp *se = static_cast<StructLiteralExp *>(e->e1);

if (se->globalVar) {
result = p->getStructLiteralConstant(se);
if (result) {
IF_LOG Logger::cout()
<< "Returning existing global: " << *se->globalVar << '\n';
result = se->globalVar;
<< "Returning existing global: " << *result << '\n';
return;
}

Expand All @@ -425,11 +425,12 @@ class ToConstElemVisitor : public Visitor {
llvm::GlobalValue::InternalLinkage, nullptr, ".structliteral");
globalVar->setAlignment(DtoAlignment(se->type));

se->globalVar = globalVar;
p->setStructLiteralConstant(se, globalVar);
llvm::Constant *constValue = toConstElem(se);
se->globalVar = p->setGlobalVarInitializer(globalVar, constValue);
constValue = p->setGlobalVarInitializer(globalVar, constValue);
p->setStructLiteralConstant(se, constValue);

result = se->globalVar;
result = constValue;
return;
}

Expand Down Expand Up @@ -579,14 +580,14 @@ class ToConstElemVisitor : public Visitor {
DtoResolveClass(origClass);
StructLiteralExp *value = e->value;

if (value->globalVar) {
IF_LOG Logger::cout()
<< "Using existing global: " << *value->globalVar << '\n';
result = p->getStructLiteralConstant(value);
if (result) {
IF_LOG Logger::cout() << "Using existing global: " << *result << '\n';
} else {
auto globalVar = new llvm::GlobalVariable(
p->module, origClass->type->ctype->isClass()->getMemoryLLType(),
false, llvm::GlobalValue::InternalLinkage, nullptr, ".classref");
value->globalVar = globalVar;
p->setStructLiteralConstant(value, globalVar);

std::map<VarDeclaration *, llvm::Constant *> varInits;

Expand Down Expand Up @@ -623,12 +624,12 @@ class ToConstElemVisitor : public Visitor {

llvm::Constant *constValue =
getIrAggr(origClass)->createInitializerConstant(varInits);
constValue = p->setGlobalVarInitializer(globalVar, constValue);
p->setStructLiteralConstant(value, constValue);

value->globalVar = p->setGlobalVarInitializer(globalVar, constValue);
result = constValue;
}

result = value->globalVar;

if (e->type->ty == Tclass) {
ClassDeclaration *targetClass = static_cast<TypeClass *>(e->type)->sym;
if (InterfaceDeclaration *it = targetClass->isInterfaceDeclaration()) {
Expand Down

0 comments on commit 79a22f7

Please sign in to comment.