1 /** 2 * Convert statements to Intermediate Representation (IR) for the back-end. 3 * 4 * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/tocsym.d, _s2ir.d) 8 * Documentation: $(LINK https://dlang.org/phobos/dmd_s2ir.html) 9 * Coverage: $(LINK https://codecov.io/gh/dlang/dmd/src/master/src/dmd/s2ir.d) 10 */ 11 12 module dmd.s2ir; 13 14 import core.stdc.stdio; 15 import core.stdc.string; 16 import core.stdc.stddef; 17 import core.stdc.stdlib; 18 import core.stdc.time; 19 20 import dmd.root.array; 21 import dmd.root.rmem; 22 import dmd.root.rootobject; 23 24 import dmd.aggregate; 25 import dmd.dclass; 26 import dmd.declaration; 27 import dmd.denum; 28 import dmd.dmodule; 29 import dmd.dsymbol; 30 import dmd.dstruct; 31 import dmd.dtemplate; 32 import dmd.e2ir; 33 import dmd.errors; 34 import dmd.expression; 35 import dmd.func; 36 import dmd.globals; 37 import dmd.glue; 38 import dmd.id; 39 import dmd.init; 40 import dmd.mtype; 41 import dmd.statement; 42 import dmd.stmtstate; 43 import dmd.target; 44 import dmd.toctype; 45 import dmd.tocsym; 46 import dmd.toir; 47 import dmd.tokens; 48 import dmd.visitor; 49 50 import dmd.backend.cc; 51 import dmd.backend.cdef; 52 import dmd.backend.cgcv; 53 import dmd.backend.code; 54 import dmd.backend.code_x86; 55 import dmd.backend.cv4; 56 import dmd.backend.dlist; 57 import dmd.backend.dt; 58 import dmd.backend.el; 59 import dmd.backend.global; 60 import dmd.backend.obj; 61 import dmd.backend.oper; 62 import dmd.backend.rtlsym; 63 import dmd.backend.symtab; 64 import dmd.backend.ty; 65 import dmd.backend.type; 66 67 extern (C++): 68 69 alias toSymbol = dmd.tocsym.toSymbol; 70 alias toSymbol = dmd.glue.toSymbol; 71 72 alias StmtState = dmd.stmtstate.StmtState!block; 73 74 75 void elem_setLoc(elem *e, const ref Loc loc) pure nothrow 76 { 77 srcpos_setLoc(e.Esrcpos, loc); 78 } 79 80 private void block_setLoc(block *b, const ref Loc loc) pure nothrow 81 { 82 srcpos_setLoc(b.Bsrcpos, loc); 83 } 84 85 private void srcpos_setLoc(ref Srcpos s, const ref Loc loc) pure nothrow 86 { 87 s.set(loc.filename, loc.linnum, loc.charnum); 88 } 89 90 91 /*********************************************** 92 * Generate code to set index into scope table. 93 */ 94 95 private void setScopeIndex(Blockx *blx, block *b, int scope_index) 96 { 97 if (config.ehmethod == EHmethod.EH_WIN32 && !(blx.funcsym.Sfunc.Fflags3 & Feh_none)) 98 block_appendexp(b, nteh_setScopeTableIndex(blx, scope_index)); 99 } 100 101 /**************************************** 102 * Allocate a new block, and set the tryblock. 103 */ 104 105 private block *block_calloc(Blockx *blx) 106 { 107 block *b = dmd.backend.global.block_calloc(); 108 b.Btry = blx.tryblock; 109 return b; 110 } 111 112 /************************************** 113 * Add in code to increment usage count for linnum. 114 */ 115 116 private void incUsage(IRState *irs, const ref Loc loc) 117 { 118 119 if (irs.params.cov && loc.linnum) 120 { 121 block_appendexp(irs.blx.curblock, incUsageElem(irs, loc)); 122 } 123 } 124 125 126 private extern (C++) class S2irVisitor : Visitor 127 { 128 IRState* irs; 129 StmtState* stmtstate; 130 131 this(IRState *irs, StmtState* stmtstate) 132 { 133 this.irs = irs; 134 this.stmtstate = stmtstate; 135 } 136 137 alias visit = Visitor.visit; 138 139 /**************************************** 140 * This should be overridden by each statement class. 141 */ 142 143 override void visit(Statement s) 144 { 145 assert(0); 146 } 147 148 /************************************* 149 */ 150 151 override void visit(ScopeGuardStatement s) 152 { 153 } 154 155 /**************************************** 156 */ 157 158 override void visit(IfStatement s) 159 { 160 elem *e; 161 Blockx *blx = irs.blx; 162 163 //printf("IfStatement.toIR('%s')\n", s.condition.toChars()); 164 165 StmtState mystate = StmtState(stmtstate, s); 166 167 // bexit is the block that gets control after this IfStatement is done 168 block *bexit = mystate.breakBlock ? mystate.breakBlock : dmd.backend.global.block_calloc(); 169 170 incUsage(irs, s.loc); 171 e = toElemDtor(s.condition, irs); 172 block_appendexp(blx.curblock, e); 173 block *bcond = blx.curblock; 174 block_next(blx, BCiftrue, null); 175 176 bcond.appendSucc(blx.curblock); 177 if (s.ifbody) 178 Statement_toIR(s.ifbody, irs, &mystate); 179 blx.curblock.appendSucc(bexit); 180 181 if (s.elsebody) 182 { 183 block_next(blx, BCgoto, null); 184 bcond.appendSucc(blx.curblock); 185 Statement_toIR(s.elsebody, irs, &mystate); 186 blx.curblock.appendSucc(bexit); 187 } 188 else 189 bcond.appendSucc(bexit); 190 191 block_next(blx, BCgoto, bexit); 192 193 } 194 195 /************************************** 196 */ 197 198 override void visit(PragmaStatement s) 199 { 200 //printf("PragmaStatement.toIR()\n"); 201 if (s.ident == Id.startaddress) 202 { 203 assert(s.args && s.args.dim == 1); 204 Expression e = (*s.args)[0]; 205 Dsymbol sa = getDsymbol(e); 206 FuncDeclaration f = sa.isFuncDeclaration(); 207 assert(f); 208 Symbol *sym = toSymbol(f); 209 irs.startaddress = sym; 210 } 211 } 212 213 /*********************** 214 */ 215 216 override void visit(WhileStatement s) 217 { 218 assert(0); // was "lowered" 219 } 220 221 /****************************************** 222 */ 223 224 override void visit(DoStatement s) 225 { 226 Blockx *blx = irs.blx; 227 228 StmtState mystate = StmtState(stmtstate, s); 229 mystate.breakBlock = block_calloc(blx); 230 mystate.contBlock = block_calloc(blx); 231 232 block *bpre = blx.curblock; 233 block_next(blx, BCgoto, null); 234 bpre.appendSucc(blx.curblock); 235 236 mystate.contBlock.appendSucc(blx.curblock); 237 mystate.contBlock.appendSucc(mystate.breakBlock); 238 239 if (s._body) 240 Statement_toIR(s._body, irs, &mystate); 241 blx.curblock.appendSucc(mystate.contBlock); 242 243 block_next(blx, BCgoto, mystate.contBlock); 244 incUsage(irs, s.condition.loc); 245 block_appendexp(mystate.contBlock, toElemDtor(s.condition, irs)); 246 block_next(blx, BCiftrue, mystate.breakBlock); 247 248 } 249 250 /***************************************** 251 */ 252 253 override void visit(ForStatement s) 254 { 255 //printf("visit(ForStatement)) %u..%u\n", s.loc.linnum, s.endloc.linnum); 256 Blockx *blx = irs.blx; 257 258 StmtState mystate = StmtState(stmtstate, s); 259 mystate.breakBlock = block_calloc(blx); 260 mystate.contBlock = block_calloc(blx); 261 262 if (s._init) 263 Statement_toIR(s._init, irs, &mystate); 264 block *bpre = blx.curblock; 265 block_next(blx,BCgoto,null); 266 block *bcond = blx.curblock; 267 bpre.appendSucc(bcond); 268 mystate.contBlock.appendSucc(bcond); 269 if (s.condition) 270 { 271 incUsage(irs, s.condition.loc); 272 block_appendexp(bcond, toElemDtor(s.condition, irs)); 273 block_next(blx,BCiftrue,null); 274 bcond.appendSucc(blx.curblock); 275 bcond.appendSucc(mystate.breakBlock); 276 } 277 else 278 { /* No conditional, it's a straight goto 279 */ 280 block_next(blx,BCgoto,null); 281 bcond.appendSucc(blx.curblock); 282 } 283 284 if (s._body) 285 Statement_toIR(s._body, irs, &mystate); 286 /* End of the body goes to the continue block 287 */ 288 blx.curblock.appendSucc(mystate.contBlock); 289 block_setLoc(blx.curblock, s.endloc); 290 block_next(blx, BCgoto, mystate.contBlock); 291 292 if (s.increment) 293 { 294 incUsage(irs, s.increment.loc); 295 block_appendexp(mystate.contBlock, toElemDtor(s.increment, irs)); 296 } 297 298 /* The 'break' block follows the for statement. 299 */ 300 block_next(blx,BCgoto, mystate.breakBlock); 301 } 302 303 304 /************************************** 305 */ 306 307 override void visit(ForeachStatement s) 308 { 309 printf("ForeachStatement.toIR() %s\n", s.toChars()); 310 assert(0); // done by "lowering" in the front end 311 } 312 313 314 /************************************** 315 */ 316 317 override void visit(ForeachRangeStatement s) 318 { 319 assert(0); 320 } 321 322 323 /**************************************** 324 */ 325 326 override void visit(BreakStatement s) 327 { 328 block *bbreak; 329 block *b; 330 Blockx *blx = irs.blx; 331 332 bbreak = stmtstate.getBreakBlock(s.ident); 333 assert(bbreak); 334 b = blx.curblock; 335 incUsage(irs, s.loc); 336 337 // Adjust exception handler scope index if in different try blocks 338 if (b.Btry != bbreak.Btry) 339 { 340 //setScopeIndex(blx, b, bbreak.Btry ? bbreak.Btry.Bscope_index : -1); 341 } 342 343 /* Nothing more than a 'goto' to the current break destination 344 */ 345 b.appendSucc(bbreak); 346 block_setLoc(b, s.loc); 347 block_next(blx, BCgoto, null); 348 } 349 350 /************************************ 351 */ 352 353 override void visit(ContinueStatement s) 354 { 355 block *bcont; 356 block *b; 357 Blockx *blx = irs.blx; 358 359 //printf("ContinueStatement.toIR() %p\n", this); 360 bcont = stmtstate.getContBlock(s.ident); 361 assert(bcont); 362 b = blx.curblock; 363 incUsage(irs, s.loc); 364 365 // Adjust exception handler scope index if in different try blocks 366 if (b.Btry != bcont.Btry) 367 { 368 //setScopeIndex(blx, b, bcont.Btry ? bcont.Btry.Bscope_index : -1); 369 } 370 371 /* Nothing more than a 'goto' to the current continue destination 372 */ 373 b.appendSucc(bcont); 374 block_setLoc(b, s.loc); 375 block_next(blx, BCgoto, null); 376 } 377 378 379 /************************************** 380 */ 381 382 override void visit(GotoStatement s) 383 { 384 Blockx *blx = irs.blx; 385 386 assert(s.label.statement); 387 assert(s.tf == s.label.statement.tf); 388 389 block* bdest = cast(block*)s.label.statement.extra; 390 block *b = blx.curblock; 391 incUsage(irs, s.loc); 392 b.appendSucc(bdest); 393 block_setLoc(b, s.loc); 394 395 block_next(blx,BCgoto,null); 396 } 397 398 override void visit(LabelStatement s) 399 { 400 //printf("LabelStatement.toIR() %p, statement: `%s`\n", this, s.statement.toChars()); 401 Blockx *blx = irs.blx; 402 block *bc = blx.curblock; 403 StmtState mystate = StmtState(stmtstate, s); 404 mystate.ident = s.ident; 405 406 block* bdest = cast(block*)s.extra; 407 // At last, we know which try block this label is inside 408 bdest.Btry = blx.tryblock; 409 410 block_next(blx, BCgoto, bdest); 411 bc.appendSucc(blx.curblock); 412 if (s.statement) 413 Statement_toIR(s.statement, irs, &mystate); 414 } 415 416 /************************************** 417 */ 418 419 override void visit(SwitchStatement s) 420 { 421 Blockx *blx = irs.blx; 422 423 //printf("SwitchStatement.toIR()\n"); 424 StmtState mystate = StmtState(stmtstate, s); 425 426 mystate.switchBlock = blx.curblock; 427 428 /* Block for where "break" goes to 429 */ 430 mystate.breakBlock = block_calloc(blx); 431 432 /* Block for where "default" goes to. 433 * If there is a default statement, then that is where default goes. 434 * If not, then do: 435 * default: break; 436 * by making the default block the same as the break block. 437 */ 438 mystate.defaultBlock = s.sdefault ? block_calloc(blx) : mystate.breakBlock; 439 440 const numcases = s.cases ? s.cases.dim : 0; 441 442 /* allocate a block for each case 443 */ 444 if (numcases) 445 foreach (cs; *s.cases) 446 { 447 cs.extra = cast(void*)block_calloc(blx); 448 } 449 450 incUsage(irs, s.loc); 451 elem *econd = toElemDtor(s.condition, irs); 452 if (s.hasVars) 453 { /* Generate a sequence of if-then-else blocks for the cases. 454 */ 455 if (econd.Eoper != OPvar) 456 { 457 elem *e = exp2_copytotemp(econd); 458 block_appendexp(mystate.switchBlock, e); 459 econd = e.EV.E2; 460 } 461 462 if (numcases) 463 foreach (cs; *s.cases) 464 { 465 elem *ecase = toElemDtor(cs.exp, irs); 466 elem *e = el_bin(OPeqeq, TYbool, el_copytree(econd), ecase); 467 block *b = blx.curblock; 468 block_appendexp(b, e); 469 block* cb = cast(block*)cs.extra; 470 block_next(blx, BCiftrue, null); 471 b.appendSucc(cb); 472 b.appendSucc(blx.curblock); 473 } 474 475 /* The final 'else' clause goes to the default 476 */ 477 block *b = blx.curblock; 478 block_next(blx, BCgoto, null); 479 b.appendSucc(mystate.defaultBlock); 480 481 Statement_toIR(s._body, irs, &mystate); 482 483 /* Have the end of the switch body fall through to the block 484 * following the switch statement. 485 */ 486 block_goto(blx, BCgoto, mystate.breakBlock); 487 return; 488 } 489 490 if (s.condition.type.isString()) 491 { 492 // This codepath was replaced by lowering during semantic 493 // to object.__switch in druntime. 494 assert(0); 495 } 496 497 block_appendexp(mystate.switchBlock, econd); 498 block_next(blx,BCswitch,null); 499 500 // Corresponding free is in block_free 501 alias TCase = typeof(mystate.switchBlock.Bswitch[0]); 502 auto pu = cast(TCase *)Mem.check(.malloc(TCase.sizeof * (numcases + 1))); 503 mystate.switchBlock.Bswitch = pu; 504 /* First pair is the number of cases, and the default block 505 */ 506 *pu++ = numcases; 507 mystate.switchBlock.appendSucc(mystate.defaultBlock); 508 509 /* Fill in the first entry for each pair, which is the case value. 510 * CaseStatement.toIR() will fill in 511 * the second entry for each pair with the block. 512 */ 513 if (numcases) 514 foreach (cs; *s.cases) 515 *pu++ = cs.exp.toInteger(); 516 517 Statement_toIR(s._body, irs, &mystate); 518 519 /* Have the end of the switch body fall through to the block 520 * following the switch statement. 521 */ 522 block_goto(blx, BCgoto, mystate.breakBlock); 523 } 524 525 override void visit(CaseStatement s) 526 { 527 Blockx *blx = irs.blx; 528 block *bcase = blx.curblock; 529 block* cb = cast(block*)s.extra; 530 block_next(blx, BCgoto, cb); 531 block *bsw = stmtstate.getSwitchBlock(); 532 if (bsw.BC == BCswitch) 533 bsw.appendSucc(cb); // second entry in pair 534 bcase.appendSucc(cb); 535 incUsage(irs, s.loc); 536 if (s.statement) 537 Statement_toIR(s.statement, irs, stmtstate); 538 } 539 540 override void visit(DefaultStatement s) 541 { 542 Blockx *blx = irs.blx; 543 block *bcase = blx.curblock; 544 block *bdefault = stmtstate.getDefaultBlock(); 545 block_next(blx,BCgoto,bdefault); 546 bcase.appendSucc(blx.curblock); 547 incUsage(irs, s.loc); 548 if (s.statement) 549 Statement_toIR(s.statement, irs, stmtstate); 550 } 551 552 override void visit(GotoDefaultStatement s) 553 { 554 block *b; 555 Blockx *blx = irs.blx; 556 block *bdest = stmtstate.getDefaultBlock(); 557 558 b = blx.curblock; 559 560 // The rest is equivalent to GotoStatement 561 562 b.appendSucc(bdest); 563 incUsage(irs, s.loc); 564 block_next(blx,BCgoto,null); 565 } 566 567 override void visit(GotoCaseStatement s) 568 { 569 Blockx *blx = irs.blx; 570 block *bdest = cast(block*)s.cs.extra; 571 block *b = blx.curblock; 572 573 // The rest is equivalent to GotoStatement 574 575 b.appendSucc(bdest); 576 incUsage(irs, s.loc); 577 block_next(blx,BCgoto,null); 578 } 579 580 override void visit(SwitchErrorStatement s) 581 { 582 // SwitchErrors are lowered to a CallExpression to object.__switch_error() in druntime 583 // We still need the call wrapped in SwitchErrorStatement to pass compiler error checks. 584 assert(s.exp !is null, "SwitchErrorStatement needs to have a valid Expression."); 585 586 Blockx *blx = irs.blx; 587 588 //printf("SwitchErrorStatement.toIR(), exp = %s\n", s.exp ? s.exp.toChars() : ""); 589 incUsage(irs, s.loc); 590 block_appendexp(blx.curblock, toElemDtor(s.exp, irs)); 591 } 592 593 /************************************** 594 */ 595 596 override void visit(ReturnStatement s) 597 { 598 //printf("s2ir.ReturnStatement: %s\n", s.toChars()); 599 Blockx *blx = irs.blx; 600 BC bc; 601 602 incUsage(irs, s.loc); 603 if (s.exp) 604 { 605 elem *e; 606 607 FuncDeclaration func = irs.getFunc(); 608 assert(func); 609 auto tf = func.type.isTypeFunction(); 610 assert(tf); 611 612 RET retmethod = retStyle(tf, func.needThis()); 613 if (retmethod == RET.stack) 614 { 615 elem *es; 616 bool writetohp; 617 618 /* If returning struct literal, write result 619 * directly into return value 620 */ 621 if (auto sle = s.exp.isStructLiteralExp()) 622 { 623 sle.sym = irs.shidden; 624 writetohp = true; 625 } 626 /* Detect function call that returns the same struct 627 * and construct directly into *shidden 628 */ 629 else if (auto ce = s.exp.isCallExp()) 630 { 631 if (ce.e1.op == TOK.variable || ce.e1.op == TOK.star) 632 { 633 Type t = ce.e1.type.toBasetype(); 634 if (t.ty == Tdelegate) 635 t = t.nextOf(); 636 if (t.ty == Tfunction && retStyle(cast(TypeFunction)t, ce.f && ce.f.needThis()) == RET.stack) 637 { 638 irs.ehidden = el_var(irs.shidden); 639 e = toElemDtor(s.exp, irs); 640 e = el_una(OPaddr, TYnptr, e); 641 goto L1; 642 } 643 } 644 else if (auto dve = ce.e1.isDotVarExp()) 645 { 646 auto fd = dve.var.isFuncDeclaration(); 647 if (fd && fd.isCtorDeclaration()) 648 { 649 if (auto sle = dve.e1.isStructLiteralExp()) 650 { 651 sle.sym = irs.shidden; 652 writetohp = true; 653 } 654 } 655 Type t = ce.e1.type.toBasetype(); 656 if (t.ty == Tdelegate) 657 t = t.nextOf(); 658 if (t.ty == Tfunction && retStyle(cast(TypeFunction)t, fd && fd.needThis()) == RET.stack) 659 { 660 irs.ehidden = el_var(irs.shidden); 661 e = toElemDtor(s.exp, irs); 662 e = el_una(OPaddr, TYnptr, e); 663 goto L1; 664 } 665 } 666 } 667 e = toElemDtor(s.exp, irs); 668 assert(e); 669 670 if (writetohp || 671 (func.nrvo_can && func.nrvo_var)) 672 { 673 // Return value via hidden pointer passed as parameter 674 // Write exp; return shidden; 675 es = e; 676 } 677 else 678 { 679 // Return value via hidden pointer passed as parameter 680 // Write *shidden=exp; return shidden; 681 es = el_una(OPind,e.Ety,el_var(irs.shidden)); 682 es = elAssign(es, e, s.exp.type, null); 683 } 684 e = el_var(irs.shidden); 685 e = el_bin(OPcomma, e.Ety, es, e); 686 } 687 else if (tf.isref) 688 { 689 // Reference return, so convert to a pointer 690 e = toElemDtor(s.exp, irs); 691 692 /* already taken care of for vresult in buildResultVar() and semantic3.d 693 * https://issues.dlang.org/show_bug.cgi?id=19384 694 */ 695 if (func.vresult) 696 if (BlitExp be = s.exp.isBlitExp()) 697 { 698 if (VarExp ve = be.e1.isVarExp()) 699 { 700 if (ve.var == func.vresult) 701 goto Lskip; 702 } 703 } 704 705 e = addressElem(e, s.exp.type.pointerTo()); 706 Lskip: 707 } 708 else 709 { 710 e = toElemDtor(s.exp, irs); 711 assert(e); 712 } 713 L1: 714 elem_setLoc(e, s.loc); 715 block_appendexp(blx.curblock, e); 716 bc = BCretexp; 717 // if (type_zeroCopy(Type_toCtype(s.exp.type))) 718 // bc = BCret; 719 } 720 else 721 bc = BCret; 722 723 block *finallyBlock; 724 if (config.ehmethod != EHmethod.EH_DWARF && 725 !irs.isNothrow() && 726 (finallyBlock = stmtstate.getFinallyBlock()) != null) 727 { 728 assert(finallyBlock.BC == BC_finally); 729 blx.curblock.appendSucc(finallyBlock); 730 } 731 732 block_next(blx, bc, null); 733 } 734 735 /************************************** 736 */ 737 738 override void visit(ExpStatement s) 739 { 740 Blockx *blx = irs.blx; 741 742 //printf("ExpStatement.toIR(), exp: %p %s\n", s.exp, s.exp ? s.exp.toChars() : ""); 743 if (s.exp) 744 { 745 if (s.exp.hasCode) 746 incUsage(irs, s.loc); 747 748 block_appendexp(blx.curblock, toElemDtor(s.exp, irs)); 749 } 750 } 751 752 /************************************** 753 */ 754 755 override void visit(CompoundStatement s) 756 { 757 if (s.statements) 758 { 759 foreach (s2; *s.statements) 760 { 761 if (s2) 762 Statement_toIR(s2, irs, stmtstate); 763 } 764 } 765 } 766 767 768 /************************************** 769 */ 770 771 override void visit(UnrolledLoopStatement s) 772 { 773 Blockx *blx = irs.blx; 774 775 StmtState mystate = StmtState(stmtstate, s); 776 mystate.breakBlock = block_calloc(blx); 777 778 block *bpre = blx.curblock; 779 block_next(blx, BCgoto, null); 780 781 block *bdo = blx.curblock; 782 bpre.appendSucc(bdo); 783 784 block *bdox; 785 786 foreach (s2; *s.statements) 787 { 788 if (s2) 789 { 790 mystate.contBlock = block_calloc(blx); 791 792 Statement_toIR(s2, irs, &mystate); 793 794 bdox = blx.curblock; 795 block_next(blx, BCgoto, mystate.contBlock); 796 bdox.appendSucc(mystate.contBlock); 797 } 798 } 799 800 bdox = blx.curblock; 801 block_next(blx, BCgoto, mystate.breakBlock); 802 bdox.appendSucc(mystate.breakBlock); 803 } 804 805 806 /************************************** 807 */ 808 809 override void visit(ScopeStatement s) 810 { 811 if (s.statement) 812 { 813 Blockx *blx = irs.blx; 814 StmtState mystate = StmtState(stmtstate, s); 815 816 if (mystate.prev.ident) 817 mystate.ident = mystate.prev.ident; 818 819 Statement_toIR(s.statement, irs, &mystate); 820 821 if (mystate.breakBlock) 822 block_goto(blx,BCgoto,mystate.breakBlock); 823 } 824 } 825 826 /*************************************** 827 */ 828 829 override void visit(WithStatement s) 830 { 831 //printf("WithStatement.toIR()\n"); 832 if (s.exp.op == TOK.scope_ || s.exp.op == TOK.type) 833 { 834 } 835 else 836 { 837 // Declare with handle 838 auto sp = toSymbol(s.wthis); 839 symbol_add(sp); 840 841 // Perform initialization of with handle 842 auto ie = s.wthis._init.isExpInitializer(); 843 assert(ie); 844 auto ei = toElemDtor(ie.exp, irs); 845 auto e = el_var(sp); 846 e = el_bin(OPeq,e.Ety, e, ei); 847 elem_setLoc(e, s.loc); 848 incUsage(irs, s.loc); 849 block_appendexp(irs.blx.curblock,e); 850 } 851 // Execute with block 852 if (s._body) 853 Statement_toIR(s._body, irs, stmtstate); 854 } 855 856 857 /*************************************** 858 */ 859 860 override void visit(ThrowStatement s) 861 { 862 // throw(exp) 863 864 Blockx *blx = irs.blx; 865 866 incUsage(irs, s.loc); 867 elem *e = toElemDtor(s.exp, irs); 868 const int rtlthrow = config.ehmethod == EHmethod.EH_DWARF ? RTLSYM_THROWDWARF : RTLSYM_THROWC; 869 e = el_bin(OPcall, TYvoid, el_var(getRtlsym(rtlthrow)),e); 870 block_appendexp(blx.curblock, e); 871 block_next(blx, BCexit, null); // throw never returns 872 } 873 874 /*************************************** 875 * Builds the following: 876 * _try 877 * block 878 * jcatch 879 * handler 880 * A try-catch statement. 881 */ 882 883 override void visit(TryCatchStatement s) 884 { 885 Blockx *blx = irs.blx; 886 887 if (blx.funcsym.Sfunc.Fflags3 & Feh_none) printf("visit %s\n", blx.funcsym.Sident.ptr); 888 if (blx.funcsym.Sfunc.Fflags3 & Feh_none) assert(0); 889 890 if (config.ehmethod == EHmethod.EH_WIN32) 891 nteh_declarvars(blx); 892 893 StmtState mystate = StmtState(stmtstate, s); 894 895 block *tryblock = block_goto(blx,BCgoto,null); 896 897 int previndex = blx.scope_index; 898 tryblock.Blast_index = previndex; 899 blx.scope_index = tryblock.Bscope_index = blx.next_index++; 900 901 // Set the current scope index 902 setScopeIndex(blx,tryblock,tryblock.Bscope_index); 903 904 // This is the catch variable 905 tryblock.jcatchvar = symbol_genauto(type_fake(mTYvolatile | TYnptr)); 906 907 blx.tryblock = tryblock; 908 block *breakblock = block_calloc(blx); 909 block_goto(blx,BC_try,null); 910 if (s._body) 911 { 912 Statement_toIR(s._body, irs, &mystate); 913 } 914 blx.tryblock = tryblock.Btry; 915 916 // break block goes here 917 block_goto(blx, BCgoto, breakblock); 918 919 setScopeIndex(blx,blx.curblock, previndex); 920 blx.scope_index = previndex; 921 922 // create new break block that follows all the catches 923 block *breakblock2 = block_calloc(blx); 924 925 blx.curblock.appendSucc(breakblock2); 926 block_next(blx,BCgoto,null); 927 928 assert(s.catches); 929 if (config.ehmethod == EHmethod.EH_DWARF) 930 { 931 /* 932 * BCjcatch: 933 * __hander = __RDX; 934 * __exception_object = __RAX; 935 * jcatchvar = *(__exception_object - target.ptrsize); // old way 936 * jcatchvar = __dmd_catch_begin(__exception_object); // new way 937 * switch (__handler) 938 * case 1: // first catch handler 939 * *(sclosure + cs.var.offset) = cs.var; 940 * ...handler body ... 941 * break; 942 * ... 943 * default: 944 * HALT 945 */ 946 // volatile so optimizer won't delete it 947 Symbol *seax = symbol_name("__EAX", SCpseudo, type_fake(mTYvolatile | TYnptr)); 948 seax.Sreglsw = 0; // EAX, RAX, whatevs 949 symbol_add(seax); 950 Symbol *sedx = symbol_name("__EDX", SCpseudo, type_fake(mTYvolatile | TYint)); 951 sedx.Sreglsw = 2; // EDX, RDX, whatevs 952 symbol_add(sedx); 953 Symbol *shandler = symbol_name("__handler", SCauto, tstypes[TYint]); 954 symbol_add(shandler); 955 Symbol *seo = symbol_name("__exception_object", SCauto, tspvoid); 956 symbol_add(seo); 957 958 elem *e1 = el_bin(OPeq, TYvoid, el_var(shandler), el_var(sedx)); // __handler = __RDX 959 elem *e2 = el_bin(OPeq, TYvoid, el_var(seo), el_var(seax)); // __exception_object = __RAX 960 961 version (none) 962 { 963 // jcatchvar = *(__exception_object - target.ptrsize) 964 elem *e = el_bin(OPmin, TYnptr, el_var(seo), el_long(TYsize_t, target.ptrsize)); 965 elem *e3 = el_bin(OPeq, TYvoid, el_var(tryblock.jcatchvar), el_una(OPind, TYnptr, e)); 966 } 967 else 968 { 969 // jcatchvar = __dmd_catch_begin(__exception_object); 970 elem *ebegin = el_var(getRtlsym(RTLSYM_BEGIN_CATCH)); 971 elem *e = el_bin(OPcall, TYnptr, ebegin, el_var(seo)); 972 elem *e3 = el_bin(OPeq, TYvoid, el_var(tryblock.jcatchvar), e); 973 } 974 975 block *bcatch = blx.curblock; 976 tryblock.appendSucc(bcatch); 977 block_goto(blx, BCjcatch, null); 978 979 block *defaultblock = block_calloc(blx); 980 981 block *bswitch = blx.curblock; 982 bswitch.Belem = el_combine(el_combine(e1, e2), 983 el_combine(e3, el_var(shandler))); 984 985 const numcases = s.catches.dim; 986 bswitch.Bswitch = cast(targ_llong *) Mem.check(.malloc((targ_llong).sizeof * (numcases + 1))); 987 bswitch.Bswitch[0] = numcases; 988 bswitch.appendSucc(defaultblock); 989 block_next(blx, BCswitch, null); 990 991 foreach (i, cs; *s.catches) 992 { 993 bswitch.Bswitch[1 + i] = 1 + i; 994 995 if (cs.var) 996 cs.var.csym = tryblock.jcatchvar; 997 998 assert(cs.type); 999 1000 /* The catch type can be a C++ class or a D class. 1001 * If a D class, insert a pointer to TypeInfo into the typesTable[]. 1002 * If a C++ class, insert a pointer to __cpp_type_info_ptr into the typesTable[]. 1003 */ 1004 Type tcatch = cs.type.toBasetype(); 1005 ClassDeclaration cd = tcatch.isClassHandle(); 1006 bool isCPPclass = cd.isCPPclass(); 1007 Symbol *catchtype; 1008 if (isCPPclass) 1009 { 1010 catchtype = toSymbolCpp(cd); 1011 if (i == 0) 1012 { 1013 // rewrite ebegin to use __cxa_begin_catch 1014 Symbol *s2 = getRtlsym(RTLSYM_CXA_BEGIN_CATCH); 1015 ebegin.EV.Vsym = s2; 1016 } 1017 } 1018 else 1019 catchtype = toSymbol(tcatch); 1020 1021 /* Look for catchtype in typesTable[] using linear search, 1022 * insert if not already there, 1023 * log index in Action Table (i.e. switch case table) 1024 */ 1025 func_t *f = blx.funcsym.Sfunc; 1026 1027 foreach (j, ct; f.typesTable[]) 1028 { 1029 if (ct == catchtype) 1030 { 1031 bswitch.Bswitch[1 + i] = 1 + j; // index starts at 1 1032 goto L1; 1033 } 1034 } 1035 f.typesTable.push(catchtype); 1036 bswitch.Bswitch[1 + i] = f.typesTable.length; // index starts at 1 1037 L1: 1038 block *bcase = blx.curblock; 1039 bswitch.appendSucc(bcase); 1040 1041 if (cs.handler !is null) 1042 { 1043 StmtState catchState = StmtState(stmtstate, s); 1044 1045 /* Append to block: 1046 * *(sclosure + cs.var.offset) = cs.var; 1047 */ 1048 if (cs.var && cs.var.offset) // if member of a closure 1049 { 1050 tym_t tym = totym(cs.var.type); 1051 elem *ex = el_var(irs.sclosure); 1052 ex = el_bin(OPadd, TYnptr, ex, el_long(TYsize_t, cs.var.offset)); 1053 ex = el_una(OPind, tym, ex); 1054 ex = el_bin(OPeq, tym, ex, el_var(toSymbol(cs.var))); 1055 block_appendexp(irs.blx.curblock, ex); 1056 } 1057 if (isCPPclass) 1058 { 1059 /* C++ catches need to end with call to __cxa_end_catch(). 1060 * Create: 1061 * try { handler } finally { __cxa_end_catch(); } 1062 * Note that this is worst case code because it always sets up an exception handler. 1063 * At some point should try to do better. 1064 */ 1065 FuncDeclaration fdend = FuncDeclaration.genCfunc(null, Type.tvoid, "__cxa_end_catch"); 1066 Expression ec = VarExp.create(Loc.initial, fdend); 1067 Expression ecc = CallExp.create(Loc.initial, ec); 1068 ecc.type = Type.tvoid; 1069 Statement sf = ExpStatement.create(Loc.initial, ecc); 1070 Statement stf = TryFinallyStatement.create(Loc.initial, cs.handler, sf); 1071 Statement_toIR(stf, irs, &catchState); 1072 } 1073 else 1074 Statement_toIR(cs.handler, irs, &catchState); 1075 } 1076 blx.curblock.appendSucc(breakblock2); 1077 if (i + 1 == numcases) 1078 { 1079 block_next(blx, BCgoto, defaultblock); 1080 defaultblock.Belem = el_calloc(); 1081 defaultblock.Belem.Ety = TYvoid; 1082 defaultblock.Belem.Eoper = OPhalt; 1083 block_next(blx, BCexit, null); 1084 } 1085 else 1086 block_next(blx, BCgoto, null); 1087 } 1088 1089 /* Make a copy of the switch case table, which will later become the Action Table. 1090 * Need a copy since the bswitch may get rewritten by the optimizer. 1091 */ 1092 alias TAction = typeof(bcatch.actionTable[0]); 1093 bcatch.actionTable = cast(TAction*)Mem.check(.malloc(TAction.sizeof * (numcases + 1))); 1094 foreach (i; 0 .. numcases + 1) 1095 bcatch.actionTable[i] = cast(TAction)bswitch.Bswitch[i]; 1096 1097 } 1098 else 1099 { 1100 foreach (cs; *s.catches) 1101 { 1102 if (cs.var) 1103 cs.var.csym = tryblock.jcatchvar; 1104 block *bcatch = blx.curblock; 1105 if (cs.type) 1106 bcatch.Bcatchtype = toSymbol(cs.type.toBasetype()); 1107 tryblock.appendSucc(bcatch); 1108 block_goto(blx, BCjcatch, null); 1109 1110 if (cs.type && irs.params.isWindows && irs.params.is64bit) // Win64 1111 { 1112 /* The linker will attempt to merge together identical functions, 1113 * even if the catch types differ. So add a reference to the 1114 * catch type here. 1115 * https://issues.dlang.org/show_bug.cgi?id=10664 1116 */ 1117 auto tc = cs.type.toBasetype().isTypeClass(); 1118 if (!tc.sym.vclassinfo) 1119 tc.sym.vclassinfo = TypeInfoClassDeclaration.create(tc); 1120 auto sinfo = toSymbol(tc.sym.vclassinfo); 1121 elem* ex = el_var(sinfo); 1122 ex.Ety = mTYvolatile | TYnptr; 1123 ex = el_una(OPind, TYint, ex); 1124 block_appendexp(irs.blx.curblock, ex); 1125 } 1126 1127 if (cs.handler !is null) 1128 { 1129 StmtState catchState = StmtState(stmtstate, s); 1130 1131 /* Append to block: 1132 * *(sclosure + cs.var.offset) = cs.var; 1133 */ 1134 if (cs.var && cs.var.offset) // if member of a closure 1135 { 1136 tym_t tym = totym(cs.var.type); 1137 elem *ex = el_var(irs.sclosure); 1138 ex = el_bin(OPadd, TYnptr, ex, el_long(TYsize_t, cs.var.offset)); 1139 ex = el_una(OPind, tym, ex); 1140 ex = el_bin(OPeq, tym, ex, el_var(toSymbol(cs.var))); 1141 block_appendexp(irs.blx.curblock, ex); 1142 } 1143 Statement_toIR(cs.handler, irs, &catchState); 1144 } 1145 blx.curblock.appendSucc(breakblock2); 1146 block_next(blx, BCgoto, null); 1147 } 1148 } 1149 1150 block_next(blx,cast(BC)blx.curblock.BC, breakblock2); 1151 } 1152 1153 /**************************************** 1154 * A try-finally statement. 1155 * Builds the following: 1156 * _try 1157 * block 1158 * _finally 1159 * finalbody 1160 * _ret 1161 */ 1162 1163 override void visit(TryFinallyStatement s) 1164 { 1165 //printf("TryFinallyStatement.toIR()\n"); 1166 1167 Blockx *blx = irs.blx; 1168 1169 if (config.ehmethod == EHmethod.EH_WIN32 && !(blx.funcsym.Sfunc.Fflags3 & Feh_none)) 1170 nteh_declarvars(blx); 1171 1172 /* Successors to BC_try block: 1173 * [0] start of try block code 1174 * [1] BC_finally 1175 */ 1176 block *tryblock = block_goto(blx, BCgoto, null); 1177 1178 int previndex = blx.scope_index; 1179 tryblock.Blast_index = previndex; 1180 tryblock.Bscope_index = blx.next_index++; 1181 blx.scope_index = tryblock.Bscope_index; 1182 1183 // Current scope index 1184 setScopeIndex(blx,tryblock,tryblock.Bscope_index); 1185 1186 blx.tryblock = tryblock; 1187 block_goto(blx,BC_try,null); 1188 1189 StmtState bodyirs = StmtState(stmtstate, s); 1190 1191 block *finallyblock = block_calloc(blx); 1192 1193 tryblock.appendSucc(finallyblock); 1194 finallyblock.BC = BC_finally; 1195 bodyirs.finallyBlock = finallyblock; 1196 1197 if (s._body) 1198 Statement_toIR(s._body, irs, &bodyirs); 1199 blx.tryblock = tryblock.Btry; // back to previous tryblock 1200 1201 setScopeIndex(blx,blx.curblock,previndex); 1202 blx.scope_index = previndex; 1203 1204 block *breakblock = block_calloc(blx); 1205 block *retblock = block_calloc(blx); 1206 1207 if (config.ehmethod == EHmethod.EH_DWARF && !(blx.funcsym.Sfunc.Fflags3 & Feh_none)) 1208 { 1209 /* Build this: 1210 * BCgoto [BC_try] 1211 * BC_try [body] [BC_finally] 1212 * body 1213 * BCgoto [breakblock] 1214 * BC_finally [BC_lpad] [finalbody] [breakblock] 1215 * BC_lpad [finalbody] 1216 * finalbody 1217 * BCgoto [BC_ret] 1218 * BC_ret 1219 * breakblock 1220 */ 1221 blx.curblock.appendSucc(breakblock); 1222 block_next(blx,BCgoto,finallyblock); 1223 1224 block *landingPad = block_goto(blx,BC_finally,null); 1225 block_goto(blx,BC_lpad,null); // lpad is [0] 1226 finallyblock.appendSucc(blx.curblock); // start of finalybody is [1] 1227 finallyblock.appendSucc(breakblock); // breakblock is [2] 1228 1229 /* Declare flag variable 1230 */ 1231 Symbol *sflag = symbol_name("__flag", SCauto, tstypes[TYint]); 1232 symbol_add(sflag); 1233 finallyblock.flag = sflag; 1234 finallyblock.b_ret = retblock; 1235 assert(!finallyblock.Belem); 1236 1237 /* Add code to landingPad block: 1238 * exception_object = RAX; 1239 * _flag = 0; 1240 */ 1241 // Make it volatile so optimizer won't delete it 1242 Symbol *sreg = symbol_name("__EAX", SCpseudo, type_fake(mTYvolatile | TYnptr)); 1243 sreg.Sreglsw = 0; // EAX, RAX, whatevs 1244 symbol_add(sreg); 1245 Symbol *seo = symbol_name("__exception_object", SCauto, tspvoid); 1246 symbol_add(seo); 1247 assert(!landingPad.Belem); 1248 elem *e = el_bin(OPeq, TYvoid, el_var(seo), el_var(sreg)); 1249 landingPad.Belem = el_combine(e, el_bin(OPeq, TYvoid, el_var(sflag), el_long(TYint, 0))); 1250 1251 /* Add code to BC_ret block: 1252 * (!_flag && _Unwind_Resume(exception_object)); 1253 */ 1254 elem *eu = el_bin(OPcall, TYvoid, el_var(getRtlsym(RTLSYM_UNWIND_RESUME)), el_var(seo)); 1255 eu = el_bin(OPandand, TYvoid, el_una(OPnot, TYbool, el_var(sflag)), eu); 1256 assert(!retblock.Belem); 1257 retblock.Belem = eu; 1258 1259 StmtState finallyState = StmtState(stmtstate, s); 1260 1261 setScopeIndex(blx, blx.curblock, previndex); 1262 if (s.finalbody) 1263 Statement_toIR(s.finalbody, irs, &finallyState); 1264 block_goto(blx, BCgoto, retblock); 1265 1266 block_next(blx,BC_ret,breakblock); 1267 } 1268 else if (config.ehmethod == EHmethod.EH_NONE || blx.funcsym.Sfunc.Fflags3 & Feh_none) 1269 { 1270 /* Build this: 1271 * BCgoto [BC_try] 1272 * BC_try [body] [BC_finally] 1273 * body 1274 * BCgoto [breakblock] 1275 * BC_finally [BC_lpad] [finalbody] [breakblock] 1276 * BC_lpad [finalbody] 1277 * finalbody 1278 * BCgoto [BC_ret] 1279 * BC_ret 1280 * breakblock 1281 */ 1282 if (s.bodyFallsThru) 1283 { 1284 // BCgoto [breakblock] 1285 blx.curblock.appendSucc(breakblock); 1286 block_next(blx,BCgoto,finallyblock); 1287 } 1288 else 1289 { 1290 if (!irs.params.optimize) 1291 { 1292 /* If this is reached at runtime, there's a bug 1293 * in the computation of s.bodyFallsThru. Inserting a HALT 1294 * makes it far easier to track down such failures. 1295 * But it makes for slower code, so only generate it for 1296 * non-optimized code. 1297 */ 1298 elem *e = el_calloc(); 1299 e.Ety = TYvoid; 1300 e.Eoper = OPhalt; 1301 elem_setLoc(e, s.loc); 1302 block_appendexp(blx.curblock, e); 1303 } 1304 1305 block_next(blx,BCexit,finallyblock); 1306 } 1307 1308 block *landingPad = block_goto(blx,BC_finally,null); 1309 block_goto(blx,BC_lpad,null); // lpad is [0] 1310 finallyblock.appendSucc(blx.curblock); // start of finalybody is [1] 1311 finallyblock.appendSucc(breakblock); // breakblock is [2] 1312 1313 /* Declare flag variable 1314 */ 1315 Symbol *sflag = symbol_name("__flag", SCauto, tstypes[TYint]); 1316 symbol_add(sflag); 1317 finallyblock.flag = sflag; 1318 finallyblock.b_ret = retblock; 1319 assert(!finallyblock.Belem); 1320 1321 landingPad.Belem = el_bin(OPeq, TYvoid, el_var(sflag), el_long(TYint, 0)); // __flag = 0; 1322 1323 StmtState finallyState = StmtState(stmtstate, s); 1324 1325 setScopeIndex(blx, blx.curblock, previndex); 1326 if (s.finalbody) 1327 Statement_toIR(s.finalbody, irs, &finallyState); 1328 block_goto(blx, BCgoto, retblock); 1329 1330 block_next(blx,BC_ret,breakblock); 1331 } 1332 else 1333 { 1334 block_goto(blx,BCgoto, breakblock); 1335 block_goto(blx,BCgoto,finallyblock); 1336 1337 /* Successors to BC_finally block: 1338 * [0] landing pad, same as start of finally code 1339 * [1] block that comes after BC_ret 1340 */ 1341 block_goto(blx,BC_finally,null); 1342 1343 StmtState finallyState = StmtState(stmtstate, s); 1344 1345 setScopeIndex(blx, blx.curblock, previndex); 1346 if (s.finalbody) 1347 Statement_toIR(s.finalbody, irs, &finallyState); 1348 block_goto(blx, BCgoto, retblock); 1349 1350 block_next(blx,BC_ret,null); 1351 1352 /* Append the last successor to finallyblock, which is the first block past the BC_ret block. 1353 */ 1354 finallyblock.appendSucc(blx.curblock); 1355 1356 retblock.appendSucc(blx.curblock); 1357 1358 /* The BCfinally..BC_ret blocks form a function that gets called from stack unwinding. 1359 * The successors to BC_ret blocks are both the next outer BCfinally and the destination 1360 * after the unwinding is complete. 1361 */ 1362 for (block *b = tryblock; b != finallyblock; b = b.Bnext) 1363 { 1364 block *btry = b.Btry; 1365 1366 if (b.BC == BCgoto && b.numSucc() == 1) 1367 { 1368 block *bdest = b.nthSucc(0); 1369 if (btry && bdest.Btry != btry) 1370 { 1371 //printf("test1 b %p b.Btry %p bdest %p bdest.Btry %p\n", b, btry, bdest, bdest.Btry); 1372 block *bfinally = btry.nthSucc(1); 1373 if (bfinally == finallyblock) 1374 { 1375 b.appendSucc(finallyblock); 1376 } 1377 } 1378 } 1379 1380 // If the goto exits a try block, then the finally block is also a successor 1381 if (b.BC == BCgoto && b.numSucc() == 2) // if goto exited a tryblock 1382 { 1383 block *bdest = b.nthSucc(0); 1384 1385 // If the last finally block executed by the goto 1386 if (bdest.Btry == tryblock.Btry) 1387 { 1388 // The finally block will exit and return to the destination block 1389 retblock.appendSucc(bdest); 1390 } 1391 } 1392 1393 if (b.BC == BC_ret && b.Btry == tryblock) 1394 { 1395 // b is nested inside this TryFinally, and so this finally will be called next 1396 b.appendSucc(finallyblock); 1397 } 1398 } 1399 } 1400 } 1401 1402 /**************************************** 1403 */ 1404 1405 override void visit(SynchronizedStatement s) 1406 { 1407 assert(0); 1408 } 1409 1410 1411 /**************************************** 1412 */ 1413 1414 override void visit(InlineAsmStatement s) 1415 // { .visit(irs, s); } 1416 { 1417 block *bpre; 1418 block *basm; 1419 Symbol *sym; 1420 Blockx *blx = irs.blx; 1421 1422 //printf("AsmStatement.toIR(asmcode = %x)\n", asmcode); 1423 bpre = blx.curblock; 1424 block_next(blx,BCgoto,null); 1425 basm = blx.curblock; 1426 bpre.appendSucc(basm); 1427 basm.Bcode = s.asmcode; 1428 basm.Balign = cast(ubyte)s.asmalign; 1429 1430 // Loop through each instruction, fixing Dsymbols into Symbol's 1431 for (code *c = s.asmcode; c; c = c.next) 1432 { 1433 switch (c.IFL1) 1434 { 1435 case FLblockoff: 1436 case FLblock: 1437 { 1438 // FLblock and FLblockoff have LabelDsymbol's - convert to blocks 1439 LabelDsymbol label = cast(LabelDsymbol)c.IEV1.Vlsym; 1440 block *b = cast(block*)label.statement.extra; 1441 basm.appendSucc(b); 1442 c.IEV1.Vblock = b; 1443 break; 1444 } 1445 1446 case FLdsymbol: 1447 case FLfunc: 1448 sym = toSymbol(cast(Dsymbol)c.IEV1.Vdsym); 1449 if (sym.Sclass == SCauto && sym.Ssymnum == SYMIDX.max) 1450 symbol_add(sym); 1451 c.IEV1.Vsym = sym; 1452 c.IFL1 = sym.Sfl ? sym.Sfl : FLauto; 1453 break; 1454 1455 default: 1456 break; 1457 } 1458 1459 // Repeat for second operand 1460 switch (c.IFL2) 1461 { 1462 case FLblockoff: 1463 case FLblock: 1464 { 1465 LabelDsymbol label = cast(LabelDsymbol)c.IEV2.Vlsym; 1466 block *b = cast(block*)label.statement.extra; 1467 basm.appendSucc(b); 1468 c.IEV2.Vblock = b; 1469 break; 1470 } 1471 1472 case FLdsymbol: 1473 case FLfunc: 1474 { 1475 Declaration d = cast(Declaration)c.IEV2.Vdsym; 1476 sym = toSymbol(cast(Dsymbol)d); 1477 if (sym.Sclass == SCauto && sym.Ssymnum == SYMIDX.max) 1478 symbol_add(sym); 1479 c.IEV2.Vsym = sym; 1480 c.IFL2 = sym.Sfl ? sym.Sfl : FLauto; 1481 if (d.isDataseg()) 1482 sym.Sflags |= SFLlivexit; 1483 break; 1484 } 1485 1486 default: 1487 break; 1488 } 1489 } 1490 1491 basm.bIasmrefparam = s.refparam; // are parameters reference? 1492 basm.usIasmregs = s.regs; // registers modified 1493 1494 block_next(blx,BCasm, null); 1495 basm.prependSucc(blx.curblock); 1496 1497 if (s.naked) 1498 { 1499 blx.funcsym.Stype.Tty |= mTYnaked; 1500 } 1501 } 1502 1503 /**************************************** 1504 */ 1505 1506 override void visit(ImportStatement s) 1507 { 1508 } 1509 1510 static void Statement_toIR(Statement s, IRState *irs, StmtState* stmtstate) 1511 { 1512 scope v = new S2irVisitor(irs, stmtstate); 1513 s.accept(v); 1514 } 1515 } 1516 1517 void Statement_toIR(Statement s, IRState *irs) 1518 { 1519 /* Generate a block for each label 1520 */ 1521 FuncDeclaration fd = irs.getFunc(); 1522 if (auto labtab = fd.labtab) 1523 foreach (keyValue; labtab.tab.asRange) 1524 { 1525 //printf(" KV: %s = %s\n", keyValue.key.toChars(), keyValue.value.toChars()); 1526 LabelDsymbol label = cast(LabelDsymbol)keyValue.value; 1527 if (label.statement) 1528 label.statement.extra = dmd.backend.global.block_calloc(); 1529 } 1530 1531 StmtState stmtstate; 1532 scope v = new S2irVisitor(irs, &stmtstate); 1533 s.accept(v); 1534 } 1535 1536 /*************************************************** 1537 * Insert finally block calls when doing a goto from 1538 * inside a try block to outside. 1539 * Done after blocks are generated because then we know all 1540 * the edges of the graph, but before the Bpred's are computed. 1541 * Only for EH_DWARF exception unwinding. 1542 * Params: 1543 * startblock = first block in function 1544 */ 1545 1546 void insertFinallyBlockCalls(block *startblock) 1547 { 1548 int flagvalue = 0; // 0 is forunwind_resume 1549 block *bcret = null; 1550 1551 block *bcretexp = null; 1552 Symbol *stmp; 1553 1554 enum log = false; 1555 1556 static if (log) 1557 { 1558 printf("------- before ----------\n"); 1559 numberBlocks(startblock); 1560 foreach (b; BlockRange(startblock)) WRblock(b); 1561 printf("-------------------------\n"); 1562 } 1563 1564 block **pb; 1565 block **pbnext; 1566 for (pb = &startblock; *pb; pb = pbnext) 1567 { 1568 block *b = *pb; 1569 pbnext = &b.Bnext; 1570 if (!b.Btry) 1571 continue; 1572 1573 switch (b.BC) 1574 { 1575 case BCret: 1576 // Rewrite into a BCgoto => BCret 1577 if (!bcret) 1578 { 1579 bcret = dmd.backend.global.block_calloc(); 1580 bcret.BC = BCret; 1581 } 1582 b.BC = BCgoto; 1583 b.appendSucc(bcret); 1584 goto case_goto; 1585 1586 case BCretexp: 1587 { 1588 // Rewrite into a BCgoto => BCretexp 1589 elem *e = b.Belem; 1590 tym_t ty = tybasic(e.Ety); 1591 if (!bcretexp) 1592 { 1593 bcretexp = dmd.backend.global.block_calloc(); 1594 bcretexp.BC = BCretexp; 1595 type *t; 1596 if ((ty == TYstruct || ty == TYarray) && e.ET) 1597 t = e.ET; 1598 else 1599 t = type_fake(ty); 1600 stmp = symbol_genauto(t); 1601 bcretexp.Belem = el_var(stmp); 1602 if ((ty == TYstruct || ty == TYarray) && e.ET) 1603 bcretexp.Belem.ET = t; 1604 } 1605 b.BC = BCgoto; 1606 b.appendSucc(bcretexp); 1607 b.Belem = elAssign(el_var(stmp), e, null, e.ET); 1608 goto case_goto; 1609 } 1610 1611 case BCgoto: 1612 case_goto: 1613 { 1614 /* From this: 1615 * BCgoto [breakblock] 1616 * BC_try [body] [BC_finally] 1617 * body 1618 * BCgoto [breakblock] 1619 * BC_finally [BC_lpad] [finalbody] [breakblock] 1620 * BC_lpad [finalbody] 1621 * finalbody 1622 * BCgoto [BC_ret] 1623 * BC_ret 1624 * breakblock 1625 * 1626 * Build this: 1627 * BCgoto [BC_try] 1628 * BC_try [body] [BC_finally] 1629 * body 1630 *x BCgoto sflag=n; [finalbody] 1631 * BC_finally [BC_lpad] [finalbody] [breakblock] 1632 * BC_lpad [finalbody] 1633 * finalbody 1634 * BCgoto [BCiftrue] 1635 *x BCiftrue (sflag==n) [breakblock] 1636 *x BC_ret 1637 * breakblock 1638 */ 1639 block *breakblock = b.nthSucc(0); 1640 block *lasttry = breakblock.Btry; 1641 block *blast = b; 1642 ++flagvalue; 1643 for (block *bt = b.Btry; bt != lasttry; bt = bt.Btry) 1644 { 1645 assert(bt.BC == BC_try); 1646 block *bf = bt.nthSucc(1); 1647 if (bf.BC == BCjcatch) 1648 continue; // skip try-catch 1649 assert(bf.BC == BC_finally); 1650 1651 block *retblock = bf.b_ret; 1652 assert(retblock.BC == BC_ret); 1653 assert(retblock.numSucc() == 0); 1654 1655 // Append (_flag = flagvalue) to b.Belem 1656 Symbol *sflag = bf.flag; 1657 elem *e = el_bin(OPeq, TYint, el_var(sflag), el_long(TYint, flagvalue)); 1658 b.Belem = el_combine(b.Belem, e); 1659 1660 if (blast.BC == BCiftrue) 1661 { 1662 blast.setNthSucc(0, bf.nthSucc(1)); 1663 } 1664 else 1665 { 1666 assert(blast.BC == BCgoto); 1667 blast.setNthSucc(0, bf.nthSucc(1)); 1668 } 1669 1670 // Create new block, bnew, which will replace retblock 1671 block *bnew = dmd.backend.global.block_calloc(); 1672 1673 /* Rewrite BC_ret block as: 1674 * if (sflag == flagvalue) goto breakblock; else goto bnew; 1675 */ 1676 e = el_bin(OPeqeq, TYbool, el_var(sflag), el_long(TYint, flagvalue)); 1677 retblock.Belem = el_combine(retblock.Belem, e); 1678 retblock.BC = BCiftrue; 1679 retblock.appendSucc(breakblock); 1680 retblock.appendSucc(bnew); 1681 1682 bnew.Bnext = retblock.Bnext; 1683 retblock.Bnext = bnew; 1684 1685 bnew.BC = BC_ret; 1686 bnew.Btry = retblock.Btry; 1687 bf.b_ret = bnew; 1688 1689 blast = retblock; 1690 } 1691 break; 1692 } 1693 1694 default: 1695 break; 1696 } 1697 } 1698 if (bcret) 1699 { 1700 *pb = bcret; 1701 pb = &(*pb).Bnext; 1702 } 1703 if (bcretexp) 1704 *pb = bcretexp; 1705 1706 static if (log) 1707 { 1708 printf("------- after ----------\n"); 1709 numberBlocks(startblock); 1710 foreach (b; BlockRange(startblock)) WRblock(b); 1711 printf("-------------------------\n"); 1712 } 1713 } 1714 1715 /*************************************************** 1716 * Insert gotos to finally blocks when doing a return or goto from 1717 * inside a try block to outside. 1718 * Done after blocks are generated because then we know all 1719 * the edges of the graph, but before the Bpred's are computed. 1720 * Only for functions with no exception handling. 1721 * Very similar to insertFinallyBlockCalls(). 1722 * Params: 1723 * startblock = first block in function 1724 */ 1725 1726 void insertFinallyBlockGotos(block *startblock) 1727 { 1728 enum log = false; 1729 1730 // Insert all the goto's 1731 insertFinallyBlockCalls(startblock); 1732 1733 /* Remove all the BC_try, BC_finally, BC_lpad and BC_ret 1734 * blocks. 1735 * Actually, just make them into no-ops and let the optimizer 1736 * delete them. 1737 */ 1738 foreach (b; BlockRange(startblock)) 1739 { 1740 b.Btry = null; 1741 switch (b.BC) 1742 { 1743 case BC_try: 1744 b.BC = BCgoto; 1745 list_subtract(&b.Bsucc, b.nthSucc(1)); 1746 break; 1747 1748 case BC_finally: 1749 b.BC = BCgoto; 1750 list_subtract(&b.Bsucc, b.nthSucc(2)); 1751 list_subtract(&b.Bsucc, b.nthSucc(0)); 1752 break; 1753 1754 case BC_lpad: 1755 b.BC = BCgoto; 1756 break; 1757 1758 case BC_ret: 1759 b.BC = BCexit; 1760 break; 1761 1762 default: 1763 break; 1764 } 1765 } 1766 1767 static if (log) 1768 { 1769 printf("------- after ----------\n"); 1770 numberBlocks(startblock); 1771 foreach (b; BlockRange(startblock)) WRblock(b); 1772 printf("-------------------------\n"); 1773 } 1774 }