Mercurial > projects > ldc
view dmd2/e2ir.c.nolink @ 1296:79b201533cf8
Add -verify-each option to ease debugging
author | Frits van Bommel <fvbommel wxs.nl> |
---|---|
date | Sun, 03 May 2009 21:58:28 +0200 |
parents | f04dde6e882c |
children |
line wrap: on
line source
// 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; }