Mercurial > projects > ldc
view dmd2/e2ir.c.nolink @ 1317:4099548c80e0
Allocate objects on the stack if they (a) don't have a destructor, and
(b) don't override the delete operator (on top of the regular conditions for
stack allocation that also apply to arrays, structs, etc.).
The "no destructor" clause is not strictly necessary, but calling them at the
right time would be tricky to say the least; it would involve, among other
things, "manually" inserting a try-finally block around anything that might
throw exceptions not caught in the current function.
Note: objects with custom new operators are automatically ignored because they
don't use the regular allocation runtime call, so there's no need to pay special
attention to them.
author | Frits van Bommel <fvbommel wxs.nl> |
---|---|
date | Sat, 09 May 2009 00:50:15 +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; }