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