Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/spesh/dead_bb_elimination.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
0
static void mark_handler_unreachable(MVMThreadContext *tc, MVMSpeshGraph *g, MVMint32 index) {
4
0
    if (!g->unreachable_handlers)
5
0
        g->unreachable_handlers = MVM_spesh_alloc(tc, g, g->num_handlers);
6
0
    g->unreachable_handlers[index] = 1;
7
0
}
8
9
static void cleanup_dead_bb_instructions(MVMThreadContext *tc, MVMSpeshGraph *g,
10
13.8k
                                         MVMSpeshBB *dead_bb, MVMint32 cleanup_facts) {
11
13.8k
    MVMSpeshIns *ins = dead_bb->first_ins;
12
13.8k
    MVMint8 *frame_handlers_started = MVM_calloc(g->num_handlers, 1);
13
48.1k
    while (ins) {
14
34.3k
        /* Look over any annotations on the instruction. */
15
34.3k
        MVMSpeshAnn *ann = ins->annotations;
16
52.7k
        while (ann) {
17
18.3k
            MVMSpeshAnn *next_ann = ann->next;
18
18.3k
            switch (ann->type) {
19
0
                case MVM_SPESH_ANN_INLINE_START:
20
0
                    /* If an inline's entrypoint becomes impossible to reach
21
0
                     * the whole inline will too. Just mark it as being
22
0
                     * unreachable. */
23
0
                    g->inlines[ann->data.inline_idx].unreachable = 1;
24
0
                    break;
25
0
                case MVM_SPESH_ANN_FH_START:
26
0
                    /* Move the start to the next basic block if possible. If
27
0
                     * not, just mark the handler deleted; its end must be in
28
0
                     * this block also. */
29
0
                    frame_handlers_started[ann->data.frame_handler_index] = 1;
30
0
                    if (dead_bb->linear_next) {
31
0
                        MVMSpeshIns *move_to_ins = dead_bb->linear_next->first_ins;
32
0
                        ann->next = move_to_ins->annotations;
33
0
                        move_to_ins->annotations = ann;
34
0
                    }
35
0
                    else {
36
0
                        mark_handler_unreachable(tc, g, ann->data.frame_handler_index);
37
0
                    }
38
0
                    break;
39
0
                case MVM_SPESH_ANN_FH_END: {
40
0
                    /* If we already saw the start, then we'll just mark it as
41
0
                     * deleted. */
42
0
                    if (frame_handlers_started[ann->data.frame_handler_index]) {
43
0
                        mark_handler_unreachable(tc, g, ann->data.frame_handler_index);
44
0
                    }
45
0
46
0
                    /* Otherwise, move it to the end of the previous basic
47
0
                     * block (which should always exist). */
48
0
                    else {
49
0
                        MVMSpeshBB *linear_prev = MVM_spesh_graph_linear_prev(tc, g, dead_bb);
50
0
                        MVMSpeshIns *move_to_ins = linear_prev->last_ins;
51
0
                        ann->next = move_to_ins->annotations;
52
0
                        move_to_ins->annotations = ann;
53
0
                    }   
54
0
                    break;
55
0
                }
56
0
                case MVM_SPESH_ANN_FH_GOTO:
57
0
                    mark_handler_unreachable(tc, g, ann->data.frame_handler_index);
58
0
                    break;
59
18.3k
            }
60
18.3k
            ann = next_ann;
61
18.3k
        }
62
34.3k
        if (cleanup_facts)
63
34.3k
            MVM_spesh_manipulate_cleanup_ins_deps(tc, g, ins);
64
34.3k
        ins = ins->next;
65
34.3k
    }
66
13.8k
    dead_bb->first_ins = NULL;
67
13.8k
    dead_bb->last_ins = NULL;
68
13.8k
    MVM_free(frame_handlers_started);
69
13.8k
}
70
71
3.04M
static void mark_bb_seen(MVMThreadContext *tc, MVMSpeshBB *bb, MVMint8 *seen) {
72
3.04M
    if (!seen[bb->idx]) {
73
1.74M
        MVMuint16 i;
74
1.74M
        seen[bb->idx] = 1;
75
4.74M
        for (i = 0; i < bb->num_succ; i++)
76
2.99M
            mark_bb_seen(tc, bb->succ[i], seen);
77
1.74M
    }
78
3.04M
}
79
80
/* Eliminates dead basic blocks, optionally cleaning up facts. (In the case
81
 * this is called during spesh graph construction, the facts do not yet
82
 * exist). */
83
46.7k
void MVM_spesh_eliminate_dead_bbs(MVMThreadContext *tc, MVMSpeshGraph *g, MVMint32 update_facts) {
84
46.7k
    MVMSpeshBB *cur_bb;
85
46.7k
86
46.7k
    /* First pass: mark every basic block that is reachable from the
87
46.7k
     * entrypoint. */
88
46.7k
    MVMint32  orig_bbs = g->num_bbs;
89
46.7k
    MVMint8  *seen = MVM_calloc(1, g->num_bbs);
90
46.7k
    mark_bb_seen(tc, g->entry, seen);
91
46.7k
92
46.7k
    /* Second pass: remove dead BBs from the graph. Do not get
93
46.7k
     * rid of any that are from inlines or that contain handler related
94
46.7k
     * annotations. */
95
46.7k
    cur_bb = g->entry;
96
1.75M
    while (cur_bb && cur_bb->linear_next) {
97
1.71M
        MVMSpeshBB *death_cand = cur_bb->linear_next;
98
1.71M
        if (!seen[death_cand->idx]) {
99
13.8k
            cleanup_dead_bb_instructions(tc, g, death_cand, update_facts);
100
13.8k
            death_cand->dead = 1;
101
13.8k
            g->num_bbs--;
102
13.8k
            cur_bb->linear_next = cur_bb->linear_next->linear_next;
103
13.8k
        }
104
1.69M
        else {
105
1.69M
            cur_bb = cur_bb->linear_next;
106
1.69M
        }
107
1.71M
    }
108
46.7k
    MVM_free(seen);
109
46.7k
110
46.7k
    /* Re-number BBs so we get sequential ordering again. */
111
46.7k
    if (g->num_bbs != orig_bbs) {
112
3.17k
        MVMint32    new_idx  = 0;
113
3.17k
        MVMSpeshBB *cur_bb   = g->entry;
114
267k
        while (cur_bb) {
115
264k
            cur_bb->idx = new_idx;
116
264k
            new_idx++;
117
264k
            cur_bb = cur_bb->linear_next;
118
264k
        }
119
3.17k
    }
120
46.7k
}