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