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 }