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 }