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