From 978c2c1b6aa504c71abb554d3fe68c3b992bece6 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 10 Jun 2013 23:07:06 +0200 Subject: [PATCH] Re-enable SymOffExp and remove associated LLVM-only modifications. --- dmd2/cast.c | 64 +--------- dmd2/ctfeexpr.c | 9 -- dmd2/declaration.c | 4 - dmd2/expression.c | 47 -------- dmd2/expression.h | 7 +- dmd2/init.c | 11 -- dmd2/interpret.c | 61 ---------- dmd2/optimize.c | 37 +----- gen/llvmhelpers.cpp | 215 +++++++++++++++++++++++++++++++++ gen/llvmhelpers.h | 3 + gen/toir.cpp | 282 +++++++++++++------------------------------- 11 files changed, 309 insertions(+), 431 deletions(-) diff --git a/dmd2/cast.c b/dmd2/cast.c index a055e4ad..27ca1ef8 100644 --- a/dmd2/cast.c +++ b/dmd2/cast.c @@ -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; } diff --git a/dmd2/ctfeexpr.c b/dmd2/ctfeexpr.c index e01b049b..d14ddda7 100644 --- a/dmd2/ctfeexpr.c +++ b/dmd2/ctfeexpr.c @@ -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) diff --git a/dmd2/declaration.c b/dmd2/declaration.c index f5b6cb22..5ee94b48 100644 --- a/dmd2/declaration.c +++ b/dmd2/declaration.c @@ -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); diff --git a/dmd2/expression.c b/dmd2/expression.c index d4b5d2fd..7605c48e 100644 --- a/dmd2/expression.c +++ b/dmd2/expression.c @@ -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; diff --git a/dmd2/expression.h b/dmd2/expression.h index 4684edf7..1ee6cf80 100644 --- a/dmd2/expression.h +++ b/dmd2/expression.h @@ -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 }; diff --git a/dmd2/init.c b/dmd2/init.c index 53796359..b0d2dacb 100644 --- a/dmd2/init.c +++ b/dmd2/init.c @@ -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 diff --git a/dmd2/interpret.c b/dmd2/interpret.c index d9284786..ee1a8895 100644 --- a/dmd2/interpret.c +++ b/dmd2/interpret.c @@ -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) diff --git a/dmd2/optimize.c b/dmd2/optimize.c index a6f8453a..016af0a0 100644 --- a/dmd2/optimize.c +++ b/dmd2/optimize.c @@ -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); diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 0417c2c3..4097e199 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -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(vd->ir.getIrValue())) + { + return new DVarValue(type, vd, vd->ir.getIrValue()); + } + else if (llvm::isa(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(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(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(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."); +} diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index 7cc8746f..7c5c4e69 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -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); diff --git a/gen/toir.cpp b/gen/toir.cpp index 5e61007e..e5583068 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -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(vd->ir.getIrValue())) { - return new DVarValue(type, vd, vd->ir.getIrValue()); - } - else if (llvm::isa(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(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(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(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(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(); }