Mercurial > projects > ldc
diff dmd2/e2ir.c.nolink @ 758:f04dde6e882c
Added initial D2 support, D2 frontend and changes to codegen to make things compile.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 11 Nov 2008 01:38:48 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd2/e2ir.c.nolink Tue Nov 11 01:38:48 2008 +0100 @@ -0,0 +1,4679 @@ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <complex.h> + +#include "lexer.h" +#include "expression.h" +#include "mtype.h" +#include "dsymbol.h" +#include "declaration.h" +#include "enum.h" +#include "aggregate.h" +#include "attrib.h" +#include "module.h" +#include "init.h" +#include "template.h" + +#if _WIN32 +#include "..\tk\mem.h" // for mem_malloc +#elif linux +#include "../tk/mem.h" // for mem_malloc +#endif + +#include "cc.h" +#include "el.h" +#include "oper.h" +#include "global.h" +#include "code.h" +#include "type.h" +#include "dt.h" +#include "irstate.h" +#include "id.h" +#include "type.h" +#include "toir.h" + +static char __file__[] = __FILE__; /* for tassert.h */ +#include "tassert.h" + + +elem *addressElem(elem *e, Type *t); +elem *array_toPtr(Type *t, elem *e); +elem *bit_assign(enum OPER op, elem *eb, elem *ei, elem *ev, int result); +elem *bit_read(elem *eb, elem *ei, int result); +elem *exp2_copytotemp(elem *e); + +#define el_setLoc(e,loc) ((e)->Esrcpos.Sfilename = (loc).filename, \ + (e)->Esrcpos.Slinnum = (loc).linnum) + +/************************************ + * 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; + enum RET retmethod; + int reverse; + TypeFunction *tf; + int op; + +#if 0 + 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()); +#endif + + t = t->toBasetype(); + if (t->ty == Tdelegate) + { + // A delegate consists of: + // { Object *this; Function *funcptr; } + assert(!fd); + assert(t->nextOf()->ty == Tfunction); + tf = (TypeFunction *)(t->nextOf()); + ethis = ec; + ec = el_same(ðis); + ethis = el_una(OP64_32, TYnptr, ethis); // get this + ec = array_toPtr(t, ec); // get funcptr + ec = el_una(OPind, tf->totym(), ec); + } + else + { assert(t->ty == Tfunction); + tf = (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 == LINKd && tf->varargs == 1); + + for (i = 0; i < arguments->dim ; i++) + { Expression *arg; + elem *ea; + + arg = (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 & (STCout | 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 (ea->Ety == TYstruct) + { + ea = el_una(OPstrpar, 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 == RETstack) + { + if (!ehidden) + { // Don't have one, so create one + type *t; + + if (tf->next->toBasetype()->ty == Tstruct) + t = tf->next->toCtype(); + else + t = type_fake(tf->next->totym()); + Symbol *stmp = symbol_genauto(t); + ehidden = el_ptr(stmp); + } + if (ep) + { +#if 0 // BUG: implement + if (reverse && type_mangle(tfunc) == mTYman_cpp) + ep = el_param(ehidden,ep); + else +#endif + ep = el_param(ep,ehidden); + } + else + ep = ehidden; + ehidden = NULL; + } + assert(ehidden == NULL); + + if (fd && fd->isMember2()) + { + InterfaceDeclaration *intd; + Symbol *sfunc; + AggregateDeclaration *ad; + + ad = fd->isThis(); + if (ad) + { + ethis = ec; + if (ad->handle->ty == Tpointer && tybasic(ec->Ety) != 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; + unsigned vindex; + + assert(ethis); + ev = el_same(ðis); + ev = el_una(OPind, TYnptr, ev); + vindex = fd->vtblIndex; + + // Build *(ev + vindex * 4) + ec = el_bin(OPadd,TYnptr,ev,el_long(TYint, vindex * 4)); + ec = el_una(OPind,TYnptr,ec); + ec = el_una(OPind,tybasic(sfunc->Stype->Tty),ec); + } + } + else if (fd && fd->isNested()) + { + assert(!ethis); + ethis = getEthis(0, irs, fd); + + } + + ep = el_param(ep, ethis); + + tyret = tret->totym(); + + // Look for intrinsic functions + if (ec->Eoper == OPvar && (op = intrinsic_op(ec->EV.sp.Vsym->Sident)) != -1) + { + el_free(ec); + if (OTbinary(op)) + { + ep->Eoper = op; + ep->Ety = tyret; + e = ep; + if (op == OPscale) + { elem *et; + + et = e->E1; + e->E1 = el_una(OPs32_d, TYdouble, e->E2); + e->E1 = el_una(OPd_ld, TYldouble, e->E1); + e->E2 = et; + e->Ety = tyret; + } + } + else + e = el_una(op,tyret,ep); + } + else if (ep) + e = el_bin(OPcall,tyret,ec,ep); + else + e = el_una(OPucall,tyret,ec); + + if (retmethod == RETstack) + { + e->Ety = TYnptr; + e = el_una(OPind, tyret, e); + } + +#if DMDV2 + if (tf->isref) + { + e->Ety = TYnptr; + e = el_una(OPind, tyret, e); + } +#endif + + if (tybasic(tyret) == TYstruct) + { + e->Enumbytes = tret->size(); + } + e = el_combine(eside, e); + return e; +} + +/******************************************* + * Take address of an elem. + */ + +elem *addressElem(elem *e, Type *t) +{ + elem **pe; + + //printf("addressElem()\n"); + + for (pe = &e; (*pe)->Eoper == OPcomma; pe = &(*pe)->E2) + ; + if ((*pe)->Eoper != OPvar && (*pe)->Eoper != OPind) + { Symbol *stmp; + elem *eeq; + elem *e = *pe; + type *tx; + + // Convert to ((tmp=e),tmp) + TY ty; + if (t && ((ty = t->toBasetype()->ty) == Tstruct || ty == Tsarray)) + tx = t->toCtype(); + else + tx = type_fake(e->Ety); + stmp = symbol_genauto(tx); + eeq = el_bin(OPeq,e->Ety,el_var(stmp),e); + if (e->Ety == TYstruct) + { + eeq->Eoper = OPstreq; + eeq->Enumbytes = e->Enumbytes; + } + else if (e->Ety == TYarray) + { + eeq->Eoper = OPstreq; + eeq->Ejty = eeq->Ety = TYstruct; + eeq->Enumbytes = t->size(); + } + *pe = el_bin(OPcomma,e->Ety,eeq,el_var(stmp)); + } + e = el_una(OPaddr,TYnptr,e); + return e; +} + +/***************************************** + * 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 Tpointer: + break; + + case Tarray: + case Tdelegate: + if (e->Eoper == OPcomma) + { + e->Ety = TYnptr; + e->E2 = array_toPtr(t, e->E2); + } + else if (e->Eoper == OPpair) + { + e->Eoper = OPcomma; + e->Ety = TYnptr; + } + else + { +#if 1 + e = el_una(OPmsw, TYnptr, e); +#else + e = el_una(OPaddr, TYnptr, e); + e = el_bin(OPadd, TYnptr, e, el_long(TYint, 4)); + e = el_una(OPind, TYnptr, e); +#endif + } + break; + + case Tsarray: + e = el_una(OPaddr, TYnptr, e); + break; + + default: + t->print(); + assert(0); + } + return e; +} + +/***************************************** + * Convert array to a dynamic array. + */ + +elem *array_toDarray(Type *t, elem *e) +{ + unsigned dim; + elem *ef = NULL; + elem *ex; + + //printf("array_toDarray(t = %s)\n", t->toChars()); + //elem_print(e); + t = t->toBasetype(); + switch (t->ty) + { + case Tarray: + break; + + case Tsarray: + e = el_una(OPaddr, TYnptr, e); + dim = ((TypeSArray *)t)->dim->toInteger(); + e = el_pair(TYullong, el_long(TYint, dim), e); + break; + + default: + L1: + switch (e->Eoper) + { + case OPconst: + { + size_t len = tysize[tybasic(e->Ety)]; + elem *es = el_calloc(); + es->Eoper = OPstring; + + // Match MEM_PH_FREE for OPstring in ztc\el.c + es->EV.ss.Vstring = (char *)mem_malloc(len); + memcpy(es->EV.ss.Vstring, &e->EV, len); + + es->EV.ss.Vstrlen = len; + es->Ety = TYnptr; + e = es; + break; + } + + case OPvar: + e = el_una(OPaddr, TYnptr, e); + break; + + case OPcomma: + ef = el_combine(ef, e->E1); + ex = e; + e = e->E2; + ex->E1 = NULL; + ex->E2 = NULL; + el_free(ex); + goto L1; + + case 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 == TYstruct) + { + if (e->Enumbytes == 4) + ty = TYint; + else if (e->Enumbytes == 8) + ty = TYllong; + } + e->Ety = ty; + stmp = symbol_genauto(type_fake(ty)); + e = el_bin(OPeq, e->Ety, el_var(stmp), e); + e = el_bin(OPcomma, TYnptr, e, el_una(OPaddr, TYnptr, el_var(stmp))); + break; + } + } + dim = 1; + e = el_pair(TYullong, el_long(TYint, dim), e); + break; + } + return el_combine(ef, e); +} + +/***************************************** + * Evaluate elem and convert to dynamic array. + */ + +elem *eval_Darray(IRState *irs, Expression *e) +{ + elem *ex; + + ex = e->toElem(irs); + return array_toDarray(e->type, ex); +} + +/************************************ + */ + +elem *sarray_toDarray(Loc loc, Type *tfrom, Type *tto, elem *e) +{ + //printf("sarray_toDarray()\n"); + //elem_print(e); + + elem *elen; + unsigned dim = ((TypeSArray *)tfrom)->dim->toInteger(); + + if (tto) + { + unsigned fsize = tfrom->nextOf()->size(); + unsigned tsize = 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(TYint, dim); + e = el_una(OPaddr, TYnptr, e); + e = el_pair(TYullong, elen, e); + return e; +} + +/******************************************* + * 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 = tb->size(); + + if (tb->ty == Tfloat80 || tb->ty == Timaginary80) + r = RTLSYM_MEMSET80; + else if (tb->ty == Tcomplex80) + r = RTLSYM_MEMSET160; + else if (tb->ty == Tcomplex64) + r = RTLSYM_MEMSET128; + else + { + switch (sz) + { + case 1: r = RTLSYM_MEMSET8; break; + case 2: r = RTLSYM_MEMSET16; break; + case 4: r = RTLSYM_MEMSET32; break; + case 8: r = RTLSYM_MEMSET64; break; + default: r = RTLSYM_MEMSETN; break; + } + + /* Determine if we need to do postblit + */ + if (op != TOKblit) + { + Type *t = tb; + while (t->ty == Tsarray) + t = t->nextOf()->toBasetype(); + if (t->ty == Tstruct) + { StructDeclaration *sd = ((TypeStruct *)t)->sym; + if (sd->postblit) + { /* Need to do postblit. + * void *_d_arraysetassign(void *p, void *value, int dim, TypeInfo ti); + */ + r = (op == TOKconstruct) ? RTLSYM_ARRAYSETCTOR : RTLSYM_ARRAYSETASSIGN; + evalue = el_una(OPaddr, TYnptr, evalue); + Expression *ti = tb->getTypeInfo(NULL); + elem *eti = ti->toElem(irs); + e = el_params(eti, edim, evalue, eptr, NULL); + e = el_bin(OPcall,TYnptr,el_var(rtlsym[r]),e); + return e; + } + } + } + + if (r == RTLSYM_MEMSETN) + { + // void *_memsetn(void *p, void *value, int dim, int sizelem) + evalue = el_una(OPaddr, TYnptr, evalue); + elem *esz = el_long(TYint, sz); + e = el_params(esz, edim, evalue, eptr, NULL); + e = el_bin(OPcall,TYnptr,el_var(rtlsym[r]),e); + return e; + } + } + if (sz > 1 && sz <= 8 && + evalue->Eoper == OPconst && el_allbits(evalue, 0)) + { + r = RTLSYM_MEMSET8; + edim = el_bin(OPmul, TYuint, edim, el_long(TYuint, sz)); + } + + if (evalue->Ety == TYstruct) + { + evalue = el_una(OPstrpar, TYstruct, evalue); + evalue->Enumbytes = evalue->E1->Enumbytes; + assert(evalue->Enumbytes); + } + + // Be careful about parameter side effect ordering + if (r == RTLSYM_MEMSET8) + { + e = el_param(edim, evalue); + e = el_bin(OPmemset,TYnptr,eptr,e); + } + else + { + e = el_params(edim, evalue, eptr, NULL); + e = el_bin(OPcall,TYnptr,el_var(rtlsym[r]),e); + } + return e; +} + +/*************************************** + */ + +elem *Expression::toElem(IRState *irs) +{ + print(); + assert(0); + return NULL; +} + +/************************************ + */ + +elem *SymbolExp::toElem(IRState *irs) +{ Symbol *s; + elem *e; + tym_t tym; + Type *tb = (op == TOKsymoff) ? var->type->toBasetype() : type->toBasetype(); + int offset = (op == TOKsymoff) ? ((SymOffExp*)this)->offset : 0; + FuncDeclaration *fd; + VarDeclaration *v = var->isVarDeclaration(); + + //printf("SymbolExp::toElem('%s') %p\n", toChars(), this); + //printf("\tparent = '%s'\n", var->parent ? var->parent->toChars() : "null"); + if (op == TOKvar && var->needThis()) + { + error("need 'this' to access member %s", toChars()); + return el_long(TYint, 0); + } + s = var->toSymbol(); + fd = NULL; + if (var->toParent2()) + fd = var->toParent2()->isFuncDeclaration(); + + int nrvo = 0; + if (fd && fd->nrvo_can && fd->nrvo_var == var) + { + s = fd->shidden; + nrvo = 1; + } + + if (s->Sclass == SCauto || s->Sclass == SCparameter) + { + if (fd && fd != irs->getFunc()) + { // 'var' is a variable in an enclosing function. + elem *ethis; + int soffset; + + ethis = getEthis(loc, irs, fd); + ethis = el_una(OPaddr, TYnptr, ethis); + + if (v && v->offset) + soffset = v->offset; + else + { + soffset = s->Soffset; + /* If fd is a non-static member function of a class or struct, + * then ethis isn't the frame pointer. + * ethis is the 'this' pointer to the class/struct instance. + * We must offset it. + */ + if (fd->vthis) + { + soffset -= fd->vthis->toSymbol()->Soffset; + } + //printf("\tSoffset = x%x, sthis->Soffset = x%x\n", s->Soffset, irs->sthis->Soffset); + } + + if (!nrvo) + soffset += offset; + + e = el_bin(OPadd, TYnptr, ethis, el_long(TYnptr, soffset)); + if (op == TOKvar) + e = el_una(OPind, TYnptr, e); + if ((var->isParameter() && tb->ty == Tsarray) || var->isOut() || var->isRef()) + e = el_una(OPind, s->ty(), e); + else if (op == TOKsymoff && nrvo) + { e = el_una(OPind, TYnptr, e); + e = el_bin(OPadd, e->Ety, e, el_long(TYint, offset)); + } + goto L1; + } + } + + /* If var is a member of a closure + */ + if (v && v->offset) + { assert(irs->sclosure); + e = el_var(irs->sclosure); + e = el_bin(OPadd, TYnptr, e, el_long(TYint, v->offset)); + if (op == TOKvar) + { e = el_una(OPind, type->totym(), e); + if (tybasic(e->Ety) == TYstruct) + e->Enumbytes = type->size(); + el_setLoc(e, loc); + } + if ((var->isParameter() && tb->ty == Tsarray) || var->isOut() || var->isRef()) + { e->Ety = TYnptr; + e = el_una(OPind, s->ty(), e); + } + else if (op == TOKsymoff && nrvo) + { e = el_una(OPind, TYnptr, e); + e = el_bin(OPadd, e->Ety, e, el_long(TYint, offset)); + } + else if (op == TOKsymoff) + { + e = el_bin(OPadd, e->Ety, e, el_long(TYint, offset)); + } + goto L1; + } + + if (s->Sclass == SCauto && s->Ssymnum == -1) + { + //printf("\tadding symbol\n"); + symbol_add(s); + } + + if (var->isImportedSymbol()) + { + assert(op == TOKvar); + e = el_var(var->toImport()); + e = el_una(OPind,s->ty(),e); + } + else if ((var->isParameter() && tb->ty == Tsarray) || var->isOut() || var->isRef()) + { // Static arrays are really passed as pointers to the array + // Out parameters are really references + e = el_var(s); + e->Ety = TYnptr; + if (op == TOKvar) + e = el_una(OPind, s->ty(), e); + else if (offset) + e = el_bin(OPadd, TYnptr, e, el_long(TYint, offset)); + } + else if (op == TOKvar) + e = el_var(s); + else + { e = nrvo ? el_var(s) : el_ptr(s); + e = el_bin(OPadd, e->Ety, e, el_long(TYint, offset)); + } +L1: + if (op == TOKvar) + { + if (nrvo) + { + e->Ety = TYnptr; + e = el_una(OPind, 0, e); + } + if (tb->ty == Tfunction) + { + tym = s->Stype->Tty; + } + else + tym = type->totym(); + e->Ejty = e->Ety = tym; + if (tybasic(tym) == TYstruct) + { + e->Enumbytes = type->size(); + } + else if (tybasic(tym) == TYarray) + { + e->Ejty = e->Ety = TYstruct; + e->Enumbytes = type->size(); + } + } + el_setLoc(e,loc); + return e; +} + +#if 0 +elem *VarExp::toElem(IRState *irs) +{ Symbol *s; + elem *e; + tym_t tym; + Type *tb = type->toBasetype(); + FuncDeclaration *fd; + VarDeclaration *v = var->isVarDeclaration(); + + //printf("VarExp::toElem('%s') %p\n", toChars(), this); + //printf("\tparent = '%s'\n", var->parent ? var->parent->toChars() : "null"); + if (var->needThis()) + { + error("need 'this' to access member %s", toChars()); + return el_long(TYint, 0); + } + s = var->toSymbol(); + fd = NULL; + if (var->toParent2()) + fd = var->toParent2()->isFuncDeclaration(); + + int nrvo = 0; + if (fd && fd->nrvo_can && fd->nrvo_var == var) + { + s = fd->shidden; + nrvo = 1; + } + + if (s->Sclass == SCauto || s->Sclass == SCparameter) + { + if (fd && fd != irs->getFunc()) + { // 'var' is a variable in an enclosing function. + elem *ethis; + int soffset; + + ethis = getEthis(loc, irs, fd); + ethis = el_una(OPaddr, TYnptr, ethis); + + if (v && v->offset) + soffset = v->offset; + else + { + soffset = s->Soffset; + /* If fd is a non-static member function of a class or struct, + * then ethis isn't the frame pointer. + * ethis is the 'this' pointer to the class/struct instance. + * We must offset it. + */ + if (fd->vthis) + { + soffset -= fd->vthis->toSymbol()->Soffset; + } + //printf("\tSoffset = x%x, sthis->Soffset = x%x\n", s->Soffset, irs->sthis->Soffset); + } + + ethis = el_bin(OPadd, TYnptr, ethis, el_long(TYnptr, soffset)); + e = el_una(OPind, 0, ethis); + if ((var->isParameter() && tb->ty == Tsarray) || var->isOut() || var->isRef()) + goto L2; + goto L1; + } + } + + /* If var is a member of a closure + */ + if (v && v->offset) + { assert(irs->sclosure); + e = el_var(irs->sclosure); + e = el_bin(OPadd, TYnptr, e, el_long(TYint, v->offset)); + e = el_una(OPind, type->totym(), e); + if (tybasic(e->Ety) == TYstruct) + e->Enumbytes = type->size(); + el_setLoc(e, loc); + + if ((var->isParameter() && tb->ty == Tsarray) || var->isOut() || var->isRef()) + goto L2; + goto L1; + } + + if (s->Sclass == SCauto && s->Ssymnum == -1) + { + //printf("\tadding symbol\n"); + symbol_add(s); + } + + if (var->isImportedSymbol()) + { + e = el_var(var->toImport()); + e = el_una(OPind,s->ty(),e); + } + else if ((var->isParameter() && tb->ty == Tsarray) || var->isOut() || var->isRef()) + { // Static arrays are really passed as pointers to the array + // Out parameters are really references + e = el_var(s); +L2: + e->Ety = TYnptr; + e = el_una(OPind, s->ty(), e); + } + else + e = el_var(s); +L1: + if (nrvo) + { + e->Ety = TYnptr; + e = el_una(OPind, 0, e); + } + if (tb->ty == Tfunction) + { + tym = s->Stype->Tty; + } + else + tym = type->totym(); + e->Ejty = e->Ety = tym; + if (tybasic(tym) == TYstruct) + { + e->Enumbytes = type->size(); + } + else if (tybasic(tym) == TYarray) + { + e->Ejty = e->Ety = TYstruct; + e->Enumbytes = type->size(); + } + el_setLoc(e,loc); + return e; +} +#endif + +#if 0 +elem *SymOffExp::toElem(IRState *irs) +{ Symbol *s; + elem *e; + Type *tb = var->type->toBasetype(); + VarDeclaration *v = var->isVarDeclaration(); + FuncDeclaration *fd = NULL; + if (var->toParent2()) + fd = var->toParent2()->isFuncDeclaration(); + + //printf("SymOffExp::toElem(): %s\n", toChars()); + s = var->toSymbol(); + + int nrvo = 0; + if (fd && fd->nrvo_can && fd->nrvo_var == var) + { s = fd->shidden; + nrvo = 1; + } + + if (s->Sclass == SCauto && s->Ssymnum == -1) + symbol_add(s); + assert(!var->isImportedSymbol()); + + // This code closely parallels that in VarExp::toElem() + if (s->Sclass == SCauto || s->Sclass == SCparameter) + { + if (fd && fd != irs->getFunc()) + { // 'var' is a variable in an enclosing function. + elem *ethis; + int soffset; + + ethis = getEthis(loc, irs, fd); + ethis = el_una(OPaddr, TYnptr, ethis); + + if (v && v->offset) + soffset = v->offset; + else + { + soffset = s->Soffset; + /* If fd is a non-static member function of a class or struct, + * then ethis isn't the frame pointer. + * ethis is the 'this' pointer to the class/struct instance. + * We must offset it. + */ + if (fd->vthis) + { + soffset -= fd->vthis->toSymbol()->Soffset; + } + //printf("\tSoffset = x%x, sthis->Soffset = x%x\n", s->Soffset, irs->sthis->Soffset); + } + + if (!nrvo) + soffset += offset; + e = el_bin(OPadd, TYnptr, ethis, el_long(TYnptr, soffset)); + if ((var->isParameter() && tb->ty == Tsarray) || var->isOut() || var->isRef()) + e = el_una(OPind, s->ty(), e); + else if (nrvo) + { e = el_una(OPind, TYnptr, e); + e = el_bin(OPadd, e->Ety, e, el_long(TYint, offset)); + } + goto L1; + } + } + + /* If var is a member of a closure + */ + if (v && v->offset) + { assert(irs->sclosure); + e = el_var(irs->sclosure); + e = el_bin(OPadd, TYnptr, e, el_long(TYint, v->offset)); + if ((var->isParameter() && tb->ty == Tsarray) || var->isOut() || var->isRef()) + e = el_una(OPind, s->ty(), e); + else if (nrvo) + { e = el_una(OPind, TYnptr, e); + e = el_bin(OPadd, e->Ety, e, el_long(TYint, offset)); + } + goto L1; + } + + if ((var->isParameter() && tb->ty == Tsarray) || var->isOut() || var->isRef()) + { // Static arrays are really passed as pointers to the array + // Out parameters are really references + e = el_var(s); + e->Ety = TYnptr; + if (offset) + e = el_bin(OPadd, TYnptr, e, el_long(TYint, offset)); + } + else + { e = nrvo ? el_var(s) : el_ptr(s); + e = el_bin(OPadd, e->Ety, e, el_long(TYint, offset)); + } + +L1: + el_setLoc(e,loc); + return e; +} +#endif + +/************************************** + */ + +elem *FuncExp::toElem(IRState *irs) +{ + elem *e; + Symbol *s; + + //printf("FuncExp::toElem() %s\n", toChars()); + s = fd->toSymbol(); + e = el_ptr(s); + if (fd->isNested()) + { + elem *ethis = getEthis(loc, irs, fd); + e = el_pair(TYullong, ethis, e); + } + + irs->deferToObj->push(fd); + el_setLoc(e,loc); + return e; +} + +/************************************** + */ + +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 = (Dsymbol *)decl->data[i]; + e = el_combine(e, Dsymbol_toElem(s, irs)); + } + } + } + else if ((vd = s->isVarDeclaration()) != NULL) + { + s = s->toAlias(); + if (s != vd) + return Dsymbol_toElem(s, irs); + if (vd->isStatic() || vd->storage_class & STCextern) + vd->toObjFile(0); + else + { + sp = s->toSymbol(); + symbol_add(sp); + //printf("\tadding symbol '%s'\n", sp->Sident); + if (vd->init) + { + ExpInitializer *ie; + + ie = vd->init->isExpInitializer(); + if (ie) + e = ie->exp->toElem(irs); + } + } + } + else if ((cd = s->isClassDeclaration()) != NULL) + { + irs->deferToObj->push(s); + } + else if ((sd = s->isStructDeclaration()) != NULL) + { + irs->deferToObj->push(sd); + } + else if ((fd = s->isFuncDeclaration()) != NULL) + { + //printf("function %s\n", fd->toChars()); + irs->deferToObj->push(fd); + } + else if ((tm = s->isTemplateMixin()) != NULL) + { + //printf("%s\n", tm->toChars()); + if (tm->members) + { + for (size_t i = 0; i < tm->members->dim; i++) + { + Dsymbol *sm = (Dsymbol *)tm->members->data[i]; + e = el_combine(e, Dsymbol_toElem(sm, irs)); + } + } + } + else if ((td = s->isTupleDeclaration()) != NULL) + { + for (size_t i = 0; i < td->objects->dim; i++) + { Object *o = (Object *)td->objects->data[i]; + if (o->dyncast() == DYNCAST_EXPRESSION) + { Expression *eo = (Expression *)o; + if (eo->op == TOKdsymbol) + { DsymbolExp *se = (DsymbolExp *)eo; + e = el_combine(e, Dsymbol_toElem(se->s, irs)); + } + } + } + } + else if ((tyd = s->isTypedefDeclaration()) != NULL) + { + irs->deferToObj->push(tyd); + } + return e; +} + +elem *DeclarationExp::toElem(IRState *irs) +{ elem *e; + + //printf("DeclarationExp::toElem() %s\n", toChars()); + e = Dsymbol_toElem(declaration, irs); + return e; +} + +/*************************************** + */ + +elem *ThisExp::toElem(IRState *irs) +{ elem *ethis; + FuncDeclaration *fd; + + //printf("ThisExp::toElem()\n"); + assert(irs->sthis); + + if (var) + { + assert(var->parent); + fd = var->toParent2()->isFuncDeclaration(); + assert(fd); + ethis = getEthis(loc, irs, fd); + } + else + ethis = el_var(irs->sthis); + + el_setLoc(ethis,loc); + return ethis; +} + +/*************************************** + */ + +elem *IntegerExp::toElem(IRState *irs) +{ elem *e; + + e = el_long(type->totym(), value); + el_setLoc(e,loc); + return e; +} + +/*************************************** + */ + +elem *RealExp::toElem(IRState *irs) +{ union eve c; + tym_t ty; + + //printf("RealExp::toElem(%p)\n", this); + memset(&c, 0, sizeof(c)); + ty = type->toBasetype()->totym(); + switch (ty) + { + case TYfloat: + case TYifloat: + c.Vfloat = value; + break; + + case TYdouble: + case TYidouble: + c.Vdouble = value; + break; + + case TYldouble: + case TYildouble: + c.Vldouble = value; + break; + + default: + print(); + type->print(); + type->toBasetype()->print(); + printf("ty = %d, tym = %x\n", type->ty, ty); + assert(0); + } + return el_const(ty, &c); +} + + +/*************************************** + */ + +elem *ComplexExp::toElem(IRState *irs) +{ union eve c; + tym_t ty; + real_t re; + real_t im; + + re = creall(value); + im = cimagl(value); + + memset(&c, 0, sizeof(c)); + ty = type->totym(); + switch (ty) + { + case TYcfloat: + c.Vcfloat.re = (float) re; + c.Vcfloat.im = (float) im; + break; + + case TYcdouble: + c.Vcdouble.re = (double) re; + c.Vcdouble.im = (double) im; + break; + + case TYcldouble: + c.Vcldouble.re = re; + c.Vcldouble.im = im; + break; + + default: + assert(0); + } + return el_const(ty, &c); +} + +/*************************************** + */ + +elem *NullExp::toElem(IRState *irs) +{ + return el_long(type->totym(), 0); +} + +/*************************************** + */ + +struct StringTab +{ + Module *m; // module we're generating code for + Symbol *si; + void *string; + size_t sz; + size_t len; +}; + +#define STSIZE 16 +StringTab stringTab[STSIZE]; +size_t stidx; + +static Symbol *assertexp_sfilename = NULL; +static char *assertexp_name = NULL; +static Module *assertexp_mn = NULL; + +void clearStringTab() +{ + //printf("clearStringTab()\n"); + memset(stringTab, 0, sizeof(stringTab)); + stidx = 0; + + assertexp_sfilename = NULL; + assertexp_name = NULL; + assertexp_mn = NULL; +} + +elem *StringExp::toElem(IRState *irs) +{ + elem *e; + Type *tb= type->toBasetype(); + + +#if 0 + printf("StringExp::toElem() %s, type = %s\n", toChars(), type->toChars()); +#endif + + if (tb->ty == Tarray) + { + Symbol *si; + dt_t *dt; + StringTab *st; + +#if 0 + printf("irs->m = %p\n", irs->m); + printf(" m = %s\n", irs->m->toChars()); + printf(" len = %d\n", len); + printf(" sz = %d\n", sz); +#endif + for (size_t i = 0; i < STSIZE; i++) + { + st = &stringTab[(stidx + i) % STSIZE]; + //if (!st->m) continue; + //printf(" st.m = %s\n", st->m->toChars()); + //printf(" st.len = %d\n", st->len); + //printf(" st.sz = %d\n", st->sz); + if (st->m == irs->m && + st->si && + st->len == len && + st->sz == sz && + memcmp(st->string, string, sz * len) == 0) + { + //printf("use cached value\n"); + si = st->si; // use cached value + goto L1; + } + } + + stidx = (stidx + 1) % STSIZE; + st = &stringTab[stidx]; + + dt = NULL; + toDt(&dt); + + si = symbol_generate(SCstatic,type_fake(TYdarray)); + si->Sdt = dt; + si->Sfl = FLdata; +#if ELFOBJ // Burton + si->Sseg = CDATA; +#endif + outdata(si); + + st->m = irs->m; + st->si = si; + st->string = string; + st->len = len; + st->sz = sz; + L1: + e = el_var(si); + } + else if (tb->ty == Tsarray) + { + Symbol *si; + dt_t *dt = NULL; + + toDt(&dt); + dtnzeros(&dt, sz); // leave terminating 0 + + si = symbol_generate(SCstatic,type_allocn(TYarray, tschar)); + si->Sdt = dt; + si->Sfl = FLdata; + +#if ELFOBJ // Burton + si->Sseg = CDATA; +#endif + outdata(si); + + e = el_var(si); + } + else if (tb->ty == Tpointer) + { + e = el_calloc(); + e->Eoper = OPstring; +#if 1 + // Match MEM_PH_FREE for OPstring in ztc\el.c + e->EV.ss.Vstring = (char *)mem_malloc((len + 1) * sz); + memcpy(e->EV.ss.Vstring, string, (len + 1) * sz); +#else + e->EV.ss.Vstring = (char *)string; +#endif + e->EV.ss.Vstrlen = (len + 1) * sz; + e->Ety = TYnptr; + } + else + { + printf("type is %s\n", type->toChars()); + assert(0); + } + el_setLoc(e,loc); + return e; +} + +elem *NewExp::toElem(IRState *irs) +{ elem *e; + Type *t; + Type *ectype; + + //printf("NewExp::toElem() %s\n", toChars()); + t = type->toBasetype(); + //printf("\ttype = %s\n", t->toChars()); + //if (member) + //printf("\tmember = %s\n", member->toChars()); + if (t->ty == Tclass) + { + Symbol *csym; + + t = newtype->toBasetype(); + assert(t->ty == Tclass); + TypeClass *tclass = (TypeClass *)(t); + ClassDeclaration *cd = tclass->sym; + + /* Things to do: + * 1) ex: call allocator + * 2) ey: set vthis for nested classes + * 3) ez: call constructor + */ + + elem *ex = NULL; + elem *ey = NULL; + elem *ez = NULL; + + if (allocator || onstack) + { elem *ei; + Symbol *si; + + if (onstack) + { + /* Create an instance of the class on the stack, + * and call it stmp. + * Set ex to be the &stmp. + */ + Symbol *s = symbol_calloc(tclass->sym->toChars()); + s->Sclass = SCstruct; + s->Sstruct = struct_calloc(); + s->Sstruct->Sflags |= 0; + s->Sstruct->Salignsize = tclass->sym->alignsize; + s->Sstruct->Sstructalign = tclass->sym->structalign; + s->Sstruct->Sstructsize = tclass->sym->structsize; + + ::type *tc = type_alloc(TYstruct); + tc->Ttag = (Classsym *)s; // structure tag name + tc->Tcount++; + s->Stype = tc; + + Symbol *stmp = symbol_genauto(tc); + ex = el_ptr(stmp); + } + else + { + ex = el_var(allocator->toSymbol()); + ex = callfunc(loc, irs, 1, type, ex, allocator->type, + allocator, allocator->type, NULL, newargs); + } + + si = tclass->sym->toInitializer(); + ei = el_var(si); + + if (cd->isNested()) + { + ey = el_same(&ex); + ez = el_copytree(ey); + } + else if (member) + ez = el_same(&ex); + + ex = el_una(OPind, TYstruct, ex); + ex = el_bin(OPstreq, TYnptr, ex, ei); + ex->Enumbytes = cd->size(loc); + ex = el_una(OPaddr, TYnptr, ex); + ectype = tclass; + } + else + { + csym = cd->toSymbol(); + ex = el_bin(OPcall,TYnptr,el_var(rtlsym[RTLSYM_NEWCLASS]),el_ptr(csym)); + ectype = NULL; + + if (cd->isNested()) + { + ey = el_same(&ex); + ez = el_copytree(ey); + } + else if (member) + ez = el_same(&ex); +//elem_print(ex); +//elem_print(ey); +//elem_print(ez); + } + + if (thisexp) + { ClassDeclaration *cdthis = thisexp->type->isClassHandle(); + assert(cdthis); + //printf("cd = %s\n", cd->toChars()); + //printf("cdthis = %s\n", cdthis->toChars()); + assert(cd->isNested()); + int offset = 0; + Dsymbol *cdp = cd->toParent2(); // class we're nested in + elem *ethis; + +//printf("member = %p\n", member); +//printf("cdp = %s\n", cdp->toChars()); +//printf("cdthis = %s\n", cdthis->toChars()); + if (cdp != cdthis) + { int i = cdp->isClassDeclaration()->isBaseOf(cdthis, &offset); + assert(i); + } + ethis = thisexp->toElem(irs); + if (offset) + ethis = el_bin(OPadd, TYnptr, ethis, el_long(TYint, offset)); + + ey = el_bin(OPadd, TYnptr, ey, el_long(TYint, cd->vthis->offset)); + ey = el_una(OPind, TYnptr, ey); + ey = el_bin(OPeq, TYnptr, ey, ethis); + +//printf("ex: "); elem_print(ex); +//printf("ey: "); elem_print(ey); +//printf("ez: "); elem_print(ez); + } + else if (cd->isNested()) + { /* Initialize cd->vthis: + * *(ey + cd.vthis.offset) = this; + */ + elem *ethis; + FuncDeclaration *thisfd = irs->getFunc(); + int offset = 0; + Dsymbol *cdp = cd->toParent2(); // class/func we're nested in + + if (cdp == thisfd) + { /* Class we're new'ing is a local class in this function: + * void thisfd() { class cd { } } + */ + if (irs->sclosure) + ethis = el_var(irs->sclosure); + else if (irs->sthis) + { +#if DMDV2 + if (thisfd->closureVars.dim) +#else + if (thisfd->nestedFrameRef) +#endif + ethis = el_ptr(irs->sthis); + else + ethis = el_var(irs->sthis); + } + else + { + ethis = el_long(TYnptr, 0); +#if DMDV2 + if (thisfd->closureVars.dim) +#else + if (thisfd->nestedFrameRef) +#endif + ethis->Eoper = 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, cd->toParent2()); + ethis = el_una(OPaddr, TYnptr, ethis); + } + + ey = el_bin(OPadd, TYnptr, ey, el_long(TYint, cd->vthis->offset)); + ey = el_una(OPind, TYnptr, ey); + ey = el_bin(OPeq, TYnptr, ey, ethis); + + } + + if (member) + // Call constructor + ez = callfunc(loc, irs, 1, type, ez, ectype, member, member->type, NULL, arguments); + + e = el_combine(ex, ey); + e = el_combine(e, ez); + } + else if (t->ty == Tpointer && t->nextOf()->toBasetype()->ty == Tstruct) + { + Symbol *csym; + + t = newtype->toBasetype(); + assert(t->ty == Tstruct); + TypeStruct *tclass = (TypeStruct *)(t); + StructDeclaration *cd = tclass->sym; + + /* Things to do: + * 1) ex: call allocator + * 2) ey: set vthis for nested classes + * 3) ez: call constructor + */ + + elem *ex = NULL; + elem *ey = NULL; + elem *ez = NULL; + + if (allocator) + { elem *ei; + Symbol *si; + + ex = el_var(allocator->toSymbol()); + ex = callfunc(loc, irs, 1, type, ex, allocator->type, + allocator, allocator->type, NULL, newargs); + + si = tclass->sym->toInitializer(); + ei = el_var(si); + + if (member) + ez = el_same(&ex); + else + { /* Statically intialize with default initializer + */ + ex = el_una(OPind, TYstruct, ex); + ex = el_bin(OPstreq, TYnptr, ex, ei); + ex->Enumbytes = cd->size(loc); + ex = el_una(OPaddr, TYnptr, ex); + } + ectype = tclass; + } + else + { + d_uns64 elemsize = cd->size(loc); + + // call _d_newarrayT(ti, 1) + e = el_long(TYsize_t, 1); + e = el_param(e, type->getTypeInfo(NULL)->toElem(irs)); + + int rtl = t->isZeroInit() ? RTLSYM_NEWARRAYT : RTLSYM_NEWARRAYIT; + e = el_bin(OPcall,TYdarray,el_var(rtlsym[rtl]),e); + + // The new functions return an array, so convert to a pointer + // ex -> (unsigned)(e >> 32) + e = el_bin(OPshr, TYdarray, e, el_long(TYint, 32)); + ex = el_una(OP64_32, TYnptr, e); + + ectype = NULL; + + if (member) + ez = el_same(&ex); +//elem_print(ex); +//elem_print(ey); +//elem_print(ez); + } + + if (member) + // Call constructor + ez = callfunc(loc, irs, 1, type, ez, ectype, member, member->type, NULL, arguments); + + e = el_combine(ex, ey); + e = el_combine(e, ez); + } + else if (t->ty == Tarray) + { + TypeDArray *tda = (TypeDArray *)(t); + + assert(arguments && arguments->dim >= 1); + if (arguments->dim == 1) + { // Single dimension array allocations + Expression *arg = (Expression *)arguments->data[0]; // gives array length + e = arg->toElem(irs); + d_uns64 elemsize = tda->next->size(); + + // call _d_newT(ti, arg) + e = el_param(e, type->getTypeInfo(NULL)->toElem(irs)); + int rtl = tda->next->isZeroInit() ? RTLSYM_NEWARRAYT : RTLSYM_NEWARRAYIT; + e = el_bin(OPcall,TYdarray,el_var(rtlsym[rtl]),e); + } + else + { // Multidimensional array allocations + e = el_long(TYint, arguments->dim); + for (size_t i = 0; i < arguments->dim; i++) + { + Expression *arg = (Expression *)arguments->data[i]; // gives array length + e = el_param(arg->toElem(irs), e); + assert(t->ty == Tarray); + t = t->nextOf(); + assert(t); + } + + e = el_param(e, type->getTypeInfo(NULL)->toElem(irs)); + + int rtl = t->isZeroInit() ? RTLSYM_NEWARRAYMT : RTLSYM_NEWARRAYMIT; + e = el_bin(OPcall,TYdarray,el_var(rtlsym[rtl]),e); + } + } + else if (t->ty == Tpointer) + { + TypePointer *tp = (TypePointer *)t; + d_uns64 elemsize = tp->next->size(); + Expression *di = tp->next->defaultInit(); + d_uns64 disize = di->type->size(); + + // call _d_newarrayT(ti, 1) + e = el_long(TYsize_t, 1); + e = el_param(e, type->getTypeInfo(NULL)->toElem(irs)); + + int rtl = tp->next->isZeroInit() ? RTLSYM_NEWARRAYT : RTLSYM_NEWARRAYIT; + e = el_bin(OPcall,TYdarray,el_var(rtlsym[rtl]),e); + + // The new functions return an array, so convert to a pointer + // e -> (unsigned)(e >> 32) + e = el_bin(OPshr, TYdarray, e, el_long(TYint, 32)); + e = el_una(OP64_32, t->totym(), e); + } + else + { + assert(0); + } + + el_setLoc(e,loc); + return e; +} + +//////////////////////////// Unary /////////////////////////////// + +/*************************************** + */ + +elem *NegExp::toElem(IRState *irs) +{ + elem *e = el_una(OPneg, type->totym(), e1->toElem(irs)); + el_setLoc(e,loc); + return e; +} + +/*************************************** + */ + +elem *ComExp::toElem(IRState *irs) +{ elem *e; + + elem *e1 = this->e1->toElem(irs); + tym_t ty = type->totym(); + if (this->e1->type->toBasetype()->ty == Tbool) + e = el_bin(OPxor, ty, e1, el_long(ty, 1)); + else + e = el_una(OPcom,ty,e1); + el_setLoc(e,loc); + return e; +} + +/*************************************** + */ + +elem *NotExp::toElem(IRState *irs) +{ + elem *e = el_una(OPnot, type->totym(), e1->toElem(irs)); + el_setLoc(e,loc); + return e; +} + + +/*************************************** + */ + +elem *HaltExp::toElem(IRState *irs) +{ elem *e; + + e = el_calloc(); + e->Ety = TYvoid; + e->Eoper = OPhalt; + el_setLoc(e,loc); + return e; +} + +/******************************************** + */ + +elem *AssertExp::toElem(IRState *irs) +{ elem *e; + elem *ea; + Type *t1 = e1->type->toBasetype(); + + //printf("AssertExp::toElem() %s\n", toChars()); + if (global.params.useAssert) + { + e = e1->toElem(irs); + + InvariantDeclaration *inv = (InvariantDeclaration *)(void *)1; + + // If e1 is a class object, call the class invariant on it + if (global.params.useInvariants && t1->ty == Tclass && + !((TypeClass *)t1)->sym->isInterfaceDeclaration()) + { +#if TARGET_LINUX + e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM__DINVARIANT]), e); +#else + e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_DINVARIANT]), e); +#endif + } + // If e1 is a struct object, call the struct invariant on it + else if (global.params.useInvariants && + t1->ty == Tpointer && + t1->nextOf()->ty == Tstruct && + (inv = ((TypeStruct *)t1->nextOf())->sym->inv) != NULL) + { + e = callfunc(loc, irs, 1, inv->type->nextOf(), e, e1->type, inv, inv->type, NULL, NULL); + } + else + { + // Construct: (e1 || ModuleAssert(line)) + Symbol *sassert; + Module *m = irs->blx->module; + char *mname = m->srcfile->toChars(); + + //printf("filename = '%s'\n", loc.filename); + //printf("module = '%s'\n", m->srcfile->toChars()); + + /* If the source file name has changed, probably due + * to a #line directive. + */ + if (loc.filename && (msg || strcmp(loc.filename, mname) != 0)) + { elem *efilename; + + /* Cache values. + */ + //static Symbol *assertexp_sfilename = NULL; + //static char *assertexp_name = NULL; + //static Module *assertexp_mn = NULL; + + if (!assertexp_sfilename || strcmp(loc.filename, assertexp_name) != 0 || assertexp_mn != m) + { + dt_t *dt = NULL; + char *id; + int len; + + id = loc.filename; + len = strlen(id); + dtdword(&dt, len); + dtabytes(&dt,TYnptr, 0, len + 1, id); + + assertexp_sfilename = symbol_generate(SCstatic,type_fake(TYdarray)); + assertexp_sfilename->Sdt = dt; + assertexp_sfilename->Sfl = FLdata; +#if ELFOBJ + assertexp_sfilename->Sseg = CDATA; +#endif + outdata(assertexp_sfilename); + + assertexp_mn = m; + assertexp_name = id; + } + + efilename = el_var(assertexp_sfilename); + + if (msg) + { elem *emsg = msg->toElem(irs); + ea = el_var(rtlsym[RTLSYM_DASSERT_MSG]); + ea = el_bin(OPcall, TYvoid, ea, el_params(el_long(TYint, loc.linnum), efilename, emsg, NULL)); + } + else + { + ea = el_var(rtlsym[RTLSYM_DASSERT]); + ea = el_bin(OPcall, TYvoid, ea, el_param(el_long(TYint, loc.linnum), efilename)); + } + } + else + { + sassert = m->toModuleAssert(); + ea = el_bin(OPcall,TYvoid,el_var(sassert), + el_long(TYint, loc.linnum)); + } + e = el_bin(OPoror,TYvoid,e,ea); + } + } + else + { // BUG: should replace assert(0); with a HLT instruction + e = el_long(TYint, 0); + } + el_setLoc(e,loc); + return e; +} + +elem *PostExp::toElem(IRState *irs) +{ elem *e; + elem *einc; + + e = e1->toElem(irs); + einc = e2->toElem(irs); + e = el_bin((op == TOKplusplus) ? OPpostinc : OPpostdec, + e->Ety,e,einc); + el_setLoc(e,loc); + return e; +} + +//////////////////////////// Binary /////////////////////////////// + +/******************************************** + */ + +elem *BinExp::toElemBin(IRState *irs,int op) +{ + //printf("toElemBin() '%s'\n", toChars()); + + tym_t tym = type->totym(); + + elem *el = e1->toElem(irs); + elem *er = e2->toElem(irs); + elem *e = el_bin(op,tym,el,er); + el_setLoc(e,loc); + return e; +} + + +/*************************************** + */ + +elem *AddExp::toElem(IRState *irs) +{ elem *e; + Type *tb1 = e1->type->toBasetype(); + Type *tb2 = e2->type->toBasetype(); + + if ((tb1->ty == Tarray || tb1->ty == Tsarray) && + (tb2->ty == Tarray || tb2->ty == Tsarray) + ) + { + error("Array operation %s not implemented", toChars()); + } + else + e = toElemBin(irs,OPadd); + return e; +} + +/*************************************** + */ + +elem *MinExp::toElem(IRState *irs) +{ + return toElemBin(irs,OPmin); +} + +/*************************************** + */ + +elem *CatExp::toElem(IRState *irs) +{ elem *e; + +#if 0 + printf("CatExp::toElem()\n"); + print(); +#endif + + Type *tb1 = e1->type->toBasetype(); + Type *tb2 = e2->type->toBasetype(); + Type *tn; + +#if 0 + if ((tb1->ty == Tarray || tb1->ty == Tsarray) && + (tb2->ty == Tarray || tb2->ty == Tsarray) + ) +#endif + + Type *ta = tb1->nextOf() ? e1->type : e2->type; + tn = tb1->nextOf() ? tb1->nextOf() : tb2->nextOf(); + { + if (e1->op == TOKcat) + { + elem *ep; + CatExp *ce = this; + int n = 2; + + ep = eval_Darray(irs, ce->e2); + do + { + n++; + ce = (CatExp *)ce->e1; + ep = el_param(ep, eval_Darray(irs, ce->e2)); + } while (ce->e1->op == TOKcat); + ep = el_param(ep, eval_Darray(irs, ce->e1)); +#if 1 + ep = el_params( + ep, + el_long(TYint, n), + ta->getTypeInfo(NULL)->toElem(irs), + NULL); + e = el_bin(OPcall, TYdarray, el_var(rtlsym[RTLSYM_ARRAYCATNT]), ep); +#else + ep = el_params( + ep, + el_long(TYint, n), + el_long(TYint, tn->size()), + NULL); + e = el_bin(OPcall, TYdarray, el_var(rtlsym[RTLSYM_ARRAYCATN]), ep); +#endif + } + else + { + elem *e1; + elem *e2; + elem *ep; + + e1 = eval_Darray(irs, this->e1); + e2 = eval_Darray(irs, this->e2); +#if 1 + ep = el_params(e2, e1, ta->getTypeInfo(NULL)->toElem(irs), NULL); + e = el_bin(OPcall, TYdarray, el_var(rtlsym[RTLSYM_ARRAYCATT]), ep); +#else + ep = el_params(el_long(TYint, tn->size()), e2, e1, NULL); + e = el_bin(OPcall, TYdarray, el_var(rtlsym[RTLSYM_ARRAYCAT]), ep); +#endif + } + el_setLoc(e,loc); + } +#if 0 + else if ((tb1->ty == Tarray || tb1->ty == Tsarray) && + e2->type->equals(tb1->next)) + { + error("array cat with element not implemented"); + e = el_long(TYint, 0); + } + else + assert(0); +#endif + return e; +} + +/*************************************** + */ + +elem *MulExp::toElem(IRState *irs) +{ + return toElemBin(irs,OPmul); +} + +/************************************ + */ + +elem *DivExp::toElem(IRState *irs) +{ + return toElemBin(irs,OPdiv); +} + +/*************************************** + */ + +elem *ModExp::toElem(IRState *irs) +{ + elem *e; + elem *e1; + elem *e2; + tym_t tym; + + tym = type->totym(); + + e1 = this->e1->toElem(irs); + e2 = this->e2->toElem(irs); + +#if 0 // Now inlined + if (this->e1->type->isfloating()) + { elem *ep; + + switch (this->e1->type->ty) + { + case Tfloat32: + case Timaginary32: + e1 = el_una(OPf_d, TYdouble, e1); + e2 = el_una(OPf_d, TYdouble, e2); + case Tfloat64: + case Timaginary64: + e1 = el_una(OPd_ld, TYldouble, e1); + e2 = el_una(OPd_ld, TYldouble, e2); + break; + case Tfloat80: + case Timaginary80: + break; + default: + assert(0); + break; + } + ep = el_param(e2,e1); + e = el_bin(OPcall,tym,el_var(rtlsym[RTLSYM_MODULO]),ep); + } + else +#endif + e = el_bin(OPmod,tym,e1,e2); + el_setLoc(e,loc); + return e; +} + +/*************************************** + */ + +elem *CmpExp::toElem(IRState *irs) +{ + elem *e; + enum OPER eop; + Type *t1 = e1->type->toBasetype(); + Type *t2 = e2->type->toBasetype(); + + switch (op) + { + case TOKlt: eop = OPlt; break; + case TOKgt: eop = OPgt; break; + case TOKle: eop = OPle; break; + case TOKge: eop = OPge; break; + case TOKequal: eop = OPeqeq; break; + case TOKnotequal: eop = OPne; break; + + // NCEG floating point compares + case TOKunord: eop = OPunord; break; + case TOKlg: eop = OPlg; break; + case TOKleg: eop = OPleg; break; + case TOKule: eop = OPule; break; + case TOKul: eop = OPul; break; + case TOKuge: eop = OPuge; break; + case TOKug: eop = OPug; break; + case TOKue: eop = OPue; break; + default: + dump(0); + assert(0); + } + if (!t1->isfloating()) + { + // Convert from floating point compare to equivalent + // integral compare + eop = (enum OPER)rel_integral(eop); + } + if ((int)eop > 1 && t1->ty == Tclass && t2->ty == Tclass) + { +#if 1 + assert(0); +#else + elem *ec1; + elem *ec2; + + ec1 = e1->toElem(irs); + ec2 = e2->toElem(irs); + e = el_bin(OPcall,TYint,el_var(rtlsym[RTLSYM_OBJ_CMP]),el_param(ec1, ec2)); + e = el_bin(eop, TYint, e, el_long(TYint, 0)); +#endif + } + else if ((int)eop > 1 && + (t1->ty == Tarray || t1->ty == Tsarray) && + (t2->ty == Tarray || t2->ty == Tsarray)) + { + elem *ea1; + elem *ea2; + elem *ep; + Type *telement = t1->nextOf()->toBasetype(); + int rtlfunc; + + ea1 = e1->toElem(irs); + ea1 = array_toDarray(t1, ea1); + ea2 = e2->toElem(irs); + ea2 = array_toDarray(t2, ea2); + +#if 1 + ep = el_params(telement->arrayOf()->getInternalTypeInfo(NULL)->toElem(irs), + ea2, ea1, NULL); + rtlfunc = RTLSYM_ARRAYCMP2; +#else + ep = el_params(telement->getInternalTypeInfo(NULL)->toElem(irs), ea2, ea1, NULL); + rtlfunc = RTLSYM_ARRAYCMP; +#endif + e = el_bin(OPcall, TYint, el_var(rtlsym[rtlfunc]), ep); + e = el_bin(eop, TYint, e, el_long(TYint, 0)); + el_setLoc(e,loc); + } + else + { + if ((int)eop <= 1) + { + /* The result is determinate, create: + * (e1 , e2) , eop + */ + e = toElemBin(irs,OPcomma); + e = el_bin(OPcomma,e->Ety,e,el_long(e->Ety,(int)eop)); + } + else + e = toElemBin(irs,eop); + } + return e; +} + +elem *EqualExp::toElem(IRState *irs) +{ + //printf("EqualExp::toElem() %s\n", toChars()); + + elem *e; + enum OPER eop; + Type *t1 = e1->type->toBasetype(); + Type *t2 = e2->type->toBasetype(); + + switch (op) + { + case TOKequal: eop = OPeqeq; break; + case TOKnotequal: eop = OPne; break; + default: + dump(0); + assert(0); + } + + //printf("EqualExp::toElem()\n"); + if (t1->ty == Tstruct) + { // Do bit compare of struct's + elem *es1; + elem *es2; + elem *ecount; + + es1 = e1->toElem(irs); + es2 = e2->toElem(irs); +#if 1 + es1 = addressElem(es1, t1); + es2 = addressElem(es2, t2); +#else + es1 = el_una(OPaddr, TYnptr, es1); + es2 = el_una(OPaddr, TYnptr, es2); +#endif + e = el_param(es1, es2); + ecount = el_long(TYint, t1->size()); + e = el_bin(OPmemcmp, TYint, e, ecount); + e = el_bin(eop, TYint, e, el_long(TYint, 0)); + el_setLoc(e,loc); + } +#if 0 + else if (t1->ty == Tclass && t2->ty == Tclass) + { + elem *ec1; + elem *ec2; + + ec1 = e1->toElem(irs); + ec2 = e2->toElem(irs); + e = el_bin(OPcall,TYint,el_var(rtlsym[RTLSYM_OBJ_EQ]),el_param(ec1, ec2)); + } +#endif + else if ((t1->ty == Tarray || t1->ty == Tsarray) && + (t2->ty == Tarray || t2->ty == Tsarray)) + { + elem *ea1; + elem *ea2; + elem *ep; + Type *telement = t1->nextOf()->toBasetype(); + int rtlfunc; + + ea1 = e1->toElem(irs); + ea1 = array_toDarray(t1, ea1); + ea2 = e2->toElem(irs); + ea2 = array_toDarray(t2, ea2); + +#if 1 + ep = el_params(telement->arrayOf()->getInternalTypeInfo(NULL)->toElem(irs), + ea2, ea1, NULL); + rtlfunc = RTLSYM_ARRAYEQ2; +#else + ep = el_params(telement->getInternalTypeInfo(NULL)->toElem(irs), ea2, ea1, NULL); + rtlfunc = RTLSYM_ARRAYEQ; +#endif + e = el_bin(OPcall, TYint, el_var(rtlsym[rtlfunc]), ep); + if (op == TOKnotequal) + e = el_bin(OPxor, TYint, e, el_long(TYint, 1)); + el_setLoc(e,loc); + } + else + e = toElemBin(irs, eop); + return e; +} + +elem *IdentityExp::toElem(IRState *irs) +{ + elem *e; + enum OPER eop; + Type *t1 = e1->type->toBasetype(); + Type *t2 = e2->type->toBasetype(); + + switch (op) + { + case TOKidentity: eop = OPeqeq; break; + case TOKnotidentity: eop = OPne; break; + default: + dump(0); + assert(0); + } + + //printf("IdentityExp::toElem() %s\n", toChars()); + + if (t1->ty == Tstruct) + { // Do bit compare of struct's + elem *es1; + elem *es2; + elem *ecount; + + es1 = e1->toElem(irs); + es1 = addressElem(es1, e1->type); + //es1 = el_una(OPaddr, TYnptr, es1); + es2 = e2->toElem(irs); + es2 = addressElem(es2, e2->type); + //es2 = el_una(OPaddr, TYnptr, es2); + e = el_param(es1, es2); + ecount = el_long(TYint, t1->size()); + e = el_bin(OPmemcmp, TYint, e, ecount); + e = el_bin(eop, TYint, e, el_long(TYint, 0)); + el_setLoc(e,loc); + } + else if ((t1->ty == Tarray || t1->ty == Tsarray) && + (t2->ty == Tarray || t2->ty == Tsarray)) + { + elem *ea1; + elem *ea2; + + ea1 = e1->toElem(irs); + ea1 = array_toDarray(t1, ea1); + ea2 = e2->toElem(irs); + ea2 = array_toDarray(t2, ea2); + + e = el_bin(eop, type->totym(), ea1, ea2); + el_setLoc(e,loc); + } + else + e = toElemBin(irs, eop); + + return e; +} + + +/*************************************** + */ + +elem *InExp::toElem(IRState *irs) +{ elem *e; + elem *key = e1->toElem(irs); + elem *aa = e2->toElem(irs); + elem *ep; + elem *keyti; + TypeAArray *taa = (TypeAArray *)e2->type->toBasetype(); + + + // set to: + // aaIn(aa, keyti, key); + + if (key->Ety == TYstruct) + { + key = el_una(OPstrpar, TYstruct, key); + key->Enumbytes = key->E1->Enumbytes; + assert(key->Enumbytes); + } + + Symbol *s = taa->aaGetSymbol("In", 0); + keyti = taa->index->getInternalTypeInfo(NULL)->toElem(irs); + ep = el_params(key, keyti, aa, NULL); + e = el_bin(OPcall, type->totym(), el_var(s), ep); + + el_setLoc(e,loc); + return e; +} + +/*************************************** + */ + +elem *RemoveExp::toElem(IRState *irs) +{ elem *e; + Type *tb = e1->type->toBasetype(); + assert(tb->ty == Taarray); + TypeAArray *taa = (TypeAArray *)tb; + elem *ea = e1->toElem(irs); + elem *ekey = e2->toElem(irs); + elem *ep; + elem *keyti; + + if (ekey->Ety == TYstruct) + { + ekey = el_una(OPstrpar, TYstruct, ekey); + ekey->Enumbytes = ekey->E1->Enumbytes; + assert(ekey->Enumbytes); + } + + Symbol *s = taa->aaGetSymbol("Del", 0); + keyti = taa->index->getInternalTypeInfo(NULL)->toElem(irs); + ep = el_params(ekey, keyti, ea, NULL); + e = el_bin(OPcall, TYnptr, el_var(s), ep); + + el_setLoc(e,loc); + return e; +} + +/*************************************** + */ + +elem *AssignExp::toElem(IRState *irs) +{ elem *e; + IndexExp *ae; + int r; + Type *t1b; + + //printf("AssignExp::toElem('%s')\n", toChars()); + t1b = e1->type->toBasetype(); + + // Look for array.length = n + if (e1->op == TOKarraylength) + { + // Generate: + // _d_arraysetlength(e2, sizeelem, &ale->e1); + + ArrayLengthExp *ale = (ArrayLengthExp *)e1; + elem *p1; + elem *p2; + elem *p3; + elem *ep; + Type *t1; + + p1 = e2->toElem(irs); + p3 = ale->e1->toElem(irs); + p3 = addressElem(p3, NULL); + t1 = ale->e1->type->toBasetype(); + +#if 1 + // call _d_arraysetlengthT(ti, e2, &ale->e1); + p2 = t1->getTypeInfo(NULL)->toElem(irs); + ep = el_params(p3, p1, p2, NULL); // c function + r = t1->nextOf()->isZeroInit() ? RTLSYM_ARRAYSETLENGTHT : RTLSYM_ARRAYSETLENGTHIT; +#else + if (t1->next->isZeroInit()) + { p2 = t1->getTypeInfo(NULL)->toElem(irs); + ep = el_params(p3, p1, p2, NULL); // c function + r = RTLSYM_ARRAYSETLENGTHT; + } + else + { + p2 = el_long(TYint, t1->next->size()); + ep = el_params(p3, p2, p1, NULL); // c function + Expression *init = t1->next->defaultInit(); + ep = el_param(el_long(TYint, init->type->size()), ep); + elem *ei = init->toElem(irs); + ep = el_param(ei, ep); + r = RTLSYM_ARRAYSETLENGTH3; + } +#endif + + e = el_bin(OPcall, type->totym(), el_var(rtlsym[r]), ep); + el_setLoc(e, loc); + return e; + } + + // Look for array[]=n + if (e1->op == TOKslice) + { + SliceExp *are = (SliceExp *)(e1); + Type *t1 = t1b; + Type *t2 = e2->type->toBasetype(); + + // which we do if the 'next' types match + if (ismemset) + { // Do a memset for array[]=v + //printf("Lpair %s\n", toChars()); + SliceExp *are = (SliceExp *)e1; + elem *elwr; + elem *eupr; + elem *n1; + elem *evalue; + elem *enbytes; + elem *elength; + elem *einit; + integer_t value; + Type *ta = are->e1->type->toBasetype(); + Type *tb = ta->nextOf()->toBasetype(); + int sz = tb->size(); + tym_t tym = type->totym(); + + n1 = are->e1->toElem(irs); + elwr = are->lwr ? are->lwr->toElem(irs) : NULL; + eupr = are->upr ? are->upr->toElem(irs) : NULL; + + elem *n1x = n1; + + // Look for array[]=n + if (ta->ty == Tsarray) + { + TypeSArray *ts; + + ts = (TypeSArray *) ta; + n1 = array_toPtr(ta, n1); + enbytes = ts->dim->toElem(irs); + n1x = n1; + n1 = el_same(&n1x); + einit = resolveLengthVar(are->lengthVar, &n1, ta); + } + else if (ta->ty == Tarray) + { + n1 = el_same(&n1x); + einit = resolveLengthVar(are->lengthVar, &n1, ta); + enbytes = el_copytree(n1); + n1 = array_toPtr(ta, n1); + enbytes = el_una(OP64_32, TYint, enbytes); + } + else if (ta->ty == Tpointer) + { + n1 = el_same(&n1x); + enbytes = el_long(TYint, -1); // largest possible index + einit = NULL; + } + + // Enforce order of evaluation of n1[elwr..eupr] as n1,elwr,eupr + elem *elwrx = elwr; + if (elwr) elwr = el_same(&elwrx); + elem *euprx = eupr; + if (eupr) eupr = el_same(&euprx); + +#if 0 + printf("sz = %d\n", sz); + printf("n1x\n"); + elem_print(n1x); + printf("einit\n"); + elem_print(einit); + printf("elwrx\n"); + elem_print(elwrx); + printf("euprx\n"); + elem_print(euprx); + printf("n1\n"); + elem_print(n1); + printf("elwr\n"); + elem_print(elwr); + printf("eupr\n"); + elem_print(eupr); + printf("enbytes\n"); + elem_print(enbytes); +#endif + einit = el_combine(n1x, einit); + einit = el_combine(einit, elwrx); + einit = el_combine(einit, euprx); + + evalue = this->e2->toElem(irs); + +#if 0 + printf("n1\n"); + elem_print(n1); + printf("enbytes\n"); + elem_print(enbytes); +#endif + + if (global.params.useArrayBounds && eupr && ta->ty != Tpointer) + { + elem *c1; + elem *c2; + elem *ea; + elem *eb; + elem *enbytesx; + + assert(elwr); + enbytesx = enbytes; + enbytes = el_same(&enbytesx); + c1 = el_bin(OPle, TYint, el_copytree(eupr), enbytesx); + c2 = el_bin(OPle, TYint, el_copytree(elwr), el_copytree(eupr)); + c1 = el_bin(OPandand, TYint, c1, c2); + + // Construct: (c1 || ModuleArray(line)) + Symbol *sassert; + + sassert = irs->blx->module->toModuleArray(); + ea = el_bin(OPcall,TYvoid,el_var(sassert), el_long(TYint, loc.linnum)); + eb = el_bin(OPoror,TYvoid,c1,ea); + einit = el_combine(einit, eb); + } + + if (elwr) + { elem *elwr2; + + el_free(enbytes); + elwr2 = el_copytree(elwr); + elwr2 = el_bin(OPmul, TYint, elwr2, el_long(TYint, sz)); + n1 = el_bin(OPadd, TYnptr, n1, elwr2); + enbytes = el_bin(OPmin, TYint, eupr, elwr); + elength = el_copytree(enbytes); + } + else + elength = el_copytree(enbytes); + e = setArray(n1, enbytes, tb, evalue, irs, op); + Lpair: + e = el_pair(TYullong, elength, e); + Lret2: + e = el_combine(einit, e); + //elem_print(e); + goto Lret; + } +#if 0 + else if (e2->op == TOKadd || e2->op == TOKmin) + { + /* It's ea[] = eb[] +- ec[] + */ + BinExp *e2a = (BinExp *)e2; + Type *t = e2->type->toBasetype()->nextOf()->toBasetype(); + if (t->ty != Tfloat32 && t->ty != Tfloat64 && t->ty != Tfloat80) + { + e2->error("array add/min for %s not supported", t->toChars()); + return el_long(TYint, 0); + } + elem *ea = e1->toElem(irs); + ea = array_toDarray(e1->type, ea); + elem *eb = e2a->e1->toElem(irs); + eb = array_toDarray(e2a->e1->type, eb); + elem *ec = e2a->e2->toElem(irs); + ec = array_toDarray(e2a->e2->type, ec); + + int rtl = RTLSYM_ARRAYASSADDFLOAT; + if (t->ty == Tfloat64) + rtl = RTLSYM_ARRAYASSADDDOUBLE; + else if (t->ty == Tfloat80) + rtl = RTLSYM_ARRAYASSADDREAL; + if (e2->op == TOKmin) + { + rtl = RTLSYM_ARRAYASSMINFLOAT; + if (t->ty == Tfloat64) + rtl = RTLSYM_ARRAYASSMINDOUBLE; + else if (t->ty == Tfloat80) + rtl = RTLSYM_ARRAYASSMINREAL; + } + + /* Set parameters so the order of evaluation is eb, ec, ea + */ + elem *ep = el_params(eb, ec, ea, NULL); + e = el_bin(OPcall, type->totym(), el_var(rtlsym[rtl]), ep); + goto Lret; + } +#endif + else + { + /* It's array1[]=array2[] + * which is a memcpy + */ + elem *eto; + elem *efrom; + elem *esize; + elem *ep; + + eto = e1->toElem(irs); + efrom = e2->toElem(irs); + + unsigned size = t1->nextOf()->size(); + esize = el_long(TYint, size); + + /* Determine if we need to do postblit + */ + int postblit = 0; + Type *t = t1; + do + t = t->nextOf()->toBasetype(); + while (t->ty == Tsarray); + if (t->ty == Tstruct) + { StructDeclaration *sd = ((TypeStruct *)t)->sym; + if (sd->postblit) + postblit = 1; + } + + assert(e2->type->ty != Tpointer); + + if (!postblit && !global.params.useArrayBounds) + { elem *epto; + elem *epfr; + elem *elen; + elem *ex; + + ex = el_same(&eto); + + // Determine if elen is a constant + if (eto->Eoper == OPpair && + eto->E1->Eoper == OPconst) + { + elen = el_copytree(eto->E1); + } + else + { + // It's not a constant, so pull it from the dynamic array + elen = el_una(OP64_32, TYint, el_copytree(ex)); + } + + esize = el_bin(OPmul, TYint, elen, esize); + epto = array_toPtr(e1->type, ex); + epfr = array_toPtr(e2->type, efrom); + e = el_bin(OPmemcpy, TYnptr, epto, el_param(epfr, esize)); + e = el_pair(eto->Ety, el_copytree(elen), e); + e = el_combine(eto, e); + } +#if DMDV2 + else if (postblit && op != TOKblit) + { + /* Generate: + * _d_arrayassign(ti, efrom, eto) + * or: + * _d_arrayctor(ti, efrom, eto) + */ + el_free(esize); + Expression *ti = t1->nextOf()->toBasetype()->getTypeInfo(NULL); + ep = el_params(eto, efrom, ti->toElem(irs), NULL); + int rtl = (op == TOKconstruct) ? RTLSYM_ARRAYCTOR : RTLSYM_ARRAYASSIGN; + e = el_bin(OPcall, type->totym(), el_var(rtlsym[rtl]), ep); + } +#endif + else + { + // Generate: + // _d_arraycopy(eto, efrom, esize) + + ep = el_params(eto, efrom, esize, NULL); + e = el_bin(OPcall, type->totym(), el_var(rtlsym[RTLSYM_ARRAYCOPY]), ep); + } + el_setLoc(e, loc); + return e; + } + } + + if (e1->op == TOKindex) + { + elem *eb; + elem *ei; + elem *ev; + TY ty; + Type *ta; + + ae = (IndexExp *)(e1); + ta = ae->e1->type->toBasetype(); + ty = ta->ty; + } +#if 1 + /* This will work if we can distinguish an assignment from + * an initialization of the lvalue. It'll work if the latter. + * If the former, because of aliasing of the return value with + * function arguments, it'll fail. + */ + if (op == TOKconstruct && e2->op == TOKcall) + { CallExp *ce = (CallExp *)e2; + + TypeFunction *tf = (TypeFunction *)ce->e1->type->toBasetype(); + if (tf->ty == Tfunction && tf->retStyle() == RETstack) + { + elem *ehidden = e1->toElem(irs); + ehidden = el_una(OPaddr, TYnptr, ehidden); + assert(!irs->ehidden); + irs->ehidden = ehidden; + e = e2->toElem(irs); + goto Lret; + } + } +#endif + if (t1b->ty == Tstruct) + { + if (e2->op == TOKint64) + { /* Implement: + * (struct = 0) + * with: + * memset(&struct, 0, struct.sizeof) + */ + elem *el = e1->toElem(irs); + elem *enbytes = el_long(TYint, e1->type->size()); + elem *evalue = el_long(TYint, 0); + + el = el_una(OPaddr, TYnptr, el); + e = el_param(enbytes, evalue); + e = el_bin(OPmemset,TYnptr,el,e); + el_setLoc(e, loc); + //e = el_una(OPind, TYstruct, e); + } + else + { + elem *e1; + elem *e2; + tym_t tym; + + //printf("toElemBin() '%s'\n", toChars()); + + tym = type->totym(); + + e1 = this->e1->toElem(irs); + elem *ex = e1; + if (e1->Eoper == OPind) + ex = e1->E1; + if (this->e2->op == TOKstructliteral && + ex->Eoper == OPvar && ex->EV.sp.Voffset == 0) + { StructLiteralExp *se = (StructLiteralExp *)this->e2; + + Symbol *symSave = se->sym; + size_t soffsetSave = se->soffset; + int fillHolesSave = se->fillHoles; + + se->sym = ex->EV.sp.Vsym; + se->soffset = 0; + se->fillHoles = (op == TOKconstruct || op == TOKblit) ? 1 : 0; + + el_free(e1); + e = this->e2->toElem(irs); + + se->sym = symSave; + se->soffset = soffsetSave; + se->fillHoles = fillHolesSave; + } + else + { + e2 = this->e2->toElem(irs); + e = el_bin(OPstreq,tym,e1,e2); + e->Enumbytes = this->e1->type->size(); + } + goto Lret; + } + } + else + e = toElemBin(irs,OPeq); + return e; + + Lret: + el_setLoc(e,loc); + return e; +} + +/*************************************** + */ + +elem *AddAssignExp::toElem(IRState *irs) +{ + //printf("AddAssignExp::toElem() %s\n", toChars()); + elem *e; + Type *tb1 = e1->type->toBasetype(); + Type *tb2 = e2->type->toBasetype(); + + if ((tb1->ty == Tarray || tb1->ty == Tsarray) && + (tb2->ty == Tarray || tb2->ty == Tsarray) + ) + { + error("Array operations not implemented"); + } + else + e = toElemBin(irs,OPaddass); + return e; +} + + +/*************************************** + */ + +elem *MinAssignExp::toElem(IRState *irs) +{ + return toElemBin(irs,OPminass); +} + +/*************************************** + */ + +elem *CatAssignExp::toElem(IRState *irs) +{ + //printf("CatAssignExp::toElem('%s')\n", toChars()); + elem *e; + Type *tb1 = e1->type->toBasetype(); + Type *tb2 = e2->type->toBasetype(); + + if (tb1->ty == Tarray || tb2->ty == Tsarray) + { elem *e1; + elem *e2; + elem *ep; + + e1 = this->e1->toElem(irs); + e1 = el_una(OPaddr, TYnptr, e1); + + e2 = this->e2->toElem(irs); + if (e2->Ety == TYstruct) + { + e2 = el_una(OPstrpar, TYstruct, e2); + e2->Enumbytes = e2->E1->Enumbytes; + assert(e2->Enumbytes); + } + + Type *tb1n = tb1->nextOf()->toBasetype(); + if ((tb2->ty == Tarray || tb2->ty == Tsarray) && + tb1n->equals(tb2->nextOf()->toBasetype())) + { // Append array +#if 1 + ep = el_params(e2, e1, this->e1->type->getTypeInfo(NULL)->toElem(irs), NULL); + e = el_bin(OPcall, TYdarray, el_var(rtlsym[RTLSYM_ARRAYAPPENDT]), ep); +#else + ep = el_params(el_long(TYint, tb1n->size()), e2, e1, NULL); + e = el_bin(OPcall, TYdarray, el_var(rtlsym[RTLSYM_ARRAYAPPEND]), ep); +#endif + } + else + { // Append element +#if 1 + ep = el_params(e2, e1, this->e1->type->getTypeInfo(NULL)->toElem(irs), NULL); + e = el_bin(OPcall, TYdarray, el_var(rtlsym[RTLSYM_ARRAYAPPENDCT]), ep); +#else + ep = el_params(e2, el_long(TYint, tb1n->size()), e1, NULL); + e = el_bin(OPcall, TYdarray, el_var(rtlsym[RTLSYM_ARRAYAPPENDC]), ep); +#endif + } + el_setLoc(e,loc); + } + else + assert(0); + return e; +} + + +/*************************************** + */ + +elem *DivAssignExp::toElem(IRState *irs) +{ + return toElemBin(irs,OPdivass); +} + + +/*************************************** + */ + +elem *ModAssignExp::toElem(IRState *irs) +{ + return toElemBin(irs,OPmodass); +} + + +/*************************************** + */ + +elem *MulAssignExp::toElem(IRState *irs) +{ + return toElemBin(irs,OPmulass); +} + + +/*************************************** + */ + +elem *ShlAssignExp::toElem(IRState *irs) +{ elem *e; + + e = toElemBin(irs,OPshlass); + return e; +} + + +/*************************************** + */ + +elem *ShrAssignExp::toElem(IRState *irs) +{ + return toElemBin(irs,OPshrass); +} + + +/*************************************** + */ + +elem *UshrAssignExp::toElem(IRState *irs) +{ + elem *eleft = e1->toElem(irs); + eleft->Ety = touns(eleft->Ety); + elem *eright = e2->toElem(irs); + elem *e = el_bin(OPshrass, type->totym(), eleft, eright); + el_setLoc(e, loc); + return e; +} + + +/*************************************** + */ + +elem *AndAssignExp::toElem(IRState *irs) +{ + return toElemBin(irs,OPandass); +} + + +/*************************************** + */ + +elem *OrAssignExp::toElem(IRState *irs) +{ + return toElemBin(irs,OPorass); +} + + +/*************************************** + */ + +elem *XorAssignExp::toElem(IRState *irs) +{ + return toElemBin(irs,OPxorass); +} + + +/*************************************** + */ + +elem *AndAndExp::toElem(IRState *irs) +{ + elem *e = toElemBin(irs,OPandand); + if (global.params.cov && e2->loc.linnum) + e->E2 = el_combine(incUsageElem(irs, e2->loc), e->E2); + return e; +} + + +/*************************************** + */ + +elem *OrOrExp::toElem(IRState *irs) +{ + elem *e = toElemBin(irs,OPoror); + if (global.params.cov && e2->loc.linnum) + e->E2 = el_combine(incUsageElem(irs, e2->loc), e->E2); + return e; +} + + +/*************************************** + */ + +elem *XorExp::toElem(IRState *irs) +{ + return toElemBin(irs,OPxor); +} + + +/*************************************** + */ + +elem *AndExp::toElem(IRState *irs) +{ + return toElemBin(irs,OPand); +} + + +/*************************************** + */ + +elem *OrExp::toElem(IRState *irs) +{ + return toElemBin(irs,OPor); +} + + +/*************************************** + */ + +elem *ShlExp::toElem(IRState *irs) +{ + return toElemBin(irs, OPshl); +} + + +/*************************************** + */ + +elem *ShrExp::toElem(IRState *irs) +{ + return toElemBin(irs,OPshr); +} + + +/*************************************** + */ + +elem *UshrExp::toElem(IRState *irs) +{ + elem *eleft = e1->toElem(irs); + eleft->Ety = touns(eleft->Ety); + elem *eright = e2->toElem(irs); + elem *e = el_bin(OPshr, type->totym(), eleft, eright); + el_setLoc(e, loc); + return e; +} + +/**************************************** + */ + +elem *CommaExp::toElem(IRState *irs) +{ + assert(e1 && e2); + elem *eleft = e1->toElem(irs); + elem *eright = e2->toElem(irs); + elem *e = el_combine(eleft, eright); + if (e) + el_setLoc(e, loc); + return e; +} + + +/*************************************** + */ + +elem *CondExp::toElem(IRState *irs) +{ elem *eleft; + elem *eright; + + elem *ec = econd->toElem(irs); + + eleft = e1->toElem(irs); + tym_t ty = eleft->Ety; + if (global.params.cov && e1->loc.linnum) + eleft = el_combine(incUsageElem(irs, e1->loc), eleft); + + eright = e2->toElem(irs); + if (global.params.cov && e2->loc.linnum) + eright = el_combine(incUsageElem(irs, e2->loc), eright); + + elem *e = el_bin(OPcond, ty, ec, el_bin(OPcolon, ty, eleft, eright)); + if (tybasic(ty) == TYstruct) + e->Enumbytes = e1->type->size(); + el_setLoc(e, loc); + return e; +} + + +/*************************************** + */ + +elem *TypeDotIdExp::toElem(IRState *irs) +{ + print(); + assert(0); + return NULL; +} + +elem *TypeExp::toElem(IRState *irs) +{ +#ifdef DEBUG + printf("TypeExp::toElem()\n"); +#endif + error("type %s is not an expression", toChars()); + return el_long(TYint, 0); +} + +elem *ScopeExp::toElem(IRState *irs) +{ + error("%s is not an expression", sds->toChars()); + return el_long(TYint, 0); +} + +elem *DotVarExp::toElem(IRState *irs) +{ + // *(&e + offset) + + //printf("DotVarExp::toElem('%s')\n", toChars()); + + VarDeclaration *v = var->isVarDeclaration(); + if (!v) + { + error("%s is not a field", var->toChars()); + } + + elem *e = e1->toElem(irs); + Type *tb1 = e1->type->toBasetype(); + if (tb1->ty != Tclass && tb1->ty != Tpointer) + e = el_una(OPaddr, TYnptr, e); + e = el_bin(OPadd, TYnptr, e, el_long(TYint, v ? v->offset : 0)); + e = el_una(OPind, type->totym(), e); + if (tybasic(e->Ety) == TYstruct) + { + e->Enumbytes = type->size(); + } + el_setLoc(e,loc); + return e; +} + +elem *DelegateExp::toElem(IRState *irs) +{ + elem *e; + elem *ethis; + elem *ep; + Symbol *sfunc; + int directcall = 0; + + //printf("DelegateExp::toElem() '%s'\n", toChars()); + sfunc = func->toSymbol(); + if (func->isNested()) + { + ep = el_ptr(sfunc); + ethis = getEthis(loc, irs, func); + } + else + { + ethis = e1->toElem(irs); + if (e1->type->ty != Tclass && e1->type->ty != Tpointer) + ethis = el_una(OPaddr, TYnptr, ethis); + + if (e1->op == TOKsuper) + directcall = 1; + + if (!func->isThis()) + error("delegates are only for non-static functions"); + + if (!func->isVirtual() || + directcall || + func->isFinal()) + { + ep = el_ptr(sfunc); + } + else + { + // Get pointer to function out of virtual table + unsigned vindex; + + assert(ethis); + ep = el_same(ðis); + ep = el_una(OPind, TYnptr, ep); + vindex = func->vtblIndex; + + // Build *(ep + vindex * 4) + ep = el_bin(OPadd,TYnptr,ep,el_long(TYint, vindex * 4)); + ep = el_una(OPind,TYnptr,ep); + } + +// if (func->tintro) +// func->error(loc, "cannot form delegate due to covariant return type"); + } + if (ethis->Eoper == OPcomma) + { + ethis->E2 = el_pair(TYullong, ethis->E2, ep); + ethis->Ety = TYullong; + e = ethis; + } + else + e = el_pair(TYullong, ethis, ep); + el_setLoc(e,loc); + return e; +} + +elem *DotTypeExp::toElem(IRState *irs) +{ + // Just a pass-thru to e1 + elem *e; + + //printf("DotTypeExp::toElem() %s\n", toChars()); + e = e1->toElem(irs); + el_setLoc(e,loc); + return e; +} + +elem *CallExp::toElem(IRState *irs) +{ + //printf("CallExp::toElem('%s')\n", toChars()); + assert(e1->type); + elem *ec; + int directcall; + FuncDeclaration *fd; + Type *t1 = e1->type->toBasetype(); + Type *ectype = t1; + + elem *ehidden = irs->ehidden; + irs->ehidden = NULL; + + directcall = 0; + fd = NULL; + if (e1->op == TOKdotvar && t1->ty != Tdelegate) + { DotVarExp *dve = (DotVarExp *)e1; + + fd = dve->var->isFuncDeclaration(); + Expression *ex = dve->e1; + while (1) + { + switch (ex->op) + { + case TOKsuper: // super.member() calls directly + case TOKdottype: // type.member() calls directly + directcall = 1; + break; + + case TOKcast: + ex = ((CastExp *)ex)->e1; + continue; + + default: + //ex->dump(0); + break; + } + break; + } + ec = dve->e1->toElem(irs); + ectype = dve->e1->type->toBasetype(); + } + else if (e1->op == TOKvar) + { + fd = ((VarExp *)e1)->var->isFuncDeclaration(); + + if (fd && fd->ident == Id::alloca && + !fd->fbody && fd->linkage == LINKc && + arguments && arguments->dim == 1) + { Expression *arg = (Expression *)arguments->data[0]; + arg = arg->optimize(WANTvalue); + if (arg->isConst() && arg->type->isintegral()) + { integer_t sz = arg->toInteger(); + if (sz > 0 && sz < 0x40000) + { + // It's an alloca(sz) of a fixed amount. + // Replace with an array allocated on the stack + // of the same size: char[sz] tmp; + + Symbol *stmp; + ::type *t; + + assert(!ehidden); + t = type_allocn(TYarray, tschar); + t->Tdim = sz; + stmp = symbol_genauto(t); + ec = el_ptr(stmp); + el_setLoc(ec,loc); + return ec; + } + } + } + + ec = e1->toElem(irs); + } + else + { + ec = e1->toElem(irs); + } + ec = callfunc(loc, irs, directcall, type, ec, ectype, fd, t1, ehidden, arguments); + el_setLoc(ec,loc); + return ec; +} + +elem *AddrExp::toElem(IRState *irs) +{ elem *e; + elem **pe; + + //printf("AddrExp::toElem('%s')\n", toChars()); + + e = e1->toElem(irs); + e = addressElem(e, e1->type); +L2: + e->Ety = type->totym(); + el_setLoc(e,loc); + return e; +} + +elem *PtrExp::toElem(IRState *irs) +{ elem *e; + + //printf("PtrExp::toElem() %s\n", toChars()); + e = e1->toElem(irs); + e = el_una(OPind,type->totym(),e); + if (tybasic(e->Ety) == TYstruct) + { + e->Enumbytes = type->size(); + } + el_setLoc(e,loc); + return e; +} + +elem *BoolExp::toElem(IRState *irs) +{ elem *e1; + + e1 = this->e1->toElem(irs); + return el_una(OPbool,type->totym(),e1); +} + +elem *DeleteExp::toElem(IRState *irs) +{ elem *e; + int rtl; + Type *tb; + + //printf("DeleteExp::toElem()\n"); + if (e1->op == TOKindex) + { + IndexExp *ae = (IndexExp *)(e1); + tb = ae->e1->type->toBasetype(); + if (tb->ty == Taarray) + { + TypeAArray *taa = (TypeAArray *)tb; + elem *ea = ae->e1->toElem(irs); + elem *ekey = ae->e2->toElem(irs); + elem *ep; + elem *keyti; + + if (ekey->Ety == TYstruct) + { + ekey = el_una(OPstrpar, TYstruct, ekey); + ekey->Enumbytes = ekey->E1->Enumbytes; + assert(ekey->Enumbytes); + } + + Symbol *s = taa->aaGetSymbol("Del", 0); + keyti = taa->index->getInternalTypeInfo(NULL)->toElem(irs); + ep = el_params(ekey, keyti, ea, NULL); + e = el_bin(OPcall, TYnptr, el_var(s), ep); + goto Lret; + } + } + //e1->type->print(); + e = e1->toElem(irs); + tb = e1->type->toBasetype(); + switch (tb->ty) + { + case Tarray: + { e = addressElem(e, e1->type); + rtl = RTLSYM_DELARRAYT; + + /* See if we need to run destructors on the array contents + */ + elem *et = NULL; + Type *tv = tb->nextOf()->toBasetype(); + while (tv->ty == Tsarray) + { TypeSArray *ta = (TypeSArray *)tv; + tv = tv->nextOf()->toBasetype(); + } + if (tv->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (sd->dtor) + et = tb->nextOf()->getTypeInfo(NULL)->toElem(irs); + } + if (!et) // if no destructors needed + et = el_long(TYnptr, 0); // pass null for TypeInfo + e = el_params(et, e, NULL); + // call _d_delarray_t(e, et); + e = el_bin(OPcall, TYvoid, el_var(rtlsym[rtl]), e); + goto Lret; + } + case Tclass: + if (e1->op == TOKvar) + { VarExp *ve = (VarExp *)e1; + if (ve->var->isVarDeclaration() && + ve->var->isVarDeclaration()->onstack) + { + rtl = RTLSYM_CALLFINALIZER; + if (tb->isClassHandle()->isInterfaceDeclaration()) + rtl = RTLSYM_CALLINTERFACEFINALIZER; + break; + } + } + e = addressElem(e, e1->type); + rtl = RTLSYM_DELCLASS; + if (tb->isClassHandle()->isInterfaceDeclaration()) + rtl = RTLSYM_DELINTERFACE; + break; + + case Tpointer: + e = addressElem(e, e1->type); + rtl = RTLSYM_DELMEMORY; + break; + + default: + assert(0); + break; + } + e = el_bin(OPcall, TYvoid, el_var(rtlsym[rtl]), e); + + Lret: + el_setLoc(e,loc); + return e; +} + +elem *CastExp::toElem(IRState *irs) +{ elem *e; + TY fty; + TY tty; + tym_t ftym; + tym_t ttym; + enum OPER eop; + Type *t; + Type *tfrom; + +#if 0 + printf("CastExp::toElem()\n"); + print(); + printf("\tfrom: %s\n", e1->type->toChars()); + printf("\tto : %s\n", to->toChars()); +#endif + + e = e1->toElem(irs); + tfrom = e1->type->toBasetype(); + t = to->toBasetype(); // skip over typedef's + if (t->equals(tfrom)) + goto Lret; + + fty = tfrom->ty; + //printf("fty = %d\n", fty); + tty = t->ty; + + if (tty == Tpointer && fty == Tarray +#if 0 + && (t->next->ty == Tvoid || t->next->equals(e1->type->next)) +#endif + ) + { + if (e->Eoper == OPvar) + { + // e1 -> *(&e1 + 4) + e = el_una(OPaddr, TYnptr, e); + e = el_bin(OPadd, TYnptr, e, el_long(TYint, 4)); + e = el_una(OPind,t->totym(),e); + } + else + { + // e1 -> (unsigned)(e1 >> 32) + e = el_bin(OPshr, TYullong, e, el_long(TYint, 32)); + e = el_una(OP64_32, t->totym(), e); + } + goto Lret; + } + + if (tty == Tpointer && fty == Tsarray +#if 0 + && (t->next->ty == Tvoid || t->next->equals(e1->type->next)) +#endif + ) + { + // e1 -> &e1 + e = el_una(OPaddr, TYnptr, e); + goto Lret; + } + + // Convert from static array to dynamic array + if (tty == Tarray && fty == Tsarray) + { + e = sarray_toDarray(loc, tfrom, t, e); + goto Lret; + } + + // Convert from dynamic array to dynamic array + if (tty == Tarray && fty == Tarray) + { + unsigned fsize = tfrom->nextOf()->size(); + unsigned tsize = t->nextOf()->size(); + + if (fsize != tsize) + { + elem *ep; + + ep = el_params(e, el_long(TYint, fsize), el_long(TYint, tsize), NULL); + e = el_bin(OPcall, type->totym(), el_var(rtlsym[RTLSYM_ARRAYCAST]), ep); + } + goto Lret; + } + + // Casting from base class to derived class requires a runtime check + if (fty == Tclass && tty == Tclass) + { + // Casting from derived class to base class is a no-op + ClassDeclaration *cdfrom; + ClassDeclaration *cdto; + int offset; + int rtl = RTLSYM_DYNAMIC_CAST; + + cdfrom = e1->type->isClassHandle(); + cdto = t->isClassHandle(); + if (cdfrom->isInterfaceDeclaration()) + { + rtl = RTLSYM_INTERFACE_CAST; + if (cdfrom->isCPPinterface()) + { + if (cdto->isCPPinterface()) + { + /* Casting from a C++ interface to a C++ interface + * is always a 'paint' operation + */ + goto Lret; // no-op + } + + /* Casting from a C++ interface to a class + * always results in null because there is no runtime + * information available to do it. + * + * Casting from a C++ interface to a non-C++ interface + * always results in null because there's no way one + * can be derived from the other. + */ + e = el_bin(OPcomma, TYnptr, e, el_long(TYnptr, 0)); + goto Lret; + } + } + if (cdto->isBaseOf(cdfrom, &offset) && offset != OFFSET_RUNTIME) + { + /* The offset from cdfrom=>cdto is known at compile time. + */ + + //printf("offset = %d\n", offset); + if (offset) + { /* Rewrite cast as (e ? e + offset : null) + */ + elem *etmp; + elem *ex; + + if (e1->op == TOKthis) + { // Assume 'this' is never null, so skip null check + e = el_bin(OPadd, TYnptr, e, el_long(TYint, offset)); + } + else + { + etmp = el_same(&e); + ex = el_bin(OPadd, TYnptr, etmp, el_long(TYint, offset)); + ex = el_bin(OPcolon, TYnptr, ex, el_long(TYnptr, 0)); + e = el_bin(OPcond, TYnptr, e, ex); + } + } + goto Lret; // no-op + } + + /* The offset from cdfrom=>cdto can only be determined at runtime. + */ + elem *ep; + + ep = el_param(el_ptr(cdto->toSymbol()), e); + e = el_bin(OPcall, TYnptr, el_var(rtlsym[rtl]), ep); + goto Lret; + } + + ftym = e->Ety; + ttym = t->totym(); + if (ftym == ttym) + goto Lret; + + switch (tty) + { + case Tpointer: + if (fty == Tdelegate) + goto Lpaint; + tty = Tuns32; + break; + + case Tchar: tty = Tuns8; break; + case Twchar: tty = Tuns16; break; + case Tdchar: tty = Tuns32; break; + case Tvoid: goto Lpaint; + + case Tbool: + { + // Construct e?true:false + elem *eq; + + e = el_una(OPbool, ttym, e); + goto Lret; + } + } + + switch (fty) + { + case Tpointer: fty = Tuns32; break; + case Tchar: fty = Tuns8; break; + case Twchar: fty = Tuns16; break; + case Tdchar: fty = Tuns32; break; + } + + #define X(fty, tty) ((fty) * TMAX + (tty)) +Lagain: + switch (X(fty,tty)) + { +#if 0 + case X(Tbit,Tint8): + case X(Tbit,Tuns8): + goto Lpaint; + case X(Tbit,Tint16): + case X(Tbit,Tuns16): + case X(Tbit,Tint32): + case X(Tbit,Tuns32): eop = OPu8_16; goto Leop; + case X(Tbit,Tint64): + case X(Tbit,Tuns64): + case X(Tbit,Tfloat32): + case X(Tbit,Tfloat64): + case X(Tbit,Tfloat80): + case X(Tbit,Tcomplex32): + case X(Tbit,Tcomplex64): + case X(Tbit,Tcomplex80): + e = el_una(OPu8_16, TYuint, e); + fty = Tuns32; + goto Lagain; + case X(Tbit,Timaginary32): + case X(Tbit,Timaginary64): + case X(Tbit,Timaginary80): goto Lzero; +#endif + /* ============================= */ + + case X(Tbool,Tint8): + case X(Tbool,Tuns8): + goto Lpaint; + case X(Tbool,Tint16): + case X(Tbool,Tuns16): + case X(Tbool,Tint32): + case X(Tbool,Tuns32): eop = OPu8_16; goto Leop; + case X(Tbool,Tint64): + case X(Tbool,Tuns64): + case X(Tbool,Tfloat32): + case X(Tbool,Tfloat64): + case X(Tbool,Tfloat80): + case X(Tbool,Tcomplex32): + case X(Tbool,Tcomplex64): + case X(Tbool,Tcomplex80): + e = el_una(OPu8_16, TYuint, e); + fty = Tuns32; + goto Lagain; + case X(Tbool,Timaginary32): + case X(Tbool,Timaginary64): + case X(Tbool,Timaginary80): goto Lzero; + + /* ============================= */ + + case X(Tint8,Tuns8): goto Lpaint; + case X(Tint8,Tint16): + case X(Tint8,Tuns16): + case X(Tint8,Tint32): + case X(Tint8,Tuns32): eop = OPs8_16; goto Leop; + case X(Tint8,Tint64): + case X(Tint8,Tuns64): + case X(Tint8,Tfloat32): + case X(Tint8,Tfloat64): + case X(Tint8,Tfloat80): + case X(Tint8,Tcomplex32): + case X(Tint8,Tcomplex64): + case X(Tint8,Tcomplex80): + e = el_una(OPs8_16, TYint, e); + fty = Tint32; + goto Lagain; + case X(Tint8,Timaginary32): + case X(Tint8,Timaginary64): + case X(Tint8,Timaginary80): goto Lzero; + + /* ============================= */ + + case X(Tuns8,Tint8): goto Lpaint; + case X(Tuns8,Tint16): + case X(Tuns8,Tuns16): + case X(Tuns8,Tint32): + case X(Tuns8,Tuns32): eop = OPu8_16; goto Leop; + case X(Tuns8,Tint64): + case X(Tuns8,Tuns64): + case X(Tuns8,Tfloat32): + case X(Tuns8,Tfloat64): + case X(Tuns8,Tfloat80): + case X(Tuns8,Tcomplex32): + case X(Tuns8,Tcomplex64): + case X(Tuns8,Tcomplex80): + e = el_una(OPu8_16, TYuint, e); + fty = Tuns32; + goto Lagain; + case X(Tuns8,Timaginary32): + case X(Tuns8,Timaginary64): + case X(Tuns8,Timaginary80): goto Lzero; + + /* ============================= */ + + case X(Tint16,Tint8): + case X(Tint16,Tuns8): eop = OP16_8; goto Leop; + case X(Tint16,Tuns16): goto Lpaint; + case X(Tint16,Tint32): + case X(Tint16,Tuns32): eop = OPs16_32; goto Leop; + case X(Tint16,Tint64): + case X(Tint16,Tuns64): e = el_una(OPs16_32, TYint, e); + fty = Tint32; + goto Lagain; + case X(Tint16,Tfloat32): + case X(Tint16,Tfloat64): + case X(Tint16,Tfloat80): + case X(Tint16,Tcomplex32): + case X(Tint16,Tcomplex64): + case X(Tint16,Tcomplex80): + e = el_una(OPs16_d, TYdouble, e); + fty = Tfloat64; + goto Lagain; + case X(Tint16,Timaginary32): + case X(Tint16,Timaginary64): + case X(Tint16,Timaginary80): goto Lzero; + + /* ============================= */ + + case X(Tuns16,Tint8): + case X(Tuns16,Tuns8): eop = OP16_8; goto Leop; + case X(Tuns16,Tint16): goto Lpaint; + case X(Tuns16,Tint32): + case X(Tuns16,Tuns32): eop = OPu16_32; goto Leop; + case X(Tuns16,Tint64): + case X(Tuns16,Tuns64): + case X(Tuns16,Tfloat64): + case X(Tuns16,Tfloat32): + case X(Tuns16,Tfloat80): + case X(Tuns16,Tcomplex32): + case X(Tuns16,Tcomplex64): + case X(Tuns16,Tcomplex80): + e = el_una(OPu16_32, TYuint, e); + fty = Tuns32; + goto Lagain; + case X(Tuns16,Timaginary32): + case X(Tuns16,Timaginary64): + case X(Tuns16,Timaginary80): goto Lzero; + + /* ============================= */ + + case X(Tint32,Tint8): + case X(Tint32,Tuns8): e = el_una(OP32_16, TYshort, e); + fty = Tint16; + goto Lagain; + case X(Tint32,Tint16): + case X(Tint32,Tuns16): eop = OP32_16; goto Leop; + case X(Tint32,Tuns32): goto Lpaint; + case X(Tint32,Tint64): + case X(Tint32,Tuns64): eop = OPs32_64; goto Leop; + case X(Tint32,Tfloat32): + case X(Tint32,Tfloat64): + case X(Tint32,Tfloat80): + case X(Tint32,Tcomplex32): + case X(Tint32,Tcomplex64): + case X(Tint32,Tcomplex80): + e = el_una(OPs32_d, TYdouble, e); + fty = Tfloat64; + goto Lagain; + case X(Tint32,Timaginary32): + case X(Tint32,Timaginary64): + case X(Tint32,Timaginary80): goto Lzero; + + /* ============================= */ + + case X(Tuns32,Tint8): + case X(Tuns32,Tuns8): e = el_una(OP32_16, TYshort, e); + fty = Tuns16; + goto Lagain; + case X(Tuns32,Tint16): + case X(Tuns32,Tuns16): eop = OP32_16; goto Leop; + case X(Tuns32,Tint32): goto Lpaint; + case X(Tuns32,Tint64): + case X(Tuns32,Tuns64): eop = OPu32_64; goto Leop; + case X(Tuns32,Tfloat32): + case X(Tuns32,Tfloat64): + case X(Tuns32,Tfloat80): + case X(Tuns32,Tcomplex32): + case X(Tuns32,Tcomplex64): + case X(Tuns32,Tcomplex80): + e = el_una(OPu32_d, TYdouble, e); + fty = Tfloat64; + goto Lagain; + case X(Tuns32,Timaginary32): + case X(Tuns32,Timaginary64): + case X(Tuns32,Timaginary80): goto Lzero; + + /* ============================= */ + + case X(Tint64,Tint8): + case X(Tint64,Tuns8): + case X(Tint64,Tint16): + case X(Tint64,Tuns16): e = el_una(OP64_32, TYint, e); + fty = Tint32; + goto Lagain; + case X(Tint64,Tint32): + case X(Tint64,Tuns32): eop = OP64_32; goto Leop; + case X(Tint64,Tuns64): goto Lpaint; + case X(Tint64,Tfloat32): + case X(Tint64,Tfloat64): + case X(Tint64,Tfloat80): + case X(Tint64,Tcomplex32): + case X(Tint64,Tcomplex64): + case X(Tint64,Tcomplex80): + e = el_una(OPs64_d, TYdouble, e); + fty = Tfloat64; + goto Lagain; + case X(Tint64,Timaginary32): + case X(Tint64,Timaginary64): + case X(Tint64,Timaginary80): goto Lzero; + + /* ============================= */ + + case X(Tuns64,Tint8): + case X(Tuns64,Tuns8): + case X(Tuns64,Tint16): + case X(Tuns64,Tuns16): e = el_una(OP64_32, TYint, e); + fty = Tint32; + goto Lagain; + case X(Tuns64,Tint32): + case X(Tuns64,Tuns32): eop = OP64_32; goto Leop; + case X(Tuns64,Tint64): goto Lpaint; + case X(Tuns64,Tfloat32): + case X(Tuns64,Tfloat64): + case X(Tuns64,Tfloat80): + case X(Tuns64,Tcomplex32): + case X(Tuns64,Tcomplex64): + case X(Tuns64,Tcomplex80): + e = el_una(OPu64_d, TYdouble, e); + fty = Tfloat64; + goto Lagain; + case X(Tuns64,Timaginary32): + case X(Tuns64,Timaginary64): + case X(Tuns64,Timaginary80): goto Lzero; + + /* ============================= */ + + case X(Tfloat32,Tint8): + case X(Tfloat32,Tuns8): + case X(Tfloat32,Tint16): + case X(Tfloat32,Tuns16): + case X(Tfloat32,Tint32): + case X(Tfloat32,Tuns32): + case X(Tfloat32,Tint64): + case X(Tfloat32,Tuns64): + case X(Tfloat32,Tfloat80): e = el_una(OPf_d, TYdouble, e); + fty = Tfloat64; + goto Lagain; + case X(Tfloat32,Tfloat64): eop = OPf_d; goto Leop; + case X(Tfloat32,Timaginary32): goto Lzero; + case X(Tfloat32,Timaginary64): goto Lzero; + case X(Tfloat32,Timaginary80): goto Lzero; + case X(Tfloat32,Tcomplex32): + case X(Tfloat32,Tcomplex64): + case X(Tfloat32,Tcomplex80): + e = el_bin(OPadd,TYcfloat,el_long(TYifloat,0),e); + fty = Tcomplex32; + goto Lagain; + + /* ============================= */ + + case X(Tfloat64,Tint8): + case X(Tfloat64,Tuns8): e = el_una(OPd_s16, TYshort, e); + fty = Tint16; + goto Lagain; + case X(Tfloat64,Tint16): eop = OPd_s16; goto Leop; + case X(Tfloat64,Tuns16): eop = OPd_u16; goto Leop; + case X(Tfloat64,Tint32): eop = OPd_s32; goto Leop; + case X(Tfloat64,Tuns32): eop = OPd_u32; goto Leop; + case X(Tfloat64,Tint64): eop = OPd_s64; goto Leop; + case X(Tfloat64,Tuns64): eop = OPd_u64; goto Leop; + case X(Tfloat64,Tfloat32): eop = OPd_f; goto Leop; + case X(Tfloat64,Tfloat80): eop = OPd_ld; goto Leop; + case X(Tfloat64,Timaginary32): goto Lzero; + case X(Tfloat64,Timaginary64): goto Lzero; + case X(Tfloat64,Timaginary80): goto Lzero; + case X(Tfloat64,Tcomplex32): + case X(Tfloat64,Tcomplex64): + case X(Tfloat64,Tcomplex80): + e = el_bin(OPadd,TYcfloat,el_long(TYidouble,0),e); + fty = Tcomplex64; + goto Lagain; + + /* ============================= */ + + case X(Tfloat80,Tint8): + case X(Tfloat80,Tuns8): + case X(Tfloat80,Tint16): + case X(Tfloat80,Tuns16): + case X(Tfloat80,Tint32): + case X(Tfloat80,Tuns32): + case X(Tfloat80,Tint64): + case X(Tfloat80,Tuns64): + case X(Tfloat80,Tfloat32): e = el_una(OPld_d, TYdouble, e); + fty = Tfloat64; + goto Lagain; + case X(Tfloat80,Tfloat64): eop = OPld_d; goto Leop; + case X(Tfloat80,Timaginary32): goto Lzero; + case X(Tfloat80,Timaginary64): goto Lzero; + case X(Tfloat80,Timaginary80): goto Lzero; + case X(Tfloat80,Tcomplex32): + case X(Tfloat80,Tcomplex64): + case X(Tfloat80,Tcomplex80): + e = el_bin(OPadd,TYcldouble,e,el_long(TYildouble,0)); + fty = Tcomplex80; + goto Lagain; + + /* ============================= */ + + case X(Timaginary32,Tint8): + case X(Timaginary32,Tuns8): + case X(Timaginary32,Tint16): + case X(Timaginary32,Tuns16): + case X(Timaginary32,Tint32): + case X(Timaginary32,Tuns32): + case X(Timaginary32,Tint64): + case X(Timaginary32,Tuns64): + case X(Timaginary32,Tfloat32): + case X(Timaginary32,Tfloat64): + case X(Timaginary32,Tfloat80): goto Lzero; + case X(Timaginary32,Timaginary64): eop = OPf_d; goto Leop; + case X(Timaginary32,Timaginary80): + e = el_una(OPf_d, TYidouble, e); + fty = Timaginary64; + goto Lagain; + case X(Timaginary32,Tcomplex32): + case X(Timaginary32,Tcomplex64): + case X(Timaginary32,Tcomplex80): + e = el_bin(OPadd,TYcfloat,el_long(TYfloat,0),e); + fty = Tcomplex32; + goto Lagain; + + /* ============================= */ + + case X(Timaginary64,Tint8): + case X(Timaginary64,Tuns8): + case X(Timaginary64,Tint16): + case X(Timaginary64,Tuns16): + case X(Timaginary64,Tint32): + case X(Timaginary64,Tuns32): + case X(Timaginary64,Tint64): + case X(Timaginary64,Tuns64): + case X(Timaginary64,Tfloat32): + case X(Timaginary64,Tfloat64): + case X(Timaginary64,Tfloat80): goto Lzero; + case X(Timaginary64,Timaginary32): eop = OPd_f; goto Leop; + case X(Timaginary64,Timaginary80): eop = OPd_ld; goto Leop; + case X(Timaginary64,Tcomplex32): + case X(Timaginary64,Tcomplex64): + case X(Timaginary64,Tcomplex80): + e = el_bin(OPadd,TYcdouble,el_long(TYdouble,0),e); + fty = Tcomplex64; + goto Lagain; + + /* ============================= */ + + case X(Timaginary80,Tint8): + case X(Timaginary80,Tuns8): + case X(Timaginary80,Tint16): + case X(Timaginary80,Tuns16): + case X(Timaginary80,Tint32): + case X(Timaginary80,Tuns32): + case X(Timaginary80,Tint64): + case X(Timaginary80,Tuns64): + case X(Timaginary80,Tfloat32): + case X(Timaginary80,Tfloat64): + case X(Timaginary80,Tfloat80): goto Lzero; + case X(Timaginary80,Timaginary32): e = el_una(OPf_d, TYidouble, e); + fty = Timaginary64; + goto Lagain; + case X(Timaginary80,Timaginary64): eop = OPld_d; goto Leop; + case X(Timaginary80,Tcomplex32): + case X(Timaginary80,Tcomplex64): + case X(Timaginary80,Tcomplex80): + e = el_bin(OPadd,TYcldouble,el_long(TYldouble,0),e); + fty = Tcomplex80; + goto Lagain; + + /* ============================= */ + + case X(Tcomplex32,Tint8): + case X(Tcomplex32,Tuns8): + case X(Tcomplex32,Tint16): + case X(Tcomplex32,Tuns16): + case X(Tcomplex32,Tint32): + case X(Tcomplex32,Tuns32): + case X(Tcomplex32,Tint64): + case X(Tcomplex32,Tuns64): + case X(Tcomplex32,Tfloat32): + case X(Tcomplex32,Tfloat64): + case X(Tcomplex32,Tfloat80): + e = el_una(OPc_r, TYfloat, e); + fty = Tfloat32; + goto Lagain; + case X(Tcomplex32,Timaginary32): + case X(Tcomplex32,Timaginary64): + case X(Tcomplex32,Timaginary80): + e = el_una(OPc_i, TYifloat, e); + fty = Timaginary32; + goto Lagain; + case X(Tcomplex32,Tcomplex64): + case X(Tcomplex32,Tcomplex80): + e = el_una(OPf_d, TYcdouble, e); + fty = Tcomplex64; + goto Lagain; + + /* ============================= */ + + case X(Tcomplex64,Tint8): + case X(Tcomplex64,Tuns8): + case X(Tcomplex64,Tint16): + case X(Tcomplex64,Tuns16): + case X(Tcomplex64,Tint32): + case X(Tcomplex64,Tuns32): + case X(Tcomplex64,Tint64): + case X(Tcomplex64,Tuns64): + case X(Tcomplex64,Tfloat32): + case X(Tcomplex64,Tfloat64): + case X(Tcomplex64,Tfloat80): + e = el_una(OPc_r, TYdouble, e); + fty = Tfloat64; + goto Lagain; + case X(Tcomplex64,Timaginary32): + case X(Tcomplex64,Timaginary64): + case X(Tcomplex64,Timaginary80): + e = el_una(OPc_i, TYidouble, e); + fty = Timaginary64; + goto Lagain; + case X(Tcomplex64,Tcomplex32): eop = OPd_f; goto Leop; + case X(Tcomplex64,Tcomplex80): eop = OPd_ld; goto Leop; + + /* ============================= */ + + case X(Tcomplex80,Tint8): + case X(Tcomplex80,Tuns8): + case X(Tcomplex80,Tint16): + case X(Tcomplex80,Tuns16): + case X(Tcomplex80,Tint32): + case X(Tcomplex80,Tuns32): + case X(Tcomplex80,Tint64): + case X(Tcomplex80,Tuns64): + case X(Tcomplex80,Tfloat32): + case X(Tcomplex80,Tfloat64): + case X(Tcomplex80,Tfloat80): + e = el_una(OPc_r, TYldouble, e); + fty = Tfloat80; + goto Lagain; + case X(Tcomplex80,Timaginary32): + case X(Tcomplex80,Timaginary64): + case X(Tcomplex80,Timaginary80): + e = el_una(OPc_i, TYildouble, e); + fty = Timaginary80; + goto Lagain; + case X(Tcomplex80,Tcomplex32): + case X(Tcomplex80,Tcomplex64): + e = el_una(OPld_d, TYcdouble, e); + fty = Tcomplex64; + goto Lagain; + + /* ============================= */ + + default: + if (fty == tty) + goto Lpaint; + //dump(0); + //printf("fty = %d, tty = %d\n", fty, tty); + error("e2ir: cannot cast from %s to %s", e1->type->toChars(), t->toChars()); + goto Lzero; + + Lzero: + e = el_long(ttym, 0); + break; + + Lpaint: + e->Ety = ttym; + break; + + Leop: + e = el_una(eop, ttym, e); + break; + } +Lret: + // Adjust for any type paints + t = type->toBasetype(); + e->Ety = t->totym(); + + el_setLoc(e,loc); + return e; +} + +elem *ArrayLengthExp::toElem(IRState *irs) +{ + elem *e = e1->toElem(irs); + e = el_una(OP64_32, type->totym(), e); + el_setLoc(e,loc); + return e; +} + +elem *SliceExp::toElem(IRState *irs) +{ elem *e; + Type *t1; + + //printf("SliceExp::toElem()\n"); + t1 = e1->type->toBasetype(); + e = e1->toElem(irs); + if (lwr) + { elem *elwr; + elem *elwr2; + elem *eupr; + elem *eptr; + elem *einit; + int sz; + + einit = resolveLengthVar(lengthVar, &e, t1); + + sz = t1->nextOf()->size(); + + elwr = lwr->toElem(irs); + eupr = upr->toElem(irs); + + elwr2 = el_same(&elwr); + + // Create an array reference where: + // length is (upr - lwr) + // pointer is (ptr + lwr*sz) + // Combine as (length pair ptr) + + if (global.params.useArrayBounds) + { + // Checks (unsigned compares): + // upr <= array.length + // lwr <= upr + + elem *c1; + elem *c2; + elem *ea; + elem *eb; + elem *eupr2; + elem *elength; + + if (t1->ty == Tpointer) + { + // Just do lwr <= upr check + + eupr2 = el_same(&eupr); + eupr2->Ety = TYuint; // make sure unsigned comparison + c1 = el_bin(OPle, TYint, elwr2, eupr2); + c1 = el_combine(eupr, c1); + goto L2; + } + else if (t1->ty == Tsarray) + { TypeSArray *tsa = (TypeSArray *)t1; + integer_t length = tsa->dim->toInteger(); + + elength = el_long(TYuint, length); + goto L1; + } + else if (t1->ty == Tarray) + { + if (lengthVar) + elength = el_var(lengthVar->toSymbol()); + else + { + elength = e; + e = el_same(&elength); + elength = el_una(OP64_32, TYuint, elength); + } + L1: + eupr2 = el_same(&eupr); + c1 = el_bin(OPle, TYint, eupr, elength); + eupr2->Ety = TYuint; // make sure unsigned comparison + c2 = el_bin(OPle, TYint, elwr2, eupr2); + c1 = el_bin(OPandand, TYint, c1, c2); // (c1 && c2) + + L2: + // Construct: (c1 || ModuleArray(line)) + Symbol *sassert; + + sassert = irs->blx->module->toModuleArray(); + ea = el_bin(OPcall,TYvoid,el_var(sassert), el_long(TYint, loc.linnum)); + eb = el_bin(OPoror,TYvoid,c1,ea); + elwr = el_combine(elwr, eb); + + elwr2 = el_copytree(elwr2); + eupr = el_copytree(eupr2); + } + } + + eptr = array_toPtr(e1->type, e); + + elem *elength = el_bin(OPmin, TYint, eupr, elwr2); + eptr = el_bin(OPadd, TYnptr, eptr, el_bin(OPmul, TYint, el_copytree(elwr2), el_long(TYint, sz))); + + e = el_pair(TYullong, elength, eptr); + e = el_combine(elwr, e); + e = el_combine(einit, e); + } + else if (t1->ty == Tsarray) + { + e = sarray_toDarray(loc, t1, NULL, e); + } + el_setLoc(e,loc); + return e; +} + +elem *IndexExp::toElem(IRState *irs) +{ elem *e; + elem *n1 = e1->toElem(irs); + elem *n2; + elem *eb = NULL; + Type *t1; + + //printf("IndexExp::toElem() %s\n", toChars()); + t1 = e1->type->toBasetype(); + if (t1->ty == Taarray) + { + // set to: + // *aaGet(aa, keyti, valuesize, index); + + TypeAArray *taa = (TypeAArray *)t1; + elem *keyti; + elem *ep; + int vsize = taa->next->size(); + elem *valuesize; + Symbol *s; + + // n2 becomes the index, also known as the key + n2 = e2->toElem(irs); + if (n2->Ety == TYstruct || n2->Ety == TYarray) + { + n2 = el_una(OPstrpar, TYstruct, n2); + n2->Enumbytes = n2->E1->Enumbytes; + //printf("numbytes = %d\n", n2->Enumbytes); + assert(n2->Enumbytes); + } + valuesize = el_long(TYuint, vsize); // BUG: should be TYsize_t + //printf("valuesize: "); elem_print(valuesize); + if (modifiable) + { + n1 = el_una(OPaddr, TYnptr, n1); + s = taa->aaGetSymbol("Get", 1); + } + else + { + s = taa->aaGetSymbol("GetRvalue", 1); + } + //printf("taa->index = %s\n", taa->index->toChars()); + keyti = taa->index->getInternalTypeInfo(NULL)->toElem(irs); + //keyti = taa->index->getTypeInfo(NULL)->toElem(irs); + //printf("keyti:\n"); + //elem_print(keyti); + ep = el_params(n2, valuesize, keyti, n1, NULL); + e = el_bin(OPcall, TYnptr, el_var(s), ep); + if (global.params.useArrayBounds) + { + elem *n; + elem *ea; + + n = el_same(&e); + + // Construct: ((e || ModuleAssert(line)),n) + Symbol *sassert; + + sassert = irs->blx->module->toModuleArray(); + ea = el_bin(OPcall,TYvoid,el_var(sassert), + el_long(TYint, loc.linnum)); + e = el_bin(OPoror,TYvoid,e,ea); + e = el_bin(OPcomma, TYnptr, e, n); + } + e = el_una(OPind, type->totym(), e); + if (tybasic(e->Ety) == TYstruct) + e->Enumbytes = type->size(); + } + else + { elem *einit; + + einit = resolveLengthVar(lengthVar, &n1, t1); + n2 = e2->toElem(irs); + + if (global.params.useArrayBounds) + { + elem *elength; + elem *n2x; + elem *ea; + + if (t1->ty == Tsarray) + { TypeSArray *tsa = (TypeSArray *)t1; + integer_t length = tsa->dim->toInteger(); + + elength = el_long(TYuint, length); + goto L1; + } + else if (t1->ty == Tarray) + { + elength = n1; + n1 = el_same(&elength); + elength = el_una(OP64_32, TYuint, elength); + L1: + n2x = n2; + n2 = el_same(&n2x); + n2x = el_bin(OPlt, TYint, n2x, elength); + + // Construct: (n2x || ModuleAssert(line)) + Symbol *sassert; + + sassert = irs->blx->module->toModuleArray(); + ea = el_bin(OPcall,TYvoid,el_var(sassert), + el_long(TYint, loc.linnum)); + eb = el_bin(OPoror,TYvoid,n2x,ea); + } + } + + n1 = array_toPtr(t1, n1); + + { elem *escale; + + escale = el_long(TYint, t1->nextOf()->size()); + n2 = el_bin(OPmul, TYint, n2, escale); + e = el_bin(OPadd, TYnptr, n1, n2); + e = el_una(OPind, type->totym(), e); + if (tybasic(e->Ety) == TYstruct || tybasic(e->Ety) == TYarray) + { e->Ety = TYstruct; + e->Enumbytes = type->size(); + } + } + + eb = el_combine(einit, eb); + e = el_combine(eb, e); + } + el_setLoc(e,loc); + return e; +} + + +elem *TupleExp::toElem(IRState *irs) +{ elem *e = NULL; + + //printf("TupleExp::toElem() %s\n", toChars()); + for (size_t i = 0; i < exps->dim; i++) + { Expression *el = (Expression *)exps->data[i]; + elem *ep = el->toElem(irs); + + e = el_combine(e, ep); + } + return e; +} + + +elem *ArrayLiteralExp::toElem(IRState *irs) +{ elem *e; + size_t dim; + + //printf("ArrayLiteralExp::toElem() %s\n", toChars()); + if (elements) + { + dim = elements->dim; + e = el_long(TYint, dim); + for (size_t i = 0; i < dim; i++) + { Expression *el = (Expression *)elements->data[i]; + elem *ep = el->toElem(irs); + + if (tybasic(ep->Ety) == TYstruct || tybasic(ep->Ety) == TYarray) + { + ep = el_una(OPstrpar, TYstruct, ep); + ep->Enumbytes = el->type->size(); + } + e = el_param(ep, e); + } + } + else + { dim = 0; + e = el_long(TYint, 0); + } + Type *tb = type->toBasetype(); +#if 1 + e = el_param(e, type->getTypeInfo(NULL)->toElem(irs)); + + // call _d_arrayliteralT(ti, dim, ...) + e = el_bin(OPcall,TYnptr,el_var(rtlsym[RTLSYM_ARRAYLITERALT]),e); +#else + e = el_param(e, el_long(TYint, tb->next->size())); + + // call _d_arrayliteral(size, dim, ...) + e = el_bin(OPcall,TYnptr,el_var(rtlsym[RTLSYM_ARRAYLITERAL]),e); +#endif + if (tb->ty == Tarray) + { + e = el_pair(TYullong, el_long(TYint, dim), e); + } + else if (tb->ty == Tpointer) + { + } + else + { + e = el_una(OPind,TYstruct,e); + e->Enumbytes = type->size(); + } + + el_setLoc(e,loc); + return e; +} + + +elem *AssocArrayLiteralExp::toElem(IRState *irs) +{ elem *e; + size_t dim; + + //printf("AssocArrayLiteralExp::toElem() %s\n", toChars()); + dim = keys->dim; + e = el_long(TYint, dim); + for (size_t i = 0; i < dim; i++) + { Expression *el = (Expression *)keys->data[i]; + + for (int j = 0; j < 2; j++) + { + elem *ep = el->toElem(irs); + + if (tybasic(ep->Ety) == TYstruct || tybasic(ep->Ety) == TYarray) + { + ep = el_una(OPstrpar, TYstruct, ep); + ep->Enumbytes = el->type->size(); + } +//printf("[%d] %s\n", i, el->toChars()); +//elem_print(ep); + e = el_param(ep, e); + el = (Expression *)values->data[i]; + } + } + + Type *t = type->toBasetype()->mutableOf(); + assert(t->ty == Taarray); + TypeAArray *ta = (TypeAArray *)t; + + /* Unfortunately, the hash function for Aa (array of chars) is custom and + * different from Axa and Aya, which get the generic hash function. + * So, rewrite the type of the AArray so that if it's key type + * is an array of const or invariant, make it an array of mutable. + */ + Type *tkey = ta->index->toBasetype(); + if (tkey->ty == Tarray) + { + tkey = tkey->nextOf()->mutableOf()->arrayOf(); + tkey = tkey->semantic(0, NULL); + ta = new TypeAArray(ta->nextOf(), tkey); + ta = (TypeAArray *)ta->merge(); + } + + e = el_param(e, ta->getTypeInfo(NULL)->toElem(irs)); + + // call _d_assocarrayliteralT(ti, dim, ...) + e = el_bin(OPcall,TYnptr,el_var(rtlsym[RTLSYM_ASSOCARRAYLITERALT]),e); + + el_setLoc(e,loc); + return e; +} + + +/******************************************* + * Generate elem to zero fill contents of Symbol stmp + * from *poffset..offset2. + * May store anywhere from 0..maxoff, as this function + * tries to use aligned int stores whereever possible. + * Update *poffset to end of initialized hole; *poffset will be >= offset2. + */ + +elem *fillHole(Symbol *stmp, size_t *poffset, size_t offset2, size_t maxoff) +{ elem *e = NULL; + int basealign = 1; + + while (*poffset < offset2) + { tym_t ty; + elem *e1; + + if (tybasic(stmp->Stype->Tty) == TYnptr) + e1 = el_var(stmp); + else + e1 = el_ptr(stmp); + if (basealign) + *poffset &= ~3; + basealign = 1; + size_t sz = maxoff - *poffset; + switch (sz) + { case 1: ty = TYchar; break; + case 2: ty = TYshort; break; + case 3: + ty = TYshort; + basealign = 0; + break; + default: + ty = TYlong; + break; + } + e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, *poffset)); + e1 = el_una(OPind, ty, e1); + e1 = el_bin(OPeq, ty, e1, el_long(ty, 0)); + e = el_combine(e, e1); + *poffset += tysize[ty]; + } + return e; +} + +elem *StructLiteralExp::toElem(IRState *irs) +{ elem *e; + size_t dim; + + //printf("StructLiteralExp::toElem() %s\n", toChars()); + + // struct symbol to initialize with the literal + Symbol *stmp = sym ? sym : symbol_genauto(sd->type->toCtype()); + + e = NULL; + + if (fillHoles) + { + /* Initialize all alignment 'holes' to zero. + * Do before initializing fields, as the hole filling process + * can spill over into the fields. + */ + size_t offset = 0; + for (size_t i = 0; i < sd->fields.dim; i++) + { + Dsymbol *s = (Dsymbol *)sd->fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v); + + e = el_combine(e, fillHole(stmp, &offset, v->offset, sd->structsize)); + size_t vend = v->offset + v->type->size(); + if (offset < vend) + offset = vend; + } + e = el_combine(e, fillHole(stmp, &offset, sd->structsize, sd->structsize)); + } + + if (elements) + { + dim = elements->dim; + assert(dim <= sd->fields.dim); + for (size_t i = 0; i < dim; i++) + { Expression *el = (Expression *)elements->data[i]; + if (!el) + continue; + + Dsymbol *s = (Dsymbol *)sd->fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v); + + elem *e1; + if (tybasic(stmp->Stype->Tty) == TYnptr) + { e1 = el_var(stmp); + e1->EV.sp.Voffset = soffset; + } + else + { e1 = el_ptr(stmp); + if (soffset) + e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, soffset)); + } + e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, v->offset)); + elem *ec = e1; // pointer to destination + + elem *ep = el->toElem(irs); + + Type *t1b = v->type->toBasetype(); + Type *t2b = el->type->toBasetype(); + if (t1b->ty == Tsarray) + { + if (t2b->implicitConvTo(t1b)) + { +#if DMDV2 + // Determine if postblit is needed + int postblit = 0; + Type *t = t1b; + do + { + t = t->nextOf()->toBasetype(); + } while (t->ty == Tsarray); + if (t->ty == Tstruct) + { StructDeclaration *sd = ((TypeStruct *)t)->sym; + if (sd->postblit) + postblit = 1; + } + + if (postblit) + { + /* Generate: + * _d_arrayctor(ti, From: ep, To: e1) + */ + Expression *ti = t1b->nextOf()->toBasetype()->getTypeInfo(NULL); + elem *esize = el_long(TYsize_t, ((TypeSArray *)t1b)->dim->toInteger()); + e1 = el_pair(TYdarray, esize, e1); + ep = el_pair(TYdarray, el_copytree(esize), array_toPtr(el->type, ep)); + ep = el_params(e1, ep, ti->toElem(irs), NULL); + int rtl = RTLSYM_ARRAYCTOR; + e1 = el_bin(OPcall, type->totym(), el_var(rtlsym[rtl]), ep); + } + else +#endif + { + elem *esize = el_long(TYsize_t, t1b->size()); + ep = array_toPtr(el->type, ep); + e1 = el_bin(OPmemcpy, TYnptr, e1, el_param(ep, esize)); + } + } + else + { + elem *edim = el_long(TYsize_t, t1b->size() / t2b->size()); + e1 = setArray(e1, edim, t2b, ep, irs, TOKconstruct); + } + } + else + { + tym_t ty = v->type->totym(); + e1 = el_una(OPind, ty, e1); + if (ty == TYstruct) + e1->Enumbytes = v->type->size(); + e1 = el_bin(OPeq, ty, e1, ep); + if (ty == TYstruct) + { e1->Eoper = OPstreq; + e1->Enumbytes = v->type->size(); + } +#if DMDV2 + /* Call postBlit() on e1 + */ + Type *tb = v->type->toBasetype(); + if (tb->ty == Tstruct) + { StructDeclaration *sd = ((TypeStruct *)tb)->sym; + if (sd->postblit) + { FuncDeclaration *fd = sd->postblit; + ec = el_copytree(ec); + ec = callfunc(loc, irs, 1, Type::tvoid, ec, tb->pointerTo(), fd, fd->type, NULL, NULL); + e1 = el_bin(OPcomma, ec->Ety, e1, ec); + } + } +#endif + } + e = el_combine(e, e1); + } + } + + elem *ev = el_var(stmp); + ev->Enumbytes = sd->structsize; + e = el_combine(e, ev); + el_setLoc(e,loc); + return e; +}