Re-enable SymOffExp and remove associated LLVM-only modifications.

This commit is contained in:
David Nadlinger
2013-06-10 23:07:06 +02:00
parent b389a3b791
commit 978c2c1b6a
11 changed files with 309 additions and 431 deletions

View File

@@ -686,13 +686,11 @@ MATCH AddrExp::implicitConvTo(Type *t)
t->ty == Tpointer && t->nextOf()->ty == Tfunction &&
e1->op == TOKvar)
{
#if !IN_LLVM
/* I don't think this can ever happen -
* it should have been
* converted to a SymOffExp.
*/
assert(0);
#endif
VarExp *ve = (VarExp *)e1;
FuncDeclaration *f = ve->var->isFuncDeclaration();
if (f && f->overloadExactMatch(t->nextOf()))
@@ -991,7 +989,6 @@ Expression *Expression::castTo(Scope *sc, Type *t)
Type *typeb = type->toBasetype();
if (tb != typeb)
{
#if !IN_LLVM
// Do (type *) cast of (type [dim])
if (tb->ty == Tpointer &&
typeb->ty == Tsarray
@@ -1004,17 +1001,15 @@ Expression *Expression::castTo(Scope *sc, Type *t)
else
e = new AddrExp(loc, e);
}
else
#endif
#if 0
if (tb->ty == Tdelegate && type->ty != Tdelegate)
else if (tb->ty == Tdelegate && type->ty != Tdelegate)
{
TypeDelegate *td = (TypeDelegate *)tb;
TypeFunction *tf = (TypeFunction *)td->nextOf();
return toDelegate(sc, tf->nextOf());
}
else
#endif
else
{
if (typeb->ty == Tstruct)
{ TypeStruct *ts = (TypeStruct *)typeb;
@@ -1432,48 +1427,6 @@ Expression *AddrExp::castTo(Scope *sc, Type *t)
f = f2;
}
}
#if IN_LLVM
if (f)
{
f = f->overloadExactMatch(tb->nextOf());
if (f)
{
if (tb->ty == Tdelegate)
{
if (f->needThis() && hasThis(sc))
{
e = new DelegateExp(loc, new ThisExp(loc), f);
e = e->semantic(sc);
}
else if (f->isNested())
{
e = new DelegateExp(loc, new IntegerExp(0), f);
e = e->semantic(sc);
}
else if (f->needThis())
{ error("no 'this' to create delegate for %s", f->toChars());
return new ErrorExp();
}
else
{ error("cannot cast from function pointer to delegate");
return new ErrorExp();
}
}
else
{
e = new VarExp(loc, f);
e->type = f->type;
e = new AddrExp(loc, e);
e->type = t;
return e;
}
#if DMDV2
f->tookAddressOf++;
#endif
return e;
}
}
#else
if (f)
{ f->tookAddressOf++;
SymOffExp *se = new SymOffExp(loc, f, 0, 0);
@@ -1481,9 +1434,9 @@ Expression *AddrExp::castTo(Scope *sc, Type *t)
// Let SymOffExp::castTo() do the heavy lifting
return se->castTo(sc, t);
}
#endif
}
if (type->ty == Tpointer && type->nextOf()->ty == Tfunction &&
tb->ty == Tpointer && tb->nextOf()->ty == Tfunction &&
e1->op == TOKvar)
@@ -1492,9 +1445,7 @@ Expression *AddrExp::castTo(Scope *sc, Type *t)
FuncDeclaration *f = ve->var->isFuncDeclaration();
if (f)
{
#if !IN_LLVM
assert(0); // should be SymOffExp instead
#endif
f = f->overloadExactMatch(tb->nextOf());
if (f)
{
@@ -1506,17 +1457,8 @@ Expression *AddrExp::castTo(Scope *sc, Type *t)
}
}
}
e = Expression::castTo(sc, t);
}
#if IN_LLVM
else if (e1->op == TOKvar)
{
VarExp *ve = (VarExp*)e1->copy();
ve->hasOverloads = 0;
e1 = ve;
}
#endif
e->type = t;
return e;
}

View File

@@ -1896,15 +1896,6 @@ bool isCtfeValueValid(Expression *newval)
if (((SymOffExp *)newval)->var->isFuncDeclaration())
return true;
}
#if IN_LLVM
if (newval->op == TOKaddress) { // function pointer
AddrExp *ae = (AddrExp *)newval;
if (ae->e1->op == TOKvar) {
if (((VarExp *)ae->e1)->var->isFuncDeclaration())
return true;
}
}
#endif
if (newval->op == TOKint64 || newval->op == TOKfloat64 ||
newval->op == TOKchar || newval->op == TOKcomplex80)

View File

@@ -2229,11 +2229,7 @@ Expression *VarDeclaration::callScopeDtor(Scope *sc)
if (array)
{
// Typeinfo.destroy(cast(void*)&v);
#if IN_LLVM
Expression *ea = new AddrExp(loc, new DsymbolExp(loc, this));
#else
Expression *ea = new SymOffExp(loc, this, 0, 0);
#endif
ea = new CastExp(loc, ea, Type::tvoid->pointerTo());
Expressions *args = new Expressions();
args->push(ea);

View File

@@ -1278,23 +1278,6 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
#endif
// Give error for overloaded function addresses
#if IN_LLVM
if (arg->op == TOKaddress)
{ AddrExp *ae = (AddrExp *)arg;
if (ae->e1->op == TOKvar) {
VarExp *ve = (VarExp*)ae->e1;
FuncDeclaration *fd = ve->var->isFuncDeclaration();
if (fd &&
#if DMDV2
ve->hasOverloads &&
#endif
!fd->isUnique())
{
arg->error("function %s is overloaded", arg->toChars());
}
}
}
#else
if (arg->op == TOKsymoff)
{ SymOffExp *se = (SymOffExp *)arg;
if (
@@ -1306,7 +1289,6 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
arg = new ErrorExp();
}
}
#endif
arg->rvalue();
arg = arg->optimize(WANTvalue);
}
@@ -7882,27 +7864,12 @@ Lagain:
e1 = new DsymbolExp(loc, se->sds);
e1 = e1->semantic(sc);
}
#if IN_LLVM
else if (e1->op == TOKaddress)
{
AddrExp *ae = (AddrExp *)e1;
if (ae->e1->op == TOKvar) {
VarExp *ve = (VarExp*)ae->e1;
if (!ve->var->isOut() && !ve->var->isRef() &&
!ve->var->isImportedSymbol() && ve->hasOverloads)
{
e1 = ve;
}
}
}
#else
else if (e1->op == TOKsymoff && ((SymOffExp *)e1)->hasOverloads)
{
SymOffExp *se = (SymOffExp *)e1;
e1 = new VarExp(se->loc, se->var, 1);
e1 = e1->semantic(sc);
}
#endif
else if (e1->op == TOKdotexp)
{
DotExp *de = (DotExp *) e1;
@@ -9283,20 +9250,6 @@ Lsafe:
void CastExp::checkEscape()
{ Type *tb = type->toBasetype();
#if IN_LLVM
if (e1->op == TOKvar &&
tb->ty == Tpointer &&
e1->type->toBasetype()->ty == Tsarray)
{
VarDeclaration *v = ((VarExp*)e1)->var->isVarDeclaration();
if (v)
{
if (!v->isDataseg() && !(v->storage_class & (STCref | STCout)))
error("escaping reference to local variable %s", v->toChars());
}
}
#endif
if (tb->ty == Tarray && e1->op == TOKvar &&
e1->type->toBasetype()->ty == Tsarray)
{ VarExp *ve = (VarExp *)e1;

View File

@@ -753,12 +753,11 @@ struct SymOffExp : SymbolExp
MATCH implicitConvTo(Type *t);
Expression *castTo(Scope *sc, Type *t);
#if IN_DMD
dt_t **toDt(dt_t **pdt);
#endif
#if IN_LLVM
DValue* toElem(IRState* irs);
llvm::Constant* toConstElem(IRState* irs);
#else
dt_t **toDt(dt_t **pdt);
#endif
};

View File

@@ -847,19 +847,8 @@ bool hasNonConstPointers(Expression *e)
}
if (e->type->ty== Tpointer && e->type->nextOf()->ty != Tfunction)
{
#if IN_LLVM
// address of a global is OK
if (e->op == TOKaddress || e->op == TOKcast)
return false;
if (e->op == TOKadd || e->op == TOKmin) {
BinExp *be = (BinExp*)e;
if (be->e1->type->ty == Tpointer || be->e2->type->ty == Tpointer)
return false;
}
#else
if (e->op == TOKsymoff) // address of a global is OK
return false;
#endif
if (e->op == TOKint64) // cast(void *)int is OK
return false;
if (e->op == TOKstring) // "abc".ptr is OK

View File

@@ -1509,59 +1509,6 @@ Expression *AddrExp::interpret(InterState *istate, CtfeGoal goal)
#if LOG
printf("%s AddrExp::interpret() %s\n", loc.toChars(), toChars());
#endif
#if IN_LLVM
if (e1->op == TOKvar)
{ VarExp *ve = (VarExp *)e1;
if (ve->var->isFuncDeclaration())
return this;
if (!ve->var->isOut() && !ve->var->isRef() &&
!ve->var->isImportedSymbol())
{
if (type->ty != Tpointer)
{ // Probably impossible
error("Cannot interpret %s at compile time", toChars());
return EXP_CANT_INTERPRET;
}
Type *pointee = ((TypePointer *)type)->next;
if (isSafePointerCast(ve->var->type, pointee))
{
ve = new VarExp(loc, ve->var);
ve->type = type;
return ve;
}
}
}
else if (e1->op == TOKindex)
{
IndexExp *ae = (IndexExp *)e1;
if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar) {
dinteger_t indx = ae->e2->toInteger();
VarExp *ve = (VarExp *)ae->e1;
if (/*ve->type->ty == Tarray || */ve->type->ty == Tsarray)
{
Expression *val = getVarExp(loc, istate, ve->var, goal);
Expression *aggregate = NULL;
if (val->op == TOKarrayliteral || val->op == TOKstring)
aggregate = val;
else if (val->op == TOKslice)
{
aggregate = ((SliceExp *)val)->e1;
Expression *lwr = ((SliceExp *)val)->lwr->interpret(istate);
indx += lwr->toInteger();
}
if (aggregate)
{
IntegerExp *ofs = new IntegerExp(loc, indx, Type::tsize_t);
IndexExp *ie = new IndexExp(loc, aggregate, ofs);
ie->type = type;
return ie;
}
}
}
}
#endif
// For reference types, we need to return an lvalue ref.
TY tb = e1->type->toBasetype()->ty;
bool needRef = (tb == Tarray || tb == Taarray || tb == Tclass);
@@ -3958,16 +3905,8 @@ Expression *CallExp::interpret(InterState *istate, CtfeGoal goal)
if (exceptionOrCantInterpret(ecall))
return ecall;
#if IN_LLVM
if (ecall->op == TOKaddress) {
AddrExp *e = (AddrExp*)ecall;
if (e->e1->op == TOKvar)
fd = ((VarExp *)e->e1)->var->isFuncDeclaration();
}
#else
if (ecall->op == TOKsymoff)
fd = ((SymOffExp *)ecall)->var->isFuncDeclaration();
#endif
}
}
else if (pe->op == TOKsymoff)

View File

@@ -320,8 +320,6 @@ Expression *AddrExp::optimize(int result, bool keepLvalue)
{ Expression *e;
//printf("AddrExp::optimize(result = %d) %s\n", result, toChars());
// LDC never try to interpret: it could change the semantics by turning
// const p = &s; into an something like const p = &(Struct());
/* Rewrite &(a,b) as (a,&b)
*/
@@ -331,35 +329,13 @@ Expression *AddrExp::optimize(int result, bool keepLvalue)
ae->type = type;
e = new CommaExp(ce->loc, ce->e1, ae);
e->type = type;
return e->optimize(result & ~WANTinterpret);
return e->optimize(result);
}
#if IN_LLVM
if (e1->op == TOKindex)
{
IndexExp *ae = (IndexExp *)e1;
if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar)
{
dinteger_t index = ae->e2->toInteger();
VarExp *ve = (VarExp *)ae->e1;
if (ve->type->ty == Tsarray
&& !ve->var->isImportedSymbol())
{
TypeSArray *ts = (TypeSArray *)ve->type;
dinteger_t dim = ts->dim->toInteger();
if (index < 0 || index >= dim)
error("array index %jd is out of bounds [0..%jd]", index, dim);
return this;
}
}
}
#endif
if (e1->op == TOKvar)
{ VarExp *ve = (VarExp *)e1;
if (ve->var->storage_class & STCmanifest)
e1 = e1->optimize(result & ~WANTinterpret);
e1 = e1->optimize(result);
}
else
e1 = e1->optimize(result);
@@ -378,7 +354,6 @@ Expression *AddrExp::optimize(int result, bool keepLvalue)
}
return e;
}
#if !IN_LLVM
if (e1->op == TOKvar)
{ VarExp *ve = (VarExp *)e1;
if (!ve->var->isOut() && !ve->var->isRef() &&
@@ -410,7 +385,6 @@ Expression *AddrExp::optimize(int result, bool keepLvalue)
}
}
}
#endif
return this;
}
@@ -617,13 +591,6 @@ Expression *CastExp::optimize(int result, bool keepLvalue)
enum TOK op1 = e1->op;
#define X 0
#if IN_LLVM
if (type->toBasetype()->ty == Tpointer &&
e1->type->toBasetype()->ty == Tsarray)
{
return this;
}
#endif
Expression *e1old = e1;
e1 = e1->optimize(result);
e1 = fromConstInitializer(result, e1);

View File

@@ -24,6 +24,7 @@
#include "gen/llvmcompat.h"
#include "gen/logger.h"
#include "gen/nested.h"
#include "gen/pragma.h"
#include "gen/runtime.h"
#include "gen/todebug.h"
#include "gen/tollvm.h"
@@ -1798,3 +1799,217 @@ void tokToIcmpPred(TOK op, bool isUnsigned, llvm::ICmpInst::Predicate* outPred,
llvm_unreachable("Invalid comparison operation");
}
}
///////////////////////////////////////////////////////////////////////////////
DValue* DtoSymbolAddress(const Loc& loc, Type* type, Declaration* decl)
{
IF_LOG Logger::println("DtoSymbolAddress ('%s' of type '%s')",
decl->toChars(), decl->type->toChars());
LOG_SCOPE
if (VarDeclaration* vd = decl->isVarDeclaration())
{
// The magic variable __ctfe is always false at runtime
if (vd->ident == Id::ctfe)
{
return new DConstValue(type, DtoConstBool(false));
}
// this is an error! must be accessed with DotVarExp
if (vd->needThis())
{
error("need 'this' to access member %s", vd->toChars());
fatal();
}
// _arguments
if (vd->ident == Id::_arguments && gIR->func()->_arguments)
{
Logger::println("Id::_arguments");
LLValue* v = gIR->func()->_arguments;
return new DVarValue(type, vd, v);
}
// _argptr
else if (vd->ident == Id::_argptr && gIR->func()->_argptr)
{
Logger::println("Id::_argptr");
LLValue* v = gIR->func()->_argptr;
return new DVarValue(type, vd, v);
}
// _dollar
else if (vd->ident == Id::dollar)
{
Logger::println("Id::dollar");
LLValue* val = 0;
if (vd->ir.isSet() && (val = vd->ir.getIrValue()))
{
// It must be length of a range
return new DVarValue(type, vd, val);
}
assert(!gIR->arrays.empty());
val = DtoArrayLen(gIR->arrays.back());
return new DImValue(type, val);
}
// classinfo
else if (ClassInfoDeclaration* cid = vd->isClassInfoDeclaration())
{
Logger::println("ClassInfoDeclaration: %s", cid->cd->toChars());
cid->cd->codegen(Type::sir);;
return new DVarValue(type, vd, cid->cd->ir.irStruct->getClassInfoSymbol());
}
// typeinfo
else if (TypeInfoDeclaration* tid = vd->isTypeInfoDeclaration())
{
Logger::println("TypeInfoDeclaration");
tid->codegen(Type::sir);
assert(tid->ir.getIrValue());
LLType* vartype = DtoType(type);
LLValue* m = tid->ir.getIrValue();
if (m->getType() != getPtrToType(vartype))
m = gIR->ir->CreateBitCast(m, vartype, "tmp");
return new DImValue(type, m);
}
// nested variable
else if (vd->nestedrefs.dim)
{
Logger::println("nested variable");
return DtoNestedVariable(loc, type, vd);
}
// function parameter
else if (vd->isParameter())
{
Logger::println("function param");
Logger::println("type: %s", vd->type->toChars());
FuncDeclaration* fd = vd->toParent2()->isFuncDeclaration();
if (fd && fd != gIR->func()->decl)
{
Logger::println("nested parameter");
return DtoNestedVariable(loc, type, vd);
}
else if (vd->storage_class & STClazy)
{
Logger::println("lazy parameter");
assert(type->ty == Tdelegate);
return new DVarValue(type, vd->ir.getIrValue());
}
else if (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type) ||
llvm::isa<llvm::AllocaInst>(vd->ir.getIrValue()))
{
return new DVarValue(type, vd, vd->ir.getIrValue());
}
else if (llvm::isa<llvm::Argument>(vd->ir.getIrValue()))
{
return new DImValue(type, vd->ir.getIrValue());
}
else llvm_unreachable("Unexpected parameter value.");
}
else
{
Logger::println("a normal variable");
// take care of forward references of global variables
const bool isGlobal = vd->isDataseg() || (vd->storage_class & STCextern);
if (isGlobal)
vd->codegen(Type::sir);
assert(vd->ir.isSet() && "Variable not resolved.");
llvm::Value* val = vd->ir.getIrValue();
assert(val && "Variable value not set yet.");
if (isGlobal)
{
llvm::Type* expectedType = llvm::PointerType::getUnqual(i1ToI8(DtoType(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);
}
}
if (FuncDeclaration* fdecl = decl->isFuncDeclaration())
{
Logger::println("FuncDeclaration");
LLValue* func = 0;
fdecl = fdecl->toAliasFunc();
if (fdecl->llvmInternal == LLVMinline_asm)
{
error("special ldc inline asm is not a normal function");
fatal();
}
else if (fdecl->llvmInternal != LLVMva_arg)
{
fdecl->codegen(Type::sir);
func = fdecl->ir.irFunc->func;
}
return new DFuncValue(fdecl, func);
}
if (StaticStructInitDeclaration* sdecl = decl->isStaticStructInitDeclaration())
{
// this seems to be the static initialiser for structs
Type* sdecltype = sdecl->type->toBasetype();
Logger::print("Sym: type=%s\n", sdecltype->toChars());
assert(sdecltype->ty == Tstruct);
TypeStruct* ts = static_cast<TypeStruct*>(sdecltype);
assert(ts->sym);
ts->sym->codegen(Type::sir);
LLValue* initsym = ts->sym->ir.irStruct->getInitSymbol();
initsym = DtoBitCast(initsym, DtoType(ts->pointerTo()));
return new DVarValue(type, initsym);
}
llvm_unreachable("Unimplemented VarExp type");
}
llvm::Constant* DtoConstSymbolAddress(const Loc& loc, Declaration* decl)
{
// Make sure 'this' isn't needed.
// TODO: This check really does not belong here, should be moved to
// semantic analysis in the frontend.
if (decl->needThis())
{
error("need 'this' to access %s", decl->toChars());
fatal();
}
// global variable
if (VarDeclaration* vd = decl->isVarDeclaration())
{
if (!vd->isDataseg())
{
// Not sure if this can be triggered from user code, but it is
// needed for the current hacky implementation of
// AssocArrayLiteralExp::toElem, which requires on error
// gagging to check for constantness of the initializer.
error(loc, "cannot use address of non-global variable '%s' "
"as constant initializer", vd->toChars());
if (!global.gag) fatal();
return NULL;
}
vd->codegen(Type::sir);
LLConstant* llc = llvm::dyn_cast<LLConstant>(vd->ir.getIrValue());
assert(llc);
return llc;
}
// static function
else if (FuncDeclaration* fd = decl->isFuncDeclaration())
{
fd->codegen(Type::sir);
IrFunction* irfunc = fd->ir.irFunc;
return irfunc->func;
}
llvm_unreachable("Taking constant address not implemented.");
}

View File

@@ -89,6 +89,9 @@ void DtoLeaveMonitor(LLValue* v);
// basic operations
void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs, int op = -1, bool canSkipPostblit = false);
DValue* DtoSymbolAddress(const Loc& loc, Type* type, Declaration* decl);
llvm::Constant* DtoConstSymbolAddress(const Loc& loc,Declaration* decl);
/// Create a null DValue.
DValue* DtoNullValue(Type* t);

View File

@@ -110,162 +110,7 @@ DValue* VarExp::toElem(IRState* p)
return new DVarValue(type, V);
}
if (VarDeclaration* vd = var->isVarDeclaration())
{
Logger::println("VarDeclaration ' %s ' of type ' %s '", vd->toChars(), vd->type->toChars());
/* The magic variable __ctfe is always false at runtime
*/
if (vd->ident == Id::ctfe) {
return new DConstValue(type, DtoConstBool(false));
}
// this is an error! must be accessed with DotVarExp
if (var->needThis())
{
error("need 'this' to access member %s", toChars());
fatal();
}
// _arguments
if (vd->ident == Id::_arguments && p->func()->_arguments)
{
Logger::println("Id::_arguments");
LLValue* v = p->func()->_arguments;
return new DVarValue(type, vd, v);
}
// _argptr
else if (vd->ident == Id::_argptr && p->func()->_argptr)
{
Logger::println("Id::_argptr");
LLValue* v = p->func()->_argptr;
return new DVarValue(type, vd, v);
}
// _dollar
else if (vd->ident == Id::dollar)
{
Logger::println("Id::dollar");
LLValue* val = 0;
if (vd->ir.isSet() && (val = vd->ir.getIrValue())) {
// It must be length of a range
return new DVarValue(type, vd, val);
}
assert(!p->arrays.empty());
val = DtoArrayLen(p->arrays.back());
return new DImValue(type, val);
}
// classinfo
else if (ClassInfoDeclaration* cid = vd->isClassInfoDeclaration())
{
Logger::println("ClassInfoDeclaration: %s", cid->cd->toChars());
cid->cd->codegen(Type::sir);;
return new DVarValue(type, vd, cid->cd->ir.irStruct->getClassInfoSymbol());
}
// typeinfo
else if (TypeInfoDeclaration* tid = vd->isTypeInfoDeclaration())
{
Logger::println("TypeInfoDeclaration");
tid->codegen(Type::sir);
assert(tid->ir.getIrValue());
LLType* vartype = DtoType(type);
LLValue* m = tid->ir.getIrValue();
if (m->getType() != getPtrToType(vartype))
m = p->ir->CreateBitCast(m, vartype, "tmp");
return new DImValue(type, m);
}
// nested variable
else if (vd->nestedrefs.dim) {
Logger::println("nested variable");
return DtoNestedVariable(loc, type, vd);
}
// function parameter
else if (vd->isParameter()) {
Logger::println("function param");
Logger::println("type: %s", vd->type->toChars());
FuncDeclaration* fd = vd->toParent2()->isFuncDeclaration();
if (fd && fd != p->func()->decl) {
Logger::println("nested parameter");
return DtoNestedVariable(loc, type, vd);
}
else if (vd->storage_class & STClazy) {
Logger::println("lazy parameter");
assert(type->ty == Tdelegate);
return new DVarValue(type, vd->ir.getIrValue());
}
else if (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type) || llvm::isa<llvm::AllocaInst>(vd->ir.getIrValue())) {
return new DVarValue(type, vd, vd->ir.getIrValue());
}
else if (llvm::isa<llvm::Argument>(vd->ir.getIrValue())) {
return new DImValue(type, vd->ir.getIrValue());
}
else llvm_unreachable("Unexpected parameter value.");
}
else {
Logger::println("a normal variable");
// take care of forward references of global variables
const bool isGlobal = vd->isDataseg() || (vd->storage_class & STCextern);
if (isGlobal)
vd->codegen(Type::sir);
assert(vd->ir.isSet() && "Variable not resolved.");
llvm::Value* val = vd->ir.getIrValue();
assert(val && "Variable value not set yet.");
if (isGlobal)
{
llvm::Type* expectedType = llvm::PointerType::getUnqual(i1ToI8(DtoType(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);
}
}
else if (FuncDeclaration* fdecl = var->isFuncDeclaration())
{
Logger::println("FuncDeclaration");
LLValue* func = 0;
fdecl = fdecl->toAliasFunc();
if (fdecl->llvmInternal == LLVMinline_asm) {
error("special ldc inline asm is not a normal function");
fatal();
}
else if (fdecl->llvmInternal != LLVMva_arg) {
fdecl->codegen(Type::sir);
func = fdecl->ir.irFunc->func;
}
return new DFuncValue(fdecl, func);
}
else if (StaticStructInitDeclaration* sdecl = var->isStaticStructInitDeclaration())
{
// this seems to be the static initialiser for structs
Type* sdecltype = sdecl->type->toBasetype();
Logger::print("Sym: type=%s\n", sdecltype->toChars());
assert(sdecltype->ty == Tstruct);
TypeStruct* ts = static_cast<TypeStruct*>(sdecltype);
assert(ts->sym);
ts->sym->codegen(Type::sir);
LLValue* initsym = ts->sym->ir.irStruct->getInitSymbol();
initsym = DtoBitCast(initsym, DtoType(ts->pointerTo()));
return new DVarValue(type, initsym);
}
else
{
llvm_unreachable("Unimplemented VarExp type");
}
return 0;
return DtoSymbolAddress(loc, type, var);
}
//////////////////////////////////////////////////////////////////////////////////////////
@@ -1269,7 +1114,86 @@ DValue* SymOffExp::toElem(IRState* p)
Logger::print("SymOffExp::toElem: %s @ %s\n", toChars(), type->toChars());
LOG_SCOPE;
llvm_unreachable("SymOffExp::toElem should no longer be called.");
DValue* base = DtoSymbolAddress(loc, var->type, var);
// This weird setup is required to be able to handle both variables as
// well as functions and TypeInfo references (which are not a DVarValue
// as well due to the level-of-indirection hack in Type::getTypeInfo that
// is unfortunately required by the frontend).
llvm::Value* baseValue;
if (base->isLVal())
baseValue = base->getLVal();
else
baseValue = base->getRVal();
assert(isaPointer(baseValue));
llvm::Value* offsetValue;
Type* offsetType;
if (offset == 0)
{
offsetValue = baseValue;
offsetType = base->type->pointerTo();
}
else
{
uint64_t elemSize = gDataLayout->getTypeStoreSize(
baseValue->getType()->getContainedType(0));
if (offset % elemSize == 0)
{
// We can turn this into a "nice" GEP.
offsetValue = DtoGEPi1(baseValue, offset / elemSize);
offsetType = base->type->pointerTo();
}
else
{
// Offset isn't a multiple of base type size, just cast to i8* and
// apply the byte offset.
offsetValue = DtoGEPi1(DtoBitCast(baseValue, getVoidPtrType()), offset);
offsetType = Type::tvoidptr;
}
}
// Casts are also "optimized into" SymOffExp by the frontend.
return DtoCast(loc, new DImValue(offsetType, offsetValue), type);
}
llvm::Constant* SymOffExp::toConstElem(IRState* p)
{
Logger::print("SymOffExp::toConstElem: %s @ %s\n", toChars(), type->toChars());
LOG_SCOPE;
// We might get null here due to the hackish implementation of
// AssocArrayLiteralExp::toElem.
llvm::Constant* base = DtoConstSymbolAddress(loc, var);
if (!base) return 0;
llvm::Constant* result;
if (offset == 0)
{
result = base;
}
else
{
uint64_t elemSize = gDataLayout->getTypeStoreSize(
base->getType()->getContainedType(0));
if (offset % elemSize == 0)
{
// We can turn this into a "nice" GEP.
result = llvm::ConstantExpr::getGetElementPtr(base,
DtoConstSize_t(offset / elemSize));
}
else
{
// Offset isn't a multiple of base type size, just cast to i8* and
// apply the byte offset.
result = llvm::ConstantExpr::getGetElementPtr(
DtoBitCast(base, getVoidPtrType()),
DtoConstSize_t(offset / elemSize));
}
}
return DtoBitCast(result, DtoType(type));
}
//////////////////////////////////////////////////////////////////////////////////////////
@@ -1324,47 +1248,8 @@ LLConstant* AddrExp::toConstElem(IRState* p)
if (e1->op == TOKvar)
{
VarExp* vexp = static_cast<VarExp*>(e1);
// make sure 'this' isn't needed
if (vexp->var->needThis())
{
error("need 'this' to access %s", vexp->var->toChars());
fatal();
}
// global variable
if (VarDeclaration* vd = vexp->var->isVarDeclaration())
{
if (!vd->isDataseg())
{
// Not sure if this can be triggered from user code, but it is
// needed for the current hacky implementation of
// AssocArrayLiteralExp::toElem, which requires on error
// gagging to check for constantness of the initializer.
error("cannot use address of non-global variable '%s' "
"as constant initializer", vd->toChars());
if (!global.gag) fatal();
return NULL;
}
vd->codegen(Type::sir);
LLConstant* llc = llvm::dyn_cast<LLConstant>(vd->ir.getIrValue());
assert(llc);
return DtoBitCast(llc, DtoType(type));
}
// static function
else if (FuncDeclaration* fd = vexp->var->isFuncDeclaration())
{
fd->codegen(Type::sir);
IrFunction* irfunc = fd->ir.irFunc;
return irfunc->func;
}
// something else
else
{
// fail
goto Lerr;
}
LLConstant *c = DtoConstSymbolAddress(loc, vexp->var);
return c ? DtoBitCast(c, DtoType(type)) : 0;
}
// address of indexExp
else if (e1->op == TOKindex)
@@ -1404,7 +1289,6 @@ LLConstant* AddrExp::toConstElem(IRState* p)
// not yet supported
else
{
Lerr:
error("constant expression '%s' not yet implemented", toChars());
fatal();
}