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