type *type_copy(type *t) { type *tn; param_t *p; type_debug(t); if (tybasic(t->Tty) == TYtemplate) { tn = type_alloc_template(((typetemp_t *)t)->Tsym); } else tn = type_alloc(t->Tty); *tn = *t; switch (tybasic(tn->Tty)) { case TYtemplate: ((typetemp_t *)tn)->Tsym = ((typetemp_t *)t)->Tsym; goto L1; case TYident: tn->Tident = (char *)MEM_PH_STRDUP(t->Tident); break; case TYarray: if (tn->Tflags & TFvla) tn->Tel = el_copytree(tn->Tel); break; default: if (tyfunc(tn->Tty)) { L1: tn->Tparamtypes = NULL; for (p = t->Tparamtypes; p; p = p->Pnext) { param_t *pn; pn = param_append_type(&tn->Tparamtypes,p->Ptype); if (p->Pident) { pn->Pident = (char *)MEM_PH_STRDUP(p->Pident); } assert(!p->Pelem); } } #if SCPP else if (tn->Talternate && typtr(tn->Tty)) tn->Talternate->Tcount++; #endif #if MARS else if (tn->Tkey && typtr(tn->Tty)) tn->Tkey->Tcount++; #endif break; } if (tn->Tnext) { type_debug(tn->Tnext); tn->Tnext->Tcount++; } tn->Tcount = 0; return tn; }
param_t *param_t::createTal(param_t *ptali) { #if SCPP param_t *ptalistart = ptali; #endif param_t *ptal = NULL; param_t **pp = &ptal; param_t *p; for (p = this; p; p = p->Pnext) { *pp = param_calloc(); if (p->Pident) { // Should find a way to just point rather than dup (*pp)->Pident = (char *)MEM_PH_STRDUP(p->Pident); } if (ptali) { if (ptali->Ptype) { (*pp)->Ptype = ptali->Ptype; (*pp)->Ptype->Tcount++; } if (ptali->Pelem) { elem *e = el_copytree(ptali->Pelem); #if SCPP if (p->Ptype) { type *t = p->Ptype; t = template_tyident(t, ptalistart, this, 1); e = poptelem3(typechk(e, t)); type_free(t); } #endif (*pp)->Pelem = e; } (*pp)->Psym = ptali->Psym; (*pp)->Pflags = ptali->Pflags; assert(!ptali->Pptpl); ptali = ptali->Pnext; } pp = &(*pp)->Pnext; } return ptal; }
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 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 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 }
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 }