refactor: Remove last bits of direct connection between DVarValue and VarDeclaration

The relationship between them is at best tenuous; DVarValue should
probably be renamed to DLValue and is used right now to describe
a general lvalue, of which variables are just one example.
This commit is contained in:
David Nadlinger 2016-03-27 12:37:31 +01:00
parent 32864c47a5
commit b47aee1750
6 changed files with 90 additions and 75 deletions

View file

@ -41,29 +41,19 @@ static bool checkVarValueType(LLType *t, bool extraDeref) {
return true; return true;
} }
DVarValue::DVarValue(Type *t, VarDeclaration *vd, LLValue *llvmValue) DVarValue::DVarValue(Type *t, LLValue *llvmValue, bool isSpecialRefVar)
: DValue(t), var(vd), val(llvmValue) { : DValue(t), val(llvmValue), isSpecialRefVar(isSpecialRefVar) {
assert(checkVarValueType(llvmValue->getType(), isSpecialRefVar(vd))); assert(llvmValue && "Unexpected null llvm::Value.");
assert(checkVarValueType(llvmValue->getType(), isSpecialRefVar));
} }
DVarValue::DVarValue(Type *t, LLValue *llvmValue) LLValue *DVarValue::getLVal() { return isSpecialRefVar ? DtoLoad(val) : val; }
: DValue(t), var(nullptr), val(llvmValue) {
assert(checkVarValueType(llvmValue->getType(), false));
}
LLValue *DVarValue::getLVal() {
assert(val);
if (var && isSpecialRefVar(var)) {
return DtoLoad(val);
}
return val;
}
LLValue *DVarValue::getRVal() { LLValue *DVarValue::getRVal() {
assert(val); assert(val);
llvm::Value *storage = val; llvm::Value *storage = val;
if (var && isSpecialRefVar(var)) { if (isSpecialRefVar) {
storage = DtoLoad(storage); storage = DtoLoad(storage);
} }
@ -83,8 +73,7 @@ LLValue *DVarValue::getRVal() {
} }
LLValue *DVarValue::getRefStorage() { LLValue *DVarValue::getRefStorage() {
assert(val); assert(isSpecialRefVar);
assert(isSpecialRefVar(var));
return val; return val;
} }

View file

@ -112,11 +112,14 @@ public:
DNullValue *isNull() override { return this; } DNullValue *isNull() override { return this; }
}; };
// variable d-value /// This is really a misnomer, DVarValue represents generic lvalues, which
/// might or might not come from variable declarations.
// TODO: Rename this, probably remove getLVal() from parent since this is the
// only lvalue. The isSpecialRefVar case should probably also be its own
// subclass.
class DVarValue : public DValue { class DVarValue : public DValue {
public: public:
DVarValue(Type *t, VarDeclaration *vd, llvm::Value *llvmValue); DVarValue(Type *t, llvm::Value *llvmValue, bool isSpecialRefVar = false);
DVarValue(Type *t, llvm::Value *llvmValue);
bool isLVal() override { return true; } bool isLVal() override { return true; }
llvm::Value *getLVal() override; llvm::Value *getLVal() override;
@ -124,13 +127,13 @@ public:
/// Returns the underlying storage for special internal ref variables. /// Returns the underlying storage for special internal ref variables.
/// Illegal to call on any other value. /// Illegal to call on any other value.
virtual llvm::Value *getRefStorage(); llvm::Value *getRefStorage();
DVarValue *isVar() override { return this; } DVarValue *isVar() override { return this; }
protected: protected:
VarDeclaration *var; llvm::Value *const val;
llvm::Value *val; bool const isSpecialRefVar;
}; };
// slice d-value // slice d-value

View file

@ -989,7 +989,7 @@ DValue *DtoDeclarationExp(Dsymbol *declaration) {
} else { } else {
DtoVarDeclaration(vd); DtoVarDeclaration(vd);
} }
return new DVarValue(vd->type, vd, getIrValue(vd)); return makeVarDValue(vd->type, vd);
} }
// struct declaration // struct declaration
if (StructDeclaration *s = declaration->isStructDeclaration()) { if (StructDeclaration *s = declaration->isStructDeclaration()) {
@ -1496,25 +1496,29 @@ DValue *DtoSymbolAddress(Loc &loc, Type *type, Declaration *decl) {
if (vd->ident == Id::_arguments && gIR->func()->_arguments) { if (vd->ident == Id::_arguments && gIR->func()->_arguments) {
Logger::println("Id::_arguments"); Logger::println("Id::_arguments");
LLValue *v = gIR->func()->_arguments; LLValue *v = gIR->func()->_arguments;
return new DVarValue(type, vd, v); assert(!isSpecialRefVar(vd) && "Code not expected to handle special ref "
"vars, although it can easily be made "
"to.");
return new DVarValue(type, v);
} }
// _argptr // _argptr
if (vd->ident == Id::_argptr && gIR->func()->_argptr) { if (vd->ident == Id::_argptr && gIR->func()->_argptr) {
Logger::println("Id::_argptr"); Logger::println("Id::_argptr");
LLValue *v = gIR->func()->_argptr; LLValue *v = gIR->func()->_argptr;
return new DVarValue(type, vd, v); assert(!isSpecialRefVar(vd) && "Code not expected to handle special ref "
"vars, although it can easily be made "
"to.");
return new DVarValue(type, v);
} }
// _dollar // _dollar
if (vd->ident == Id::dollar) { if (vd->ident == Id::dollar) {
Logger::println("Id::dollar"); Logger::println("Id::dollar");
LLValue *val = nullptr; if (isIrVarCreated(vd)) {
if (isIrVarCreated(vd) && (val = getIrValue(vd))) { // This is the length of a range.
// It must be length of a range return makeVarDValue(type, vd);
return new DVarValue(type, vd, val);
} }
assert(!gIR->arrays.empty()); assert(!gIR->arrays.empty());
val = DtoArrayLen(gIR->arrays.back()); return new DImValue(type, DtoArrayLen(gIR->arrays.back()));
return new DImValue(type, val);
} }
// typeinfo // typeinfo
if (TypeInfoDeclaration *tid = vd->isTypeInfoDeclaration()) { if (TypeInfoDeclaration *tid = vd->isTypeInfoDeclaration()) {
@ -1551,7 +1555,10 @@ DValue *DtoSymbolAddress(Loc &loc, Type *type, Declaration *decl) {
} }
if (vd->isRef() || vd->isOut() || DtoIsInMemoryOnly(vd->type) || if (vd->isRef() || vd->isOut() || DtoIsInMemoryOnly(vd->type) ||
llvm::isa<llvm::AllocaInst>(getIrValue(vd))) { llvm::isa<llvm::AllocaInst>(getIrValue(vd))) {
return new DVarValue(type, vd, getIrValue(vd)); assert(!isSpecialRefVar(vd) && "Code not expected to handle special "
"ref vars, although it can easily be "
"made to.");
return new DVarValue(type, getIrValue(vd));
} }
if (llvm::isa<llvm::Argument>(getIrValue(vd))) { if (llvm::isa<llvm::Argument>(getIrValue(vd))) {
return new DImValue(type, getIrValue(vd)); return new DImValue(type, getIrValue(vd));
@ -1562,32 +1569,11 @@ DValue *DtoSymbolAddress(Loc &loc, Type *type, Declaration *decl) {
Logger::println("a normal variable"); Logger::println("a normal variable");
// take care of forward references of global variables // take care of forward references of global variables
const bool isGlobal = vd->isDataseg() || (vd->storage_class & STCextern); if (vd->isDataseg() || (vd->storage_class & STCextern)) {
if (isGlobal) {
DtoResolveVariable(vd); DtoResolveVariable(vd);
} }
assert(isIrVarCreated(vd) && "Variable not resolved."); return makeVarDValue(type, vd);
llvm::Value *val = getIrValue(vd);
assert(val && "Variable value not set yet.");
if (isGlobal) {
llvm::Type *expectedType =
llvm::PointerType::getUnqual(DtoMemType(type));
// The type of globals is determined by their initializer, so
// we might need to cast. Make sure that the type sizes fit -
// '==' instead of '<=' should probably work as well.
if (val->getType() != expectedType) {
llvm::Type *t =
llvm::cast<llvm::PointerType>(val->getType())->getElementType();
assert(getTypeStoreSize(DtoType(type)) <= getTypeStoreSize(t) &&
"Global type mismatch, encountered type too small.");
val = DtoBitCast(val, expectedType);
}
}
return new DVarValue(type, vd, val);
} }
} }
@ -1782,3 +1768,28 @@ unsigned getFieldGEPIndex(AggregateDeclaration *ad, VarDeclaration *vd) {
assert(byteOffset == 0 && "Cannot address field by a simple GEP."); assert(byteOffset == 0 && "Cannot address field by a simple GEP.");
return fieldIndex; return fieldIndex;
} }
DValue *makeVarDValue(Type *type, VarDeclaration *vd, llvm::Value *storage) {
auto val = storage;
if (!val) {
assert(isIrVarCreated(vd) && "Variable not resolved.");
val = getIrValue(vd);
}
if (vd->isDataseg() || (vd->storage_class & STCextern)) {
// The type of globals is determined by their initializer, so
// we might need to cast. Make sure that the type sizes fit -
// '==' instead of '<=' should probably work as well.
llvm::Type *expectedType = llvm::PointerType::getUnqual(DtoMemType(type));
if (val->getType() != expectedType) {
llvm::Type *t =
llvm::cast<llvm::PointerType>(val->getType())->getElementType();
assert(getTypeStoreSize(DtoType(type)) <= getTypeStoreSize(t) &&
"Global type mismatch, encountered type too small.");
val = DtoBitCast(val, expectedType);
}
}
return new DVarValue(type, val, isSpecialRefVar(vd));
}

View file

@ -16,11 +16,11 @@
#ifndef LDC_GEN_LLVMHELPERS_H #ifndef LDC_GEN_LLVMHELPERS_H
#define LDC_GEN_LLVMHELPERS_H #define LDC_GEN_LLVMHELPERS_H
#include "mtype.h"
#include "statement.h"
#include "gen/dvalue.h" #include "gen/dvalue.h"
#include "gen/llvm.h" #include "gen/llvm.h"
#include "ir/irfuncty.h" #include "ir/irfuncty.h"
#include "mtype.h"
#include "statement.h"
// dynamic memory helpers // dynamic memory helpers
LLValue *DtoNew(Loc &loc, Type *newtype); LLValue *DtoNew(Loc &loc, Type *newtype);
@ -257,4 +257,11 @@ DValue *toElem(Expression *e, bool tryGetLvalue);
DValue *toElemDtor(Expression *e); DValue *toElemDtor(Expression *e);
LLConstant *toConstElem(Expression *e, IRState *p); LLConstant *toConstElem(Expression *e, IRState *p);
/// Creates a DVarValue for the given VarDeclaration.
///
/// If the storage is not given explicitly, the declaration is expected to be
/// already resolved, and the value from the associated IrVar will be used.
DValue *makeVarDValue(Type *type, VarDeclaration *vd,
llvm::Value *storage = nullptr);
#endif #endif

View file

@ -62,8 +62,7 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
if (fd->isStatic()) { if (fd->isStatic()) {
error(loc, "function %s cannot access frame of function %s", error(loc, "function %s cannot access frame of function %s",
irfunc->decl->toPrettyChars(), vdparent->toPrettyChars()); irfunc->decl->toPrettyChars(), vdparent->toPrettyChars());
return new DVarValue(astype, vd, return new DVarValue(astype, llvm::UndefValue::get(DtoPtrToType(astype)));
llvm::UndefValue::get(DtoPtrToType(astype)));
} }
fd = getParentFunc(fd, false); fd = getParentFunc(fd, false);
assert(fd); assert(fd);
@ -71,8 +70,7 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
// is the nested variable in this scope? // is the nested variable in this scope?
if (vdparent == irfunc->decl) { if (vdparent == irfunc->decl) {
LLValue *val = getIrValue(vd); return makeVarDValue(astype, vd);
return new DVarValue(astype, vd, val);
} }
LLValue *dwarfValue = nullptr; LLValue *dwarfValue = nullptr;
@ -120,8 +118,9 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
Logger::cout() << "of type: " << *irfunc->frameType << '\n'; Logger::cout() << "of type: " << *irfunc->frameType << '\n';
} }
unsigned vardepth = getIrLocal(vd)->nestedDepth; IrLocal *const irLocal = getIrLocal(vd);
unsigned funcdepth = irfunc->depth; const auto vardepth = irLocal->nestedDepth;
const auto funcdepth = irfunc->depth;
IF_LOG { IF_LOG {
Logger::cout() << "Variable: " << vd->toChars() << '\n'; Logger::cout() << "Variable: " << vd->toChars() << '\n';
@ -148,7 +147,7 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
IF_LOG Logger::cout() << "Frame: " << *val << '\n'; IF_LOG Logger::cout() << "Frame: " << *val << '\n';
} }
int idx = getIrLocal(vd)->nestedIndex; const auto idx = irLocal->nestedIndex;
assert(idx != -1 && "Nested context not yet resolved for variable."); assert(idx != -1 && "Nested context not yet resolved for variable.");
if (dwarfValue && global.params.symdebug) { if (dwarfValue && global.params.symdebug) {
@ -165,8 +164,8 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
val = DtoAlignedLoad(val); val = DtoAlignedLoad(val);
// dwarfOpDeref(dwarfAddr); // dwarfOpDeref(dwarfAddr);
IF_LOG { IF_LOG {
Logger::cout() << "Was byref, now: " << *val << '\n'; Logger::cout() << "Was byref, now: " << *irLocal->value << '\n';
Logger::cout() << "of type: " << *val->getType() << '\n'; Logger::cout() << "of type: " << *irLocal->value->getType() << '\n';
} }
} }
@ -174,7 +173,7 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
gIR->DBuilder.EmitLocalVariable(dwarfValue, vd, nullptr, false, dwarfAddr); gIR->DBuilder.EmitLocalVariable(dwarfValue, vd, nullptr, false, dwarfAddr);
} }
return new DVarValue(astype, vd, val); return makeVarDValue(astype, vd, val);
} }
void DtoResolveNestedContext(Loc &loc, AggregateDeclaration *decl, void DtoResolveNestedContext(Loc &loc, AggregateDeclaration *decl,

View file

@ -156,7 +156,9 @@ static void write_struct_literal(Loc loc, LLValue *mem, StructDeclaration *sd,
} }
// get a pointer to this field // get a pointer to this field
DVarValue field(vd->type, vd, DtoIndexAggregate(mem, sd, vd)); assert(!isSpecialRefVar(vd) && "Code not expected to handle special ref "
"vars, although it can easily be made to.");
DVarValue field(vd->type, DtoIndexAggregate(mem, sd, vd));
// store the initializer there // store the initializer there
DtoAssign(loc, &field, val, TOKconstruct, true); DtoAssign(loc, &field, val, TOKconstruct, true);
@ -1143,9 +1145,10 @@ public:
if (e->cachedLvalue) { if (e->cachedLvalue) {
Logger::println("using cached lvalue"); Logger::println("using cached lvalue");
LLValue *V = e->cachedLvalue; LLValue *V = e->cachedLvalue;
VarDeclaration *vd = e->var->isVarDeclaration(); assert(!isSpecialRefVar(e->var->isVarDeclaration()) &&
assert(vd); "Code not expected to handle special ref vars, although it can "
result = new DVarValue(e->type, vd, V); "easily be made to.");
result = new DVarValue(e->type, V);
return; return;
} }
@ -1178,7 +1181,7 @@ public:
} }
// Logger::cout() << "mem: " << *arrptr << '\n'; // Logger::cout() << "mem: " << *arrptr << '\n';
result = new DVarValue(e->type, vd, arrptr); result = new DVarValue(e->type, arrptr);
} else if (FuncDeclaration *fdecl = e->var->isFuncDeclaration()) { } else if (FuncDeclaration *fdecl = e->var->isFuncDeclaration()) {
DtoResolveFunction(fdecl); DtoResolveFunction(fdecl);
@ -1240,7 +1243,10 @@ public:
Logger::println("normal this exp"); Logger::println("normal this exp");
v = p->func()->thisArg; v = p->func()->thisArg;
} }
result = new DVarValue(e->type, vd, v); assert(!isSpecialRefVar(vd) && "Code not expected to handle special ref "
"vars, although it can easily be made "
"to.");
result = new DVarValue(e->type, v);
} else { } else {
llvm_unreachable("No VarDeclaration in ThisExp."); llvm_unreachable("No VarDeclaration in ThisExp.");
} }