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