void visit(ForStatement *s) { //printf("visit(ForStatement)) %u..%u\n", s->loc.linnum, s->endloc.linnum); Blockx *blx = irs->blx; IRState mystate(irs,s); mystate.breakBlock = block_calloc(blx); mystate.contBlock = block_calloc(blx); if (s->_init) Statement_toIR(s->_init, &mystate); block *bpre = blx->curblock; block_next(blx,BCgoto,NULL); block *bcond = blx->curblock; bpre->appendSucc(bcond); mystate.contBlock->appendSucc(bcond); if (s->condition) { incUsage(irs, s->condition->loc); block_appendexp(bcond, toElemDtor(s->condition, &mystate)); block_next(blx,BCiftrue,NULL); bcond->appendSucc(blx->curblock); bcond->appendSucc(mystate.breakBlock); } else { /* No conditional, it's a straight goto */ block_next(blx,BCgoto,NULL); bcond->appendSucc(blx->curblock); } if (s->_body) Statement_toIR(s->_body, &mystate); /* End of the body goes to the continue block */ blx->curblock->appendSucc(mystate.contBlock); block_setLoc(blx->curblock, s->endloc); block_next(blx, BCgoto, mystate.contBlock); if (s->increment) { incUsage(irs, s->increment->loc); block_appendexp(mystate.contBlock, toElemDtor(s->increment, &mystate)); } /* The 'break' block follows the for statement. */ block_next(blx,BCgoto, mystate.breakBlock); }
void visit(WithStatement *s) { Symbol *sp; elem *e; elem *ei; ExpInitializer *ie; Blockx *blx = irs->blx; //printf("WithStatement::toIR()\n"); if (s->exp->op == TOKimport || s->exp->op == TOKtype) { } else { // Declare with handle sp = toSymbol(s->wthis); symbol_add(sp); // Perform initialization of with handle ie = s->wthis->_init->isExpInitializer(); assert(ie); ei = toElemDtor(ie->exp, irs); e = el_var(sp); e = el_bin(OPeq,e->Ety, e, ei); elem_setLoc(e, s->loc); incUsage(irs, s->loc); block_appendexp(blx->curblock,e); } // Execute with block if (s->_body) Statement_toIR(s->_body, irs); }
void visit(DoStatement *s) { Blockx *blx = irs->blx; IRState mystate(irs,s); mystate.breakBlock = block_calloc(blx); mystate.contBlock = block_calloc(blx); block *bpre = blx->curblock; block_next(blx, BCgoto, NULL); bpre->appendSucc(blx->curblock); mystate.contBlock->appendSucc(blx->curblock); mystate.contBlock->appendSucc(mystate.breakBlock); if (s->_body) Statement_toIR(s->_body, &mystate); blx->curblock->appendSucc(mystate.contBlock); block_next(blx, BCgoto, mystate.contBlock); incUsage(irs, s->condition->loc); block_appendexp(mystate.contBlock, toElemDtor(s->condition, &mystate)); block_next(blx, BCiftrue, mystate.breakBlock); }
void visit(ExpStatement *s) { Blockx *blx = irs->blx; //printf("ExpStatement::toIR(), exp = %s\n", exp ? exp->toChars() : ""); incUsage(irs, s->loc); if (s->exp) block_appendexp(blx->curblock,toElemDtor(s->exp, irs)); }
void visit(ThrowStatement *s) { // throw(exp) Blockx *blx = irs->blx; incUsage(irs, s->loc); elem *e = toElemDtor(s->exp, irs); e = el_bin(OPcall, TYvoid, el_var(getRtlsym(RTLSYM_THROWC)),e); block_appendexp(blx->curblock, e); }
void visit(IfStatement *s) { elem *e; Blockx *blx = irs->blx; //printf("IfStatement::toIR('%s')\n", s->condition->toChars()); IRState mystate(irs, s); // bexit is the block that gets control after this IfStatement is done block *bexit = mystate.breakBlock ? mystate.breakBlock : block_calloc(); incUsage(irs, s->loc); e = toElemDtor(s->condition, &mystate); block_appendexp(blx->curblock, e); block *bcond = blx->curblock; block_next(blx, BCiftrue, NULL); bcond->appendSucc(blx->curblock); if (s->ifbody) Statement_toIR(s->ifbody, &mystate); blx->curblock->appendSucc(bexit); if (s->elsebody) { block_next(blx, BCgoto, NULL); bcond->appendSucc(blx->curblock); Statement_toIR(s->elsebody, &mystate); blx->curblock->appendSucc(bexit); } else bcond->appendSucc(bexit); block_next(blx, BCgoto, bexit); }
void visit(ReturnStatement *s) { Blockx *blx = irs->blx; enum BC bc; incUsage(irs, s->loc); if (s->exp) { elem *e; FuncDeclaration *func = irs->getFunc(); assert(func); assert(func->type->ty == Tfunction); TypeFunction *tf = (TypeFunction *)(func->type); RET retmethod = retStyle(tf); if (retmethod == RETstack) { elem *es; /* If returning struct literal, write result * directly into return value */ if (s->exp->op == TOKstructliteral) { StructLiteralExp *se = (StructLiteralExp *)s->exp; char save[sizeof(StructLiteralExp)]; memcpy(save, (void*)se, sizeof(StructLiteralExp)); se->sym = irs->shidden; se->soffset = 0; se->fillHoles = 1; e = toElemDtor(s->exp, irs); memcpy((void*)se, save, sizeof(StructLiteralExp)); } else e = toElemDtor(s->exp, irs); assert(e); if (s->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 = Type_toCtype(s->exp->type); } e = el_var(irs->shidden); e = el_bin(OPcomma, e->Ety, es, e); } else if (tf->isref) { // Reference return, so convert to a pointer e = toElemDtor(s->exp, irs); e = addressElem(e, s->exp->type->pointerTo()); } else { e = toElemDtor(s->exp, irs); assert(e); } elem_setLoc(e, s->loc); block_appendexp(blx->curblock, e); bc = BCretexp; } else bc = BCret; if (block *finallyBlock = irs->getFinallyBlock()) { assert(finallyBlock->BC == BC_finally); blx->curblock->appendSucc(finallyBlock); } block_next(blx, bc, NULL); }
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); }
DValue *DtoNewClass(Loc &loc, TypeClass *tc, NewExp *newexp) { // resolve type DtoResolveClass(tc->sym); // allocate LLValue *mem; bool doInit = true; if (newexp->onstack) { unsigned alignment = tc->sym->alignsize; if (alignment == STRUCTALIGN_DEFAULT) alignment = 0; mem = DtoRawAlloca(DtoType(tc)->getContainedType(0), alignment, ".newclass_alloca"); } // custom allocator else if (newexp->allocator) { DtoResolveFunction(newexp->allocator); DFuncValue dfn(newexp->allocator, DtoCallee(newexp->allocator)); DValue *res = DtoCallFunction(newexp->loc, nullptr, &dfn, newexp->newargs); mem = DtoBitCast(DtoRVal(res), DtoType(tc), ".newclass_custom"); } // default allocator else { const bool useEHAlloc = global.params.ehnogc && newexp->thrownew; llvm::Function *fn = getRuntimeFunction( loc, gIR->module, useEHAlloc ? "_d_newThrowable" : "_d_allocclass"); LLConstant *ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(), DtoType(getClassInfoType())); mem = gIR->CreateCallOrInvoke(fn, ci, useEHAlloc ? ".newthrowable_alloc" : ".newclass_gc_alloc") .getInstruction(); mem = DtoBitCast(mem, DtoType(tc), useEHAlloc ? ".newthrowable" : ".newclass_gc"); doInit = !useEHAlloc; } // init if (doInit) DtoInitClass(tc, mem); // init inner-class outer reference if (newexp->thisexp) { Logger::println("Resolving outer class"); LOG_SCOPE; unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis); LLValue *src = DtoRVal(newexp->thisexp); LLValue *dst = DtoGEPi(mem, 0, idx); IF_LOG Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n'; DtoStore(src, DtoBitCast(dst, getPtrToType(src->getType()))); } // set the context for nested classes else if (tc->sym->isNested() && tc->sym->vthis) { DtoResolveNestedContext(loc, tc->sym, mem); } // call constructor if (newexp->member) { // evaluate argprefix if (newexp->argprefix) { toElemDtor(newexp->argprefix); } Logger::println("Calling constructor"); assert(newexp->arguments != NULL); DtoResolveFunction(newexp->member); DFuncValue dfn(newexp->member, DtoCallee(newexp->member), mem); // ignore ctor return value (C++ ctors on Posix may not return `this`) DtoCallFunction(newexp->loc, tc, &dfn, newexp->arguments); return new DImValue(tc, mem); } assert(newexp->argprefix == NULL); // return default constructed class return new DImValue(tc, mem); }
DValue *DtoNewClass(Loc &loc, TypeClass *tc, NewExp *newexp) { // resolve type DtoResolveClass(tc->sym); // allocate LLValue *mem; if (newexp->onstack) { mem = DtoRawAlloca(DtoType(tc)->getContainedType(0), DtoAlignment(tc), ".newclass_alloca"); } // custom allocator else if (newexp->allocator) { DtoResolveFunction(newexp->allocator); DFuncValue dfn(newexp->allocator, DtoCallee(newexp->allocator)); DValue *res = DtoCallFunction(newexp->loc, nullptr, &dfn, newexp->newargs); mem = DtoBitCast(DtoRVal(res), DtoType(tc), ".newclass_custom"); } // default allocator else { llvm::Function *fn = getRuntimeFunction(loc, gIR->module, "_d_allocclass"); LLConstant *ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(), DtoType(Type::typeinfoclass->type)); mem = gIR->CreateCallOrInvoke(fn, ci, ".newclass_gc_alloc").getInstruction(); mem = DtoBitCast(mem, DtoType(tc), ".newclass_gc"); } // init DtoInitClass(tc, mem); // init inner-class outer reference if (newexp->thisexp) { Logger::println("Resolving outer class"); LOG_SCOPE; unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis); LLValue *src = DtoRVal(newexp->thisexp); LLValue *dst = DtoGEPi(mem, 0, idx); IF_LOG Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n'; DtoStore(src, DtoBitCast(dst, getPtrToType(src->getType()))); } // set the context for nested classes else if (tc->sym->isNested() && tc->sym->vthis) { DtoResolveNestedContext(loc, tc->sym, mem); } // call constructor if (newexp->member) { // evaluate argprefix if (newexp->argprefix) { toElemDtor(newexp->argprefix); } Logger::println("Calling constructor"); assert(newexp->arguments != NULL); DtoResolveFunction(newexp->member); DFuncValue dfn(newexp->member, DtoCallee(newexp->member), mem); return DtoCallFunction(newexp->loc, tc, &dfn, newexp->arguments); } assert(newexp->argprefix == NULL); // return default constructed class return new DImValue(tc, mem); }