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