Mercurial > projects > ddmd
diff dmd/codegen/Util.d @ 0:10317f0c89a5
Initial commit
author | korDen |
---|---|
date | Sat, 24 Oct 2009 08:42:06 +0400 |
parents | |
children | 7427ded8caf7 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/codegen/Util.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,1149 @@ +module dmd.codegen.Util; + +import dmd.Loc; +import dmd.IRState; +import dmd.Type; +import dmd.Array; +import dmd.Dsymbol; +import dmd.FuncDeclaration; +import dmd.Identifier; +import dmd.RET; +import dmd.TY; +import dmd.LINK; +import dmd.Expression; +import dmd.Argument; +import dmd.STC; +import dmd.Global; +import dmd.InterfaceDeclaration; +import dmd.AggregateDeclaration; +import dmd.AttribDeclaration; +import dmd.TupleDeclaration; +import dmd.StructDeclaration; +import dmd.VarDeclaration; +import dmd.ClassDeclaration; +import dmd.TemplateMixin; +import dmd.TypedefDeclaration; +import dmd.ExpInitializer; +import dmd.TypeFunction; +import dmd.TypeStruct; +import dmd.TypeSArray; +import dmd.TOK; +import dmd.Util; +import dmd.LabelStatement; +import dmd.DsymbolExp; +import dmd.LabelDsymbol; +import dmd.backend.elem; +import dmd.backend.TYPE; +import dmd.backend.Util; +import dmd.backend.Classsym; +import dmd.backend.SC; +import dmd.backend.FL; +import dmd.backend.SFL; +import dmd.backend.STR; +import dmd.backend.TYM; +import dmd.backend.TF; +import dmd.backend.OPER; +import dmd.backend.mTYman; +import dmd.backend.TYFL; +import dmd.backend.mTY; +import dmd.backend.Symbol; +import dmd.backend.Blockx; +import dmd.backend.RTLSYM; +import dmd.backend.block; +import dmd.backend.LIST; + +import std.string; +import core.stdc.string; + +/************************************ + * Call a function. + */ + +elem* callfunc(Loc loc, + IRState* irs, + int directcall, // 1: don't do virtual call + Type tret, // return type + elem *ec, // evaluates to function address + Type ectype, // original type of ec + FuncDeclaration fd, // if !=null, this is the function being called + Type t, // TypeDelegate or TypeFunction for this function + elem* ehidden, // if !=null, this is the 'hidden' argument + Array arguments) +{ + elem* ep; + elem* e; + elem* ethis = null; + elem* eside = null; + int i; + tym_t ty; + tym_t tyret; + RET retmethod; + int reverse; + TypeFunction tf; + OPER op; + +static if (false) { + printf("callfunc(directcall = %d, tret = '%s', ec = %p, fd = %p)\n", + directcall, tret.toChars(), ec, fd); + printf("ec: "); elem_print(ec); + if (fd) + printf("fd = '%s'\n", fd.toChars()); +} + + t = t.toBasetype(); + if (t.ty == TY.Tdelegate) + { + // A delegate consists of: + // { Object *this; Function *funcptr; } + assert(!fd); + assert(t.nextOf().ty == TY.Tfunction); + tf = cast(TypeFunction)t.nextOf(); + ethis = ec; + ec = el_same(ðis); + ethis = el_una(OPER.OP64_32, TYM.TYnptr, ethis); // get this + ec = array_toPtr(t, ec); // get funcptr + ec = el_una(OPER.OPind, tf.totym(), ec); + } + else + { + assert(t.ty == TY.Tfunction); + tf = cast(TypeFunction)t; + } + + retmethod = tf.retStyle(); + ty = ec.Ety; + if (fd) + ty = fd.toSymbol().Stype.Tty; + reverse = tyrevfunc(ty); + ep = null; + if (arguments) + { + // j=1 if _arguments[] is first argument + int j = (tf.linkage == LINK.LINKd && tf.varargs == 1); + + for (i = 0; i < arguments.dim ; i++) + { + Expression arg; + elem* ea; + + arg = cast(Expression)arguments.data[i]; + //printf("\targ[%d]: %s\n", i, arg.toChars()); + + size_t nparams = Argument.dim(tf.parameters); + if (i - j < nparams && i >= j) + { + Argument p = Argument.getNth(tf.parameters, i - j); + + if (p.storageClass & (STC.STCout | STC.STCref)) + { + // Convert argument to a pointer, + // use AddrExp.toElem() + Expression ae = arg.addressOf(null); + ea = ae.toElem(irs); + goto L1; + } + } + ea = arg.toElem(irs); + L1: + if (tybasic(ea.Ety) == TYM.TYstruct) + { + ea = el_una(OPER.OPstrpar, TYM.TYstruct, ea); + ea.Enumbytes = ea.E1.Enumbytes; + assert(ea.Enumbytes); + } + if (reverse) + ep = el_param(ep,ea); + else + ep = el_param(ea,ep); + } + } + + if (retmethod == RET.RETstack) + { + if (!ehidden) + { + // Don't have one, so create one + type* tt; + + if (tf.next.toBasetype().ty == TY.Tstruct) + tt = tf.next.toCtype(); + else + tt = type_fake(tf.next.totym()); + + Symbol* stmp = symbol_genauto(tt); + ehidden = el_ptr(stmp); + } + if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) && tf.linkage != LINK.LINKd) { + ; // ehidden goes last on Linux/OSX C++ + } else { + if (ep) + { +static if (false) { // BUG: implement + if (reverse && type_mangle(tfunc) == mTYman.mTYman_cpp) { + ep = el_param(ehidden,ep); + } else { + ep = el_param(ep,ehidden); + } +} else { + ep = el_param(ep,ehidden); +} + } + else + ep = ehidden; + ehidden = null; + } + } + + if (fd && fd.isMember2()) + { + InterfaceDeclaration intd; + Symbol* sfunc; + AggregateDeclaration ad; + + ad = fd.isThis(); + if (ad) + { + ethis = ec; + if (ad.isStructDeclaration() && tybasic(ec.Ety) != TYM.TYnptr) + { + ethis = addressElem(ec, ectype); + } + } + else + { + // Evaluate ec for side effects + eside = ec; + } + sfunc = fd.toSymbol(); + + if (!fd.isVirtual() || + directcall || // BUG: fix + fd.isFinal()) + { + // make static call + ec = el_var(sfunc); + } + else + { + // make virtual call + elem* ev; + uint vindex; + + assert(ethis); + ev = el_same(ðis); + ev = el_una(OPER.OPind, TYM.TYnptr, ev); + vindex = fd.vtblIndex; + + // Build *(ev + vindex * 4) + ec = el_bin(OPER.OPadd, TYM.TYnptr, ev, el_long(TYM.TYint, vindex * 4)); + ec = el_una(OPER.OPind, TYM.TYnptr, ec); + ec = el_una(OPER.OPind, tybasic(sfunc.Stype.Tty), ec); + } + } + else if (fd && fd.isNested()) + { + assert(!ethis); + ethis = getEthis(Loc(0), irs, fd); + } + + ep = el_param(ep, ethis); + if (ehidden) + ep = el_param(ep, ehidden); // if ehidden goes last + + tyret = tret.totym(); + + // Look for intrinsic functions + if (ec.Eoper == OPER.OPvar && (op = intrinsic_oper(ec.EV.sp.Vsym.Sident.ptr)) != OPER.OPMAX) + { + el_free(ec); + if (OTbinary(op)) + { + ep.Eoper = op; + ep.Ety = tyret; + e = ep; + if (op == OPER.OPscale) + { + elem *et = e.E1; + e.E1() = el_una(OPER.OPd_ld, TYM.TYldouble, e.E1); + e.E1() = el_una(OPER.OPs32_d, TYM.TYdouble, e.E2); + e.E2() = et; + } + else if (op == OPER.OPyl2x || op == OPER.OPyl2xp1) + { + elem *et = e.E1; + e.E1() = e.E2; + e.E2() = et; + } + } + else + e = el_una(op,tyret,ep); + } + else if (ep) + e = el_bin(tf.ispure ? OPER.OPcallns : OPER.OPcall, tyret, ec, ep); + else + e = el_una(tf.ispure ? OPER.OPucallns : OPER.OPucall, tyret, ec); + + if (retmethod == RET.RETstack) + { + e.Ety = TYM.TYnptr; + e = el_una(OPER.OPind, tyret, e); + } + +version (DMDV2) { + if (tf.isref) + { + e.Ety = TYM.TYnptr; + e = el_una(OPER.OPind, tyret, e); + } +} + + if (tybasic(tyret) == TYM.TYstruct) + { + e.Enumbytes = cast(uint)tret.size(); + } + + e = el_combine(eside, e); + return e; +} + +/************************************** + * Fake a struct symbol. + */ + +Classsym* fake_classsym(Identifier id) +{ + TYPE* t; + Classsym* scc; + + scc = cast(Classsym*)symbol_calloc(toStringz(id.toChars())); + scc.Sclass = SC.SCstruct; + scc.Sstruct = struct_calloc(); + scc.Sstruct.Sstructalign = 8; + //scc.Sstruct.ptrtype = TYM.TYnptr; + scc.Sstruct.Sflags = STR.STRglobal; + + t = type_alloc(TYM.TYstruct); + t.Tflags |= TF.TFsizeunknown | TF.TFforward; + t.Ttag = scc; // structure tag name + assert(t.Tmangle == 0); + t.Tmangle = mTYman.mTYman_d; + t.Tcount++; + scc.Stype = t; + slist_add(scc); + return scc; +} + +/****************************************** + * Return elem that evaluates to the static frame pointer for function fd. + * If fd is a member function, the returned expression will compute the value + * of fd's 'this' variable. + * This routine is critical for implementing nested functions. + */ + +elem* getEthis(Loc loc, IRState* irs, Dsymbol fd) +{ + elem* ethis; + FuncDeclaration thisfd = irs.getFunc(); + Dsymbol fdparent = fd.toParent2(); + + //printf("getEthis(thisfd = '%s', fd = '%s', fdparent = '%s')\n", thisfd.toChars(), fd.toChars(), fdparent.toChars()); + if (fdparent == thisfd) + { + /* Going down one nesting level, i.e. we're calling + * a nested function from its enclosing function. + */ +///version (DMDV2) { + if (irs.sclosure) + ethis = el_var(irs.sclosure); + else +///} + if (irs.sthis) + { + // We have a 'this' pointer for the current function + ethis = el_var(irs.sthis); + + /* If no variables in the current function's frame are + * referenced by nested functions, then we can 'skip' + * adding this frame into the linked list of stack + * frames. + */ +version (DMDV2) { + bool cond = (thisfd.closureVars.dim != 0); +} else { + bool cond = thisfd.nestedFrameRef; +} + if (cond) + { + /* Local variables are referenced, can't skip. + * Address of 'this' gives the 'this' for the nested + * function + */ + ethis = el_una(OPER.OPaddr, TYM.TYnptr, ethis); + } + } + else + { + /* No 'this' pointer for current function, + * use null if no references to the current function's frame + */ + ethis = el_long(TYM.TYnptr, 0); +version (DMDV2) { + bool cond = (thisfd.closureVars.dim != 0); +} else { + bool cond = thisfd.nestedFrameRef; +} + if (cond) + { + /* OPframeptr is an operator that gets the frame pointer + * for the current function, i.e. for the x86 it gets + * the value of EBP + */ + ethis.Eoper = OPER.OPframeptr; + } + } + } + else + { + if (!irs.sthis) // if no frame pointer for this function + { + fd.error(loc, "is a nested function and cannot be accessed from %s", irs.getFunc().toChars()); + ethis = el_long(TYM.TYnptr, 0); // error recovery + } + else + { + ethis = el_var(irs.sthis); + Dsymbol s = thisfd; + while (fd != s) + { + /* Go up a nesting level, i.e. we need to find the 'this' + * of an enclosing function. + * Our 'enclosing function' may also be an inner class. + */ + + //printf("\ts = '%s'\n", s.toChars()); + thisfd = s.isFuncDeclaration(); + if (thisfd) + { + /* Enclosing function is a function. + */ + if (fdparent == s.toParent2()) + break; + + if (thisfd.isNested()) + { + FuncDeclaration p = s.toParent2().isFuncDeclaration(); +version (DMDV2) { + bool cond = !p || p.closureVars.dim; +} else { + bool cond = !p || p.nestedFrameRef; +} + if (cond) { + ethis = el_una(OPER.OPind, TYM.TYnptr, ethis); + } + } + else if (thisfd.vthis) + { + ; + } + else + { + // Error should have been caught by front end + assert(0); + } + } + else + { + /* Enclosed by an aggregate. That means the current + * function must be a member function of that aggregate. + */ + ClassDeclaration cd; + StructDeclaration sd; + AggregateDeclaration ad = s.isAggregateDeclaration(); + + if (!ad) + goto Lnoframe; + + cd = s.isClassDeclaration(); + + if (cd && fd.isClassDeclaration() && fd.isClassDeclaration().isBaseOf(cd, null)) + break; + + sd = s.isStructDeclaration(); + + if (fd == sd) + break; + + if (!ad.isNested() || !ad.vthis) + { + Lnoframe: + irs.getFunc().error(loc, "cannot get frame pointer to %s", fd.toChars()); + return el_long(TYM.TYnptr, 0); // error recovery + } + + ethis = el_bin(OPER.OPadd, TYM.TYnptr, ethis, el_long(TYM.TYint, ad.vthis.offset)); + ethis = el_una(OPER.OPind, TYM.TYnptr, ethis); + + if (fdparent == s.toParent2()) + break; + + if (auto fdd = s.toParent2().isFuncDeclaration()) + { + /* Remember that frames for functions that have no + * nested references are skipped in the linked list + * of frames. + */ +version (DMDV2) { + bool cond = (fdd.closureVars.dim != 0); +} else { + bool cond = fdd.nestedFrameRef; +} + if (cond) { + ethis = el_una(OPER.OPind, TYM.TYnptr, ethis); + } + break; + } + } + s = s.toParent2(); + assert(s); + } + } + } + +static if (false) { + printf("ethis:\n"); + elem_print(ethis); + printf("\n"); +} + + return ethis; +} + +/***************************************** + * Convert array to a pointer to the data. + */ + +elem* array_toPtr(Type t, elem* e) +{ + //printf("array_toPtr()\n"); + //elem_print(e); + t = t.toBasetype(); + switch (t.ty) + { + case TY.Tpointer: + break; + + case TY.Tarray: + case TY.Tdelegate: + if (e.Eoper == OPER.OPcomma) + { + e.Ety = TYM.TYnptr; + e.E2() = array_toPtr(t, e.E2); + } + else if (e.Eoper == OPER.OPpair) + { + e.Eoper = OPER.OPcomma; + e.Ety = TYM.TYnptr; + } + else + { +static if (true) { + e = el_una(OPER.OPmsw, TYM.TYnptr, e); +} else { + e = el_una(OPER.OPaddr, TYM.TYnptr, e); + e = el_bin(OPER.OPadd, TYM.TYnptr, e, el_long(TYM.TYint, 4)); + e = el_una(OPER.OPind, TYM.TYnptr, e); +} + } + break; + + case TY.Tsarray: + e = el_una(OPER.OPaddr, TYM.TYnptr, e); + break; + + default: + ///t.print(); + assert(0); + } + return e; +} + +/******************************************* + * Take address of an elem. + */ + +elem* addressElem(elem* e, Type t) +{ + elem** pe; + + //printf("addressElem()\n"); + + for (pe = &e; (*pe).Eoper == OPER.OPcomma; pe = &(*pe).E2()) { + ; + } + + if ((*pe).Eoper != OPER.OPvar && (*pe).Eoper != OPER.OPind) + { + Symbol* stmp; + elem* eeq; + elem* ee = *pe; + type* tx; + + // Convert to ((tmp=ee),tmp) + TY ty; + if (t && ((ty = t.toBasetype().ty) == TY.Tstruct || ty == TY.Tsarray)) + tx = t.toCtype(); + else + tx = type_fake(ee.Ety); + stmp = symbol_genauto(tx); + eeq = el_bin(OPER.OPeq,ee.Ety,el_var(stmp),ee); + + if (tybasic(ee.Ety) == TYM.TYstruct) + { + eeq.Eoper = OPER.OPstreq; + eeq.Enumbytes = ee.Enumbytes; + } + else if (tybasic(ee.Ety) == TYM.TYarray) + { + eeq.Eoper = OPER.OPstreq; + eeq.Ety = TYM.TYstruct; + eeq.Ejty = cast(ubyte)eeq.Ety; + eeq.Enumbytes = cast(uint)t.size(); + } + *pe = el_bin(OPER.OPcomma, ee.Ety, eeq, el_var(stmp)); + } + + e = el_una(OPER.OPaddr, TYM.TYnptr, e); + return e; +} + +/******************************************* + * Convert intrinsic function to operator. + * Returns that operator, -1 if not an intrinsic function. + */ + +extern (C++) extern int intrinsic_op(char* name); + +OPER intrinsic_oper(const(char)* name) +{ + int result = intrinsic_op(cast(char*)name); + if (result == -1) return OPER.OPMAX; + return cast(OPER)result; +} + +/************************************** + */ + +elem* Dsymbol_toElem(Dsymbol s, IRState *irs) +{ + elem *e = null; + Symbol* sp; + AttribDeclaration ad; + VarDeclaration vd; + ClassDeclaration cd; + StructDeclaration sd; + FuncDeclaration fd; + TemplateMixin tm; + TupleDeclaration td; + TypedefDeclaration tyd; + + //printf("Dsymbol_toElem() %s\n", s.toChars()); + ad = s.isAttribDeclaration(); + if (ad) + { + Array decl = ad.include(null, null); + if (decl && decl.dim) + { + for (size_t i = 0; i < decl.dim; i++) + { + s = cast(Dsymbol)decl.data[i]; + e = el_combine(e, Dsymbol_toElem(s, irs)); + } + } + } + else if ((vd = s.isVarDeclaration()) !is null) + { + s = s.toAlias(); + if (s != vd) + return Dsymbol_toElem(s, irs); + if (vd.isStatic() || vd.storage_class & (STC.STCextern | STC.STCtls | STC.STCgshared)) + vd.toObjFile(0); + else + { + sp = s.toSymbol(); + symbol_add(sp); + //printf("\tadding symbol '%s'\n", sp.Sident); + if (vd.init) + { + ExpInitializer ie = vd.init.isExpInitializer(); + if (ie) { + e = ie.exp.toElem(irs); + } + } + } + } + else if ((cd = s.isClassDeclaration()) !is null) + { + irs.deferToObj.push(cast(void*)s); + } + else if ((sd = s.isStructDeclaration()) !is null) + { + irs.deferToObj.push(cast(void*)sd); + } + else if ((fd = s.isFuncDeclaration()) !is null) + { + //printf("function %s\n", fd.toChars()); + irs.deferToObj.push(cast(void*)fd); + } + else if ((tm = s.isTemplateMixin()) !is null) + { + //printf("%s\n", tm.toChars()); + if (tm.members) + { + for (size_t i = 0; i < tm.members.dim; i++) + { + Dsymbol sm = cast(Dsymbol)tm.members.data[i]; + e = el_combine(e, Dsymbol_toElem(sm, irs)); + } + } + } + else if ((td = s.isTupleDeclaration()) !is null) + { + for (size_t i = 0; i < td.objects.dim; i++) + { + Object o = cast(Object)td.objects.data[i]; + ///if (o.dyncast() == DYNCAST_EXPRESSION) + if (Expression eo = cast(Expression)o) + { + if (eo.op == TOK.TOKdsymbol) + { + DsymbolExp se = cast(DsymbolExp)eo; + e = el_combine(e, Dsymbol_toElem(se.s, irs)); + } + } + } + } + else if ((tyd = s.isTypedefDeclaration()) !is null) + { + irs.deferToObj.push(cast(void*)tyd); + } + + return e; +} + +/************************************** + * Given an expression e that is an array, + * determine and set the 'length' variable. + * Input: + * lengthVar Symbol of 'length' variable + * &e expression that is the array + * t1 Type of the array + * Output: + * e is rewritten to avoid side effects + * Returns: + * expression that initializes 'length' + */ + +elem* resolveLengthVar(VarDeclaration lengthVar, elem** pe, Type t1) +{ + //printf("resolveLengthVar()\n"); + elem* einit = null; + + if (lengthVar && !(lengthVar.storage_class & STC.STCconst)) + { + elem* elength; + Symbol* slength; + + if (t1.ty == TY.Tsarray) + { + TypeSArray tsa = cast(TypeSArray)t1; + long length = tsa.dim.toInteger(); + + elength = el_long(TYM.TYuint, length); + goto L3; + } + else if (t1.ty == TY.Tarray) + { + elength = *pe; + *pe = el_same(&elength); + elength = el_una(OPER.OP64_32, TYM.TYuint, elength); + + L3: + slength = lengthVar.toSymbol(); + //symbol_add(slength); + + einit = el_bin(OPER.OPeq, TYM.TYuint, el_var(slength), elength); + } + } + return einit; +} + +/******************************************* + * Set an array pointed to by eptr to evalue: + * eptr[0..edim] = evalue; + * Input: + * eptr where to write the data to + * evalue value to write + * edim number of times to write evalue to eptr[] + * tb type of evalue + */ + +elem* setArray(elem* eptr, elem* edim, Type tb, elem* evalue, IRState* irs, int op) +{ + int r; + elem* e; + int sz = cast(int)tb.size(); + + if (tb.ty == TY.Tfloat80 || tb.ty == TY.Timaginary80) + r = RTLSYM.RTLSYM_MEMSET80; + else if (tb.ty == TY.Tcomplex80) + r = RTLSYM.RTLSYM_MEMSET160; + else if (tb.ty == TY.Tcomplex64) + r = RTLSYM.RTLSYM_MEMSET128; + else + { + switch (sz) + { + case 1: r = RTLSYM.RTLSYM_MEMSET8; break; + case 2: r = RTLSYM.RTLSYM_MEMSET16; break; + case 4: r = RTLSYM.RTLSYM_MEMSET32; break; + case 8: r = RTLSYM.RTLSYM_MEMSET64; break; + default: r = RTLSYM.RTLSYM_MEMSETN; break; + } + + /* Determine if we need to do postblit + */ + if (op != TOK.TOKblit) + { + StructDeclaration sd = needsPostblit(tb); + if (sd) + { + /* Need to do postblit. + * void *_d_arraysetassign(void *p, void *value, int dim, TypeInfo ti); + */ + r = (op == TOK.TOKconstruct) ? RTLSYM.RTLSYM_ARRAYSETCTOR : RTLSYM.RTLSYM_ARRAYSETASSIGN; + evalue = el_una(OPER.OPaddr, TYM.TYnptr, evalue); + Expression ti = tb.getTypeInfo(null); + elem* eti = ti.toElem(irs); + e = el_params(eti, edim, evalue, eptr, null); + e = el_bin(OPER.OPcall, TYM.TYnptr, el_var(rtlsym[r]), e); + return e; + } + } + + if (r == RTLSYM.RTLSYM_MEMSETN) + { + // void *_memsetn(void *p, void *value, int dim, int sizelem) + evalue = el_una(OPER.OPaddr, TYM.TYnptr, evalue); + elem *esz = el_long(TYM.TYint, sz); + e = el_params(esz, edim, evalue, eptr, null); + e = el_bin(OPER.OPcall, TYM.TYnptr, el_var(rtlsym[r]), e); + return e; + } + } + if (sz > 1 && sz <= 8 && evalue.Eoper == OPER.OPconst && el_allbits(evalue, 0)) + { + r = RTLSYM.RTLSYM_MEMSET8; + edim = el_bin(OPER.OPmul, TYM.TYuint, edim, el_long(TYM.TYuint, sz)); + } + + if (tybasic(evalue.Ety) == TYM.TYstruct) + { + evalue = el_una(OPER.OPstrpar, TYM.TYstruct, evalue); + evalue.Enumbytes = evalue.E1.Enumbytes; + assert(evalue.Enumbytes); + } + + // Be careful about parameter side effect ordering + if (r == RTLSYM.RTLSYM_MEMSET8) + { + e = el_param(edim, evalue); + e = el_bin(OPER.OPmemset, TYM.TYnptr, eptr, e); + } + else + { + e = el_params(edim, evalue, eptr, null); + e = el_bin(OPER.OPcall, TYM.TYnptr, el_var(rtlsym[r]), e); + } + return e; +} + +/************************* + * Initialize the hidden aggregate member, vthis, with + * the context pointer. + * Returns: + * *(ey + ad.vthis.offset) = this; + */ +version (DMDV2) { + elem* setEthis(Loc loc, IRState* irs, elem* ey, AggregateDeclaration ad) + { + elem* ethis; + FuncDeclaration thisfd = irs.getFunc(); + int offset = 0; + Dsymbol cdp = ad.toParent2(); // class/func we're nested in + + //printf("setEthis(ad = %s, cdp = %s, thisfd = %s)\n", ad.toChars(), cdp.toChars(), thisfd.toChars()); + + if (cdp is thisfd) + { + /* Class we're new'ing is a local class in this function: + * void thisfd() { class ad { } } + */ + if (irs.sclosure) + ethis = el_var(irs.sclosure); + else if (irs.sthis) + { +/// version (DMDV2) { + if (thisfd.closureVars.dim) +/// } else { +/// if (thisfd.nestedFrameRef) +/// } + { + ethis = el_ptr(irs.sthis); + } + else + ethis = el_var(irs.sthis); + } + else + { + ethis = el_long(TYM.TYnptr, 0); +/// version (DMDV2) { + if (thisfd.closureVars.dim) +/// } else { +/// if (thisfd.nestedFrameRef) +/// } + { + ethis.Eoper = OPER.OPframeptr; + } + } + } + else if (thisfd.vthis && ( + cdp == thisfd.toParent2() || ( + cdp.isClassDeclaration() && cdp.isClassDeclaration().isBaseOf(thisfd.toParent2().isClassDeclaration(), &offset) + ) + ) + ) + { + /* Class we're new'ing is at the same level as thisfd + */ + assert(offset == 0); // BUG: should handle this case + ethis = el_var(irs.sthis); + } + else + { + ethis = getEthis(loc, irs, ad.toParent2()); + ethis = el_una(OPER.OPaddr, TYM.TYnptr, ethis); + } + + ey = el_bin(OPER.OPadd, TYM.TYnptr, ey, el_long(TYM.TYint, ad.vthis.offset)); + ey = el_una(OPER.OPind, TYM.TYnptr, ey); + ey = el_bin(OPER.OPeq, TYM.TYnptr, ey, ethis); + + return ey; + } +} + +/******************************************** + * Determine if t is an array of structs that need a postblit. + */ +StructDeclaration needsPostblit(Type t) +{ + t = t.toBasetype(); + + while (t.ty == TY.Tsarray) + t = t.nextOf().toBasetype(); + + if (t.ty == TY.Tstruct) + { + StructDeclaration sd = (cast(TypeStruct)t).sym; + if (sd.postblit) + return sd; + } + + return null; +} + +/***************************************** + * Convert array to a dynamic array. + */ + +elem* array_toDarray(Type t, elem* e) +{ + uint dim; + elem* ef = null; + elem* ex; + + //printf("array_toDarray(t = %s)\n", t.toChars()); + //elem_print(e); + t = t.toBasetype(); + switch (t.ty) + { + case TY.Tarray: + break; + + case TY.Tsarray: + e = el_una(OPER.OPaddr, TYM.TYnptr, e); + dim = cast(uint)(cast(TypeSArray)t).dim.toInteger(); + e = el_pair(TYM.TYullong, el_long(TYM.TYint, dim), e); + break; + + default: + L1: + switch (e.Eoper) + { + case OPER.OPconst: + { + size_t len = tysize[tybasic(e.Ety)]; + elem* es = el_calloc(); + es.Eoper = OPER.OPstring; + + // Match MEM_PH_FREE for OPstring in ztc\el.c + es.EV.ss.Vstring = cast(char*)malloc(len); /// + memcpy(es.EV.ss.Vstring, &e.EV, len); + + es.EV.ss.Vstrlen = len; + es.Ety = TYM.TYnptr; + e = es; + break; + } + + case OPER.OPvar: + e = el_una(OPER.OPaddr, TYM.TYnptr, e); + break; + + case OPER.OPcomma: + ef = el_combine(ef, e.E1); + ex = e; + e = e.E2; + ex.E1() = null; + ex.E2() = null; + el_free(ex); + goto L1; + + case OPER.OPind: + ex = e; + e = e.E1; + ex.E1() = null; + ex.E2() = null; + el_free(ex); + break; + + default: + { + // Copy expression to a variable and take the + // address of that variable. + Symbol* stmp; + tym_t ty = tybasic(e.Ety); + + if (ty == TYM.TYstruct) + { + if (e.Enumbytes == 4) + ty = TYM.TYint; + else if (e.Enumbytes == 8) + ty = TYM.TYllong; + } + e.Ety = ty; + stmp = symbol_genauto(type_fake(ty)); + e = el_bin(OPER.OPeq, e.Ety, el_var(stmp), e); + e = el_bin(OPER.OPcomma, TYM.TYnptr, e, el_una(OPER.OPaddr, TYM.TYnptr, el_var(stmp))); + break; + } + } + dim = 1; + e = el_pair(TYM.TYullong, el_long(TYM.TYint, dim), e); + break; + } + + return el_combine(ef, e); +} + +elem* sarray_toDarray(Loc loc, Type tfrom, Type tto, elem* e) +{ + //printf("sarray_toDarray()\n"); + //elem_print(e); + + elem* elen; + uint dim = cast(uint)(cast(TypeSArray)tfrom).dim.toInteger(); + + if (tto) + { + uint fsize = cast(uint)tfrom.nextOf().size(); + uint tsize = cast(uint)tto.nextOf().size(); + + if ((dim * fsize) % tsize != 0) + { + Lerr: + error(loc, "cannot cast %s to %s since sizes don't line up", tfrom.toChars(), tto.toChars()); + } + dim = (dim * fsize) / tsize; + } + + L1: + elen = el_long(TYM.TYint, dim); + e = el_una(OPER.OPaddr, TYM.TYnptr, e); + e = el_pair(TYM.TYullong, elen, e); + return e; +} + +elem* eval_Darray(IRState* irs, Expression e) +{ + elem* ex = e.toElem(irs); + return array_toDarray(e.type, ex); +} + +/*********************************************** + * Generate code to set index into scope table. + */ + +void setScopeIndex(Blockx* blx, block* b, int scope_index) +{ +version (SEH) { + block_appendexp(b, nteh_setScopeTableIndex(blx, scope_index)); +} +} + +/**************************************** + * Create a static symbol we can hang DT initializers onto. + */ + +Symbol* static_sym() +{ + Symbol* s; + type* t; + + t = type_alloc(TYint); + t.Tcount++; + s = symbol_calloc("internal"); + s.Sclass = SCstatic; + s.Sfl = FLextern; + s.Sflags |= SFLnodebug; + s.Stype = t; +version (ELFOBJ_OR_MACHOBJ) { + s.Sseg = DATA; +} + slist_add(s); + return s; +} + +/************************************** + * Convert label to block. + */ + +block* labelToBlock(Loc loc, Blockx *blx, LabelDsymbol label) +{ + LabelStatement s; + + if (!label.statement) + { + error(loc, "undefined label %s", label.toChars()); + return null; + } + + s = label.statement; + if (!s.lblock) + { + s.lblock = block_calloc(blx); + if (s.isReturnLabel) + s.lblock.Btry = null; + } + return s.lblock; +} \ No newline at end of file