mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-23 08:13:13 +01:00
1723 lines
45 KiB
C
1723 lines
45 KiB
C
|
|
// Compiler implementation of the D programming language
|
|
// Copyright (c) 2000-2011 by Digital Mars
|
|
// All Rights Reserved
|
|
// Written by Walter Bright
|
|
// http://www.digitalmars.com
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#include "mars.h"
|
|
#include "lexer.h"
|
|
#include "statement.h"
|
|
#include "expression.h"
|
|
#include "mtype.h"
|
|
#include "dsymbol.h"
|
|
#include "declaration.h"
|
|
#include "irstate.h"
|
|
#include "init.h"
|
|
#include "module.h"
|
|
#include "enum.h"
|
|
#include "aggregate.h"
|
|
#include "template.h"
|
|
#include "id.h"
|
|
|
|
// Back end
|
|
#include "cc.h"
|
|
#include "type.h"
|
|
#include "code.h"
|
|
#include "oper.h"
|
|
#include "global.h"
|
|
#include "dt.h"
|
|
|
|
#include "rmem.h"
|
|
|
|
static char __file__[] = __FILE__; // for tassert.h
|
|
#include "tassert.h"
|
|
|
|
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
|
|
Expressions *arguments);
|
|
|
|
elem *exp2_copytotemp(elem *e);
|
|
elem *incUsageElem(IRState *irs, Loc loc);
|
|
StructDeclaration *needsPostblit(Type *t);
|
|
|
|
#define elem_setLoc(e,loc) ((e)->Esrcpos.Sfilename = (char *)(loc).filename, \
|
|
(e)->Esrcpos.Slinnum = (loc).linnum)
|
|
|
|
#define SEH (TARGET_WINDOS)
|
|
|
|
/***********************************************
|
|
* Generate code to set index into scope table.
|
|
*/
|
|
|
|
#if SEH
|
|
void setScopeIndex(Blockx *blx, block *b, int scope_index)
|
|
{
|
|
block_appendexp(b, nteh_setScopeTableIndex(blx, scope_index));
|
|
}
|
|
#else
|
|
#define setScopeIndex(blx, b, scope_index) ;
|
|
#endif
|
|
|
|
/****************************************
|
|
* Allocate a new block, and set the tryblock.
|
|
*/
|
|
|
|
block *block_calloc(Blockx *blx)
|
|
{
|
|
block *b = block_calloc();
|
|
b->Btry = blx->tryblock;
|
|
return b;
|
|
}
|
|
|
|
/**************************************
|
|
* Convert label to block.
|
|
*/
|
|
|
|
block *labelToBlock(Loc loc, Blockx *blx, LabelDsymbol *label, int flag = 0)
|
|
{
|
|
if (!label->statement)
|
|
{
|
|
error(loc, "undefined label %s", label->toChars());
|
|
return NULL;
|
|
}
|
|
LabelStatement *s = label->statement;
|
|
if (!s->lblock)
|
|
{ s->lblock = block_calloc(blx);
|
|
s->lblock->Btry = NULL; // fill this in later
|
|
|
|
if (flag)
|
|
{
|
|
// Keep track of the forward reference to this block, so we can check it later
|
|
if (!s->fwdrefs)
|
|
s->fwdrefs = new Blocks();
|
|
s->fwdrefs->push(blx->curblock);
|
|
}
|
|
}
|
|
return s->lblock;
|
|
}
|
|
|
|
/**************************************
|
|
* Add in code to increment usage count for linnum.
|
|
*/
|
|
|
|
void incUsage(IRState *irs, Loc loc)
|
|
{
|
|
|
|
if (global.params.cov && loc.linnum)
|
|
{
|
|
block_appendexp(irs->blx->curblock, incUsageElem(irs, loc));
|
|
}
|
|
}
|
|
|
|
/****************************************
|
|
* This should be overridden by each statement class.
|
|
*/
|
|
|
|
void Statement::toIR(IRState *irs)
|
|
{
|
|
print();
|
|
assert(0);
|
|
}
|
|
|
|
/*************************************
|
|
*/
|
|
|
|
void OnScopeStatement::toIR(IRState *irs)
|
|
{
|
|
}
|
|
|
|
/****************************************
|
|
*/
|
|
|
|
void IfStatement::toIR(IRState *irs)
|
|
{
|
|
elem *e;
|
|
Blockx *blx = irs->blx;
|
|
|
|
//printf("IfStatement::toIR('%s')\n", condition->toChars());
|
|
|
|
IRState mystate(irs, this);
|
|
|
|
// bexit is the block that gets control after this IfStatement is done
|
|
block *bexit = mystate.breakBlock ? mystate.breakBlock : block_calloc();
|
|
|
|
incUsage(irs, loc);
|
|
#if 0
|
|
if (match)
|
|
{ /* Generate:
|
|
* if (match = RTLSYM_IFMATCH(string, pattern)) ...
|
|
*/
|
|
assert(condition->op == TOKmatch);
|
|
e = matchexp_toelem((MatchExp *)condition, &mystate, RTLSYM_IFMATCH);
|
|
Symbol *s = match->toSymbol();
|
|
symbol_add(s);
|
|
e = el_bin(OPeq, TYnptr, el_var(s), e);
|
|
}
|
|
else
|
|
#endif
|
|
e = condition->toElemDtor(&mystate);
|
|
block_appendexp(blx->curblock, e);
|
|
block *bcond = blx->curblock;
|
|
block_next(blx, BCiftrue, NULL);
|
|
|
|
list_append(&bcond->Bsucc, blx->curblock);
|
|
if (ifbody)
|
|
ifbody->toIR(&mystate);
|
|
list_append(&blx->curblock->Bsucc, bexit);
|
|
|
|
if (elsebody)
|
|
{
|
|
block_next(blx, BCgoto, NULL);
|
|
list_append(&bcond->Bsucc, blx->curblock);
|
|
elsebody->toIR(&mystate);
|
|
list_append(&blx->curblock->Bsucc, bexit);
|
|
}
|
|
else
|
|
list_append(&bcond->Bsucc, bexit);
|
|
|
|
block_next(blx, BCgoto, bexit);
|
|
|
|
}
|
|
|
|
/**************************************
|
|
*/
|
|
|
|
#if DMDV2
|
|
void PragmaStatement::toIR(IRState *irs)
|
|
{
|
|
//printf("PragmaStatement::toIR()\n");
|
|
if (ident == Id::startaddress)
|
|
{
|
|
assert(args && args->dim == 1);
|
|
Expression *e = args->tdata()[0];
|
|
Dsymbol *sa = getDsymbol(e);
|
|
FuncDeclaration *f = sa->isFuncDeclaration();
|
|
assert(f);
|
|
Symbol *s = f->toSymbol();
|
|
while (irs->prev)
|
|
irs = irs->prev;
|
|
irs->startaddress = s;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/***********************
|
|
*/
|
|
|
|
void WhileStatement::toIR(IRState *irs)
|
|
{
|
|
assert(0); // was "lowered"
|
|
#if 0
|
|
Blockx *blx = irs->blx;
|
|
|
|
/* Create a new state, because we need a new continue and break target
|
|
*/
|
|
IRState mystate(irs,this);
|
|
mystate.breakBlock = block_calloc(blx);
|
|
mystate.contBlock = block_calloc(blx);
|
|
|
|
list_append(&blx->curblock->Bsucc, mystate.contBlock);
|
|
block_next(blx, BCgoto, mystate.contBlock);
|
|
incUsage(irs, loc);
|
|
block_appendexp(mystate.contBlock, condition->toElem(&mystate));
|
|
|
|
block_next(blx, BCiftrue, NULL);
|
|
|
|
/* curblock is the start of the while loop body
|
|
*/
|
|
list_append(&mystate.contBlock->Bsucc, blx->curblock);
|
|
if (body)
|
|
body->toIR(&mystate);
|
|
list_append(&blx->curblock->Bsucc, mystate.contBlock);
|
|
block_next(blx, BCgoto, mystate.breakBlock);
|
|
|
|
list_append(&mystate.contBlock->Bsucc, mystate.breakBlock);
|
|
#endif
|
|
}
|
|
|
|
/******************************************
|
|
*/
|
|
|
|
void DoStatement::toIR(IRState *irs)
|
|
{
|
|
Blockx *blx = irs->blx;
|
|
|
|
IRState mystate(irs,this);
|
|
mystate.breakBlock = block_calloc(blx);
|
|
mystate.contBlock = block_calloc(blx);
|
|
|
|
block *bpre = blx->curblock;
|
|
block_next(blx, BCgoto, NULL);
|
|
list_append(&bpre->Bsucc, blx->curblock);
|
|
|
|
list_append(&mystate.contBlock->Bsucc, blx->curblock);
|
|
list_append(&mystate.contBlock->Bsucc, mystate.breakBlock);
|
|
|
|
if (body)
|
|
body->toIR(&mystate);
|
|
list_append(&blx->curblock->Bsucc, mystate.contBlock);
|
|
|
|
block_next(blx, BCgoto, mystate.contBlock);
|
|
incUsage(irs, condition->loc);
|
|
block_appendexp(mystate.contBlock, condition->toElemDtor(&mystate));
|
|
block_next(blx, BCiftrue, mystate.breakBlock);
|
|
|
|
}
|
|
|
|
/*****************************************
|
|
*/
|
|
|
|
void ForStatement::toIR(IRState *irs)
|
|
{
|
|
Blockx *blx = irs->blx;
|
|
|
|
IRState mystate(irs,this);
|
|
mystate.breakBlock = block_calloc(blx);
|
|
mystate.contBlock = block_calloc(blx);
|
|
|
|
if (init)
|
|
init->toIR(&mystate);
|
|
block *bpre = blx->curblock;
|
|
block_next(blx,BCgoto,NULL);
|
|
block *bcond = blx->curblock;
|
|
list_append(&bpre->Bsucc, bcond);
|
|
list_append(&mystate.contBlock->Bsucc, bcond);
|
|
if (condition)
|
|
{
|
|
incUsage(irs, condition->loc);
|
|
block_appendexp(bcond, condition->toElemDtor(&mystate));
|
|
block_next(blx,BCiftrue,NULL);
|
|
list_append(&bcond->Bsucc, blx->curblock);
|
|
list_append(&bcond->Bsucc, mystate.breakBlock);
|
|
}
|
|
else
|
|
{ /* No conditional, it's a straight goto
|
|
*/
|
|
block_next(blx,BCgoto,NULL);
|
|
list_append(&bcond->Bsucc, blx->curblock);
|
|
}
|
|
|
|
if (body)
|
|
body->toIR(&mystate);
|
|
/* End of the body goes to the continue block
|
|
*/
|
|
list_append(&blx->curblock->Bsucc, mystate.contBlock);
|
|
block_next(blx, BCgoto, mystate.contBlock);
|
|
|
|
if (increment)
|
|
{
|
|
incUsage(irs, increment->loc);
|
|
block_appendexp(mystate.contBlock, increment->toElemDtor(&mystate));
|
|
}
|
|
|
|
/* The 'break' block follows the for statement.
|
|
*/
|
|
block_next(blx,BCgoto, mystate.breakBlock);
|
|
}
|
|
|
|
|
|
/**************************************
|
|
*/
|
|
|
|
void ForeachStatement::toIR(IRState *irs)
|
|
{
|
|
printf("ForeachStatement::toIR() %s\n", toChars());
|
|
assert(0); // done by "lowering" in the front end
|
|
#if 0
|
|
Type *tab;
|
|
elem *eaggr;
|
|
elem *e;
|
|
elem *elength;
|
|
tym_t keytym;
|
|
|
|
//printf("ForeachStatement::toIR()\n");
|
|
block *bpre;
|
|
block *bcond;
|
|
block *bbody;
|
|
block *bbodyx;
|
|
Blockx *blx = irs->blx;
|
|
|
|
IRState mystate(irs,this);
|
|
mystate.breakBlock = block_calloc(blx);
|
|
mystate.contBlock = block_calloc(blx);
|
|
|
|
tab = aggr->type->toBasetype();
|
|
assert(tab->ty == Tarray || tab->ty == Tsarray);
|
|
|
|
incUsage(irs, aggr->loc);
|
|
eaggr = aggr->toElem(irs);
|
|
|
|
/* Create sp: pointer to start of array data
|
|
*/
|
|
|
|
Symbol *sp = symbol_genauto(TYnptr);
|
|
|
|
if (tab->ty == Tarray)
|
|
{
|
|
// stmp is copy of eaggr (the array), so eaggr is evaluated only once
|
|
Symbol *stmp;
|
|
|
|
// Initialize stmp
|
|
stmp = symbol_genauto(eaggr);
|
|
e = el_bin(OPeq, eaggr->Ety, el_var(stmp), eaggr);
|
|
block_appendexp(blx->curblock, e);
|
|
|
|
// Initialize sp
|
|
e = el_una(OPmsw, TYnptr, el_var(stmp));
|
|
e = el_bin(OPeq, TYnptr, el_var(sp), e);
|
|
block_appendexp(blx->curblock, e);
|
|
|
|
// Get array.length
|
|
elength = el_var(stmp);
|
|
elength->Ety = TYsize_t;
|
|
}
|
|
else // Tsarray
|
|
{
|
|
// Initialize sp
|
|
e = el_una(OPaddr, TYnptr, eaggr);
|
|
e = el_bin(OPeq, TYnptr, el_var(sp), e);
|
|
block_appendexp(blx->curblock, e);
|
|
|
|
// Get array.length
|
|
elength = el_long(TYsize_t, ((TypeSArray *)tab)->dim->toInteger());
|
|
}
|
|
|
|
Symbol *spmax;
|
|
Symbol *skey;
|
|
|
|
if (key)
|
|
{
|
|
/* Create skey, the index to the array.
|
|
* Initialize skey to 0 (foreach) or .length (foreach_reverse).
|
|
*/
|
|
skey = key->toSymbol();
|
|
symbol_add(skey);
|
|
keytym = key->type->totym();
|
|
elem *einit = (op == TOKforeach_reverse) ? elength : el_long(keytym, 0);
|
|
e = el_bin(OPeq, keytym, el_var(skey), einit);
|
|
}
|
|
else
|
|
{
|
|
/* Create spmax, pointer past end of data.
|
|
* Initialize spmax = sp + array.length * size
|
|
*/
|
|
spmax = symbol_genauto(TYnptr);
|
|
e = el_bin(OPmul, TYsize_t, elength, el_long(TYsize_t, tab->nextOf()->size()));
|
|
e = el_bin(OPadd, TYnptr, el_var(sp), e);
|
|
e = el_bin(OPeq, TYnptr, el_var(spmax), e);
|
|
|
|
/* For foreach_reverse, swap sp and spmax
|
|
*/
|
|
if (op == TOKforeach_reverse)
|
|
{ Symbol *s = sp;
|
|
sp = spmax;
|
|
spmax = s;
|
|
}
|
|
}
|
|
block_appendexp(blx->curblock, e);
|
|
|
|
bpre = blx->curblock;
|
|
block_next(blx,BCgoto,NULL);
|
|
bcond = blx->curblock;
|
|
|
|
if (key)
|
|
{
|
|
if (op == TOKforeach_reverse)
|
|
{
|
|
// Construct (key != 0)
|
|
e = el_bin(OPne, TYint, el_var(skey), el_long(keytym, 0));
|
|
}
|
|
else
|
|
{
|
|
// Construct (key < elength)
|
|
e = el_bin(OPlt, TYint, el_var(skey), elength);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (op == TOKforeach_reverse)
|
|
{
|
|
// Construct (sp > spmax)
|
|
e = el_bin(OPgt, TYint, el_var(sp), el_var(spmax));
|
|
}
|
|
else
|
|
{
|
|
// Construct (sp < spmax)
|
|
e = el_bin(OPlt, TYint, el_var(sp), el_var(spmax));
|
|
}
|
|
}
|
|
bcond->Belem = e;
|
|
block_next(blx, BCiftrue, NULL);
|
|
|
|
if (op == TOKforeach_reverse)
|
|
{
|
|
if (key)
|
|
{ // Construct (skey -= 1)
|
|
e = el_bin(OPminass, keytym, el_var(skey), el_long(keytym, 1));
|
|
}
|
|
else
|
|
{ // Construct (sp--)
|
|
e = el_bin(OPminass, TYnptr, el_var(sp), el_long(TYsize_t, tab->nextOf()->size()));
|
|
}
|
|
block_appendexp(blx->curblock, e);
|
|
}
|
|
|
|
Symbol *s;
|
|
FuncDeclaration *fd = NULL;
|
|
if (value->toParent2())
|
|
fd = value->toParent2()->isFuncDeclaration();
|
|
int nrvo = 0;
|
|
if (fd && fd->nrvo_can && fd->nrvo_var == value)
|
|
{
|
|
s = fd->shidden;
|
|
nrvo = 1;
|
|
}
|
|
else
|
|
{ s = value->toSymbol();
|
|
symbol_add(s);
|
|
}
|
|
|
|
// Construct (value = *sp) or (value = sp[skey * elemsize])
|
|
tym_t tym = value->type->totym();
|
|
if (key)
|
|
{ // sp + skey * elemsize
|
|
e = el_bin(OPmul, keytym, el_var(skey), el_long(keytym, tab->nextOf()->size()));
|
|
e = el_bin(OPadd, TYnptr, el_var(sp), e);
|
|
}
|
|
else
|
|
e = el_var(sp);
|
|
|
|
elem *evalue;
|
|
#if DMDV2
|
|
if (value->offset) // if value is a member of a closure
|
|
{
|
|
assert(irs->sclosure);
|
|
evalue = el_var(irs->sclosure);
|
|
evalue = el_bin(OPadd, TYnptr, evalue, el_long(TYint, value->offset));
|
|
evalue = el_una(OPind, value->type->totym(), evalue);
|
|
}
|
|
else
|
|
#endif
|
|
evalue = el_var(s);
|
|
|
|
if (value->isOut() || value->isRef())
|
|
{
|
|
assert(value->storage_class & (STCout | STCref));
|
|
e = el_bin(OPeq, TYnptr, evalue, e);
|
|
}
|
|
else
|
|
{
|
|
if (nrvo)
|
|
evalue = el_una(OPind, tym, evalue);
|
|
StructDeclaration *sd = needsPostblit(value->type);
|
|
if (tybasic(tym) == TYstruct)
|
|
{
|
|
e = el_bin(OPeq, tym, evalue, el_una(OPind, tym, e));
|
|
e->Eoper = OPstreq;
|
|
e->ET = value->type->toCtype();
|
|
#if DMDV2
|
|
// Call postblit on e
|
|
if (sd)
|
|
{ FuncDeclaration *fd = sd->postblit;
|
|
elem *ec = el_copytree(evalue);
|
|
ec = el_una(OPaddr, TYnptr, ec);
|
|
ec = callfunc(loc, irs, 1, Type::tvoid, ec, sd->type->pointerTo(), fd, fd->type, NULL, NULL);
|
|
e = el_combine(e, ec);
|
|
}
|
|
#endif
|
|
}
|
|
else if (tybasic(tym) == TYarray)
|
|
{
|
|
if (sd)
|
|
{
|
|
/* Generate:
|
|
* _d_arrayctor(ti, efrom, eto)
|
|
*/
|
|
Expression *ti = value->type->toBasetype()->nextOf()->toBasetype()->getTypeInfo(NULL);
|
|
elem *esize = el_long(TYsize_t, ((TypeSArray *)value->type->toBasetype())->dim->toInteger());
|
|
elem *eto = el_pair(TYdarray, esize, el_una(OPaddr, TYnptr, evalue));
|
|
elem *efrom = el_pair(TYdarray, el_copytree(esize), e);
|
|
elem *ep = el_params(eto, efrom, ti->toElem(irs), NULL);
|
|
int rtl = RTLSYM_ARRAYCTOR;
|
|
e = el_bin(OPcall, TYvoid, el_var(rtlsym[rtl]), ep);
|
|
}
|
|
else
|
|
{
|
|
e = el_bin(OPeq, tym, evalue, el_una(OPind, tym, e));
|
|
e->Eoper = OPstreq;
|
|
e->Ejty = e->Ety = TYstruct;
|
|
e->ET = value->type->toCtype();
|
|
}
|
|
}
|
|
else
|
|
e = el_bin(OPeq, tym, evalue, el_una(OPind, tym, e));
|
|
}
|
|
incUsage(irs, loc);
|
|
block_appendexp(blx->curblock, e);
|
|
|
|
bbody = blx->curblock;
|
|
if (body)
|
|
body->toIR(&mystate);
|
|
bbodyx = blx->curblock;
|
|
block_next(blx,BCgoto,mystate.contBlock);
|
|
|
|
if (op == TOKforeach)
|
|
{
|
|
if (key)
|
|
{ // Construct (skey += 1)
|
|
e = el_bin(OPaddass, keytym, el_var(skey), el_long(keytym, 1));
|
|
}
|
|
else
|
|
{ // Construct (sp++)
|
|
e = el_bin(OPaddass, TYnptr, el_var(sp), el_long(TYsize_t, tab->nextOf()->size()));
|
|
}
|
|
mystate.contBlock->Belem = e;
|
|
}
|
|
block_next(blx,BCgoto,mystate.breakBlock);
|
|
|
|
list_append(&bpre->Bsucc,bcond);
|
|
list_append(&bcond->Bsucc,bbody);
|
|
list_append(&bcond->Bsucc,mystate.breakBlock);
|
|
list_append(&bbodyx->Bsucc,mystate.contBlock);
|
|
list_append(&mystate.contBlock->Bsucc,bcond);
|
|
#endif
|
|
}
|
|
|
|
|
|
/**************************************
|
|
*/
|
|
|
|
#if DMDV2
|
|
void ForeachRangeStatement::toIR(IRState *irs)
|
|
{
|
|
assert(0);
|
|
#if 0
|
|
Type *tab;
|
|
elem *eaggr;
|
|
elem *elwr;
|
|
elem *eupr;
|
|
elem *e;
|
|
elem *elength;
|
|
tym_t keytym;
|
|
|
|
//printf("ForeachStatement::toIR()\n");
|
|
block *bpre;
|
|
block *bcond;
|
|
block *bbody;
|
|
block *bbodyx;
|
|
Blockx *blx = irs->blx;
|
|
|
|
IRState mystate(irs,this);
|
|
mystate.breakBlock = block_calloc(blx);
|
|
mystate.contBlock = block_calloc(blx);
|
|
|
|
incUsage(irs, lwr->loc);
|
|
elwr = lwr->toElem(irs);
|
|
|
|
incUsage(irs, upr->loc);
|
|
eupr = upr->toElem(irs);
|
|
|
|
/* Create skey, the index to the array.
|
|
* Initialize skey to elwr (foreach) or eupr (foreach_reverse).
|
|
*/
|
|
Symbol *skey = key->toSymbol();
|
|
symbol_add(skey);
|
|
keytym = key->type->totym();
|
|
|
|
elem *ekey;
|
|
if (key->offset) // if key is member of a closure
|
|
{
|
|
assert(irs->sclosure);
|
|
ekey = el_var(irs->sclosure);
|
|
ekey = el_bin(OPadd, TYnptr, ekey, el_long(TYint, key->offset));
|
|
ekey = el_una(OPind, keytym, ekey);
|
|
}
|
|
else
|
|
ekey = el_var(skey);
|
|
|
|
elem *einit = (op == TOKforeach_reverse) ? eupr : elwr;
|
|
e = el_bin(OPeq, keytym, ekey, einit); // skey = einit;
|
|
block_appendexp(blx->curblock, e);
|
|
|
|
/* Make a copy of the end condition, so it only
|
|
* gets evaluated once.
|
|
*/
|
|
elem *eend = (op == TOKforeach_reverse) ? elwr : eupr;
|
|
Symbol *send = symbol_genauto(eend);
|
|
e = el_bin(OPeq, eend->Ety, el_var(send), eend);
|
|
assert(tybasic(e->Ety) != TYstruct);
|
|
block_appendexp(blx->curblock, e);
|
|
|
|
bpre = blx->curblock;
|
|
block_next(blx,BCgoto,NULL);
|
|
bcond = blx->curblock;
|
|
|
|
if (op == TOKforeach_reverse)
|
|
{
|
|
// Construct (key > elwr)
|
|
e = el_bin(OPgt, TYint, el_copytree(ekey), el_var(send));
|
|
}
|
|
else
|
|
{
|
|
// Construct (key < eupr)
|
|
e = el_bin(OPlt, TYint, el_copytree(ekey), el_var(send));
|
|
}
|
|
|
|
// The size of the increment
|
|
size_t sz = 1;
|
|
Type *tkeyb = key->type->toBasetype();
|
|
if (tkeyb->ty == Tpointer)
|
|
sz = tkeyb->nextOf()->size();
|
|
|
|
bcond->Belem = e;
|
|
block_next(blx, BCiftrue, NULL);
|
|
|
|
if (op == TOKforeach_reverse)
|
|
{
|
|
// Construct (skey -= 1)
|
|
e = el_bin(OPminass, keytym, el_copytree(ekey), el_long(keytym, sz));
|
|
block_appendexp(blx->curblock, e);
|
|
}
|
|
|
|
bbody = blx->curblock;
|
|
if (body)
|
|
body->toIR(&mystate);
|
|
bbodyx = blx->curblock;
|
|
block_next(blx,BCgoto,mystate.contBlock);
|
|
|
|
if (op == TOKforeach)
|
|
{
|
|
// Construct (skey += 1)
|
|
e = el_bin(OPaddass, keytym, el_copytree(ekey), el_long(keytym, sz));
|
|
mystate.contBlock->Belem = e;
|
|
}
|
|
block_next(blx,BCgoto,mystate.breakBlock);
|
|
|
|
list_append(&bpre->Bsucc,bcond);
|
|
list_append(&bcond->Bsucc,bbody);
|
|
list_append(&bcond->Bsucc,mystate.breakBlock);
|
|
list_append(&bbodyx->Bsucc,mystate.contBlock);
|
|
list_append(&mystate.contBlock->Bsucc,bcond);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
|
|
/****************************************
|
|
*/
|
|
|
|
void BreakStatement::toIR(IRState *irs)
|
|
{
|
|
block *bbreak;
|
|
block *b;
|
|
Blockx *blx = irs->blx;
|
|
|
|
bbreak = irs->getBreakBlock(ident);
|
|
assert(bbreak);
|
|
b = blx->curblock;
|
|
incUsage(irs, loc);
|
|
|
|
// Adjust exception handler scope index if in different try blocks
|
|
if (b->Btry != bbreak->Btry)
|
|
{
|
|
//setScopeIndex(blx, b, bbreak->Btry ? bbreak->Btry->Bscope_index : -1);
|
|
}
|
|
|
|
/* Nothing more than a 'goto' to the current break destination
|
|
*/
|
|
list_append(&b->Bsucc, bbreak);
|
|
block_next(blx, BCgoto, NULL);
|
|
}
|
|
|
|
/************************************
|
|
*/
|
|
|
|
void ContinueStatement::toIR(IRState *irs)
|
|
{
|
|
block *bcont;
|
|
block *b;
|
|
Blockx *blx = irs->blx;
|
|
|
|
//printf("ContinueStatement::toIR() %p\n", this);
|
|
bcont = irs->getContBlock(ident);
|
|
assert(bcont);
|
|
b = blx->curblock;
|
|
incUsage(irs, loc);
|
|
|
|
// Adjust exception handler scope index if in different try blocks
|
|
if (b->Btry != bcont->Btry)
|
|
{
|
|
//setScopeIndex(blx, b, bcont->Btry ? bcont->Btry->Bscope_index : -1);
|
|
}
|
|
|
|
/* Nothing more than a 'goto' to the current continue destination
|
|
*/
|
|
list_append(&b->Bsucc, bcont);
|
|
block_next(blx, BCgoto, NULL);
|
|
}
|
|
|
|
/**************************************
|
|
*/
|
|
|
|
void el_setVolatile(elem *e)
|
|
{
|
|
elem_debug(e);
|
|
while (1)
|
|
{
|
|
e->Ety |= mTYvolatile;
|
|
if (OTunary(e->Eoper))
|
|
e = e->E1;
|
|
else if (OTbinary(e->Eoper))
|
|
{ el_setVolatile(e->E2);
|
|
e = e->E1;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
void VolatileStatement::toIR(IRState *irs)
|
|
{
|
|
block *b;
|
|
|
|
if (statement)
|
|
{
|
|
Blockx *blx = irs->blx;
|
|
|
|
block_goto(blx, BCgoto, NULL);
|
|
b = blx->curblock;
|
|
|
|
statement->toIR(irs);
|
|
|
|
block_goto(blx, BCgoto, NULL);
|
|
|
|
// Mark the blocks generated as volatile
|
|
for (; b != blx->curblock; b = b->Bnext)
|
|
{ b->Bflags |= BFLvolatile;
|
|
if (b->Belem)
|
|
el_setVolatile(b->Belem);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************
|
|
*/
|
|
|
|
void GotoStatement::toIR(IRState *irs)
|
|
{
|
|
Blockx *blx = irs->blx;
|
|
|
|
if (!label->statement)
|
|
{ error("label %s is undefined", label->toChars());
|
|
return;
|
|
}
|
|
if (tf != label->statement->tf)
|
|
error("cannot goto forward out of or into finally block");
|
|
|
|
block *bdest = labelToBlock(loc, blx, label, 1);
|
|
if (!bdest)
|
|
return;
|
|
block *b = blx->curblock;
|
|
incUsage(irs, loc);
|
|
|
|
if (b->Btry != bdest->Btry)
|
|
{
|
|
// Check that bdest is in an enclosing try block
|
|
for (block *bt = b->Btry; bt != bdest->Btry; bt = bt->Btry)
|
|
{
|
|
if (!bt)
|
|
{
|
|
//printf("b->Btry = %p, bdest->Btry = %p\n", b->Btry, bdest->Btry);
|
|
error("cannot goto into try block");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
list_append(&b->Bsucc,bdest);
|
|
block_next(blx,BCgoto,NULL);
|
|
}
|
|
|
|
void LabelStatement::toIR(IRState *irs)
|
|
{
|
|
//printf("LabelStatement::toIR() %p, statement = %p\n", this, statement);
|
|
Blockx *blx = irs->blx;
|
|
block *bc = blx->curblock;
|
|
IRState mystate(irs,this);
|
|
mystate.ident = ident;
|
|
|
|
if (lblock)
|
|
{
|
|
// At last, we know which try block this label is inside
|
|
lblock->Btry = blx->tryblock;
|
|
|
|
/* Go through the forward references and check.
|
|
*/
|
|
if (fwdrefs)
|
|
{
|
|
for (size_t i = 0; i < fwdrefs->dim; i++)
|
|
{ block *b = fwdrefs->tdata()[i];
|
|
|
|
if (b->Btry != lblock->Btry)
|
|
{
|
|
// Check that lblock is in an enclosing try block
|
|
for (block *bt = b->Btry; bt != lblock->Btry; bt = bt->Btry)
|
|
{
|
|
if (!bt)
|
|
{
|
|
//printf("b->Btry = %p, lblock->Btry = %p\n", b->Btry, lblock->Btry);
|
|
error("cannot goto into try block");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
delete fwdrefs;
|
|
fwdrefs = NULL;
|
|
}
|
|
}
|
|
else
|
|
lblock = block_calloc(blx);
|
|
block_next(blx,BCgoto,lblock);
|
|
list_append(&bc->Bsucc,blx->curblock);
|
|
if (statement)
|
|
statement->toIR(&mystate);
|
|
}
|
|
|
|
/**************************************
|
|
*/
|
|
|
|
void SwitchStatement::toIR(IRState *irs)
|
|
{
|
|
int string;
|
|
Blockx *blx = irs->blx;
|
|
|
|
//printf("SwitchStatement::toIR()\n");
|
|
IRState mystate(irs,this);
|
|
|
|
mystate.switchBlock = blx->curblock;
|
|
|
|
/* Block for where "break" goes to
|
|
*/
|
|
mystate.breakBlock = block_calloc(blx);
|
|
|
|
/* Block for where "default" goes to.
|
|
* If there is a default statement, then that is where default goes.
|
|
* If not, then do:
|
|
* default: break;
|
|
* by making the default block the same as the break block.
|
|
*/
|
|
mystate.defaultBlock = sdefault ? block_calloc(blx) : mystate.breakBlock;
|
|
|
|
int numcases = 0;
|
|
if (cases)
|
|
numcases = cases->dim;
|
|
|
|
incUsage(irs, loc);
|
|
elem *econd = condition->toElemDtor(&mystate);
|
|
#if DMDV2
|
|
if (hasVars)
|
|
{ /* Generate a sequence of if-then-else blocks for the cases.
|
|
*/
|
|
if (econd->Eoper != OPvar)
|
|
{
|
|
elem *e = exp2_copytotemp(econd);
|
|
block_appendexp(mystate.switchBlock, e);
|
|
econd = e->E2;
|
|
}
|
|
|
|
for (int i = 0; i < numcases; i++)
|
|
{ CaseStatement *cs = cases->tdata()[i];
|
|
|
|
elem *ecase = cs->exp->toElemDtor(&mystate);
|
|
elem *e = el_bin(OPeqeq, TYbool, el_copytree(econd), ecase);
|
|
block *b = blx->curblock;
|
|
block_appendexp(b, e);
|
|
block *bcase = block_calloc(blx);
|
|
cs->cblock = bcase;
|
|
block_next(blx, BCiftrue, NULL);
|
|
list_append(&b->Bsucc, bcase);
|
|
list_append(&b->Bsucc, blx->curblock);
|
|
}
|
|
|
|
/* The final 'else' clause goes to the default
|
|
*/
|
|
block *b = blx->curblock;
|
|
block_next(blx, BCgoto, NULL);
|
|
list_append(&b->Bsucc, mystate.defaultBlock);
|
|
|
|
body->toIR(&mystate);
|
|
|
|
/* Have the end of the switch body fall through to the block
|
|
* following the switch statement.
|
|
*/
|
|
block_goto(blx, BCgoto, mystate.breakBlock);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (condition->type->isString())
|
|
{
|
|
// Number the cases so we can unscramble things after the sort()
|
|
for (int i = 0; i < numcases; i++)
|
|
{ CaseStatement *cs = cases->tdata()[i];
|
|
cs->index = i;
|
|
}
|
|
|
|
cases->sort();
|
|
|
|
/* Create a sorted array of the case strings, and si
|
|
* will be the symbol for it.
|
|
*/
|
|
dt_t *dt = NULL;
|
|
Symbol *si = symbol_generate(SCstatic,type_fake(TYdarray));
|
|
#if MACHOBJ
|
|
si->Sseg = DATA;
|
|
#endif
|
|
dtsize_t(&dt, numcases);
|
|
dtxoff(&dt, si, PTRSIZE * 2, TYnptr);
|
|
|
|
for (int i = 0; i < numcases; i++)
|
|
{ CaseStatement *cs = cases->tdata()[i];
|
|
|
|
if (cs->exp->op != TOKstring)
|
|
{ error("case '%s' is not a string", cs->exp->toChars()); // BUG: this should be an assert
|
|
}
|
|
else
|
|
{
|
|
StringExp *se = (StringExp *)(cs->exp);
|
|
unsigned len = se->len;
|
|
dtsize_t(&dt, len);
|
|
dtabytes(&dt, TYnptr, 0, se->len * se->sz, (char *)se->string);
|
|
}
|
|
}
|
|
|
|
si->Sdt = dt;
|
|
si->Sfl = FLdata;
|
|
outdata(si);
|
|
|
|
/* Call:
|
|
* _d_switch_string(string[] si, string econd)
|
|
*/
|
|
elem *eparam = el_param(econd, el_var(si));
|
|
switch (condition->type->nextOf()->ty)
|
|
{
|
|
case Tchar:
|
|
econd = el_bin(OPcall, TYint, el_var(rtlsym[RTLSYM_SWITCH_STRING]), eparam);
|
|
break;
|
|
case Twchar:
|
|
econd = el_bin(OPcall, TYint, el_var(rtlsym[RTLSYM_SWITCH_USTRING]), eparam);
|
|
break;
|
|
case Tdchar: // BUG: implement
|
|
econd = el_bin(OPcall, TYint, el_var(rtlsym[RTLSYM_SWITCH_DSTRING]), eparam);
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
elem_setLoc(econd, loc);
|
|
string = 1;
|
|
}
|
|
else
|
|
string = 0;
|
|
block_appendexp(mystate.switchBlock, econd);
|
|
block_next(blx,BCswitch,NULL);
|
|
|
|
// Corresponding free is in block_free
|
|
targ_llong *pu = (targ_llong *) ::malloc(sizeof(*pu) * (numcases + 1));
|
|
mystate.switchBlock->BS.Bswitch = pu;
|
|
/* First pair is the number of cases, and the default block
|
|
*/
|
|
*pu++ = numcases;
|
|
list_append(&mystate.switchBlock->Bsucc, mystate.defaultBlock);
|
|
|
|
/* Fill in the first entry in each pair, which is the case value.
|
|
* CaseStatement::toIR() will fill in
|
|
* the second entry for each pair with the block.
|
|
*/
|
|
for (int i = 0; i < numcases; i++)
|
|
{
|
|
CaseStatement *cs = cases->tdata()[i];
|
|
if (string)
|
|
{
|
|
pu[cs->index] = i;
|
|
}
|
|
else
|
|
{
|
|
pu[i] = cs->exp->toInteger();
|
|
}
|
|
}
|
|
|
|
body->toIR(&mystate);
|
|
|
|
/* Have the end of the switch body fall through to the block
|
|
* following the switch statement.
|
|
*/
|
|
block_goto(blx, BCgoto, mystate.breakBlock);
|
|
}
|
|
|
|
void CaseStatement::toIR(IRState *irs)
|
|
{
|
|
Blockx *blx = irs->blx;
|
|
block *bcase = blx->curblock;
|
|
if (!cblock)
|
|
cblock = block_calloc(blx);
|
|
block_next(blx,BCgoto,cblock);
|
|
block *bsw = irs->getSwitchBlock();
|
|
if (bsw->BC == BCswitch)
|
|
list_append(&bsw->Bsucc,cblock); // second entry in pair
|
|
list_append(&bcase->Bsucc,cblock);
|
|
if (blx->tryblock != bsw->Btry)
|
|
error("case cannot be in different try block level from switch");
|
|
incUsage(irs, loc);
|
|
if (statement)
|
|
statement->toIR(irs);
|
|
}
|
|
|
|
void DefaultStatement::toIR(IRState *irs)
|
|
{
|
|
Blockx *blx = irs->blx;
|
|
block *bcase = blx->curblock;
|
|
block *bdefault = irs->getDefaultBlock();
|
|
block_next(blx,BCgoto,bdefault);
|
|
list_append(&bcase->Bsucc,blx->curblock);
|
|
if (blx->tryblock != irs->getSwitchBlock()->Btry)
|
|
error("default cannot be in different try block level from switch");
|
|
incUsage(irs, loc);
|
|
if (statement)
|
|
statement->toIR(irs);
|
|
}
|
|
|
|
void GotoDefaultStatement::toIR(IRState *irs)
|
|
{
|
|
block *b;
|
|
Blockx *blx = irs->blx;
|
|
block *bdest = irs->getDefaultBlock();
|
|
|
|
b = blx->curblock;
|
|
|
|
// The rest is equivalent to GotoStatement
|
|
|
|
// Adjust exception handler scope index if in different try blocks
|
|
if (b->Btry != bdest->Btry)
|
|
{
|
|
// Check that bdest is in an enclosing try block
|
|
for (block *bt = b->Btry; bt != bdest->Btry; bt = bt->Btry)
|
|
{
|
|
if (!bt)
|
|
{
|
|
//printf("b->Btry = %p, bdest->Btry = %p\n", b->Btry, bdest->Btry);
|
|
error("cannot goto into try block");
|
|
break;
|
|
}
|
|
}
|
|
|
|
//setScopeIndex(blx, b, bdest->Btry ? bdest->Btry->Bscope_index : -1);
|
|
}
|
|
|
|
list_append(&b->Bsucc,bdest);
|
|
incUsage(irs, loc);
|
|
block_next(blx,BCgoto,NULL);
|
|
}
|
|
|
|
void GotoCaseStatement::toIR(IRState *irs)
|
|
{
|
|
block *b;
|
|
Blockx *blx = irs->blx;
|
|
block *bdest = cs->cblock;
|
|
|
|
if (!bdest)
|
|
{
|
|
bdest = block_calloc(blx);
|
|
cs->cblock = bdest;
|
|
}
|
|
|
|
b = blx->curblock;
|
|
|
|
// The rest is equivalent to GotoStatement
|
|
|
|
// Adjust exception handler scope index if in different try blocks
|
|
if (b->Btry != bdest->Btry)
|
|
{
|
|
// Check that bdest is in an enclosing try block
|
|
for (block *bt = b->Btry; bt != bdest->Btry; bt = bt->Btry)
|
|
{
|
|
if (!bt)
|
|
{
|
|
//printf("b->Btry = %p, bdest->Btry = %p\n", b->Btry, bdest->Btry);
|
|
error("cannot goto into try block");
|
|
break;
|
|
}
|
|
}
|
|
|
|
//setScopeIndex(blx, b, bdest->Btry ? bdest->Btry->Bscope_index : -1);
|
|
}
|
|
|
|
list_append(&b->Bsucc,bdest);
|
|
incUsage(irs, loc);
|
|
block_next(blx,BCgoto,NULL);
|
|
}
|
|
|
|
void SwitchErrorStatement::toIR(IRState *irs)
|
|
{
|
|
Blockx *blx = irs->blx;
|
|
|
|
//printf("SwitchErrorStatement::toIR()\n");
|
|
|
|
elem *efilename = el_ptr(blx->module->toSymbol());
|
|
elem *elinnum = el_long(TYint, loc.linnum);
|
|
elem *e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_DSWITCHERR]), el_param(elinnum, efilename));
|
|
block_appendexp(blx->curblock, e);
|
|
}
|
|
|
|
/**************************************
|
|
*/
|
|
|
|
void ReturnStatement::toIR(IRState *irs)
|
|
{
|
|
Blockx *blx = irs->blx;
|
|
|
|
incUsage(irs, loc);
|
|
if (exp)
|
|
{ elem *e;
|
|
|
|
FuncDeclaration *func = irs->getFunc();
|
|
assert(func);
|
|
assert(func->type->ty == Tfunction);
|
|
TypeFunction *tf = (TypeFunction *)(func->type);
|
|
|
|
enum RET retmethod = tf->retStyle();
|
|
if (retmethod == RETstack)
|
|
{
|
|
elem *es;
|
|
|
|
/* If returning struct literal, write result
|
|
* directly into return value
|
|
*/
|
|
if (exp->op == TOKstructliteral)
|
|
{ StructLiteralExp *se = (StructLiteralExp *)exp;
|
|
char save[sizeof(StructLiteralExp)];
|
|
memcpy(save, se, sizeof(StructLiteralExp));
|
|
se->sym = irs->shidden;
|
|
se->soffset = 0;
|
|
se->fillHoles = 1;
|
|
e = exp->toElemDtor(irs);
|
|
memcpy(se, save, sizeof(StructLiteralExp));
|
|
|
|
}
|
|
else
|
|
e = exp->toElemDtor(irs);
|
|
assert(e);
|
|
|
|
if (exp->op == TOKstructliteral ||
|
|
(func->nrvo_can && func->nrvo_var))
|
|
{
|
|
// Return value via hidden pointer passed as parameter
|
|
// Write exp; return shidden;
|
|
es = e;
|
|
}
|
|
else
|
|
{
|
|
// Return value via hidden pointer passed as parameter
|
|
// Write *shidden=exp; return shidden;
|
|
int op;
|
|
tym_t ety;
|
|
|
|
ety = e->Ety;
|
|
es = el_una(OPind,ety,el_var(irs->shidden));
|
|
op = (tybasic(ety) == TYstruct) ? OPstreq : OPeq;
|
|
es = el_bin(op, ety, es, e);
|
|
if (op == OPstreq)
|
|
es->ET = exp->type->toCtype();
|
|
#if DMDV2
|
|
/* Call postBlit() on *shidden
|
|
*/
|
|
Type *tb = exp->type->toBasetype();
|
|
//if (tb->ty == Tstruct) exp->dump(0);
|
|
if ((exp->op == TOKvar || exp->op == TOKdotvar || exp->op == TOKstar || exp->op == TOKthis) &&
|
|
tb->ty == Tstruct)
|
|
{ StructDeclaration *sd = ((TypeStruct *)tb)->sym;
|
|
if (sd->postblit)
|
|
{ FuncDeclaration *fd = sd->postblit;
|
|
if (fd->storage_class & STCdisable)
|
|
{
|
|
fd->toParent()->error(loc, "is not copyable because it is annotated with @disable");
|
|
}
|
|
elem *ec = el_var(irs->shidden);
|
|
ec = callfunc(loc, irs, 1, Type::tvoid, ec, tb->pointerTo(), fd, fd->type, NULL, NULL);
|
|
es = el_bin(OPcomma, ec->Ety, es, ec);
|
|
}
|
|
|
|
#if 0
|
|
/* It has been moved, so disable destructor
|
|
*/
|
|
if (exp->op == TOKvar)
|
|
{ VarExp *ve = (VarExp *)exp;
|
|
VarDeclaration *v = ve->var->isVarDeclaration();
|
|
if (v && v->rundtor)
|
|
{
|
|
elem *er = el_var(v->rundtor->toSymbol());
|
|
er = el_bin(OPeq, TYint, er, el_long(TYint, 0));
|
|
es = el_bin(OPcomma, TYint, es, er);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
e = el_var(irs->shidden);
|
|
e = el_bin(OPcomma, e->Ety, es, e);
|
|
}
|
|
#if DMDV2
|
|
else if (tf->isref)
|
|
{ // Reference return, so convert to a pointer
|
|
Expression *ae = exp->addressOf(NULL);
|
|
e = ae->toElemDtor(irs);
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
e = exp->toElemDtor(irs);
|
|
assert(e);
|
|
}
|
|
|
|
elem_setLoc(e, loc);
|
|
block_appendexp(blx->curblock, e);
|
|
block_next(blx, BCretexp, NULL);
|
|
}
|
|
else
|
|
block_next(blx, BCret, NULL);
|
|
}
|
|
|
|
/**************************************
|
|
*/
|
|
|
|
void ExpStatement::toIR(IRState *irs)
|
|
{
|
|
Blockx *blx = irs->blx;
|
|
|
|
//printf("ExpStatement::toIR(), exp = %s\n", exp ? exp->toChars() : "");
|
|
incUsage(irs, loc);
|
|
if (exp)
|
|
block_appendexp(blx->curblock,exp->toElemDtor(irs));
|
|
}
|
|
|
|
/**************************************
|
|
*/
|
|
|
|
void DtorExpStatement::toIR(IRState *irs)
|
|
{
|
|
//printf("DtorExpStatement::toIR(), exp = %s\n", exp ? exp->toChars() : "");
|
|
|
|
FuncDeclaration *fd = irs->getFunc();
|
|
assert(fd);
|
|
if (fd->nrvo_can && fd->nrvo_var == var)
|
|
/* Do not call destructor, because var is returned as the nrvo variable.
|
|
* This is done at this stage because nrvo can be turned off at a
|
|
* very late stage in semantic analysis.
|
|
*/
|
|
;
|
|
else
|
|
{
|
|
ExpStatement::toIR(irs);
|
|
}
|
|
}
|
|
|
|
/**************************************
|
|
*/
|
|
|
|
void CompoundStatement::toIR(IRState *irs)
|
|
{
|
|
if (statements)
|
|
{
|
|
size_t dim = statements->dim;
|
|
for (size_t i = 0 ; i < dim ; i++)
|
|
{
|
|
Statement *s = statements->tdata()[i];
|
|
if (s != NULL)
|
|
{
|
|
s->toIR(irs);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************
|
|
*/
|
|
|
|
void UnrolledLoopStatement::toIR(IRState *irs)
|
|
{
|
|
Blockx *blx = irs->blx;
|
|
|
|
IRState mystate(irs, this);
|
|
mystate.breakBlock = block_calloc(blx);
|
|
|
|
block *bpre = blx->curblock;
|
|
block_next(blx, BCgoto, NULL);
|
|
|
|
block *bdo = blx->curblock;
|
|
list_append(&bpre->Bsucc, bdo);
|
|
|
|
block *bdox;
|
|
|
|
size_t dim = statements->dim;
|
|
for (size_t i = 0 ; i < dim ; i++)
|
|
{
|
|
Statement *s = statements->tdata()[i];
|
|
if (s != NULL)
|
|
{
|
|
mystate.contBlock = block_calloc(blx);
|
|
|
|
s->toIR(&mystate);
|
|
|
|
bdox = blx->curblock;
|
|
block_next(blx, BCgoto, mystate.contBlock);
|
|
list_append(&bdox->Bsucc, mystate.contBlock);
|
|
}
|
|
}
|
|
|
|
bdox = blx->curblock;
|
|
block_next(blx, BCgoto, mystate.breakBlock);
|
|
list_append(&bdox->Bsucc, mystate.breakBlock);
|
|
}
|
|
|
|
|
|
/**************************************
|
|
*/
|
|
|
|
void ScopeStatement::toIR(IRState *irs)
|
|
{
|
|
if (statement)
|
|
{
|
|
Blockx *blx = irs->blx;
|
|
IRState mystate(irs,this);
|
|
|
|
if (mystate.prev->ident)
|
|
mystate.ident = mystate.prev->ident;
|
|
|
|
statement->toIR(&mystate);
|
|
|
|
if (mystate.breakBlock)
|
|
block_goto(blx,BCgoto,mystate.breakBlock);
|
|
}
|
|
}
|
|
|
|
/***************************************
|
|
*/
|
|
|
|
void WithStatement::toIR(IRState *irs)
|
|
{
|
|
Symbol *sp;
|
|
elem *e;
|
|
elem *ei;
|
|
ExpInitializer *ie;
|
|
Blockx *blx = irs->blx;
|
|
|
|
//printf("WithStatement::toIR()\n");
|
|
if (exp->op == TOKimport || exp->op == TOKtype)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
// Declare with handle
|
|
sp = wthis->toSymbol();
|
|
symbol_add(sp);
|
|
|
|
// Perform initialization of with handle
|
|
ie = wthis->init->isExpInitializer();
|
|
assert(ie);
|
|
ei = ie->exp->toElemDtor(irs);
|
|
e = el_var(sp);
|
|
e = el_bin(OPeq,e->Ety, e, ei);
|
|
elem_setLoc(e, loc);
|
|
incUsage(irs, loc);
|
|
block_appendexp(blx->curblock,e);
|
|
}
|
|
// Execute with block
|
|
if (body)
|
|
body->toIR(irs);
|
|
}
|
|
|
|
|
|
/***************************************
|
|
*/
|
|
|
|
void ThrowStatement::toIR(IRState *irs)
|
|
{
|
|
// throw(exp)
|
|
|
|
Blockx *blx = irs->blx;
|
|
|
|
incUsage(irs, loc);
|
|
elem *e = exp->toElemDtor(irs);
|
|
e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_THROWC]),e);
|
|
block_appendexp(blx->curblock, e);
|
|
}
|
|
|
|
/***************************************
|
|
* Builds the following:
|
|
* _try
|
|
* block
|
|
* jcatch
|
|
* handler
|
|
* A try-catch statement.
|
|
*/
|
|
|
|
void TryCatchStatement::toIR(IRState *irs)
|
|
{
|
|
Blockx *blx = irs->blx;
|
|
|
|
#if SEH
|
|
nteh_declarvars(blx);
|
|
#endif
|
|
|
|
IRState mystate(irs, this);
|
|
|
|
block *tryblock = block_goto(blx,BCgoto,NULL);
|
|
|
|
int previndex = blx->scope_index;
|
|
tryblock->Blast_index = previndex;
|
|
blx->scope_index = tryblock->Bscope_index = blx->next_index++;
|
|
|
|
// Set the current scope index
|
|
setScopeIndex(blx,tryblock,tryblock->Bscope_index);
|
|
|
|
// This is the catch variable
|
|
tryblock->jcatchvar = symbol_genauto(type_fake(mTYvolatile | TYnptr));
|
|
|
|
blx->tryblock = tryblock;
|
|
block *breakblock = block_calloc(blx);
|
|
block_goto(blx,BC_try,NULL);
|
|
if (body)
|
|
{
|
|
body->toIR(&mystate);
|
|
}
|
|
blx->tryblock = tryblock->Btry;
|
|
|
|
// break block goes here
|
|
block_goto(blx, BCgoto, breakblock);
|
|
|
|
setScopeIndex(blx,blx->curblock, previndex);
|
|
blx->scope_index = previndex;
|
|
|
|
// create new break block that follows all the catches
|
|
breakblock = block_calloc(blx);
|
|
|
|
list_append(&blx->curblock->Bsucc, breakblock);
|
|
block_next(blx,BCgoto,NULL);
|
|
|
|
assert(catches);
|
|
for (size_t i = 0 ; i < catches->dim; i++)
|
|
{
|
|
Catch *cs = catches->tdata()[i];
|
|
if (cs->var)
|
|
cs->var->csym = tryblock->jcatchvar;
|
|
block *bcatch = blx->curblock;
|
|
if (cs->type)
|
|
bcatch->Bcatchtype = cs->type->toBasetype()->toSymbol();
|
|
list_append(&tryblock->Bsucc,bcatch);
|
|
block_goto(blx,BCjcatch,NULL);
|
|
if (cs->handler != NULL)
|
|
{
|
|
IRState catchState(irs, this);
|
|
cs->handler->toIR(&catchState);
|
|
}
|
|
list_append(&blx->curblock->Bsucc, breakblock);
|
|
block_next(blx, BCgoto, NULL);
|
|
}
|
|
|
|
block_next(blx,(enum BC)blx->curblock->BC, breakblock);
|
|
}
|
|
|
|
/****************************************
|
|
* A try-finally statement.
|
|
* Builds the following:
|
|
* _try
|
|
* block
|
|
* _finally
|
|
* finalbody
|
|
* _ret
|
|
*/
|
|
|
|
void TryFinallyStatement::toIR(IRState *irs)
|
|
{
|
|
//printf("TryFinallyStatement::toIR()\n");
|
|
|
|
Blockx *blx = irs->blx;
|
|
|
|
#if SEH
|
|
nteh_declarvars(blx);
|
|
#endif
|
|
|
|
block *tryblock = block_goto(blx, BCgoto, NULL);
|
|
|
|
int previndex = blx->scope_index;
|
|
tryblock->Blast_index = previndex;
|
|
tryblock->Bscope_index = blx->next_index++;
|
|
blx->scope_index = tryblock->Bscope_index;
|
|
|
|
// Current scope index
|
|
setScopeIndex(blx,tryblock,tryblock->Bscope_index);
|
|
|
|
blx->tryblock = tryblock;
|
|
block_goto(blx,BC_try,NULL);
|
|
|
|
IRState bodyirs(irs, this);
|
|
block *breakblock = block_calloc(blx);
|
|
block *contblock = block_calloc(blx);
|
|
|
|
if (body)
|
|
body->toIR(&bodyirs);
|
|
blx->tryblock = tryblock->Btry; // back to previous tryblock
|
|
|
|
setScopeIndex(blx,blx->curblock,previndex);
|
|
blx->scope_index = previndex;
|
|
|
|
block_goto(blx,BCgoto, breakblock);
|
|
block *finallyblock = block_goto(blx,BCgoto,contblock);
|
|
|
|
list_append(&tryblock->Bsucc,finallyblock);
|
|
|
|
block_goto(blx,BC_finally,NULL);
|
|
|
|
IRState finallyState(irs, this);
|
|
breakblock = block_calloc(blx);
|
|
contblock = block_calloc(blx);
|
|
|
|
setScopeIndex(blx, blx->curblock, previndex);
|
|
if (finalbody)
|
|
finalbody->toIR(&finallyState);
|
|
block_goto(blx, BCgoto, contblock);
|
|
block_goto(blx, BCgoto, breakblock);
|
|
|
|
block *retblock = blx->curblock;
|
|
block_next(blx,BC_ret,NULL);
|
|
|
|
list_append(&finallyblock->Bsucc, blx->curblock);
|
|
list_append(&retblock->Bsucc, blx->curblock);
|
|
}
|
|
|
|
/****************************************
|
|
*/
|
|
|
|
void SynchronizedStatement::toIR(IRState *irs)
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
|
|
/****************************************
|
|
*/
|
|
|
|
void AsmStatement::toIR(IRState *irs)
|
|
{
|
|
block *bpre;
|
|
block *basm;
|
|
Declaration *d;
|
|
Symbol *s;
|
|
Blockx *blx = irs->blx;
|
|
|
|
//printf("AsmStatement::toIR(asmcode = %x)\n", asmcode);
|
|
bpre = blx->curblock;
|
|
block_next(blx,BCgoto,NULL);
|
|
basm = blx->curblock;
|
|
list_append(&bpre->Bsucc, basm);
|
|
basm->Bcode = asmcode;
|
|
basm->Balign = asmalign;
|
|
#if 0
|
|
if (label)
|
|
{ block *b;
|
|
|
|
b = labelToBlock(loc, blx, label);
|
|
printf("AsmStatement::toIR() %p\n", b);
|
|
if (b)
|
|
list_append(&basm->Bsucc, b);
|
|
}
|
|
#endif
|
|
// Loop through each instruction, fixing Dsymbols into Symbol's
|
|
for (code *c = asmcode; c; c = c->next)
|
|
{ LabelDsymbol *label;
|
|
block *b;
|
|
|
|
switch (c->IFL1)
|
|
{
|
|
case FLblockoff:
|
|
case FLblock:
|
|
// FLblock and FLblockoff have LabelDsymbol's - convert to blocks
|
|
label = c->IEVlsym1;
|
|
b = labelToBlock(loc, blx, label);
|
|
list_append(&basm->Bsucc, b);
|
|
c->IEV1.Vblock = b;
|
|
break;
|
|
|
|
case FLdsymbol:
|
|
case FLfunc:
|
|
s = c->IEVdsym1->toSymbol();
|
|
if (s->Sclass == SCauto && s->Ssymnum == -1)
|
|
symbol_add(s);
|
|
c->IEVsym1 = s;
|
|
c->IFL1 = s->Sfl ? s->Sfl : FLauto;
|
|
break;
|
|
}
|
|
|
|
// Repeat for second operand
|
|
switch (c->IFL2)
|
|
{
|
|
case FLblockoff:
|
|
case FLblock:
|
|
label = c->IEVlsym2;
|
|
b = labelToBlock(loc, blx, label);
|
|
list_append(&basm->Bsucc, b);
|
|
c->IEV2.Vblock = b;
|
|
break;
|
|
|
|
case FLdsymbol:
|
|
case FLfunc:
|
|
d = c->IEVdsym2;
|
|
s = d->toSymbol();
|
|
if (s->Sclass == SCauto && s->Ssymnum == -1)
|
|
symbol_add(s);
|
|
c->IEVsym2 = s;
|
|
c->IFL2 = s->Sfl ? s->Sfl : FLauto;
|
|
if (d->isDataseg())
|
|
s->Sflags |= SFLlivexit;
|
|
break;
|
|
}
|
|
//c->print();
|
|
}
|
|
|
|
basm->bIasmrefparam = refparam; // are parameters reference?
|
|
basm->usIasmregs = regs; // registers modified
|
|
|
|
block_next(blx,BCasm, NULL);
|
|
list_prepend(&basm->Bsucc, blx->curblock);
|
|
|
|
if (naked)
|
|
{
|
|
blx->funcsym->Stype->Tty |= mTYnaked;
|
|
}
|
|
}
|
|
|
|
/****************************************
|
|
*/
|
|
|
|
void ImportStatement::toIR(IRState *irs)
|
|
{
|
|
}
|
|
|
|
|
|
|