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 1
    srcpos_setLoc(e.Esrcpos, loc);
77
}
78

79
private void block_setLoc(block *b, const ref Loc loc) pure nothrow
80
{
81 1
    srcpos_setLoc(b.Bsrcpos, loc);
82
}
83

84
private void srcpos_setLoc(ref Srcpos s, const ref Loc loc) pure nothrow
85
{
86 1
    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 1
    if (config.ehmethod == EHmethod.EH_WIN32 && !(blx.funcsym.Sfunc.Fflags3 & Feh_none))
97 0
        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 1
    block *b = dmd.backend.global.block_calloc();
107 1
    b.Btry = blx.tryblock;
108 1
    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 1
    if (irs.params.cov && loc.linnum)
119
    {
120 1
        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 1
    this(IRState *irs, StmtState* stmtstate)
131
    {
132 1
        this.irs = irs;
133 1
        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 0
        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 1
        elem *e;
160 1
        Blockx *blx = irs.blx;
161

162
        //printf("IfStatement.toIR('%s')\n", s.condition.toChars());
163

164 1
        StmtState mystate = StmtState(stmtstate, s);
165

166
        // bexit is the block that gets control after this IfStatement is done
167 1
        block *bexit = mystate.breakBlock ? mystate.breakBlock : dmd.backend.global.block_calloc();
168

169 1
        incUsage(irs, s.loc);
170 1
        e = toElemDtor(s.condition, irs);
171 1
        block_appendexp(blx.curblock, e);
172 1
        block *bcond = blx.curblock;
173 1
        block_next(blx, BCiftrue, null);
174

175 1
        bcond.appendSucc(blx.curblock);
176 1
        if (s.ifbody)
177 1
            Statement_toIR(s.ifbody, irs, &mystate);
178 1
        blx.curblock.appendSucc(bexit);
179

180 1
        if (s.elsebody)
181
        {
182 1
            block_next(blx, BCgoto, null);
183 1
            bcond.appendSucc(blx.curblock);
184 1
            Statement_toIR(s.elsebody, irs, &mystate);
185 1
            blx.curblock.appendSucc(bexit);
186
        }
187
        else
188 1
            bcond.appendSucc(bexit);
189

190 1
        block_next(blx, BCgoto, bexit);
191

192
    }
193

194
    /**************************************
195
     */
196

197
    override void visit(PragmaStatement s)
198
    {
199
        //printf("PragmaStatement.toIR()\n");
200 0
        if (s.ident == Id.startaddress)
201
        {
202 0
            assert(s.args && s.args.dim == 1);
203 0
            Expression e = (*s.args)[0];
204 0
            Dsymbol sa = getDsymbol(e);
205 0
            FuncDeclaration f = sa.isFuncDeclaration();
206 0
            assert(f);
207 0
            Symbol *sym = toSymbol(f);
208 0
            irs.startaddress = sym;
209
        }
210
    }
211

212
    /***********************
213
     */
214

215
    override void visit(WhileStatement s)
216
    {
217 0
        assert(0); // was "lowered"
218
    }
219

220
    /******************************************
221
     */
222

223
    override void visit(DoStatement s)
224
    {
225 1
        Blockx *blx = irs.blx;
226

227 1
        StmtState mystate = StmtState(stmtstate, s);
228 1
        mystate.breakBlock = block_calloc(blx);
229 1
        mystate.contBlock = block_calloc(blx);
230

231 1
        block *bpre = blx.curblock;
232 1
        block_next(blx, BCgoto, null);
233 1
        bpre.appendSucc(blx.curblock);
234

235 1
        mystate.contBlock.appendSucc(blx.curblock);
236 1
        mystate.contBlock.appendSucc(mystate.breakBlock);
237

238 1
        if (s._body)
239 1
            Statement_toIR(s._body, irs, &mystate);
240 1
        blx.curblock.appendSucc(mystate.contBlock);
241

242 1
        block_next(blx, BCgoto, mystate.contBlock);
243 1
        incUsage(irs, s.condition.loc);
244 1
        block_appendexp(mystate.contBlock, toElemDtor(s.condition, irs));
245 1
        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 1
        Blockx *blx = irs.blx;
256

257 1
        StmtState mystate = StmtState(stmtstate, s);
258 1
        mystate.breakBlock = block_calloc(blx);
259 1
        mystate.contBlock = block_calloc(blx);
260

261 1
        if (s._init)
262 0
            Statement_toIR(s._init, irs, &mystate);
263 1
        block *bpre = blx.curblock;
264 1
        block_next(blx,BCgoto,null);
265 1
        block *bcond = blx.curblock;
266 1
        bpre.appendSucc(bcond);
267 1
        mystate.contBlock.appendSucc(bcond);
268 1
        if (s.condition)
269
        {
270 1
            incUsage(irs, s.condition.loc);
271 1
            block_appendexp(bcond, toElemDtor(s.condition, irs));
272 1
            block_next(blx,BCiftrue,null);
273 1
            bcond.appendSucc(blx.curblock);
274 1
            bcond.appendSucc(mystate.breakBlock);
275
        }
276
        else
277
        {   /* No conditional, it's a straight goto
278
             */
279 1
            block_next(blx,BCgoto,null);
280 1
            bcond.appendSucc(blx.curblock);
281
        }
282

283 1
        if (s._body)
284 1
            Statement_toIR(s._body, irs, &mystate);
285
        /* End of the body goes to the continue block
286
         */
287 1
        blx.curblock.appendSucc(mystate.contBlock);
288 1
        block_setLoc(blx.curblock, s.endloc);
289 1
        block_next(blx, BCgoto, mystate.contBlock);
290

291 1
        if (s.increment)
292
        {
293 1
            incUsage(irs, s.increment.loc);
294 1
            block_appendexp(mystate.contBlock, toElemDtor(s.increment, irs));
295
        }
296

297
        /* The 'break' block follows the for statement.
298
         */
299 1
        block_next(blx,BCgoto, mystate.breakBlock);
300
    }
301

302

303
    /**************************************
304
     */
305

306
    override void visit(ForeachStatement s)
307
    {
308 0
        printf("ForeachStatement.toIR() %s\n", s.toChars());
309 0
        assert(0);  // done by "lowering" in the front end
310
    }
311

312

313
    /**************************************
314
     */
315

316
    override void visit(ForeachRangeStatement s)
317
    {
318 0
        assert(0);
319
    }
320

321

322
    /****************************************
323
     */
324

325
    override void visit(BreakStatement s)
326
    {
327 1
        block *bbreak;
328 1
        block *b;
329 1
        Blockx *blx = irs.blx;
330

331 1
        bbreak = stmtstate.getBreakBlock(s.ident);
332 1
        assert(bbreak);
333 1
        b = blx.curblock;
334 1
        incUsage(irs, s.loc);
335

336
        // Adjust exception handler scope index if in different try blocks
337 1
        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 1
        b.appendSucc(bbreak);
345 1
        block_setLoc(b, s.loc);
346 1
        block_next(blx, BCgoto, null);
347
    }
348

349
    /************************************
350
     */
351

352
    override void visit(ContinueStatement s)
353
    {
354 1
        block *bcont;
355 1
        block *b;
356 1
        Blockx *blx = irs.blx;
357

358
        //printf("ContinueStatement.toIR() %p\n", this);
359 1
        bcont = stmtstate.getContBlock(s.ident);
360 1
        assert(bcont);
361 1
        b = blx.curblock;
362 1
        incUsage(irs, s.loc);
363

364
        // Adjust exception handler scope index if in different try blocks
365 1
        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 1
        b.appendSucc(bcont);
373 1
        block_setLoc(b, s.loc);
374 1
        block_next(blx, BCgoto, null);
375
    }
376

377

378
    /**************************************
379
     */
380

381
    override void visit(GotoStatement s)
382
    {
383 1
        Blockx *blx = irs.blx;
384

385 1
        assert(s.label.statement);
386 1
        assert(s.tf == s.label.statement.tf);
387

388 1
        block* bdest = cast(block*)s.label.statement.extra;
389 1
        block *b = blx.curblock;
390 1
        incUsage(irs, s.loc);
391 1
        b.appendSucc(bdest);
392 1
        block_setLoc(b, s.loc);
393

394 1
        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 1
        Blockx *blx = irs.blx;
401 1
        block *bc = blx.curblock;
402 1
        StmtState mystate = StmtState(stmtstate, s);
403 1
        mystate.ident = s.ident;
404

405 1
        block* bdest = cast(block*)s.extra;
406
        // At last, we know which try block this label is inside
407 1
        bdest.Btry = blx.tryblock;
408

409 1
        block_next(blx, BCgoto, bdest);
410 1
        bc.appendSucc(blx.curblock);
411 1
        if (s.statement)
412 1
            Statement_toIR(s.statement, irs, &mystate);
413
    }
414

415
    /**************************************
416
     */
417

418
    override void visit(SwitchStatement s)
419
    {
420 1
        Blockx *blx = irs.blx;
421

422
        //printf("SwitchStatement.toIR()\n");
423 1
        StmtState mystate = StmtState(stmtstate, s);
424

425 1
        mystate.switchBlock = blx.curblock;
426

427
        /* Block for where "break" goes to
428
         */
429 1
        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 1
        mystate.defaultBlock = s.sdefault ? block_calloc(blx) : mystate.breakBlock;
438

439 1
        const numcases = s.cases ? s.cases.dim : 0;
440

441
        /* allocate a block for each case
442
         */
443 1
        if (numcases)
444 1
            foreach (cs; *s.cases)
445
            {
446 1
                cs.extra = cast(void*)block_calloc(blx);
447
            }
448

449 1
        incUsage(irs, s.loc);
450 1
        elem *econd = toElemDtor(s.condition, irs);
451 1
        if (s.hasVars)
452
        {   /* Generate a sequence of if-then-else blocks for the cases.
453
             */
454 1
            if (econd.Eoper != OPvar)
455
            {
456 1
                elem *e = exp2_copytotemp(econd);
457 1
                block_appendexp(mystate.switchBlock, e);
458 1
                econd = e.EV.E2;
459
            }
460

461 1
            if (numcases)
462 1
                foreach (cs; *s.cases)
463
                {
464 1
                    elem *ecase = toElemDtor(cs.exp, irs);
465 1
                    elem *e = el_bin(OPeqeq, TYbool, el_copytree(econd), ecase);
466 1
                    block *b = blx.curblock;
467 1
                    block_appendexp(b, e);
468 1
                    block* cb = cast(block*)cs.extra;
469 1
                    block_next(blx, BCiftrue, null);
470 1
                    b.appendSucc(cb);
471 1
                    b.appendSucc(blx.curblock);
472
                }
473

474
            /* The final 'else' clause goes to the default
475
             */
476 1
            block *b = blx.curblock;
477 1
            block_next(blx, BCgoto, null);
478 1
            b.appendSucc(mystate.defaultBlock);
479

480 1
            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 1
            block_goto(blx, BCgoto, mystate.breakBlock);
486 1
            return;
487
        }
488

489 1
        if (s.condition.type.isString())
490
        {
491
            // This codepath was replaced by lowering during semantic
492
            // to object.__switch in druntime.
493 0
            assert(0);
494
        }
495

496 1
        block_appendexp(mystate.switchBlock, econd);
497 1
        block_next(blx,BCswitch,null);
498

499
        // Corresponding free is in block_free
500
        alias TCase = typeof(mystate.switchBlock.Bswitch[0]);
501 1
        auto pu = cast(TCase *)Mem.check(.malloc(TCase.sizeof * (numcases + 1)));
502 1
        mystate.switchBlock.Bswitch = pu;
503
        /* First pair is the number of cases, and the default block
504
         */
505 1
        *pu++ = numcases;
506 1
        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 1
        if (numcases)
513 1
            foreach (cs; *s.cases)
514 1
                *pu++ = cs.exp.toInteger();
515

516 1
        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 1
        block_goto(blx, BCgoto, mystate.breakBlock);
522
    }
523

524
    override void visit(CaseStatement s)
525
    {
526 1
        Blockx *blx = irs.blx;
527 1
        block *bcase = blx.curblock;
528 1
        block* cb = cast(block*)s.extra;
529 1
        block_next(blx, BCgoto, cb);
530 1
        block *bsw = stmtstate.getSwitchBlock();
531 1
        if (bsw.BC == BCswitch)
532 1
            bsw.appendSucc(cb);   // second entry in pair
533 1
        bcase.appendSucc(cb);
534 1
        incUsage(irs, s.loc);
535 1
        if (s.statement)
536 1
            Statement_toIR(s.statement, irs, stmtstate);
537
    }
538

539
    override void visit(DefaultStatement s)
540
    {
541 1
        Blockx *blx = irs.blx;
542 1
        block *bcase = blx.curblock;
543 1
        block *bdefault = stmtstate.getDefaultBlock();
544 1
        block_next(blx,BCgoto,bdefault);
545 1
        bcase.appendSucc(blx.curblock);
546 1
        incUsage(irs, s.loc);
547 1
        if (s.statement)
548 1
            Statement_toIR(s.statement, irs, stmtstate);
549
    }
550

551
    override void visit(GotoDefaultStatement s)
552
    {
553 1
        block *b;
554 1
        Blockx *blx = irs.blx;
555 1
        block *bdest = stmtstate.getDefaultBlock();
556

557 1
        b = blx.curblock;
558

559
        // The rest is equivalent to GotoStatement
560

561 1
        b.appendSucc(bdest);
562 1
        incUsage(irs, s.loc);
563 1
        block_next(blx,BCgoto,null);
564
    }
565

566
    override void visit(GotoCaseStatement s)
567
    {
568 1
        Blockx *blx = irs.blx;
569 1
        block *bdest = cast(block*)s.cs.extra;
570 1
        block *b = blx.curblock;
571

572
        // The rest is equivalent to GotoStatement
573

574 1
        b.appendSucc(bdest);
575 1
        incUsage(irs, s.loc);
576 1
        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 1
        assert(s.exp !is null, "SwitchErrorStatement needs to have a valid Expression.");
584

585 1
        Blockx *blx = irs.blx;
586

587
        //printf("SwitchErrorStatement.toIR(), exp = %s\n", s.exp ? s.exp.toChars() : "");
588 1
        incUsage(irs, s.loc);
589 1
        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 1
        Blockx *blx = irs.blx;
599 1
        BC bc;
600

601 1
        incUsage(irs, s.loc);
602 1
        if (s.exp)
603
        {
604 1
            elem *e;
605

606 1
            FuncDeclaration func = irs.getFunc();
607 1
            assert(func);
608 1
            auto tf = func.type.isTypeFunction();
609 1
            assert(tf);
610

611 1
            RET retmethod = retStyle(tf, func.needThis());
612 1
            if (retmethod == RET.stack)
613
            {
614 1
                elem *es;
615 1
                bool writetohp;
616

617
                /* If returning struct literal, write result
618
                 * directly into return value
619
                 */
620 1
                if (auto sle = s.exp.isStructLiteralExp())
621
                {
622 1
                    sle.sym = irs.shidden;
623 1
                    writetohp = true;
624
                }
625
                /* Detect function call that returns the same struct
626
                 * and construct directly into *shidden
627
                 */
628 1
                else if (auto ce = s.exp.isCallExp())
629
                {
630 1
                    if (ce.e1.op == TOK.variable || ce.e1.op == TOK.star)
631
                    {
632 1
                        Type t = ce.e1.type.toBasetype();
633 1
                        if (t.ty == Tdelegate)
634 0
                            t = t.nextOf();
635 1
                        if (t.ty == Tfunction && retStyle(cast(TypeFunction)t, ce.f && ce.f.needThis()) == RET.stack)
636
                        {
637 1
                            irs.ehidden = el_var(irs.shidden);
638 1
                            e = toElemDtor(s.exp, irs);
639 1
                            e = el_una(OPaddr, TYnptr, e);
640 1
                            goto L1;
641
                        }
642
                    }
643 1
                    else if (auto dve = ce.e1.isDotVarExp())
644
                    {
645 1
                        auto fd = dve.var.isFuncDeclaration();
646 1
                        if (fd && fd.isCtorDeclaration())
647
                        {
648 1
                            if (auto sle = dve.e1.isStructLiteralExp())
649
                            {
650 1
                                sle.sym = irs.shidden;
651 1
                                writetohp = true;
652
                            }
653
                        }
654 1
                        Type t = ce.e1.type.toBasetype();
655 1
                        if (t.ty == Tdelegate)
656 0
                            t = t.nextOf();
657 1
                        if (t.ty == Tfunction && retStyle(cast(TypeFunction)t, fd && fd.needThis()) == RET.stack)
658
                        {
659 1
                            irs.ehidden = el_var(irs.shidden);
660 1
                            e = toElemDtor(s.exp, irs);
661 1
                            e = el_una(OPaddr, TYnptr, e);
662 1
                            goto L1;
663
                        }
664
                    }
665
                }
666 1
                e = toElemDtor(s.exp, irs);
667 1
                assert(e);
668

669 1
                if (writetohp ||
670 1
                    (func.nrvo_can && func.nrvo_var))
671
                {
672
                    // Return value via hidden pointer passed as parameter
673
                    // Write exp; return shidden;
674 1
                    es = e;
675
                }
676
                else
677
                {
678
                    // Return value via hidden pointer passed as parameter
679
                    // Write *shidden=exp; return shidden;
680 1
                    es = el_una(OPind,e.Ety,el_var(irs.shidden));
681 1
                    es = elAssign(es, e, s.exp.type, null);
682
                }
683 1
                e = el_var(irs.shidden);
684 1
                e = el_bin(OPcomma, e.Ety, es, e);
685
            }
686 1
            else if (tf.isref)
687
            {
688
                // Reference return, so convert to a pointer
689 1
                e = toElemDtor(s.exp, irs);
690 1
                e = addressElem(e, s.exp.type.pointerTo());
691
            }
692
            else
693
            {
694 1
                e = toElemDtor(s.exp, irs);
695 1
                assert(e);
696
            }
697
        L1:
698 1
            elem_setLoc(e, s.loc);
699 1
            block_appendexp(blx.curblock, e);
700 1
            bc = BCretexp;
701
//            if (type_zeroCopy(Type_toCtype(s.exp.type)))
702
//                bc = BCret;
703
        }
704
        else
705 1
            bc = BCret;
706

707 1
        block *finallyBlock;
708 1
        if (config.ehmethod != EHmethod.EH_DWARF &&
709 1
            !irs.isNothrow() &&
710 0
            (finallyBlock = stmtstate.getFinallyBlock()) != null)
711
        {
712 0
            assert(finallyBlock.BC == BC_finally);
713 0
            blx.curblock.appendSucc(finallyBlock);
714
        }
715

716 1
        block_next(blx, bc, null);
717
    }
718

719
    /**************************************
720
     */
721

722
    override void visit(ExpStatement s)
723
    {
724 1
        Blockx *blx = irs.blx;
725

726
        //printf("ExpStatement.toIR(), exp: %p %s\n", s.exp, s.exp ? s.exp.toChars() : "");
727 1
        if (s.exp)
728
        {
729 1
            if (s.exp.hasCode)
730 1
                incUsage(irs, s.loc);
731

732 1
            block_appendexp(blx.curblock, toElemDtor(s.exp, irs));
733
        }
734
    }
735

736
    /**************************************
737
     */
738

739
    override void visit(CompoundStatement s)
740
    {
741 1
        if (s.statements)
742
        {
743 1
            foreach (s2; *s.statements)
744
            {
745 1
                if (s2)
746 1
                    Statement_toIR(s2, irs, stmtstate);
747
            }
748
        }
749
    }
750

751

752
    /**************************************
753
     */
754

755
    override void visit(UnrolledLoopStatement s)
756
    {
757 1
        Blockx *blx = irs.blx;
758

759 1
        StmtState mystate = StmtState(stmtstate, s);
760 1
        mystate.breakBlock = block_calloc(blx);
761

762 1
        block *bpre = blx.curblock;
763 1
        block_next(blx, BCgoto, null);
764

765 1
        block *bdo = blx.curblock;
766 1
        bpre.appendSucc(bdo);
767

768 1
        block *bdox;
769

770 1
        foreach (s2; *s.statements)
771
        {
772 1
            if (s2)
773
            {
774 1
                mystate.contBlock = block_calloc(blx);
775

776 1
                Statement_toIR(s2, irs, &mystate);
777

778 1
                bdox = blx.curblock;
779 1
                block_next(blx, BCgoto, mystate.contBlock);
780 1
                bdox.appendSucc(mystate.contBlock);
781
            }
782
        }
783

784 1
        bdox = blx.curblock;
785 1
        block_next(blx, BCgoto, mystate.breakBlock);
786 1
        bdox.appendSucc(mystate.breakBlock);
787
    }
788

789

790
    /**************************************
791
     */
792

793
    override void visit(ScopeStatement s)
794
    {
795 1
        if (s.statement)
796
        {
797 1
            Blockx *blx = irs.blx;
798 1
            StmtState mystate = StmtState(stmtstate, s);
799

800 1
            if (mystate.prev.ident)
801 1
                mystate.ident = mystate.prev.ident;
802

803 1
            Statement_toIR(s.statement, irs, &mystate);
804

805 1
            if (mystate.breakBlock)
806 0
                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 1
        if (s.exp.op == TOK.scope_ || s.exp.op == TOK.type)
817
        {
818
        }
819
        else
820
        {
821
            // Declare with handle
822 1
            auto sp = toSymbol(s.wthis);
823 1
            symbol_add(sp);
824

825
            // Perform initialization of with handle
826 1
            auto ie = s.wthis._init.isExpInitializer();
827 1
            assert(ie);
828 1
            auto ei = toElemDtor(ie.exp, irs);
829 1
            auto e = el_var(sp);
830 1
            e = el_bin(OPeq,e.Ety, e, ei);
831 1
            elem_setLoc(e, s.loc);
832 1
            incUsage(irs, s.loc);
833 1
            block_appendexp(irs.blx.curblock,e);
834
        }
835
        // Execute with block
836 1
        if (s._body)
837 1
            Statement_toIR(s._body, irs, stmtstate);
838
    }
839

840

841
    /***************************************
842
     */
843

844
    override void visit(ThrowStatement s)
845
    {
846
        // throw(exp)
847

848 1
        Blockx *blx = irs.blx;
849

850 1
        incUsage(irs, s.loc);
851 1
        elem *e = toElemDtor(s.exp, irs);
852 1
        const int rtlthrow = config.ehmethod == EHmethod.EH_DWARF ? RTLSYM_THROWDWARF : RTLSYM_THROWC;
853 1
        e = el_bin(OPcall, TYvoid, el_var(getRtlsym(rtlthrow)),e);
854 1
        block_appendexp(blx.curblock, e);
855 1
        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 1
        Blockx *blx = irs.blx;
870

871 1
        if (blx.funcsym.Sfunc.Fflags3 & Feh_none) printf("visit %s\n", blx.funcsym.Sident.ptr);
872 1
        if (blx.funcsym.Sfunc.Fflags3 & Feh_none) assert(0);
873

874 1
        if (config.ehmethod == EHmethod.EH_WIN32)
875 0
            nteh_declarvars(blx);
876

877 1
        StmtState mystate = StmtState(stmtstate, s);
878

879 1
        block *tryblock = block_goto(blx,BCgoto,null);
880

881 1
        int previndex = blx.scope_index;
882 1
        tryblock.Blast_index = previndex;
883 1
        blx.scope_index = tryblock.Bscope_index = blx.next_index++;
884

885
        // Set the current scope index
886 1
        setScopeIndex(blx,tryblock,tryblock.Bscope_index);
887

888
        // This is the catch variable
889 1
        tryblock.jcatchvar = symbol_genauto(type_fake(mTYvolatile | TYnptr));
890

891 1
        blx.tryblock = tryblock;
892 1
        block *breakblock = block_calloc(blx);
893 1
        block_goto(blx,BC_try,null);
894 1
        if (s._body)
895
        {
896 1
            Statement_toIR(s._body, irs, &mystate);
897
        }
898 1
        blx.tryblock = tryblock.Btry;
899

900
        // break block goes here
901 1
        block_goto(blx, BCgoto, breakblock);
902

903 1
        setScopeIndex(blx,blx.curblock, previndex);
904 1
        blx.scope_index = previndex;
905

906
        // create new break block that follows all the catches
907 1
        block *breakblock2 = block_calloc(blx);
908

909 1
        blx.curblock.appendSucc(breakblock2);
910 1
        block_next(blx,BCgoto,null);
911

912 1
        assert(s.catches);
913 1
        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 1
            Symbol *seax = symbol_name("__EAX", SCpseudo, type_fake(mTYvolatile | TYnptr));
932 1
            seax.Sreglsw = 0;          // EAX, RAX, whatevs
933 1
            symbol_add(seax);
934 1
            Symbol *sedx = symbol_name("__EDX", SCpseudo, type_fake(mTYvolatile | TYint));
935 1
            sedx.Sreglsw = 2;          // EDX, RDX, whatevs
936 1
            symbol_add(sedx);
937 1
            Symbol *shandler = symbol_name("__handler", SCauto, tstypes[TYint]);
938 1
            symbol_add(shandler);
939 1
            Symbol *seo = symbol_name("__exception_object", SCauto, tspvoid);
940 1
            symbol_add(seo);
941

942 1
            elem *e1 = el_bin(OPeq, TYvoid, el_var(shandler), el_var(sedx)); // __handler = __RDX
943 1
            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 1
                elem *ebegin = el_var(getRtlsym(RTLSYM_BEGIN_CATCH));
955 1
                elem *e = el_bin(OPcall, TYnptr, ebegin, el_var(seo));
956 1
                elem *e3 = el_bin(OPeq, TYvoid, el_var(tryblock.jcatchvar), e);
957
            }
958

959 1
            block *bcatch = blx.curblock;
960 1
            tryblock.appendSucc(bcatch);
961 1
            block_goto(blx, BCjcatch, null);
962

963 1
            block *defaultblock = block_calloc(blx);
964

965 1
            block *bswitch = blx.curblock;
966 1
            bswitch.Belem = el_combine(el_combine(e1, e2),
967
                                        el_combine(e3, el_var(shandler)));
968

969 1
            const numcases = s.catches.dim;
970 1
            bswitch.Bswitch = cast(targ_llong *) Mem.check(.malloc((targ_llong).sizeof * (numcases + 1)));
971 1
            bswitch.Bswitch[0] = numcases;
972 1
            bswitch.appendSucc(defaultblock);
973 1
            block_next(blx, BCswitch, null);
974

975 1
            foreach (i, cs; *s.catches)
976
            {
977 1
                bswitch.Bswitch[1 + i] = 1 + i;
978

979 1
                if (cs.var)
980 1
                    cs.var.csym = tryblock.jcatchvar;
981

982 1
                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 1
                Type tcatch = cs.type.toBasetype();
989 1
                ClassDeclaration cd = tcatch.isClassHandle();
990 1
                bool isCPPclass = cd.isCPPclass();
991 1
                Symbol *catchtype;
992 1
                if (isCPPclass)
993
                {
994 1
                    catchtype = toSymbolCpp(cd);
995 1
                    if (i == 0)
996
                    {
997
                        // rewrite ebegin to use __cxa_begin_catch
998 1
                        Symbol *s2 = getRtlsym(RTLSYM_CXA_BEGIN_CATCH);
999 1
                        ebegin.EV.Vsym = s2;
1000
                    }
1001
                }
1002
                else
1003 1
                    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 1
                func_t *f = blx.funcsym.Sfunc;
1010

1011 1
                foreach (j, ct; f.typesTable[])
1012
                {
1013 1
                    if (ct == catchtype)
1014
                    {
1015 1
                        bswitch.Bswitch[1 + i] = 1 + j;  // index starts at 1
1016 1
                        goto L1;
1017
                    }
1018
                }
1019 1
                f.typesTable.push(catchtype);
1020 1
                bswitch.Bswitch[1 + i] = f.typesTable.length;  // index starts at 1
1021
           L1:
1022 1
                block *bcase = blx.curblock;
1023 1
                bswitch.appendSucc(bcase);
1024

1025 1
                if (cs.handler !is null)
1026
                {
1027 1
                    StmtState catchState = StmtState(stmtstate, s);
1028

1029
                    /* Append to block:
1030
                     *   *(sclosure + cs.var.offset) = cs.var;
1031
                     */
1032 1
                    if (cs.var && cs.var.offset) // if member of a closure
1033
                    {
1034 0
                        tym_t tym = totym(cs.var.type);
1035 0
                        elem *ex = el_var(irs.sclosure);
1036 0
                        ex = el_bin(OPadd, TYnptr, ex, el_long(TYsize_t, cs.var.offset));
1037 0
                        ex = el_una(OPind, tym, ex);
1038 0
                        ex = el_bin(OPeq, tym, ex, el_var(toSymbol(cs.var)));
1039 0
                        block_appendexp(irs.blx.curblock, ex);
1040
                    }
1041 1
                    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 1
                        FuncDeclaration fdend = FuncDeclaration.genCfunc(null, Type.tvoid, "__cxa_end_catch");
1050 1
                        Expression ec = VarExp.create(Loc.initial, fdend);
1051 1
                        Expression ecc = CallExp.create(Loc.initial, ec);
1052 1
                        ecc.type = Type.tvoid;
1053 1
                        Statement sf = ExpStatement.create(Loc.initial, ecc);
1054 1
                        Statement stf = TryFinallyStatement.create(Loc.initial, cs.handler, sf);
1055 1
                        Statement_toIR(stf, irs, &catchState);
1056
                    }
1057
                    else
1058 1
                        Statement_toIR(cs.handler, irs, &catchState);
1059
                }
1060 1
                blx.curblock.appendSucc(breakblock2);
1061 1
                if (i + 1 == numcases)
1062
                {
1063 1
                    block_next(blx, BCgoto, defaultblock);
1064 1
                    defaultblock.Belem = el_calloc();
1065 1
                    defaultblock.Belem.Ety = TYvoid;
1066 1
                    defaultblock.Belem.Eoper = OPhalt;
1067 1
                    block_next(blx, BCexit, null);
1068
                }
1069
                else
1070 1
                    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 1
            bcatch.actionTable = cast(TAction*)Mem.check(.malloc(TAction.sizeof * (numcases + 1)));
1078 1
            foreach (i; 0 .. numcases + 1)
1079 1
                bcatch.actionTable[i] = cast(TAction)bswitch.Bswitch[i];
1080

1081
        }
1082
        else
1083
        {
1084 0
            foreach (cs; *s.catches)
1085
            {
1086 0
                if (cs.var)
1087 0
                    cs.var.csym = tryblock.jcatchvar;
1088 0
                block *bcatch = blx.curblock;
1089 0
                if (cs.type)
1090 0
                    bcatch.Bcatchtype = toSymbol(cs.type.toBasetype());
1091 0
                tryblock.appendSucc(bcatch);
1092 0
                block_goto(blx, BCjcatch, null);
1093 0
                if (cs.handler !is null)
1094
                {
1095 0
                    StmtState catchState = StmtState(stmtstate, s);
1096

1097
                    /* Append to block:
1098
                     *   *(sclosure + cs.var.offset) = cs.var;
1099
                     */
1100 0
                    if (cs.var && cs.var.offset) // if member of a closure
1101
                    {
1102 0
                        tym_t tym = totym(cs.var.type);
1103 0
                        elem *ex = el_var(irs.sclosure);
1104 0
                        ex = el_bin(OPadd, TYnptr, ex, el_long(TYsize_t, cs.var.offset));
1105 0
                        ex = el_una(OPind, tym, ex);
1106 0
                        ex = el_bin(OPeq, tym, ex, el_var(toSymbol(cs.var)));
1107 0
                        block_appendexp(irs.blx.curblock, ex);
1108
                    }
1109 0
                    Statement_toIR(cs.handler, irs, &catchState);
1110
                }
1111 0
                blx.curblock.appendSucc(breakblock2);
1112 0
                block_next(blx, BCgoto, null);
1113
            }
1114
        }
1115

1116 1
        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 1
        Blockx *blx = irs.blx;
1134

1135 1
        if (config.ehmethod == EHmethod.EH_WIN32 && !(blx.funcsym.Sfunc.Fflags3 & Feh_none))
1136 0
            nteh_declarvars(blx);
1137

1138
        /* Successors to BC_try block:
1139
         *      [0] start of try block code
1140
         *      [1] BC_finally
1141
         */
1142 1
        block *tryblock = block_goto(blx, BCgoto, null);
1143

1144 1
        int previndex = blx.scope_index;
1145 1
        tryblock.Blast_index = previndex;
1146 1
        tryblock.Bscope_index = blx.next_index++;
1147 1
        blx.scope_index = tryblock.Bscope_index;
1148

1149
        // Current scope index
1150 1
        setScopeIndex(blx,tryblock,tryblock.Bscope_index);
1151

1152 1
        blx.tryblock = tryblock;
1153 1
        block_goto(blx,BC_try,null);
1154

1155 1
        StmtState bodyirs = StmtState(stmtstate, s);
1156

1157 1
        block *finallyblock = block_calloc(blx);
1158

1159 1
        tryblock.appendSucc(finallyblock);
1160 1
        finallyblock.BC = BC_finally;
1161 1
        bodyirs.finallyBlock = finallyblock;
1162

1163 1
        if (s._body)
1164 1
            Statement_toIR(s._body, irs, &bodyirs);
1165 1
        blx.tryblock = tryblock.Btry;     // back to previous tryblock
1166

1167 1
        setScopeIndex(blx,blx.curblock,previndex);
1168 1
        blx.scope_index = previndex;
1169

1170 1
        block *breakblock = block_calloc(blx);
1171 1
        block *retblock = block_calloc(blx);
1172

1173 1
        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 1
            blx.curblock.appendSucc(breakblock);
1188 1
            block_next(blx,BCgoto,finallyblock);
1189

1190 1
            block *landingPad = block_goto(blx,BC_finally,null);
1191 1
            block_goto(blx,BC_lpad,null);               // lpad is [0]
1192 1
            finallyblock.appendSucc(blx.curblock);    // start of finalybody is [1]
1193 1
            finallyblock.appendSucc(breakblock);       // breakblock is [2]
1194

1195
            /* Declare flag variable
1196
             */
1197 1
            Symbol *sflag = symbol_name("__flag", SCauto, tstypes[TYint]);
1198 1
            symbol_add(sflag);
1199 1
            finallyblock.flag = sflag;
1200 1
            finallyblock.b_ret = retblock;
1201 1
            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 1
            Symbol *sreg = symbol_name("__EAX", SCpseudo, type_fake(mTYvolatile | TYnptr));
1209 1
            sreg.Sreglsw = 0;          // EAX, RAX, whatevs
1210 1
            symbol_add(sreg);
1211 1
            Symbol *seo = symbol_name("__exception_object", SCauto, tspvoid);
1212 1
            symbol_add(seo);
1213 1
            assert(!landingPad.Belem);
1214 1
            elem *e = el_bin(OPeq, TYvoid, el_var(seo), el_var(sreg));
1215 1
            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 1
            elem *eu = el_bin(OPcall, TYvoid, el_var(getRtlsym(RTLSYM_UNWIND_RESUME)), el_var(seo));
1221 1
            eu = el_bin(OPandand, TYvoid, el_una(OPnot, TYbool, el_var(sflag)), eu);
1222 1
            assert(!retblock.Belem);
1223 1
            retblock.Belem = eu;
1224

1225 1
            StmtState finallyState = StmtState(stmtstate, s);
1226

1227 1
            setScopeIndex(blx, blx.curblock, previndex);
1228 1
            if (s.finalbody)
1229 1
                Statement_toIR(s.finalbody, irs, &finallyState);
1230 1
            block_goto(blx, BCgoto, retblock);
1231

1232 1
            block_next(blx,BC_ret,breakblock);
1233
        }
1234 1
        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 1
            if (s.bodyFallsThru)
1249
            {
1250
                // BCgoto [breakblock]
1251 1
                blx.curblock.appendSucc(breakblock);
1252 1
                block_next(blx,BCgoto,finallyblock);
1253
            }
1254
            else
1255
            {
1256 1
                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 1
                    elem *e = el_calloc();
1265 1
                    e.Ety = TYvoid;
1266 1
                    e.Eoper = OPhalt;
1267 1
                    elem_setLoc(e, s.loc);
1268 1
                    block_appendexp(blx.curblock, e);
1269
                }
1270

1271 1
                block_next(blx,BCexit,finallyblock);
1272
            }
1273

1274 1
            block *landingPad = block_goto(blx,BC_finally,null);
1275 1
            block_goto(blx,BC_lpad,null);               // lpad is [0]
1276 1
            finallyblock.appendSucc(blx.curblock);    // start of finalybody is [1]
1277 1
            finallyblock.appendSucc(breakblock);       // breakblock is [2]
1278

1279
            /* Declare flag variable
1280
             */
1281 1
            Symbol *sflag = symbol_name("__flag", SCauto, tstypes[TYint]);
1282 1
            symbol_add(sflag);
1283 1
            finallyblock.flag = sflag;
1284 1
            finallyblock.b_ret = retblock;
1285 1
            assert(!finallyblock.Belem);
1286

1287 1
            landingPad.Belem = el_bin(OPeq, TYvoid, el_var(sflag), el_long(TYint, 0)); // __flag = 0;
1288

1289 1
            StmtState finallyState = StmtState(stmtstate, s);
1290

1291 1
            setScopeIndex(blx, blx.curblock, previndex);
1292 1
            if (s.finalbody)
1293 1
                Statement_toIR(s.finalbody, irs, &finallyState);
1294 1
            block_goto(blx, BCgoto, retblock);
1295

1296 1
            block_next(blx,BC_ret,breakblock);
1297
        }
1298
        else
1299
        {
1300 0
            block_goto(blx,BCgoto, breakblock);
1301 0
            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 0
            block_goto(blx,BC_finally,null);
1308

1309 0
            StmtState finallyState = StmtState(stmtstate, s);
1310

1311 0
            setScopeIndex(blx, blx.curblock, previndex);
1312 0
            if (s.finalbody)
1313 0
                Statement_toIR(s.finalbody, irs, &finallyState);
1314 0
            block_goto(blx, BCgoto, retblock);
1315

1316 0
            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 0
            finallyblock.appendSucc(blx.curblock);
1321

1322 0
            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 0
            for (block *b = tryblock; b != finallyblock; b = b.Bnext)
1329
            {
1330 0
                block *btry = b.Btry;
1331

1332 0
                if (b.BC == BCgoto && b.numSucc() == 1)
1333
                {
1334 0
                    block *bdest = b.nthSucc(0);
1335 0
                    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 0
                        block *bfinally = btry.nthSucc(1);
1339 0
                        if (bfinally == finallyblock)
1340
                        {
1341 0
                            b.appendSucc(finallyblock);
1342
                        }
1343
                    }
1344
                }
1345

1346
                // If the goto exits a try block, then the finally block is also a successor
1347 0
                if (b.BC == BCgoto && b.numSucc() == 2) // if goto exited a tryblock
1348
                {
1349 0
                    block *bdest = b.nthSucc(0);
1350

1351
                    // If the last finally block executed by the goto
1352 0
                    if (bdest.Btry == tryblock.Btry)
1353
                    {
1354
                        // The finally block will exit and return to the destination block
1355 0
                        retblock.appendSucc(bdest);
1356
                    }
1357
                }
1358

1359 0
                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 0
                    b.appendSucc(finallyblock);
1363
                }
1364
            }
1365
        }
1366
    }
1367

1368
    /****************************************
1369
     */
1370

1371
    override void visit(SynchronizedStatement s)
1372
    {
1373 0
        assert(0);
1374
    }
1375

1376

1377
    /****************************************
1378
     */
1379

1380
    override void visit(InlineAsmStatement s)
1381
//    { .visit(irs, s); }
1382
    {
1383 1
        block *bpre;
1384 1
        block *basm;
1385 1
        Symbol *sym;
1386 1
        Blockx *blx = irs.blx;
1387

1388
        //printf("AsmStatement.toIR(asmcode = %x)\n", asmcode);
1389 1
        bpre = blx.curblock;
1390 1
        block_next(blx,BCgoto,null);
1391 1
        basm = blx.curblock;
1392 1
        bpre.appendSucc(basm);
1393 1
        basm.Bcode = s.asmcode;
1394 1
        basm.Balign = cast(ubyte)s.asmalign;
1395

1396
        // Loop through each instruction, fixing Dsymbols into Symbol's
1397 1
        for (code *c = s.asmcode; c; c = c.next)
1398
        {
1399 1
            switch (c.IFL1)
1400
            {
1401 1
                case FLblockoff:
1402 1
                case FLblock:
1403
                {
1404
                    // FLblock and FLblockoff have LabelDsymbol's - convert to blocks
1405 1
                    LabelDsymbol label = cast(LabelDsymbol)c.IEV1.Vlsym;
1406 1
                    block *b = cast(block*)label.statement.extra;
1407 1
                    basm.appendSucc(b);
1408 1
                    c.IEV1.Vblock = b;
1409 1
                    break;
1410
                }
1411

1412 1
                case FLdsymbol:
1413 1
                case FLfunc:
1414 1
                    sym = toSymbol(cast(Dsymbol)c.IEV1.Vdsym);
1415 1
                    if (sym.Sclass == SCauto && sym.Ssymnum == -1)
1416 0
                        symbol_add(sym);
1417 1
                    c.IEV1.Vsym = sym;
1418 1
                    c.IFL1 = sym.Sfl ? sym.Sfl : FLauto;
1419 1
                    break;
1420

1421 1
                default:
1422 1
                    break;
1423
            }
1424

1425
            // Repeat for second operand
1426 1
            switch (c.IFL2)
1427
            {
1428 0
                case FLblockoff:
1429 1
                case FLblock:
1430
                {
1431 1
                    LabelDsymbol label = cast(LabelDsymbol)c.IEV2.Vlsym;
1432 1
                    block *b = cast(block*)label.statement.extra;
1433 1
                    basm.appendSucc(b);
1434 1
                    c.IEV2.Vblock = b;
1435 1
                    break;
1436
                }
1437

1438 0
                case FLdsymbol:
1439 1
                case FLfunc:
1440
                {
1441 1
                    Declaration d = cast(Declaration)c.IEV2.Vdsym;
1442 1
                    sym = toSymbol(cast(Dsymbol)d);
1443 1
                    if (sym.Sclass == SCauto && sym.Ssymnum == -1)
1444 0
                        symbol_add(sym);
1445 1
                    c.IEV2.Vsym = sym;
1446 1
                    c.IFL2 = sym.Sfl ? sym.Sfl : FLauto;
1447 1
                    if (d.isDataseg())
1448 0
                        sym.Sflags |= SFLlivexit;
1449 1
                    break;
1450
                }
1451

1452 1
                default:
1453 1
                    break;
1454
            }
1455
        }
1456

1457 1
        basm.bIasmrefparam = s.refparam;             // are parameters reference?
1458 1
        basm.usIasmregs = s.regs;                    // registers modified
1459

1460 1
        block_next(blx,BCasm, null);
1461 1
        basm.prependSucc(blx.curblock);
1462

1463 1
        if (s.naked)
1464
        {
1465 1
            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 1
        scope v = new S2irVisitor(irs, stmtstate);
1479 1
        s.accept(v);
1480
    }
1481
}
1482

1483
void Statement_toIR(Statement s, IRState *irs)
1484
{
1485
    /* Generate a block for each label
1486
     */
1487 1
    FuncDeclaration fd = irs.getFunc();
1488 1
    if (auto labtab = fd.labtab)
1489 1
        foreach (keyValue; labtab.tab.asRange)
1490
        {
1491
            //printf("  KV: %s = %s\n", keyValue.key.toChars(), keyValue.value.toChars());
1492 1
            LabelDsymbol label = cast(LabelDsymbol)keyValue.value;
1493 1
            if (label.statement)
1494 1
                label.statement.extra = dmd.backend.global.block_calloc();
1495
        }
1496

1497 1
    StmtState stmtstate;
1498 1
    scope v = new S2irVisitor(irs, &stmtstate);
1499 1
    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 1
    int flagvalue = 0;          // 0 is forunwind_resume
1515 1
    block *bcret = null;
1516

1517 1
    block *bcretexp = null;
1518 1
    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 1
    block **pb;
1531 1
    block **pbnext;
1532 1
    for (pb = &startblock; *pb; pb = pbnext)
1533
    {
1534 1
        block *b = *pb;
1535 1
        pbnext = &b.Bnext;
1536 1
        if (!b.Btry)
1537 1
            continue;
1538

1539 1
        switch (b.BC)
1540
        {
1541 1
            case BCret:
1542
                // Rewrite into a BCgoto => BCret
1543 1
                if (!bcret)
1544
                {
1545 1
                    bcret = dmd.backend.global.block_calloc();
1546 1
                    bcret.BC = BCret;
1547
                }
1548 1
                b.BC = BCgoto;
1549 1
                b.appendSucc(bcret);
1550 1
                goto case_goto;
1551

1552 1
            case BCretexp:
1553
            {
1554
                // Rewrite into a BCgoto => BCretexp
1555 1
                elem *e = b.Belem;
1556 1
                tym_t ty = tybasic(e.Ety);
1557 1
                if (!bcretexp)
1558
                {
1559 1
                    bcretexp = dmd.backend.global.block_calloc();
1560 1
                    bcretexp.BC = BCretexp;
1561 1
                    type *t;
1562 1
                    if ((ty == TYstruct || ty == TYarray) && e.ET)
1563 1
                        t = e.ET;
1564
                    else
1565 1
                        t = type_fake(ty);
1566 1
                    stmp = symbol_genauto(t);
1567 1
                    bcretexp.Belem = el_var(stmp);
1568 1
                    if ((ty == TYstruct || ty == TYarray) && e.ET)
1569 1
                        bcretexp.Belem.ET = t;
1570
                }
1571 1
                b.BC = BCgoto;
1572 1
                b.appendSucc(bcretexp);
1573 1
                b.Belem = elAssign(el_var(stmp), e, null, e.ET);
1574 1
                goto case_goto;
1575
            }
1576

1577 1
            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 1
                block *breakblock = b.nthSucc(0);
1606 1
                block *lasttry = breakblock.Btry;
1607 1
                block *blast = b;
1608 1
                ++flagvalue;
1609 1
                for (block *bt = b.Btry; bt != lasttry; bt = bt.Btry)
1610
                {
1611 1
                    assert(bt.BC == BC_try);
1612 1
                    block *bf = bt.nthSucc(1);
1613 1
                    if (bf.BC == BCjcatch)
1614 1
                        continue;                       // skip try-catch
1615 1
                    assert(bf.BC == BC_finally);
1616

1617 1
                    block *retblock = bf.b_ret;
1618 1
                    assert(retblock.BC == BC_ret);
1619 1
                    assert(retblock.numSucc() == 0);
1620

1621
                    // Append (_flag = flagvalue) to b.Belem
1622 1
                    Symbol *sflag = bf.flag;
1623 1
                    elem *e = el_bin(OPeq, TYint, el_var(sflag), el_long(TYint, flagvalue));
1624 1
                    b.Belem = el_combine(b.Belem, e);
1625

1626 1
                    if (blast.BC == BCiftrue)
1627
                    {
1628 1
                        blast.setNthSucc(0, bf.nthSucc(1));
1629
                    }
1630
                    else
1631
                    {
1632 1
                        assert(blast.BC == BCgoto);
1633 1
                        blast.setNthSucc(0, bf.nthSucc(1));
1634
                    }
1635

1636
                    // Create new block, bnew, which will replace retblock
1637 1
                    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 1
                    e = el_bin(OPeqeq, TYbool, el_var(sflag), el_long(TYint, flagvalue));
1643 1
                    retblock.Belem = el_combine(retblock.Belem, e);
1644 1
                    retblock.BC = BCiftrue;
1645 1
                    retblock.appendSucc(breakblock);
1646 1
                    retblock.appendSucc(bnew);
1647

1648 1
                    bnew.Bnext = retblock.Bnext;
1649 1
                    retblock.Bnext = bnew;
1650

1651 1
                    bnew.BC = BC_ret;
1652 1
                    bnew.Btry = retblock.Btry;
1653 1
                    bf.b_ret = bnew;
1654

1655 1
                    blast = retblock;
1656
                }
1657 1
                break;
1658
            }
1659

1660 1
            default:
1661 1
                break;
1662
        }
1663
    }
1664 1
    if (bcret)
1665
    {
1666 1
        *pb = bcret;
1667 1
        pb = &(*pb).Bnext;
1668
    }
1669 1
    if (bcretexp)
1670 1
        *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 1
    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 1
    foreach (b; BlockRange(startblock))
1705
    {
1706 1
        b.Btry = null;
1707 1
        switch (b.BC)
1708
        {
1709 1
            case BC_try:
1710 1
                b.BC = BCgoto;
1711 1
                list_subtract(&b.Bsucc, b.nthSucc(1));
1712 1
                break;
1713

1714 1
            case BC_finally:
1715 1
                b.BC = BCgoto;
1716 1
                list_subtract(&b.Bsucc, b.nthSucc(2));
1717 1
                list_subtract(&b.Bsucc, b.nthSucc(0));
1718 1
                break;
1719

1720 1
            case BC_lpad:
1721 1
                b.BC = BCgoto;
1722 1
                break;
1723

1724 1
            case BC_ret:
1725 1
                b.BC = BCexit;
1726 1
                break;
1727

1728 1
            default:
1729 1
                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
}

Read our documentation on viewing source code .

Loading