Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/jit/expr.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
/* Mathematical min and max macro's */
4
#ifndef MAX
5
316k
#define MAX(a,b) ((a) > (b) ? (a) : (b));
6
#endif
7
8
#ifndef MIN
9
#define MIN(a,b) ((a) < (b) ? (a) : (b));
10
#endif
11
12
13
/* macros used in the expression list templates, defined here so they
14
   don't overwrite other definitions */
15
#define CONST_PTR(x) ((uintptr_t)(x))
16
#define QUOTE(x) (x)
17
#define MSG(...) CONST_PTR(#__VA_ARGS__)
18
#define SIZEOF_MEMBER(type, member) sizeof(((type*)0)->member)
19
20
#include "jit/core_templates.h"
21
22
23
static const MVMJitExprOpInfo expr_op_info[] = {
24
#define OP_INFO(name, nchild, nargs, vtype, cast) { #name, nchild, nargs, MVM_JIT_ ## vtype, MVM_JIT_ ## cast }
25
    MVM_JIT_EXPR_OPS(OP_INFO)
26
#undef OP_INFO
27
};
28
29
30
42.7M
const MVMJitExprOpInfo * MVM_jit_expr_op_info(MVMThreadContext *tc, MVMint32 op) {
31
42.7M
    if (op < 0 || op >= MVM_JIT_MAX_NODES) {
32
0
        MVM_oops(tc, "JIT: Expr op index out of bounds: %d", op);
33
0
    }
34
42.7M
    return &expr_op_info[op];
35
42.7M
}
36
37
/* Record the node that defines a value */
38
struct ValueDefinition {
39
    MVMint32 node;
40
    MVMint32 root;
41
    MVMint32 addr;
42
};
43
44
45
46
/* Logical negation of MVMJitExprOp flags. */
47
392k
MVMint32 MVM_jit_expr_op_negate_flag(MVMThreadContext *tc, MVMint32 op) {
48
392k
    switch(op) {
49
0
    case MVM_JIT_LT:
50
0
        return MVM_JIT_GE;
51
0
    case MVM_JIT_LE:
52
0
        return MVM_JIT_GT;
53
634
    case MVM_JIT_EQ:
54
634
        return MVM_JIT_NE;
55
18.3k
    case MVM_JIT_NE:
56
18.3k
        return MVM_JIT_EQ;
57
0
    case MVM_JIT_GE:
58
0
        return MVM_JIT_LT;
59
0
    case MVM_JIT_GT:
60
0
        return MVM_JIT_LE;
61
282k
    case MVM_JIT_NZ:
62
282k
        return MVM_JIT_ZR;
63
90.6k
    case MVM_JIT_ZR:
64
90.6k
        return MVM_JIT_NZ;
65
0
    default:
66
0
        break;
67
392k
    }
68
0
    return -1; /* not a flag */
69
392k
}
70
71
0
MVMint32 MVM_jit_expr_op_is_binary_noncommutative(MVMThreadContext *tc, MVMint32 op) {
72
0
    switch (op) {
73
0
    case MVM_JIT_SUB:
74
0
    case MVM_JIT_XOR:
75
0
        /* and DIV, SHIFT, etc */
76
0
        return 1;
77
0
    default:
78
0
        /* ADD, MUL, AND, OR, etc. are commutative */
79
0
        return 0;
80
0
    }
81
0
}
82
83
84
static MVMint32 MVM_jit_expr_add_regaddr(MVMThreadContext *tc, MVMJitExprTree *tree,
85
909k
                                         MVMuint16 reg) {
86
909k
    MVMint32 num  = tree->nodes_num;
87
909k
    MVMJitExprNode template[] = { MVM_JIT_LOCAL,
88
909k
                                  MVM_JIT_ADDR, num, reg * MVM_JIT_REG_SZ };
89
909k
    MVM_VECTOR_APPEND(tree->nodes, template, sizeof(template)/sizeof(MVMJitExprNode));
90
909k
    return num + 1;
91
909k
}
92
93
30
static MVMint32 MVM_jit_expr_add_loadframe(MVMThreadContext *tc, MVMJitExprTree *tree) {
94
30
    MVMint32 num = tree->nodes_num;
95
30
    MVMJitExprNode template[] = { MVM_JIT_TC,
96
30
                                  MVM_JIT_ADDR, num, offsetof(MVMThreadContext, cur_frame),
97
30
                                  MVM_JIT_LOAD, num + 1, sizeof(MVMFrame*) };
98
30
    MVM_VECTOR_APPEND(tree->nodes, template, sizeof(template)/sizeof(MVMJitExprNode));
99
30
    return num + 4;
100
30
}
101
102
103
104
static MVMint32 MVM_jit_expr_add_load(MVMThreadContext *tc, MVMJitExprTree *tree,
105
339k
                                      MVMint32 addr) {
106
339k
    MVMint32 num        = tree->nodes_num;
107
339k
    MVMJitExprNode template[] = { MVM_JIT_LOAD, addr, MVM_JIT_REG_SZ };
108
339k
    MVM_VECTOR_APPEND(tree->nodes, template, sizeof(template)/sizeof(MVMJitExprNode));
109
339k
    return num;
110
339k
}
111
112
113
static MVMint32 MVM_jit_expr_add_store(MVMThreadContext *tc, MVMJitExprTree *tree,
114
412k
                                       MVMint32 addr, MVMint32 val, MVMint32 sz) {
115
412k
    MVMint32 num = tree->nodes_num;
116
412k
    MVMJitExprNode template[] = { MVM_JIT_STORE, addr, val, sz };
117
412k
    MVM_VECTOR_APPEND(tree->nodes, template, sizeof(template)/sizeof(MVMJitExprNode));
118
412k
    return num;
119
412k
}
120
121
122
5.30k
static MVMint32 MVM_jit_expr_add_cast(MVMThreadContext *tc, MVMJitExprTree *tree, MVMint32 node, MVMint32 to_size, MVMint32 from_size, MVMint32 is_signed) {
123
5.30k
    MVMint32 num = tree->nodes_num;
124
5.30k
    MVMJitExprNode template[] = { MVM_JIT_CAST, node, to_size, from_size, is_signed };
125
5.30k
    MVM_VECTOR_APPEND(tree->nodes, template, sizeof(template)/sizeof(MVMJitExprNode));
126
5.30k
    return num;
127
5.30k
}
128
129
5.69k
static MVMint32 MVM_jit_expr_add_label(MVMThreadContext *tc, MVMJitExprTree *tree, MVMint32 label) {
130
5.69k
    MVMint32 num = tree->nodes_num;
131
5.69k
    MVMJitExprNode template[] = { MVM_JIT_MARK, label };
132
5.69k
    MVM_VECTOR_APPEND(tree->nodes, template, sizeof(template)/sizeof(template[0]));
133
5.69k
    return num;
134
5.69k
}
135
136
static MVMint32 MVM_jit_expr_add_lexaddr(MVMThreadContext *tc, MVMJitExprTree *tree,
137
30
                                         MVMuint16 outers, MVMuint16 idx) {
138
30
    MVMint32 i;
139
30
    /* (frame) as the root */
140
30
    MVMint32 num = MVM_jit_expr_add_loadframe(tc, tree);
141
30
    for (i = 0; i < outers; i++) {
142
0
        /* (load (addr $val (&offsetof MVMFrame outer)) (&sizeof MVMFrame*)) */
143
0
        MVMJitExprNode template[] = { MVM_JIT_ADDR, num, offsetof(MVMFrame, outer),
144
0
                                      MVM_JIT_LOAD, tree->nodes_num, sizeof(MVMFrame*) };
145
0
        MVM_VECTOR_APPEND(tree->nodes, template, sizeof(template)/sizeof(MVMJitExprNode));
146
0
        num = tree->nodes_num - 3;
147
0
    }
148
30
    /* (addr (load (addr $frame (&offsetof MVMFrame env)) ptr_sz) ptr_sz*idx) */
149
30
    {
150
30
        MVMJitExprNode template[] = {
151
30
            MVM_JIT_ADDR, num, offsetof(MVMFrame, env), /* (addr $frame (&offsetof MVMFrame env)) */
152
30
            MVM_JIT_LOAD, tree->nodes_num, MVM_JIT_PTR_SZ, /* (load $addr ptr_sz) */
153
30
            MVM_JIT_ADDR, tree->nodes_num + 3, idx * MVM_JIT_REG_SZ /* (addr $frame_env idx*reg_sz) */
154
30
        };
155
30
        MVM_VECTOR_APPEND(tree->nodes, template, sizeof(template)/sizeof(MVMJitExprNode));
156
30
        num = tree->nodes_num - 3;
157
30
    }
158
30
    return num;
159
30
}
160
161
162
static MVMint32 MVM_jit_expr_add_const(MVMThreadContext *tc, MVMJitExprTree *tree,
163
371k
                                       MVMSpeshOperand opr, MVMuint8 info) {
164
371k
165
371k
    MVMJitExprNode template[]  = { MVM_JIT_CONST, 0, 0 };
166
371k
    MVMint32 num               = tree->nodes_num;
167
371k
    MVMint32 size              = 3;
168
371k
    switch(info & MVM_operand_type_mask) {
169
0
    case MVM_operand_int8:
170
0
        template[1] = opr.lit_i8;
171
0
        template[2] = sizeof(MVMint8);
172
0
        break;
173
163k
    case MVM_operand_int16:
174
163k
        template[1] = opr.lit_i16;
175
163k
        template[2] = sizeof(MVMint16);
176
163k
        break;
177
496
    case MVM_operand_coderef:
178
496
        template[1] = opr.coderef_idx;
179
496
        template[2] = sizeof(MVMuint16);
180
496
        break;
181
1.62k
    case MVM_operand_int32:
182
1.62k
        template[1] = opr.lit_i32;
183
1.62k
        template[2] = sizeof(MVMint32);
184
1.62k
        break;
185
1
    case MVM_operand_int64:
186
1
        template[1] = opr.lit_i64;
187
1
        template[2] = sizeof(MVMint64);
188
1
        break;
189
0
    case MVM_operand_num32:
190
0
        /* possible endianess issue here */
191
0
        template[1] = opr.lit_i32;
192
0
        template[2] = sizeof(MVMnum32);
193
0
        break;
194
1.02k
    case MVM_operand_num64:
195
1.02k
        /* use i64 to get the bits */
196
1.02k
        template[1] = opr.lit_i64;
197
1.02k
        template[2] = sizeof(MVMnum64);
198
1.02k
        break;
199
37.8k
    case MVM_operand_str:
200
37.8k
        /* string index really */
201
37.8k
        template[1] = opr.lit_str_idx;
202
37.8k
        template[2] = sizeof(MVMuint32);
203
37.8k
        break;
204
111k
    case MVM_operand_ins:
205
111k
        template[0] = MVM_JIT_LABEL;
206
111k
        template[1] = MVM_jit_label_before_bb(tc, tree->graph, opr.ins_bb);
207
111k
        size        = 2;
208
111k
        break;
209
0
    case MVM_operand_callsite:
210
0
        template[1] = opr.callsite_idx;
211
0
        template[2] = sizeof(MVMuint16);
212
0
        break;
213
55.5k
    case MVM_operand_spesh_slot:
214
55.5k
        template[1] = opr.lit_i16;
215
55.5k
        template[2] = sizeof(MVMuint16);
216
55.5k
        break;
217
0
    default:
218
0
        MVM_oops(tc, "Can't add constant for operand type %d\n", (info & MVM_operand_type_mask) >> 3);
219
371k
    }
220
371k
    MVM_VECTOR_APPEND(tree->nodes, template, size);
221
371k
    return num;
222
371k
}
223
224
0
static MVMint32 getlex_needs_autoviv(MVMThreadContext *tc, MVMJitGraph *jg, MVMSpeshIns *ins) {
225
0
    MVMSpeshOperand opr = ins->operands[1];
226
0
    MVMuint16 lexical_type = MVM_spesh_get_lex_type(tc, jg->sg, opr.lex.outers, opr.lex.idx);
227
0
    return lexical_type == MVM_reg_obj;
228
0
}
229
230
816
static MVMint32 bindlex_needs_write_barrier(MVMThreadContext *tc, MVMJitGraph *jg, MVMSpeshIns *ins) {
231
816
    MVMSpeshOperand opr = ins->operands[0];
232
816
    MVMuint16 lexical_type = MVM_spesh_get_lex_type(tc, jg->sg, opr.lex.outers, opr.lex.idx);
233
816
    /* need to hit a write barrier if we bindlex to a string */
234
816
    return lexical_type == MVM_reg_obj || lexical_type == MVM_reg_str;
235
816
}
236
237
238
748k
static MVMint32 ins_has_single_input_output_operand(MVMSpeshIns *ins) {
239
748k
    switch (ins->info->opcode) {
240
20.1k
    case MVM_OP_inc_i:
241
20.1k
    case MVM_OP_inc_u:
242
20.1k
    case MVM_OP_dec_i:
243
20.1k
    case MVM_OP_dec_u:
244
20.1k
        return 1;
245
728k
      default:
246
728k
          break;
247
748k
    }
248
728k
    return 0;
249
748k
}
250
251
void MVM_jit_expr_load_operands(MVMThreadContext *tc, MVMJitExprTree *tree, MVMSpeshIns *ins,
252
738k
                                struct ValueDefinition *values, MVMint32 *operands) {
253
738k
    MVMint32 i;
254
2.27M
    for (i = 0; i < ins->info->num_operands; i++) {
255
1.53M
        MVMSpeshOperand opr = ins->operands[i];
256
1.53M
        MVMint8    opr_kind = ins->info->operands[i];
257
1.53M
        switch(opr_kind & MVM_operand_rw_mask) {
258
588k
        case MVM_operand_read_reg:
259
588k
            if (values[opr.reg.orig].node >= 0) {
260
257k
                operands[i] = values[opr.reg.orig].node;
261
331k
            } else {
262
331k
                MVMint32 addr = MVM_jit_expr_add_regaddr(tc, tree, opr.reg.orig);
263
331k
                operands[i] = MVM_jit_expr_add_load(tc, tree, addr);
264
331k
                values[opr.reg.orig].node = operands[i];
265
331k
                values[opr.reg.orig].addr = addr;
266
331k
                values[opr.reg.orig].root = -1; /* load is not part of a root */
267
331k
            }
268
588k
            break;
269
578k
        case MVM_operand_write_reg:
270
578k
            /* get address of register to write */
271
578k
            operands[i] = MVM_jit_expr_add_regaddr(tc, tree, opr.reg.orig);
272
578k
            break;
273
371k
        case MVM_operand_literal:
274
371k
            operands[i] = MVM_jit_expr_add_const(tc, tree, opr, ins->info->operands[i]);
275
371k
            break;
276
0
        case MVM_operand_read_lex:
277
0
        {
278
0
            MVMint32 addr = MVM_jit_expr_add_lexaddr(tc, tree, opr.lex.outers, opr.lex.idx);
279
0
            operands[i] = MVM_jit_expr_add_load(tc, tree, addr);
280
0
            break;
281
588k
        }
282
30
        case MVM_operand_write_lex:
283
30
            operands[i] = MVM_jit_expr_add_lexaddr(tc, tree, opr.lex.outers, opr.lex.idx);
284
30
            break;
285
0
        default:
286
0
            continue;
287
1.53M
        }
288
1.53M
        if (operands[i] >= tree->nodes_num || operands[i] < 0) {
289
0
            MVM_oops(tc, "JIT: something is wrong with operand loading");
290
0
        }
291
1.53M
    }
292
738k
293
738k
    /* A HACK.
294
738k
     *
295
738k
     * dec_i and inc_i have a single operand that acts both as input and output.
296
738k
     * This is marked only as an output operand, though. Thus, we load the
297
738k
     * address here, and define the value later. However, if we have multiple of
298
738k
     * these in sequence, each will load the old value from memory, disregarding
299
738k
     * the value that an earlier operator has defined, i.e. losing the update.
300
738k
     * That's a bug, and this tries to fix it, by forcing a 'split' between the
301
738k
     * input and the output operand.
302
738k
     */
303
738k
    if (ins_has_single_input_output_operand(ins)) {
304
10.0k
        MVMuint16 reg = ins->operands[0].reg.orig;
305
10.0k
        if (values[reg].node >= 0) {
306
2.28k
            operands[1] = values[reg].node;
307
7.81k
        } else {
308
7.81k
            /* operands[0] has the address */
309
7.81k
            operands[1] = MVM_jit_expr_add_load(tc, tree, operands[0]);
310
7.81k
            /* no need to insert it in the table since it will be directly
311
7.81k
             * overwritten */
312
7.81k
        }
313
10.0k
    }
314
738k
}
315
316
/* This function is to check the internal consistency of a template
317
 * before I apply it.  I need this because I make a lot of mistakes in
318
 * writing templates, and debugging is hard. */
319
738k
static void check_template(MVMThreadContext *tc, const MVMJitExprTemplate *template, MVMSpeshIns *ins) {
320
738k
    MVMint32 i;
321
21.2M
    for (i = 0; i < template->len; i++) {
322
20.5M
        switch(template->info[i]) {
323
0
        case 0:
324
0
            MVM_oops(tc, "JIT: Template info shorter than template length (instruction %s)", ins->info->name);
325
0
            break;
326
6.54M
        case 'l':
327
6.54M
            if (template->code[i] >= i || template->code[i] < 0)
328
0
                MVM_oops(tc, "JIT: Template link out of bounds (instruction: %s)", ins->info->name);
329
6.54M
            break;
330
1.76M
        case 'f':
331
1.76M
            if (template->code[i] < 0 ||
332
1.76M
                (template->code[i] >= ins->info->num_operands &&
333
10.0k
                 !ins_has_single_input_output_operand(ins)))
334
0
                MVM_oops(tc, "JIT: Operand access out of bounds (instruction: %s)", ins->info->name);
335
1.76M
            break;
336
12.2M
        default:
337
12.2M
            continue;
338
20.5M
        }
339
20.5M
    }
340
738k
    if (template->info[i])
341
0
        MVM_oops(tc, "JIT: Template info longer than template length (instruction: %s)",
342
0
                 ins->info->name);
343
738k
}
344
345
/* Add template to nodes, filling in operands and linking tree nodes. Return template root */
346
MVMint32 MVM_jit_expr_apply_template(MVMThreadContext *tc, MVMJitExprTree *tree,
347
738k
                                     const MVMJitExprTemplate *template, MVMint32 *operands) {
348
738k
    MVMint32 i, num;
349
738k
    num = tree->nodes_num;
350
738k
    MVM_VECTOR_ENSURE_SPACE(tree->nodes, template->len);
351
738k
    /* Loop over string until the end */
352
21.2M
    for (i = 0; template->info[i]; i++) {
353
20.5M
        switch (template->info[i]) {
354
6.54M
        case 'l':
355
6.54M
            /* link template-relative to nodes-relative */
356
6.54M
            tree->nodes[num+i] = template->code[i] + num;
357
6.54M
            break;
358
1.76M
        case 'f':
359
1.76M
            /* add operand node into the nodes */
360
1.76M
            tree->nodes[num+i] = operands[template->code[i]];
361
1.76M
            break;
362
12.2M
        default:
363
12.2M
            /* copy from template to nodes */
364
12.2M
            tree->nodes[num+i] = template->code[i];
365
12.2M
            break;
366
20.5M
        }
367
20.5M
    }
368
738k
    tree->nodes_num = num + template->len;
369
738k
    return num + template->root; /* root relative to nodes */
370
738k
}
371
372
373
374
/* Collect tree analysis information, add stores of computed values */
375
static void analyze_node(MVMThreadContext *tc, MVMJitTreeTraverser *traverser,
376
9.82M
                         MVMJitExprTree *tree, MVMint32 node) {
377
9.82M
378
9.82M
    const MVMJitExprOpInfo   *op_info = MVM_jit_expr_op_info(tc, tree->nodes[node]);
379
9.82M
    MVMint32   first_child = node + 1;
380
9.24M
    MVMint32        nchild = op_info->nchild < 0 ? tree->nodes[first_child++] : op_info->nchild;
381
9.82M
    MVMJitExprNode   *args = tree->nodes + first_child + nchild;
382
9.82M
    MVMJitExprNodeInfo *node_info = tree->info + node;
383
9.82M
    MVMint32 i;
384
9.82M
385
9.82M
    node_info->op_info   = op_info;
386
9.82M
    /* propagate node sizes and assign labels */
387
9.82M
    switch (tree->nodes[node]) {
388
683k
    case MVM_JIT_CONST:
389
683k
        /* node size is given */
390
683k
        node_info->size        = args[1];
391
683k
        break;
392
193k
    case MVM_JIT_COPY:
393
193k
        node_info->size = tree->info[tree->nodes[first_child]].size;
394
193k
        break;
395
1.51M
    case MVM_JIT_LOAD:
396
1.51M
        node_info->size = args[0];
397
1.51M
        break;
398
5.30k
    case MVM_JIT_CAST:
399
5.30k
        node_info->size = args[0];
400
5.30k
        break;
401
3.71M
    case MVM_JIT_ADDR:
402
3.71M
    case MVM_JIT_IDX:
403
3.71M
    case MVM_JIT_LABEL:
404
3.71M
    case MVM_JIT_TC:
405
3.71M
    case MVM_JIT_CU:
406
3.71M
    case MVM_JIT_LOCAL:
407
3.71M
    case MVM_JIT_STACK:
408
3.71M
        /* addresses result in pointers */
409
3.71M
        node_info->size = MVM_JIT_PTR_SZ;
410
3.71M
        break;
411
3.71M
        /* binary operations */
412
213k
    case MVM_JIT_ADD:
413
213k
    case MVM_JIT_SUB:
414
213k
    case MVM_JIT_AND:
415
213k
    case MVM_JIT_OR:
416
213k
    case MVM_JIT_XOR:
417
213k
    case MVM_JIT_NOT:
418
213k
        /* comparisons */
419
213k
    case MVM_JIT_NE:
420
213k
    case MVM_JIT_LT:
421
213k
    case MVM_JIT_LE:
422
213k
    case MVM_JIT_EQ:
423
213k
    case MVM_JIT_GE:
424
213k
    case MVM_JIT_GT:
425
213k
        {
426
213k
            /* arithmetic nodes use their largest operand */
427
213k
            MVMint32 left  = tree->nodes[first_child];
428
213k
            MVMint32 right = tree->nodes[first_child+1];
429
213k
            node_info->size = MAX(tree->info[left].size,
430
213k
                                  tree->info[right].size);
431
213k
            break;
432
213k
        }
433
33.1k
    case MVM_JIT_FLAGVAL:
434
33.1k
        /* XXX THIS IS A HACK
435
33.1k
         *
436
33.1k
         * The true size of 'flagval' is a single byte.  But that would mean it
437
33.1k
         * had to be upcast to be used as a 64-bit word, and that subtly
438
33.1k
         * doesn't work if the value is STORE-d to memory. */
439
33.1k
        node_info->size = 4;
440
33.1k
        break;
441
113k
    case MVM_JIT_DO:
442
113k
        /* node size of last child */
443
113k
        {
444
113k
            MVMint32 last_child = tree->nodes[first_child + nchild - 1];
445
113k
            node_info->size = tree->info[last_child].size;
446
113k
            break;
447
213k
        }
448
102k
    case MVM_JIT_IF:
449
102k
        {
450
102k
            MVMint32 left  = tree->nodes[first_child+1];
451
102k
            MVMint32 right = tree->nodes[first_child+2];
452
102k
            node_info->size = MAX(tree->info[left].size,
453
102k
                                         tree->info[right].size);
454
102k
            break;
455
213k
        }
456
113k
    case MVM_JIT_CALL:
457
113k
        node_info->size = args[0];
458
113k
        break;
459
391k
    case MVM_JIT_NZ:
460
391k
    case MVM_JIT_ZR:
461
391k
        node_info->size = tree->info[tree->nodes[first_child]].size;
462
391k
        break;
463
2.74M
    default:
464
2.74M
        /* all other things, branches, labels, when, arglist, carg,
465
2.74M
         * comparisons, etc, have no value size */
466
2.74M
        node_info->size = 0;
467
2.74M
        break;
468
9.82M
    }
469
9.82M
470
9.82M
    /* Insert casts as necessary */
471
9.82M
    if (op_info->cast != MVM_JIT_NO_CAST) {
472
5.80M
        for (i = 0; i < nchild; i++) {
473
3.06M
            MVMint32 child = tree->nodes[first_child+i];
474
3.06M
            if (tree->nodes[child] == MVM_JIT_CONST) {
475
275k
                /* CONST nodes can always take over their target size, so they never need to be cast */
476
275k
                tree->info[child].size = tree->info[node].size;
477
2.79M
            } else if (tree->info[child].size < node_info->size) {
478
5.30k
                /* Widening casts need to be handled explicitly, shrinking casts do not */
479
5.30k
                MVMint32 cast = MVM_jit_expr_add_cast(tc, tree, child, node_info->size, tree->info[child].size, op_info->cast);
480
5.30k
                /* Because the cast may have grown the backing nodes array, the info array needs to grow as well */
481
5.30k
                MVM_VECTOR_ENSURE_SIZE(tree->info, cast);
482
5.30k
                /* And because analyze_node is called in postorder,
483
5.30k
                   the newly added cast node would be neglected by the
484
5.30k
                   traverser. So we traverse it explicitly.. */
485
5.30k
                MVM_VECTOR_ENSURE_SIZE(traverser->visits, cast);
486
5.30k
                traverser->visits[cast] = 1;
487
5.30k
                analyze_node(tc, traverser, tree, cast);
488
5.30k
                /* Finally we replace the child with its cast */
489
5.30k
                tree->nodes[first_child+i] = cast;
490
5.30k
            }
491
3.06M
        }
492
2.73M
    }
493
9.82M
}
494
495
static void assign_labels(MVMThreadContext *tc, MVMJitTreeTraverser *traverser,
496
9.82M
                          MVMJitExprTree *tree, MVMint32 node) {
497
9.82M
    /* IF has two blocks, the first I call left, the second I call right.
498
9.82M
       Regular IF is implemented by the following sequence:
499
9.82M
500
9.82M
       * test
501
9.82M
       * negated conditional jump to label 1
502
9.82M
       * left block
503
9.82M
       * unconditional jump to label 2
504
9.82M
       * label 1
505
9.82M
       * right block
506
9.82M
       * label 2
507
9.82M
508
9.82M
       The 'short-circuiting' cases of IF ALL and IF ANY require special
509
9.82M
       treatment. IF ALL simply repeats the test+negated branch for each of the
510
9.82M
       ALL's children. IF ANY on the other hand must short circuit not into the
511
9.82M
       default (right) but into the (left) conditional block. So IF ANY must be
512
9.82M
       implemented as:
513
9.82M
514
9.82M
       (* test
515
9.82M
        * conditional jump to label 3) - repeated n times
516
9.82M
       * unconditional jump to label 1
517
9.82M
       * label 3
518
9.82M
       * left block
519
9.82M
       * unconditional jump to label 2
520
9.82M
       * label 1
521
9.82M
       * right block
522
9.82M
       * label 2
523
9.82M
524
9.82M
       NB - the label before the left block has been given the number
525
9.82M
       3 for consistency with the regular case.
526
9.82M
527
9.82M
       Simpilar observations are applicable to WHEN and WHEN ANY/WHEN
528
9.82M
       ALL.  Different altogether are the cases of ANY ALL and ALL
529
9.82M
       ANY.
530
9.82M
531
9.82M
       ANY ALL can be implemented as:
532
9.82M
       ( test
533
9.82M
         negated conditional jump to label 4) - repeated for all in ALL
534
9.82M
       * unconditional jump to label 3
535
9.82M
       * label 4 (continuing the ANY)
536
9.82M
537
9.82M
       This way the 'short-circuit' jump of the ALL sequence implies
538
9.82M
       the continuation of the ANY sequence, whereas the finishing of
539
9.82M
       the ALL sequence implies it succeeded and hence the ANY needs
540
9.82M
       to short-circuit.
541
9.82M
542
9.82M
       ALL ANY can be implemented analogously as:
543
9.82M
       ( test
544
9.82M
         conditional jump to label 4) repeated for all children of ANY
545
9.82M
       * unconditional short-circuit jump to label 1
546
9.82M
       * label 4
547
9.82M
548
9.82M
       Nested ALL in ALL and ANY in ANY all have the same
549
9.82M
       short-circuiting behaviour (i.e.  a nested ALL in ALL is
550
9.82M
       indistinguishable from inserting all the children of the nested
551
9.82M
       ALL into the nesting ALL), so they don't require special
552
9.82M
       treatment.
553
9.82M
554
9.82M
       All this goes to say in that the number of labels required and
555
9.82M
       the actual labels assigned to different children depends on the
556
9.82M
       structure of the tree, which is why labels are 'pushed down'
557
9.82M
       from parents to children, at least when those children are ANY
558
9.82M
       and ALL. */
559
9.82M
560
9.82M
    switch (tree->nodes[node]) {
561
91.7k
    case MVM_JIT_WHEN:
562
91.7k
        {
563
91.7k
            /* WHEN just requires one label in the default case */
564
91.7k
            MVMint32 test = tree->nodes[node+1];
565
91.7k
            tree->info[node].label = tree->num_labels++;
566
91.7k
            if (tree->nodes[test] == MVM_JIT_ANY) {
567
0
                /* ANY requires a pre-left-block label */
568
0
                tree->info[test].label = tree->num_labels++;
569
91.7k
            } else if (tree->nodes[test] == MVM_JIT_ALL) {
570
44.0k
                /* ALL takes over the label of its parent */
571
44.0k
                tree->info[test].label = tree->info[node].label;
572
44.0k
            }
573
91.7k
        }
574
91.7k
        break;
575
160k
    case MVM_JIT_IF:
576
160k
    case MVM_JIT_IFV:
577
160k
        {
578
160k
            MVMint32 test = tree->nodes[node+1];
579
160k
            /* take two labels, one for the left block and one for the right block */
580
160k
            tree->info[node].label = tree->num_labels;
581
160k
            tree->num_labels += 2;
582
160k
            if (tree->nodes[test] == MVM_JIT_ANY) {
583
22
                /* assign 'label 3' to the ANY */
584
22
                tree->info[test].label = tree->num_labels++;
585
160k
            } else if (tree->nodes[test] == MVM_JIT_ALL) {
586
43.8k
                /* assign 'label 1' to the ALL */
587
43.8k
                tree->info[test].label = tree->info[node].label;
588
43.8k
            }
589
160k
        }
590
160k
        break;
591
87.9k
    case MVM_JIT_ALL:
592
87.9k
        {
593
87.9k
            MVMint32 nchild = tree->nodes[node+1];
594
87.9k
            MVMint32 i;
595
328k
            for (i = 0; i < nchild; i++) {
596
240k
                MVMint32 test = tree->nodes[node+2+i];
597
240k
                if (tree->nodes[test] == MVM_JIT_ALL) {
598
0
                    /* use same label for child as parent */
599
0
                    tree->info[test].label = tree->info[node].label;
600
240k
                } else if (tree->nodes[test] == MVM_JIT_ANY) {
601
0
                    /* assign an extra label for ANY to short-circuit into */
602
0
                    tree->info[test].label = tree->num_labels++;
603
0
                }
604
240k
            }
605
87.9k
        }
606
87.9k
        break;
607
22
    case MVM_JIT_ANY:
608
22
        {
609
22
            MVMint32 nchild = tree->nodes[node+1];
610
22
            MVMint32 i;
611
66
            for (i = 0; i < nchild; i++) {
612
44
                MVMint32 test = tree->nodes[node+2+i];
613
44
                if (tree->nodes[test] == MVM_JIT_ANY) {
614
0
                    tree->info[test].label = tree->info[node].label;
615
44
                } else if (tree->nodes[test] == MVM_JIT_ALL) {
616
0
                    tree->info[test].label = tree->num_labels++;
617
0
                }
618
44
            }
619
22
        }
620
22
        break;
621
9.48M
    default:
622
9.48M
        break;
623
9.82M
    }
624
9.82M
}
625
626
627
262k
void MVM_jit_expr_tree_analyze(MVMThreadContext *tc, MVMJitExprTree *tree) {
628
262k
    /* analyse the tree, calculate usage and destination information */
629
262k
    MVMJitTreeTraverser traverser;
630
262k
    MVM_VECTOR_ENSURE_SIZE(tree->info, tree->nodes_num);
631
262k
    traverser.policy    = MVM_JIT_TRAVERSER_ONCE;
632
262k
    traverser.data      = NULL;
633
262k
    traverser.preorder  = &assign_labels;
634
262k
    traverser.inorder   = NULL;
635
262k
    traverser.postorder = &analyze_node;
636
262k
    MVM_jit_expr_tree_traverse(tc, tree, &traverser);
637
262k
}
638
639
640
641
/* insert stores for all the active unstored values */
642
static void active_values_flush(MVMThreadContext *tc, MVMJitExprTree *tree,
643
353k
                                struct ValueDefinition *values, MVMint32 num_values) {
644
353k
    MVMint32 i;
645
28.1M
    for (i = 0; i < num_values; i++) {
646
27.7M
        if (values[i].root >= 0) {
647
412k
            tree->roots[values[i].root] = MVM_jit_expr_add_store(
648
412k
                tc, tree, values[i].addr,
649
412k
                values[i].node, MVM_JIT_REG_SZ
650
412k
            );
651
412k
        }
652
27.7M
        if (values[i].node >= 0) {
653
715k
            memset(values + i, -1, sizeof(struct ValueDefinition));
654
715k
        }
655
27.7M
    }
656
353k
}
657
658
659
/* TODO add labels to the expression tree */
660
296k
MVMJitExprTree * MVM_jit_expr_tree_build(MVMThreadContext *tc, MVMJitGraph *jg, MVMSpeshIterator *iter) {
661
296k
    MVMSpeshGraph *sg = jg->sg;
662
296k
    MVMSpeshIns *entry = iter->ins;
663
296k
    MVMSpeshIns *ins;
664
296k
    MVMJitExprTree *tree;
665
296k
    MVMint32 operands[MVM_MAX_OPERANDS];
666
296k
    struct ValueDefinition *values;
667
296k
    MVMint32 root, node;
668
296k
    MVMuint16 i;
669
296k
    /* No instructions, just skip */
670
296k
    if (!iter->ins)
671
0
        return NULL;
672
296k
673
296k
    /* Make the tree */
674
296k
    tree = MVM_malloc(sizeof(MVMJitExprTree));
675
296k
    MVM_VECTOR_INIT(tree->nodes, 256);
676
296k
    MVM_VECTOR_INIT(tree->info,  256);
677
296k
    MVM_VECTOR_INIT(tree->roots, 16);
678
296k
679
296k
    /* ensure that all references are nonzero */
680
296k
    MVM_VECTOR_PUSH(tree->nodes, MVM_JIT_NOOP);
681
296k
682
296k
    tree->graph      = jg;
683
296k
    tree->num_labels = 0;
684
296k
    /* Hold indices to the node that last computed a value belonging
685
296k
     * to a register. Initialized as -1 to indicate that these
686
296k
     * values are empty. */
687
296k
    values = MVM_malloc(sizeof(struct ValueDefinition)*sg->num_locals);
688
296k
    memset(values, -1, sizeof(struct ValueDefinition)*sg->num_locals);
689
296k
690
4.94M
#define BAIL(x, ...) do { if (x) { MVM_jit_log(tc, __VA_ARGS__); goto done; } } while (0)
691
296k
692
296k
    /* Generate a tree based on templates. The basic idea is to keep a
693
296k
       index to the node that last computed the value of a local.
694
296k
       Each opcode is translated to the expression using a template,
695
296k
       which is a): filled with nodes coming from operands and b):
696
296k
       internally linked together (relative to absolute indexes).
697
296k
       Afterwards stores are inserted for computed values. */
698
296k
699
1.71M
    for (ins = iter->ins; ins != NULL; ins = MVM_spesh_iterator_next_ins(tc, iter)) {
700
1.49M
        /* NB - we probably will want to involve the spesh info in selecting a
701
1.49M
           template. And for optimisation, I'd like to copy spesh facts (if any)
702
1.49M
           to the tree info */
703
1.49M
        MVMuint16 opcode = ins->info->opcode;
704
1.49M
        MVMSpeshAnn *ann;
705
1.49M
        const MVMJitExprTemplate *template;
706
1.49M
        MVMint32 before_label = -1, after_label = -1, store_directly = 0;
707
1.49M
708
1.49M
        struct ValueDefinition *defined_value = NULL;
709
1.49M
710
1.49M
        /* check if this is a getlex and if we can handle it */
711
1.49M
        BAIL(opcode == MVM_OP_getlex && getlex_needs_autoviv(tc, jg, ins), "Can't compile object getlex");
712
1.49M
        BAIL(opcode == MVM_OP_bindlex && bindlex_needs_write_barrier(tc, jg, ins), "Can't compile write-barrier bindlex");
713
1.49M
714
1.49M
        /* Check annotations that may require handling or wrapping the expression */
715
1.74M
        for (ann = ins->annotations; ann != NULL; ann = ann->next) {
716
268k
            MVMint32 idx;
717
268k
            switch (ann->type) {
718
17.3k
            case MVM_SPESH_ANN_FH_START:
719
17.3k
                /* start of a frame handler (inclusive). We need to mark this
720
17.3k
                 * instruction with a label so that we know the handler covers
721
17.3k
                 * this code */
722
17.3k
                before_label = MVM_jit_label_before_ins(tc, jg, iter->bb, ins);
723
17.3k
                jg->handlers[ann->data.frame_handler_index].start_label = before_label;
724
17.3k
                break;
725
16.0k
            case MVM_SPESH_ANN_FH_END:
726
16.0k
                /* end of the frame handler (exclusive), funnily enough not
727
16.0k
                 * necessarily the end of a basic block. */
728
16.0k
                before_label = MVM_jit_label_before_ins(tc, jg, iter->bb, ins);
729
16.0k
                jg->handlers[ann->data.frame_handler_index].end_label = before_label;
730
16.0k
                break;
731
17.4k
            case MVM_SPESH_ANN_FH_GOTO:
732
17.4k
                /* A label to jump to for when a handler catches an
733
17.4k
                 * exception. Thus, this can be a control flow entry point (and
734
17.4k
                 * should be the start of a basic block, but I'm not sure if it
735
17.4k
                 * always is).  */
736
17.4k
                before_label = MVM_jit_label_before_ins(tc, jg, iter->bb, ins);
737
17.4k
                jg->handlers[ann->data.frame_handler_index].goto_label = before_label;
738
17.4k
                active_values_flush(tc, tree, values, sg->num_locals);
739
17.4k
                break;
740
4.94k
            case MVM_SPESH_ANN_DEOPT_OSR:
741
4.94k
                /* A label the OSR can jump into to 'start running', so to
742
4.94k
                 * speak. As it breaks the basic-block assumption, arguably,
743
4.94k
                 * this should only ever be at the start of a basic block. But
744
4.94k
                 * it's not. So we have to insert the label and compute it. */
745
4.94k
                before_label = MVM_jit_label_before_ins(tc, jg, iter->bb, ins);
746
4.94k
                /* OSR reuses the deopt label mechanism */
747
4.94k
                MVM_VECTOR_ENSURE_SIZE(jg->deopts, idx = jg->deopts_num++);
748
4.94k
                jg->deopts[idx].label = before_label;
749
4.94k
                jg->deopts[idx].idx   = ann->data.deopt_idx;
750
4.94k
                /* possible entrypoint, so flush intermediates */
751
4.94k
                active_values_flush(tc, tree, values, sg->num_locals);
752
4.94k
                break;
753
8.45k
            case MVM_SPESH_ANN_INLINE_START:
754
8.45k
                /* start of an inline, used for reconstructing state when deoptimizing */
755
8.45k
                before_label = MVM_jit_label_before_ins(tc, jg, iter->bb, ins);
756
8.45k
                jg->inlines[ann->data.inline_idx].start_label = before_label;
757
8.45k
                break;
758
7.04k
            case MVM_SPESH_ANN_INLINE_END:
759
7.04k
                /* end of the inline (inclusive), so we need to add a label,
760
7.04k
                 * which should be the end of the basic block. */
761
7.04k
                after_label = MVM_jit_label_after_ins(tc, jg, iter->bb, ins);
762
7.04k
                jg->inlines[ann->data.inline_idx].end_label = after_label;
763
7.04k
                break;
764
34.3k
            case MVM_SPESH_ANN_DEOPT_INLINE:
765
34.3k
                MVM_jit_log(tc, "Not sure if we can handle DEOPT_INLINE on instruction %s\n", ins->info->name);
766
34.3k
                break;
767
124k
            case MVM_SPESH_ANN_DEOPT_ONE_INS:
768
124k
                /* we should only see this in guards, which we don't do just
769
124k
                 * yet, although we will. At the very least, this implies a flush. */
770
124k
                switch (opcode) {
771
12.6k
                case MVM_OP_sp_guard:
772
12.6k
                case MVM_OP_sp_guardconc:
773
12.6k
                case MVM_OP_sp_guardtype:
774
12.6k
                case MVM_OP_sp_guardsf:
775
12.6k
                    BAIL(1, "Cannot handle DEOPT_ONE (ins=%s)\n", ins->info->name);
776
0
                    break;
777
124k
                }
778
111k
                break;
779
0
            case MVM_SPESH_ANN_DEOPT_ALL_INS:
780
0
                /* don't expect to be handling these, either, but these also
781
0
                 * might need a label-after-the-fact */
782
0
                after_label = MVM_jit_label_after_ins(tc, jg, iter->bb, ins);
783
0
                /* ensure a consistent state for deoptimization */
784
0
                active_values_flush(tc, tree, values, sg->num_locals);
785
0
                /* add deopt idx */
786
0
                MVM_VECTOR_ENSURE_SIZE(jg->deopts, idx = jg->deopts_num++);
787
0
                jg->deopts[idx].label = after_label;
788
0
                jg->deopts[idx].idx   = ann->data.deopt_idx;
789
0
                break;
790
268k
            }
791
268k
        }
792
1.49M
793
1.49M
794
1.47M
        if (opcode == MVM_SSA_PHI || opcode == MVM_OP_no_op) {
795
681k
            /* By definition, a PHI node can only occur at the start of a basic
796
681k
             * block. (A no_op instruction only seems to happen as the very
797
681k
             * first instruction of a frame, and I'm not sure why).
798
681k
             *
799
681k
             * Thus, if it happens that we've processed annotations on those
800
681k
             * instructions (which probably means they migrated there from
801
681k
             * somewhere else), they always refer to the start of the basic
802
681k
             * block, which is already assigned a label and
803
681k
             * dynamic-control-handler.
804
681k
             *
805
681k
             * So we never need to do anything with this label and wrapper, but
806
681k
             * we do need to process the annotation to setup the frame handler
807
681k
             * correctly.
808
681k
             */
809
681k
            BAIL(after_label >= 0, "A PHI node should not have an after label");
810
681k
            continue;
811
681k
        }
812
1.47M
813
796k
        template = MVM_jit_get_template_for_opcode(opcode);
814
796k
        BAIL(template == NULL, "Cannot get template for: %s\n", ins->info->name);
815
796k
816
738k
        check_template(tc, template, ins);
817
738k
818
738k
        MVM_jit_expr_load_operands(tc, tree, ins, values, operands);
819
738k
        root = MVM_jit_expr_apply_template(tc, tree, template, operands);
820
738k
821
738k
        /* root is highest node by construction, so we don't have to check the size of info later */
822
738k
        MVM_VECTOR_ENSURE_SIZE(tree->info, root);
823
738k
        tree->info[root].spesh_ins = ins;
824
738k
825
738k
826
738k
        /* mark operand types */
827
2.27M
        for (i = 0; i < ins->info->num_operands; i++) {
828
1.53M
            MVMint8 opr_kind = ins->info->operands[i];
829
1.53M
            MVMint8 opr_type = opr_kind & MVM_operand_type_mask;
830
1.53M
            MVMSpeshOperand opr = ins->operands[i];
831
1.53M
            if (opr_type == MVM_operand_type_var) {
832
300k
                switch (opr_kind & MVM_operand_rw_mask) {
833
300k
                case MVM_operand_read_reg:
834
300k
                case MVM_operand_write_reg:
835
300k
                    opr_type = MVM_spesh_get_reg_type(tc, sg, opr.reg.orig) << 3; /* shift up 3 to match operand type */
836
300k
                    break;
837
30
                case MVM_operand_read_lex:
838
30
                case MVM_operand_write_lex:
839
30
                    opr_type = MVM_spesh_get_lex_type(tc, sg, opr.lex.outers, opr.lex.idx) << 3;
840
30
                    break;
841
300k
                }
842
300k
            }
843
1.53M
            switch(opr_kind & MVM_operand_rw_mask) {
844
588k
            case MVM_operand_read_reg:
845
588k
            case MVM_operand_read_lex:
846
588k
                tree->info[operands[i]].opr_type = opr_type;
847
588k
                break;
848
578k
            case MVM_operand_write_reg:
849
578k
                /* for write_reg and write_lex, operands[i] is the *address*,
850
578k
                 * the *value* is the root, but this is only valid if the
851
578k
                 * operand index is 0 */
852
578k
                if (template->flags & MVM_JIT_EXPR_TEMPLATE_DESTRUCTIVE) {
853
113k
                    /* overrides any earlier definition of this local variable */
854
113k
                    memset(values + opr.reg.orig, -1, sizeof(struct ValueDefinition));
855
465k
                } else {
856
465k
                    /* record this value, should be only one for the root */
857
465k
                    BAIL(i != 0, "Write reg operand %d", i);
858
465k
                    tree->info[root].opr_type  = opr_type;
859
465k
                    defined_value = values + opr.reg.orig;
860
465k
                    defined_value->addr = operands[i];
861
465k
                    defined_value->node = root;
862
465k
                    /* this overwrites any previous definition */
863
465k
                    defined_value->root = -1;
864
465k
                }
865
578k
                break;
866
30
            case MVM_operand_write_lex:
867
30
                /* does not define a value we can look up, but we may need to
868
30
                 * insert a store */
869
30
                if (!(template->flags & MVM_JIT_EXPR_TEMPLATE_DESTRUCTIVE)) {
870
0
                    BAIL(i != 0, "Write lex operand %d", i);
871
0
                    tree->info[root].opr_type = opr_type;
872
0
                    /* insert the store to lexicals directly, do not record as value */
873
0
                    root = MVM_jit_expr_add_store(tc, tree, operands[i], root, MVM_JIT_REG_SZ);
874
0
                }
875
30
                break;
876
1.53M
            }
877
1.53M
        }
878
738k
879
738k
880
738k
881
738k
882
738k
        if (ins->info->jittivity & (MVM_JIT_INFO_THROWISH | MVM_JIT_INFO_INVOKISH)) {
883
67.7k
            /* NB: we should make this a template-level flag; should be possible
884
67.7k
             * to replace an invokish version with a non-invokish version (but
885
67.7k
             * perhaps best if that is opt-in so people don't accidentally
886
67.7k
             * forget to set it). */
887
67.7k
            MVM_jit_log(tc, "EXPR: adding throwish guard to op (%s)\n", ins->info->name);
888
67.7k
            active_values_flush(tc, tree, values, sg->num_locals);
889
67.7k
            store_directly = 1;
890
67.7k
        }
891
738k
892
738k
893
738k
        /* Add root to tree to ensure source evaluation order, wrapped with
894
738k
         * labels if necessary. */
895
738k
        if (before_label >= 0 && MVM_jit_label_is_for_ins(tc, jg, before_label)) {
896
5.69k
            MVM_VECTOR_PUSH(tree->roots, MVM_jit_expr_add_label(tc, tree, before_label));
897
5.69k
        }
898
738k
899
738k
        /* NB: GUARD only wraps void nodes. Currently, we replace any
900
738k
         * value-yielding node with it's STORE (and thereby make sure it is
901
738k
         * flushed directly) */
902
738k
        if (store_directly && defined_value != NULL) {
903
0
            /* If we're wrapping this template and it defines a value, we
904
0
             * had maybe better flush it directly */
905
0
            root = MVM_jit_expr_add_store(tc, tree, defined_value->addr, root, MVM_JIT_REG_SZ);
906
0
            defined_value = NULL;
907
0
        }
908
738k
909
738k
        if (defined_value != NULL) {
910
465k
            defined_value->root = tree->roots_num;
911
465k
        }
912
738k
913
738k
        MVM_VECTOR_PUSH(tree->roots, root);
914
738k
        if (after_label >= 0 && MVM_jit_label_is_for_ins(tc, jg, after_label)) {
915
0
            MVM_VECTOR_PUSH(tree->roots, MVM_jit_expr_add_label(tc, tree, after_label));
916
0
        }
917
738k
    }
918
296k
919
296k
 done:
920
296k
    if (tree->roots_num > 0) {
921
262k
        active_values_flush(tc, tree, values, sg->num_locals);
922
262k
        MVM_jit_expr_tree_analyze(tc, tree);
923
262k
        MVM_jit_log(tc, "Build tree out of: [");
924
1.65M
        for (ins = entry; ins != iter->ins; ins = ins->next) {
925
1.38M
            if (ins->info->opcode == MVM_SSA_PHI)
926
650k
                continue;
927
738k
            MVM_jit_log(tc, "%s, ", ins->info->name);
928
738k
        }
929
262k
        MVM_jit_log(tc, "]\n");
930
33.7k
    } else {
931
33.7k
        /* Don't return empty trees, nobody wants that */
932
33.7k
        MVM_jit_expr_tree_destroy(tc, tree);
933
33.7k
        tree = NULL;
934
33.7k
    }
935
296k
    MVM_free(values);
936
296k
    return tree;
937
296k
}
938
939
284k
void MVM_jit_expr_tree_destroy(MVMThreadContext *tc, MVMJitExprTree *tree) {
940
284k
    if (tree->info)
941
284k
        MVM_free(tree->info);
942
284k
    MVM_free(tree->nodes);
943
284k
    MVM_free(tree->roots);
944
284k
    MVM_free(tree);
945
284k
}
946
947
static void walk_tree(MVMThreadContext *tc, MVMJitExprTree *tree,
948
32.9M
                 MVMJitTreeTraverser *traverser, MVMint32 node) {
949
32.9M
    const MVMJitExprOpInfo *info = MVM_jit_expr_op_info(tc, tree->nodes[node]);
950
32.9M
    MVMint32 nchild = info->nchild;
951
32.9M
    MVMint32 first_child = node + 1;
952
32.9M
    MVMint32 i;
953
32.9M
    if (traverser->policy == MVM_JIT_TRAVERSER_ONCE &&
954
32.9M
        traverser->visits[node] >= 1)
955
3.72M
        return;
956
32.9M
957
29.2M
    traverser->visits[node]++;
958
29.2M
    /* visiting on the way down - NB want to add visitation information */
959
29.2M
    if (traverser->preorder)
960
19.7M
        traverser->preorder(tc, traverser, tree, node);
961
29.2M
    if (nchild < 0) {
962
1.70M
        /* Variadic case: take first child as constant signifying the
963
1.70M
         * number of children. Increment because the 'real' children now
964
1.70M
         * start node later */
965
1.70M
        nchild = tree->nodes[first_child++];
966
1.70M
    }
967
60.0M
    for (i = 0; i < nchild; i++) {
968
30.7M
        /* Enter child node */
969
30.7M
        walk_tree(tc, tree, traverser, tree->nodes[first_child+i]);
970
30.7M
        if (traverser->inorder) {
971
10.3M
            traverser->inorder(tc, traverser, tree, node, i);
972
10.3M
        }
973
30.7M
    }
974
29.2M
    if (traverser->postorder) {
975
29.2M
        traverser->postorder(tc, traverser, tree, node);
976
29.2M
    }
977
29.2M
}
978
979
/* TODO specify revisiting policy */
980
void MVM_jit_expr_tree_traverse(MVMThreadContext *tc, MVMJitExprTree *tree,
981
770k
                                MVMJitTreeTraverser *traverser) {
982
770k
    MVMint32 i;
983
770k
    MVM_VECTOR_INIT(traverser->visits, tree->nodes_num);
984
2.96M
    for (i = 0; i < tree->roots_num; i++) {
985
2.19M
        /* TODO deal with nodes with multiple entries */
986
2.19M
        walk_tree(tc, tree, traverser, tree->roots[i]);
987
2.19M
    }
988
770k
    MVM_free(traverser->visits);
989
770k
}
990
991
992
18.0M
#define FIRST_CHILD(t,x) (t->info[x].op_info->nchild < 0 ? x + 2 : x + 1)
993
/* Walk tree to get nodes along a path */
994
MVMint32 MVM_jit_expr_tree_get_nodes(MVMThreadContext *tc, MVMJitExprTree *tree,
995
                                     MVMint32 node, const char *path,
996
5.34M
                                     MVMJitExprNode *buffer) {
997
5.34M
    MVMJitExprNode *ptr = buffer;
998
16.1M
    while (*path) {
999
10.7M
        MVMJitExprNode cur_node = node;
1000
18.0M
        do {
1001
18.0M
            MVMint32 first_child = FIRST_CHILD(tree, cur_node) - 1;
1002
18.0M
            MVMint32 child_nr    = *path++ - '0';
1003
18.0M
            cur_node = tree->nodes[first_child+child_nr];
1004
18.0M
        } while (*path != '.');
1005
10.7M
        /* regs nodes go to values, others to args */
1006
10.7M
        *ptr++ = cur_node;
1007
10.7M
        path++;
1008
10.7M
    }
1009
5.34M
    return ptr - buffer;
1010
5.34M
}
1011
#undef FIRST_CHILD