Coverage Report

Created: 2017-04-15 07:07

/home/travis/build/MoarVM/MoarVM/src/spesh/manipulate.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
/* This file contains various routines for manipulating a spesh graph, such
4
 * as adding/removing/replacing instructions. */
5
6
555k
void MVM_spesh_manipulate_delete_ins(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins) {
7
555k
    /* Remove it from the double linked list. */
8
555k
    MVMSpeshIns *prev = ins->prev;
9
555k
    MVMSpeshIns *next = ins->next;
10
555k
    if (prev)
11
474k
        prev->next = next;
12
555k
    else
13
81.7k
        bb->first_ins = next;
14
555k
    if (next)
15
538k
        next->prev = prev;
16
555k
    else
17
17.4k
        bb->last_ins = prev;
18
555k
19
555k
    /* Move it's annotations. */
20
606k
    while (ins->annotations) {
21
50.4k
        MVMSpeshAnn *ann      = ins->annotations;
22
50.4k
        MVMSpeshAnn *ann_next = ann->next;
23
50.4k
        switch (ann->type) {
24
6.74k
            case MVM_SPESH_ANN_FH_START:
25
6.74k
            case MVM_SPESH_ANN_FH_GOTO:
26
6.74k
            case MVM_SPESH_ANN_INLINE_START:
27
6.74k
            case MVM_SPESH_ANN_DEOPT_OSR:
28
6.74k
                if (!next && bb->linear_next)
29
0
                    next = bb->linear_next->first_ins;
30
6.74k
                if (next) {
31
6.74k
                    ann->next = next->annotations;
32
6.74k
                    next->annotations = ann;
33
6.74k
                }
34
6.74k
                break;
35
43.6k
            case MVM_SPESH_ANN_FH_END:
36
43.6k
            case MVM_SPESH_ANN_DEOPT_ONE_INS:
37
43.6k
                if (!prev) {
38
24.5k
                    MVMSpeshBB *prev_bb = MVM_spesh_graph_linear_prev(tc, g, bb);
39
24.5k
                    if (prev_bb)
40
24.5k
                        prev = prev_bb->last_ins;
41
24.5k
                }
42
43.6k
                if (prev) {
43
43.6k
                    ann->next = prev->annotations;
44
43.6k
                    prev->annotations = ann;
45
43.6k
                }
46
43.6k
                break;
47
50.4k
        }
48
50.4k
        ins->annotations = ann_next;
49
50.4k
    }
50
555k
}
51
52
264k
void MVM_spesh_manipulate_insert_ins(MVMThreadContext *tc, MVMSpeshBB *bb, MVMSpeshIns *previous, MVMSpeshIns *to_insert) {
53
264k
    MVMSpeshIns *next;
54
264k
    if (previous) {
55
86.1k
        next = previous->next;
56
86.1k
        previous->next = to_insert;
57
178k
    } else {
58
178k
        next = bb->first_ins;
59
178k
        bb->first_ins = to_insert;
60
178k
    }
61
264k
    to_insert->next = next;
62
264k
    if (next) {
63
255k
        next->prev = to_insert;
64
8.57k
    } else {
65
8.57k
        bb->last_ins = to_insert;
66
8.57k
    }
67
264k
    to_insert->prev = previous;
68
264k
}
69
70
/* Inserts a goto. */
71
6.28k
void MVM_spesh_manipulate_insert_goto(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins, MVMSpeshBB *target) {
72
6.28k
    MVMSpeshIns *inserted_goto = MVM_spesh_alloc(tc, g, sizeof( MVMSpeshIns ));
73
6.28k
    MVMSpeshOperand *operands  = MVM_spesh_alloc(tc, g, sizeof( MVMSpeshOperand ));
74
6.28k
    inserted_goto->info        = MVM_op_get_op(MVM_OP_goto);
75
6.28k
    inserted_goto->operands    = operands;
76
6.28k
    operands[0].ins_bb         = target;
77
6.28k
    MVM_spesh_manipulate_insert_ins(tc, bb, ins, inserted_goto);
78
6.28k
}
79
80
8.48k
void MVM_spesh_manipulate_remove_successor(MVMThreadContext *tc, MVMSpeshBB *bb, MVMSpeshBB *succ) {
81
8.48k
    MVMSpeshBB ** const   bb_succ = bb->succ;
82
8.48k
    MVMSpeshBB ** const succ_pred = succ->pred;
83
8.48k
    const MVMuint16   bb_num_succ = --bb->num_succ;
84
8.48k
    const MVMuint16 succ_num_pred = --succ->num_pred;
85
8.48k
    MVMuint16 i, k;
86
8.48k
87
11.2k
    for (i = 0; i <= bb_num_succ; i++) {
88
11.2k
        if (bb_succ[i] == succ) {
89
8.48k
            break;
90
8.48k
        }
91
11.2k
    }
92
8.48k
93
8.48k
    if (bb_succ[i] != succ) {
94
0
        MVM_oops(tc, "Didn't find the successor to remove from a Spesh Basic Block");
95
0
    }
96
8.48k
97
8.48k
    /* Remove the succ from the list, shuffle other successors back in place */
98
14.1k
    for (k = i; k < bb_num_succ; k++) {
99
5.68k
        bb_succ[k] = bb_succ[k + 1];
100
5.68k
    }
101
8.48k
102
8.48k
    bb_succ[bb_num_succ] = NULL;
103
8.48k
104
8.48k
    /* Now hunt the bb in the succ's pred, so that we remove all traces of the connection */
105
8.84k
    for (i = 0; i <= succ_num_pred; i++) {
106
8.84k
        if (succ_pred[i] == bb) {
107
8.48k
            break;
108
8.48k
        }
109
8.84k
    }
110
8.48k
111
8.48k
    if (succ_pred[i] != bb) {
112
0
        MVM_oops(tc, "Didn't find the predecessor to remove from a Spesh Basic Block");
113
0
    }
114
8.48k
115
13.5k
    for (k = i; k < succ_num_pred; k++) {
116
5.03k
        succ_pred[k] = succ_pred[k + 1];
117
5.03k
    }
118
8.48k
119
8.48k
    succ_pred[succ_num_pred] = NULL;
120
8.48k
}
121
122
/* Gets a temporary register of the specified kind to use in some transform.
123
 * Will only actaully extend the frame if needed; if an existing temproary
124
 * was requested and then released, then it will just use a new version of
125
 * that. */
126
6.63k
MVMSpeshOperand MVM_spesh_manipulate_get_temp_reg(MVMThreadContext *tc, MVMSpeshGraph *g, MVMuint16 kind) {
127
6.63k
    MVMSpeshOperand   result;
128
6.63k
    MVMSpeshFacts   **new_facts;
129
6.63k
    MVMuint16        *new_fact_counts;
130
6.63k
    MVMuint16         i;
131
6.63k
132
6.63k
    /* First, see if we can find an existing free temporary; use it if so. */
133
9.18k
    for (i = 0; i < g->num_temps; i++) {
134
3.33k
        if (g->temps[i].kind == kind && !g->temps[i].in_use) {
135
785
            /* Add new facts slot. */
136
785
            MVMuint16 orig = g->temps[i].orig;
137
785
            MVMSpeshFacts *new_fact_row = MVM_spesh_alloc(tc, g,
138
785
                (g->fact_counts[orig] + 1) * sizeof(MVMSpeshFacts));
139
785
            memcpy(new_fact_row, g->facts[orig],
140
785
                g->fact_counts[orig] * sizeof(MVMSpeshFacts));
141
785
            g->facts[orig] = new_fact_row;
142
785
            g->fact_counts[orig]++;
143
785
144
785
            /* Mark it in use an add extra version. */
145
785
            g->temps[i].in_use++;
146
785
            g->temps[i].i++;
147
785
148
785
            /* Produce and return result. */
149
785
            result.reg.orig = orig;
150
785
            result.reg.i    = g->temps[i].i;
151
785
            return result;
152
785
        }
153
3.33k
    }
154
6.63k
155
6.63k
    /* Make sure we've space in the temporaries store. */
156
5.84k
    if (g->num_temps == g->alloc_temps) {
157
3.76k
        MVMSpeshTemporary *new_temps;
158
3.76k
        g->alloc_temps += 4;
159
3.76k
        new_temps = MVM_spesh_alloc(tc, g, g->alloc_temps * sizeof(MVMSpeshTemporary));
160
3.76k
        if (g->num_temps)
161
1
            memcpy(new_temps, g->temps, g->num_temps * sizeof(MVMSpeshTemporary));
162
3.76k
        g->temps = new_temps;
163
3.76k
    }
164
5.84k
165
5.84k
    /* Allocate temporary and set up result. */
166
5.84k
    g->temps[g->num_temps].orig   = result.reg.orig = g->num_locals;
167
5.84k
    g->temps[g->num_temps].i      = result.reg.i    = 0;
168
5.84k
    g->temps[g->num_temps].kind   = kind;
169
5.84k
    g->temps[g->num_temps].in_use = 1;
170
5.84k
    g->num_temps++;
171
5.84k
172
5.84k
    /* Add locals table entry. */
173
5.84k
    if (!g->local_types) {
174
3.48k
        MVMint32 local_types_size = g->num_locals * sizeof(MVMuint16);
175
3.48k
        g->local_types = MVM_malloc(local_types_size);
176
3.48k
        memcpy(g->local_types, g->sf->body.local_types, local_types_size);
177
3.48k
    }
178
5.84k
    g->local_types = MVM_realloc(g->local_types, (g->num_locals + 1) * sizeof(MVMuint16));
179
5.84k
    g->local_types[g->num_locals] = kind;
180
5.84k
181
5.84k
    /* Add facts table entry. */
182
5.84k
    new_facts       = MVM_spesh_alloc(tc, g, (g->num_locals + 1) * sizeof(MVMSpeshFacts *));
183
5.84k
    new_fact_counts = MVM_spesh_alloc(tc, g, (g->num_locals + 1) * sizeof(MVMuint16));
184
5.84k
    memcpy(new_facts, g->facts, g->num_locals * sizeof(MVMSpeshFacts *));
185
5.84k
    memcpy(new_fact_counts, g->fact_counts, g->num_locals * sizeof(MVMuint16));
186
5.84k
    new_facts[g->num_locals]       = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshFacts));
187
5.84k
    new_fact_counts[g->num_locals] = 1;
188
5.84k
    g->facts                       = new_facts;
189
5.84k
    g->fact_counts                 = new_fact_counts;
190
5.84k
191
5.84k
    /* Increment number of locals. */
192
5.84k
    g->num_locals++;
193
5.84k
194
5.84k
    return result;
195
6.63k
}
196
197
/* Releases a temporary register, so it can be used again later. */
198
6.50k
void MVM_spesh_manipulate_release_temp_reg(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshOperand temp) {
199
6.50k
    MVMuint16 i;
200
8.97k
    for (i = 0; i < g->num_temps; i++) {
201
8.97k
        if (g->temps[i].orig == temp.reg.orig && g->temps[i].i == temp.reg.i) {
202
6.50k
            if (g->temps[i].in_use)
203
6.50k
                g->temps[i].in_use = 0;
204
6.50k
            else
205
0
                MVM_oops(tc, "Spesh: releasing temp not in use");
206
6.50k
            return;
207
6.50k
        }
208
8.97k
    }
209
0
    MVM_oops(tc, "Spesh: releasing non-existing temp");
210
0
}
211
212
213
0
MVMSpeshBB *MVM_spesh_manipulate_split_BB_at(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *ins) {
214
0
    MVMSpeshBB *new_bb = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshBB));
215
0
    MVMSpeshBB *linear_next = bb->linear_next;
216
0
217
0
    /* Step one: insert the new BB into the linear order */
218
0
    bb->linear_next = new_bb;
219
0
    new_bb->linear_next = linear_next;
220
0
221
0
    /* Step two: update all idx fields. */
222
0
    new_bb->idx = bb->idx + 1;
223
0
    {
224
0
        MVMSpeshBB *ptr = linear_next;
225
0
        while (ptr != NULL) {
226
0
            ptr->idx += 1;
227
0
            ptr = ptr->linear_next;
228
0
        }
229
0
    }
230
0
231
0
    /* Step three: fix up the dominator tree */
232
0
    new_bb->children = bb->children;
233
0
    new_bb->num_children = bb->num_children;
234
0
235
0
    /* We expect the user of this API to fill whatever BB the code
236
0
     * will additionally branch into into the children list, as well.
237
0
     * Hopefully, setting num_children to 2 makes the code crash in case
238
0
     * that step has been forgotten. */
239
0
    bb->children = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshBB *) * 2);
240
0
    bb->num_children = 2;
241
0
    bb->children[0] = new_bb;
242
0
    bb->children[1] = 0;
243
0
244
0
    /* Step three: fix up succs and preds */
245
0
    new_bb->pred = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshBB *));
246
0
    new_bb->num_pred = 1;
247
0
    new_bb->pred[0] = bb;
248
0
249
0
    new_bb->succ = bb->succ;
250
0
251
0
    /* We assume the reason for the split is to add a new succ in the middle
252
0
     * which is why we allocate two slots instead of 1 */
253
0
    bb->succ = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshBB *) * 2);
254
0
    bb->num_succ = 2;
255
0
    bb->succ[0] = new_bb;
256
0
    bb->succ[1] = 0;
257
0
258
0
    new_bb->initial_pc = bb->initial_pc;
259
0
260
0
    new_bb->num_df = 0;
261
0
262
0
    /* Last step: Transfer over the instructions after the split point */
263
0
    new_bb->last_ins = bb->last_ins;
264
0
    bb->last_ins = ins->prev;
265
0
    new_bb->first_ins = ins;
266
0
    ins->prev->next = NULL;
267
0
    ins->prev = NULL;
268
0
269
0
    return new_bb;
270
0
}