Files
ldc/dmd2/e2ir.c.nolink

4680 lines
110 KiB
Plaintext

// 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(&ethis);
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(&ethis);
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(&ethis);
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;
}