void TryFinallyStatement::toIR(IRState *irs) { //printf("TryFinallyStatement::toIR()\n"); Blockx *blx = irs->blx; #if SEH if (!global.params.is64bit) 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); tryblock->appendSucc(contblock); contblock->BC = BC_finally; 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); assert(finallyblock == contblock); 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); finallyblock->appendSucc(blx->curblock); retblock->appendSucc(blx->curblock); }
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 visit(ScopeStatement *s) { if (s->statement) { Blockx *blx = irs->blx; IRState mystate(irs,s); if (mystate.prev->ident) mystate.ident = mystate.prev->ident; Statement_toIR(s->statement, &mystate); if (mystate.breakBlock) block_goto(blx,BCgoto,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 visit(TryCatchStatement *s) { Blockx *blx = irs->blx; #if SEH if (!global.params.is64bit) nteh_declarvars(blx); #endif IRState mystate(irs, s); 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 (s->_body) { Statement_toIR(s->_body, &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); blx->curblock->appendSucc(breakblock); block_next(blx,BCgoto,NULL); assert(s->catches); for (size_t i = 0 ; i < s->catches->dim; i++) { Catch *cs = (*s->catches)[i]; if (cs->var) cs->var->csym = tryblock->jcatchvar; block *bcatch = blx->curblock; if (cs->type) bcatch->Bcatchtype = toSymbol(cs->type->toBasetype()); tryblock->appendSucc(bcatch); block_goto(blx, BCjcatch, NULL); if (cs->handler != NULL) { IRState catchState(irs, s); /* Append to block: * *(sclosure + cs.offset) = cs; */ if (cs->var && cs->var->offset) { tym_t tym = totym(cs->var->type); elem *ex = el_var(irs->sclosure); ex = el_bin(OPadd, TYnptr, ex, el_long(TYsize_t, cs->var->offset)); ex = el_una(OPind, tym, ex); ex = el_bin(OPeq, tym, ex, el_var(toSymbol(cs->var))); block_appendexp(catchState.blx->curblock, ex); } Statement_toIR(cs->handler, &catchState); } blx->curblock->appendSucc(breakblock); block_next(blx, BCgoto, NULL); } block_next(blx,(enum BC)blx->curblock->BC, breakblock); }
void visit(SwitchStatement *s) { int string; Blockx *blx = irs->blx; //printf("SwitchStatement::toIR()\n"); IRState mystate(irs,s); 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 = s->sdefault ? block_calloc(blx) : mystate.breakBlock; size_t numcases = 0; if (s->cases) numcases = s->cases->dim; incUsage(irs, s->loc); elem *econd = toElemDtor(s->condition, &mystate); if (s->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 (size_t i = 0; i < numcases; i++) { CaseStatement *cs = (*s->cases)[i]; elem *ecase = toElemDtor(cs->exp, &mystate); elem *e = el_bin(OPeqeq, TYbool, el_copytree(econd), ecase); block *b = blx->curblock; block_appendexp(b, e); Label *clabel = getLabel(irs, blx, cs); block_next(blx, BCiftrue, NULL); b->appendSucc(clabel->lblock); b->appendSucc(blx->curblock); } /* The final 'else' clause goes to the default */ block *b = blx->curblock; block_next(blx, BCgoto, NULL); b->appendSucc(mystate.defaultBlock); Statement_toIR(s->_body, &mystate); /* Have the end of the switch body fall through to the block * following the switch statement. */ block_goto(blx, BCgoto, mystate.breakBlock); return; } if (s->condition->type->isString()) { // Number the cases so we can unscramble things after the sort() for (size_t i = 0; i < numcases; i++) { CaseStatement *cs = (*s->cases)[i]; cs->index = i; } s->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)); dtsize_t(&dt, numcases); dtxoff(&dt, si, Target::ptrsize * 2, TYnptr); for (size_t i = 0; i < numcases; i++) { CaseStatement *cs = (*s->cases)[i]; if (cs->exp->op != TOKstring) { s->error("case '%s' is not a string", cs->exp->toChars()); // BUG: this should be an assert } else { StringExp *se = (StringExp *)(cs->exp); Symbol *si = toStringSymbol((char *)se->string, se->len, se->sz); dtsize_t(&dt, se->len); dtxoff(&dt, si, 0); } } si->Sdt = dt; si->Sfl = FLdata; outdata(si); /* Call: * _d_switch_string(string[] si, string econd) */ if (config.exe == EX_WIN64) econd = addressElem(econd, s->condition->type, true); elem *eparam = el_param(econd, (config.exe == EX_WIN64) ? el_ptr(si) : el_var(si)); switch (s->condition->type->nextOf()->ty) { case Tchar: econd = el_bin(OPcall, TYint, el_var(getRtlsym(RTLSYM_SWITCH_STRING)), eparam); break; case Twchar: econd = el_bin(OPcall, TYint, el_var(getRtlsym(RTLSYM_SWITCH_USTRING)), eparam); break; case Tdchar: // BUG: implement econd = el_bin(OPcall, TYint, el_var(getRtlsym(RTLSYM_SWITCH_DSTRING)), eparam); break; default: assert(0); } elem_setLoc(econd, s->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; mystate.switchBlock->appendSucc(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 (size_t i = 0; i < numcases; i++) { CaseStatement *cs = (*s->cases)[i]; if (string) { pu[cs->index] = i; } else { pu[i] = cs->exp->toInteger(); } } Statement_toIR(s->_body, &mystate); /* Have the end of the switch body fall through to the block * following the switch statement. */ block_goto(blx, BCgoto, mystate.breakBlock); }
void visit(TryFinallyStatement *s) { //printf("TryFinallyStatement::toIR()\n"); Blockx *blx = irs->blx; #if SEH if (!global.params.is64bit) 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, s); block *breakblock = block_calloc(blx); block *contblock = block_calloc(blx); tryblock->appendSucc(contblock); contblock->BC = BC_finally; bodyirs.finallyBlock = contblock; if (s->_body) Statement_toIR(s->_body, &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); assert(finallyblock == contblock); block_goto(blx,BC_finally,NULL); IRState finallyState(irs, s); breakblock = block_calloc(blx); contblock = block_calloc(blx); setScopeIndex(blx, blx->curblock, previndex); if (s->finalbody) Statement_toIR(s->finalbody, &finallyState); block_goto(blx, BCgoto, contblock); block_goto(blx, BCgoto, breakblock); block *retblock = blx->curblock; block_next(blx,BC_ret,NULL); finallyblock->appendSucc(blx->curblock); retblock->appendSucc(blx->curblock); /* The BCfinally..BC_ret blocks form a function that gets called from stack unwinding. * The successors to BC_ret blocks are both the next outer BCfinally and the destination * after the unwinding is complete. */ for (block *b = tryblock; b != finallyblock; b = b->Bnext) { block *btry = b->Btry; if (b->BC == BCgoto && b->numSucc() == 1) { block *bdest = b->nthSucc(0); if (btry && bdest->Btry != btry) { //printf("test1 b %p b->Btry %p bdest %p bdest->Btry %p\n", b, btry, bdest, bdest->Btry); block *bfinally = btry->nthSucc(1); if (bfinally == finallyblock) b->appendSucc(finallyblock); } } // If the goto exits a try block, then the finally block is also a successor if (b->BC == BCgoto && b->numSucc() == 2) // if goto exited a tryblock { block *bdest = b->nthSucc(0); // If the last finally block executed by the goto if (bdest->Btry == tryblock->Btry) // The finally block will exit and return to the destination block retblock->appendSucc(bdest); } if (b->BC == BC_ret && b->Btry == tryblock) { // b is nested inside this TryFinally, and so this finally will be called next b->appendSucc(finallyblock); } } }
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 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); }