Coverage Report

Created: 2017-04-15 07:07

/home/travis/build/MoarVM/MoarVM/src/spesh/args.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
/* Maximum number of positional args we'll consider for optimization purposes. */
4
87.2k
#define MAX_POS_ARGS 8
5
6
/* Maximum number of named args we'll consider for optimization purposes. */
7
55.3k
#define MAX_NAMED_ARGS 8
8
9
/* Adds guards and facts for an object arg. */
10
static void add_guards_and_facts(MVMThreadContext *tc, MVMSpeshGraph *g, MVMint32 slot,
11
27.2k
                          MVMObject *arg, MVMSpeshIns *arg_ins) {
12
27.2k
    /* Grab type and concreteness. */
13
27.2k
    MVMObject *type     = STABLE(arg)->WHAT;
14
27.2k
    MVMint32   concrete = IS_CONCRETE(arg);
15
27.2k
    MVMint32   is_cont  = 0;
16
27.2k
17
27.2k
    /* Add appropriate facts from arg itself. */
18
27.2k
    MVMint16 orig = arg_ins->operands[0].reg.orig;
19
27.2k
    MVMint16 i    = arg_ins->operands[0].reg.i;
20
27.2k
    g->facts[orig][i].type   = type;
21
27.2k
    g->facts[orig][i].flags |= MVM_SPESH_FACT_KNOWN_TYPE;
22
27.2k
    if (concrete) {
23
22.2k
        g->facts[orig][i].flags |= MVM_SPESH_FACT_CONCRETE;
24
22.2k
        if (!STABLE(type)->container_spec)
25
22.2k
            g->facts[orig][i].flags |= MVM_SPESH_FACT_DECONTED;
26
22.2k
        else
27
0
            is_cont = 1;
28
22.2k
    }
29
4.95k
    else {
30
4.95k
        g->facts[orig][i].flags |= MVM_SPESH_FACT_TYPEOBJ | MVM_SPESH_FACT_DECONTED;
31
4.95k
    }
32
27.2k
33
27.2k
    /* Add guard record for the arg type. */
34
27.2k
    g->arg_guards[g->num_arg_guards].slot  = slot;
35
27.2k
    g->arg_guards[g->num_arg_guards].match = (MVMCollectable *)STABLE(type);
36
27.2k
    if (concrete)
37
22.2k
        g->arg_guards[g->num_arg_guards].kind = MVM_SPESH_GUARD_CONC;
38
27.2k
    else
39
4.95k
        g->arg_guards[g->num_arg_guards].kind = MVM_SPESH_GUARD_TYPE;
40
27.2k
    g->num_arg_guards++;
41
27.2k
42
27.2k
    /* If we know it's a container, might be able to look inside it to
43
27.2k
     * further optimize. */
44
27.2k
    if (is_cont && STABLE(type)->container_spec->fetch_never_invokes &&
45
0
            REPR(type)->ID != MVM_REPR_ID_NativeRef) {
46
0
        /* See if it's an rw container. */
47
0
        MVMint32 is_rw = STABLE(type)->container_spec->can_store(tc, arg);
48
0
49
0
        /* Fetch argument from the container. */
50
0
        MVMRegister r;
51
0
        STABLE(type)->container_spec->fetch(tc, arg, &r);
52
0
        arg = r.o;
53
0
        if (!arg)
54
0
            return;
55
0
56
0
        /* Add facts about it. */
57
0
        type                           = STABLE(arg)->WHAT;
58
0
        concrete                       = IS_CONCRETE(arg);
59
0
        g->facts[orig][i].decont_type  = type;
60
0
        g->facts[orig][i].flags       |= MVM_SPESH_FACT_KNOWN_DECONT_TYPE;
61
0
        if (concrete)
62
0
            g->facts[orig][i].flags |= MVM_SPESH_FACT_DECONT_CONCRETE;
63
0
        else
64
0
            g->facts[orig][i].flags |= MVM_SPESH_FACT_DECONT_TYPEOBJ;
65
0
        if (is_rw)
66
0
            g->facts[orig][i].flags |= MVM_SPESH_FACT_RW_CONT;
67
0
68
0
        /* Add guard for contained value. */
69
0
        g->arg_guards[g->num_arg_guards].slot  = slot;
70
0
        g->arg_guards[g->num_arg_guards].match = (MVMCollectable *)STABLE(type);
71
0
        if (is_rw) {
72
0
            if (concrete)
73
0
                g->arg_guards[g->num_arg_guards].kind = MVM_SPESH_GUARD_DC_CONC_RW;
74
0
            else
75
0
                g->arg_guards[g->num_arg_guards].kind = MVM_SPESH_GUARD_DC_TYPE_RW;
76
0
        }
77
0
        else {
78
0
            if (concrete)
79
0
                g->arg_guards[g->num_arg_guards].kind = MVM_SPESH_GUARD_DC_CONC;
80
0
            else
81
0
                g->arg_guards[g->num_arg_guards].kind = MVM_SPESH_GUARD_DC_TYPE;
82
0
        }
83
0
        g->num_arg_guards++;
84
0
    }
85
27.2k
}
86
87
/* Adds an instruction marking a name arg as being used (if we turned its
88
 * fetching into a positional). */
89
static MVMSpeshIns * add_named_used_ins(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb,
90
1.58k
                               MVMSpeshIns *ins, MVMint32 idx) {
91
1.58k
    MVMSpeshIns *inserted_ins = MVM_spesh_alloc(tc, g, sizeof( MVMSpeshIns ));
92
1.58k
    MVMSpeshOperand *operands = MVM_spesh_alloc(tc, g, sizeof( MVMSpeshOperand ));
93
1.58k
    inserted_ins->info        = MVM_op_get_op(MVM_OP_sp_namedarg_used);
94
1.58k
    inserted_ins->operands    = operands;
95
1.58k
    operands[0].lit_i16       = (MVMint16)idx;
96
1.58k
    MVM_spesh_manipulate_insert_ins(tc, bb, ins, inserted_ins);
97
1.58k
    return inserted_ins;
98
1.58k
}
99
100
/* Handles a pos arg that needs unboxing. */
101
static void pos_unbox(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb,
102
977
                      MVMSpeshIns *ins, const MVMOpInfo *unbox_op) {
103
977
    MVMSpeshOperand  temp  = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_obj);
104
977
    MVMSpeshIns     *unbox = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
105
977
    unbox->info            = unbox_op;
106
977
    unbox->operands        = MVM_spesh_alloc(tc, g, 2 * sizeof(MVMSpeshOperand));
107
977
    unbox->operands[0]     = ins->operands[0];
108
977
    unbox->operands[1]     = temp;
109
977
    ins->info              = MVM_op_get_op(MVM_OP_sp_getarg_o);
110
977
    ins->operands[0]       = temp;
111
977
    MVM_spesh_manipulate_insert_ins(tc, bb, ins, unbox);
112
977
    MVM_spesh_manipulate_release_temp_reg(tc, g, temp);
113
977
}
114
115
/* Handles a pos arg that needs boxing. */
116
static void pos_box(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb,
117
                    MVMSpeshIns *ins, const MVMOpInfo *hlltype_op, const MVMOpInfo *box_op,
118
2.02k
                    const MVMOpInfo *arg_op, MVMuint8 kind) {
119
2.02k
    MVMSpeshOperand  temp_bt, temp_arg;
120
2.02k
    MVMSpeshIns     *hlltype, *box;
121
2.02k
122
2.02k
    /* Add HLL type op. */
123
2.02k
    temp_bt              = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_obj);
124
2.02k
    hlltype              = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
125
2.02k
    hlltype->info        = hlltype_op;
126
2.02k
    hlltype->operands    = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshOperand));
127
2.02k
    hlltype->operands[0] = temp_bt;
128
2.02k
    MVM_spesh_manipulate_insert_ins(tc, bb, ins, hlltype);
129
2.02k
130
2.02k
    /* Add box op. */
131
2.02k
    temp_arg         = MVM_spesh_manipulate_get_temp_reg(tc, g, kind);
132
2.02k
    box              = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
133
2.02k
    box->info        = box_op;
134
2.02k
    box->operands    = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand));
135
2.02k
    box->operands[0] = ins->operands[0];
136
2.02k
    box->operands[1] = temp_arg;
137
2.02k
    box->operands[2] = temp_bt;
138
2.02k
    MVM_spesh_manipulate_insert_ins(tc, bb, hlltype, box);
139
2.02k
140
2.02k
    /* Update instruction to receive unboxed arg. */
141
2.02k
    ins->info        = arg_op;
142
2.02k
    ins->operands[0] = temp_arg;
143
2.02k
144
2.02k
    /* Release temporary registers. */
145
2.02k
    MVM_spesh_manipulate_release_temp_reg(tc, g, temp_bt);
146
2.02k
    MVM_spesh_manipulate_release_temp_reg(tc, g, temp_arg);
147
2.02k
}
148
149
/* Gets the primitive boxed by a type. */
150
1.16k
static MVMuint16 prim_spec(MVMThreadContext *tc, MVMObject *type) {
151
1.16k
    return type
152
1.16k
        ? REPR(type)->get_storage_spec(tc, STABLE(type))->boxed_primitive
153
0
        : 0;
154
1.16k
}
155
156
/* Takes information about the incoming callsite and arguments, and performs
157
 * various optimizations based on that information. */
158
17.1k
void MVM_spesh_args(MVMThreadContext *tc, MVMSpeshGraph *g, MVMCallsite *cs, MVMRegister *args) {
159
17.1k
    /* We need to identify the various arg-related instructions in the graph,
160
17.1k
     * then manipulate them as a whole. */
161
17.1k
    MVMSpeshIns  *checkarity_ins     = NULL;
162
17.1k
    MVMSpeshBB   *checkarity_bb      = NULL;
163
17.1k
    MVMSpeshIns  *paramnamesused_ins = NULL;
164
17.1k
    MVMSpeshBB   *paramnamesused_bb  = NULL;
165
17.1k
    MVMSpeshIns  *param_sn_ins       = NULL;
166
17.1k
167
17.1k
    MVMSpeshIns **pos_ins    = MVM_calloc(MAX_POS_ARGS, sizeof(MVMSpeshIns *));
168
17.1k
    MVMSpeshBB  **pos_bb     = MVM_calloc(MAX_POS_ARGS, sizeof(MVMSpeshBB *));
169
17.1k
    MVMuint8     *pos_added  = MVM_calloc(MAX_POS_ARGS, sizeof(MVMuint8));
170
17.1k
    MVMSpeshIns **named_ins  = MVM_calloc(MAX_NAMED_ARGS, sizeof(MVMSpeshIns *));
171
17.1k
    MVMSpeshBB  **named_bb   = MVM_calloc(MAX_NAMED_ARGS, sizeof(MVMSpeshBB *));
172
17.1k
    MVMSpeshIns **used_ins   = MVM_calloc(MAX_NAMED_ARGS, sizeof(MVMSpeshIns *));
173
17.1k
    MVMint32      req_max    = -1;
174
17.1k
    MVMint32      opt_min    = -1;
175
17.1k
    MVMint32      opt_max    = -1;
176
17.1k
    MVMint32      num_named  = 0;
177
17.1k
    MVMint32      named_used = 0;
178
17.1k
    MVMint32      got_named  = cs->num_pos != cs->arg_count;
179
17.1k
180
17.1k
    MVMSpeshBB *bb = g->entry;
181
17.1k
182
17.1k
    g->cs = cs;
183
17.1k
184
17.1k
    /* Walk through the graph, looking for arg related instructions. */
185
331k
    while (bb) {
186
314k
        MVMSpeshIns *ins = bb->first_ins;
187
2.38M
        while (ins) {
188
2.07M
            switch (ins->info->opcode) {
189
17.1k
            case MVM_OP_checkarity:
190
17.1k
                if (checkarity_ins)
191
0
                    goto cleanup; /* Dupe; weird; bail out! */
192
17.1k
                checkarity_ins = ins;
193
17.1k
                checkarity_bb  = bb;
194
17.1k
                break;
195
32.0k
            case MVM_OP_param_rp_i:
196
32.0k
            case MVM_OP_param_rp_n:
197
32.0k
            case MVM_OP_param_rp_s:
198
32.0k
            case MVM_OP_param_rp_o: {
199
32.0k
                /* Required positional. */
200
32.0k
                MVMint16 idx = ins->operands[1].lit_i16;
201
32.0k
                if (idx < 0 || idx >= MAX_POS_ARGS)
202
0
                    goto cleanup;
203
32.0k
                if (pos_ins[idx]) /* Dupe; weird. */
204
0
                    goto cleanup;
205
32.0k
                pos_ins[idx] = ins;
206
32.0k
                pos_bb[idx]  = bb;
207
32.0k
                if (idx > req_max)
208
32.0k
                    req_max = idx;
209
32.0k
                break;
210
32.0k
            }
211
3.73k
            case MVM_OP_param_op_i:
212
3.73k
            case MVM_OP_param_op_n:
213
3.73k
            case MVM_OP_param_op_s:
214
3.73k
            case MVM_OP_param_op_o: {
215
3.73k
                /* Optional Positional int/num/string/object */
216
3.73k
                MVMint16 idx = ins->operands[1].lit_i16;
217
3.73k
                if (idx < 0 || idx >= MAX_POS_ARGS)
218
0
                    goto cleanup;
219
3.73k
                if (pos_ins[idx]) /* Dupe; weird. */
220
0
                    goto cleanup;
221
3.73k
                pos_ins[idx] = ins;
222
3.73k
                pos_bb[idx]  = bb;
223
3.73k
                if (idx > opt_max)
224
3.73k
                    opt_max = idx;
225
3.73k
                if (opt_min == -1 || idx < opt_min)
226
3.73k
                    opt_min = idx;
227
3.73k
                break;
228
3.73k
            }
229
3.79k
            case MVM_OP_param_on_i:
230
3.79k
            case MVM_OP_param_on_n:
231
3.79k
            case MVM_OP_param_on_s:
232
3.79k
            case MVM_OP_param_on_o:
233
3.79k
            case MVM_OP_param_rn_i:
234
3.79k
            case MVM_OP_param_rn_n:
235
3.79k
            case MVM_OP_param_rn_s:
236
3.79k
            case MVM_OP_param_rn_o:
237
3.79k
                /* Named (optional or required). */
238
3.79k
                if (num_named == MAX_NAMED_ARGS)
239
0
                    goto cleanup;
240
3.79k
                named_ins[num_named] = ins;
241
3.79k
                named_bb[num_named]  = bb;
242
3.79k
                num_named++;
243
3.79k
                break;
244
714
            case MVM_OP_param_sp:
245
714
                break;
246
716
            case MVM_OP_param_sn:
247
716
                param_sn_ins = ins;
248
716
                break;
249
0
            case MVM_OP_usecapture:
250
0
            case MVM_OP_savecapture:
251
0
                /* Require full args processing context for now; bail. */
252
0
                goto cleanup;
253
16.4k
            case MVM_OP_paramnamesused:
254
16.4k
                if (paramnamesused_ins)
255
0
                    goto cleanup; /* Dupe; weird; bail out! */
256
16.4k
                paramnamesused_ins = ins;
257
16.4k
                paramnamesused_bb  = bb;
258
16.4k
                break;
259
1.99M
            default:
260
1.99M
                break;
261
2.07M
            }
262
2.07M
            ins = ins->next;
263
2.07M
        }
264
314k
        bb = bb->linear_next;
265
314k
    }
266
17.1k
267
17.1k
    /* If we didn't find a checkarity instruction, bail. */
268
17.1k
    if (!checkarity_ins)
269
0
        goto cleanup;
270
17.1k
271
17.1k
    /* If required and optional aren't contiguous, bail. */
272
17.1k
    if (opt_min >= 0 && req_max + 1 != opt_min)
273
0
        goto cleanup;
274
17.1k
275
17.1k
    /* If the number of passed args is in range... */
276
17.1k
    if (cs->num_pos >= req_max + 1 && (opt_max < 0 || cs->num_pos <= opt_max + 1)) {
277
17.1k
        /* Ensure we've got all the arg fetch instructions we need, and that
278
17.1k
         * types match or it's a box/unbox. */
279
17.1k
        MVMint32 i;
280
50.3k
        for (i = 0; i < cs->num_pos; i++) {
281
33.6k
            MVMCallsiteEntry arg_flag = cs->arg_flags[i];
282
33.6k
            if (!pos_ins[i])
283
488
                goto cleanup;
284
33.1k
            switch (pos_ins[i]->info->opcode) {
285
1.93k
            case MVM_OP_param_rp_i:
286
1.93k
            case MVM_OP_param_op_i:
287
1.93k
                if (arg_flag != MVM_CALLSITE_ARG_INT)
288
829
                    if (arg_flag != MVM_CALLSITE_ARG_OBJ ||
289
829
                            prim_spec(tc, args[i].o) != MVM_STORAGE_SPEC_BP_INT)
290
0
                        goto cleanup;
291
1.93k
                break;
292
0
            case MVM_OP_param_rp_n:
293
0
            case MVM_OP_param_op_n:
294
0
                if (arg_flag != MVM_CALLSITE_ARG_NUM)
295
0
                    if (arg_flag != MVM_CALLSITE_ARG_OBJ ||
296
0
                            prim_spec(tc, args[i].o) != MVM_STORAGE_SPEC_BP_NUM)
297
0
                        goto cleanup;
298
0
                break;
299
3.83k
            case MVM_OP_param_rp_s:
300
3.83k
            case MVM_OP_param_op_s:
301
3.83k
                if (arg_flag != MVM_CALLSITE_ARG_STR)
302
248
                    if (arg_flag != MVM_CALLSITE_ARG_OBJ ||
303
248
                            prim_spec(tc, args[i].o) != MVM_STORAGE_SPEC_BP_STR)
304
0
                        goto cleanup;
305
3.83k
                break;
306
27.4k
            case MVM_OP_param_rp_o:
307
27.4k
            case MVM_OP_param_op_o:
308
27.4k
                if (arg_flag != MVM_CALLSITE_ARG_OBJ && arg_flag != MVM_CALLSITE_ARG_INT &&
309
744
                    arg_flag != MVM_CALLSITE_ARG_NUM && arg_flag != MVM_CALLSITE_ARG_STR)
310
0
                    goto cleanup;
311
27.4k
                break;
312
0
            default:
313
0
                break;
314
33.1k
            }
315
33.1k
        }
316
17.1k
317
17.1k
        /* If we know there's no incoming nameds we can always turn param_sn into a
318
17.1k
         * simple hash creation. This will typically be further lowered in optimize. */
319
16.6k
        if (param_sn_ins && !got_named) {
320
172
            MVMObject *hash_type = g->sf->body.cu->body.hll_config->slurpy_hash_type;
321
172
            if (REPR(hash_type)->ID == MVM_REPR_ID_MVMHash) {
322
172
                MVMSpeshOperand target    = param_sn_ins->operands[0];
323
172
                param_sn_ins->info        = MVM_op_get_op(MVM_OP_sp_fastcreate);
324
172
                param_sn_ins->operands    = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand));
325
172
                param_sn_ins->operands[0] = target;
326
172
                param_sn_ins->operands[1].lit_i16 = sizeof(MVMHash);
327
172
                param_sn_ins->operands[2].lit_i16 = MVM_spesh_add_spesh_slot(tc, g,
328
172
                    (MVMCollectable *)STABLE(hash_type));
329
172
            }
330
0
            else {
331
0
                goto cleanup;
332
0
            }
333
172
        }
334
16.6k
335
16.6k
        /* We can optimize. Toss checkarity. */
336
16.6k
        MVM_spesh_manipulate_delete_ins(tc, g, checkarity_bb, checkarity_ins);
337
16.6k
338
16.6k
        /* Re-write the passed required positionals to spesh ops, and store
339
16.6k
         * any gurads. */
340
16.6k
        if (cs->arg_count)
341
16.6k
            g->arg_guards = MVM_malloc(2 * cs->arg_count * sizeof(MVMSpeshGuard));
342
49.1k
        for (i = 0; i < cs->num_pos; i++) {
343
32.4k
            MVMCallsiteEntry arg_flag = cs->arg_flags[i];
344
32.4k
            switch (pos_ins[i]->info->opcode) {
345
1.93k
            case MVM_OP_param_rp_i:
346
1.93k
            case MVM_OP_param_op_i:
347
1.93k
                if (arg_flag == MVM_CALLSITE_ARG_INT) {
348
1.10k
                    pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_i);
349
1.10k
                }
350
829
                else {
351
829
                    pos_unbox(tc, g, pos_bb[i], pos_ins[i], MVM_op_get_op(MVM_OP_unbox_i));
352
829
                    pos_added[i]++;
353
829
                    if (args[i].o)
354
829
                        add_guards_and_facts(tc, g, i, args[i].o, pos_ins[i]);
355
829
                }
356
1.93k
                break;
357
0
            case MVM_OP_param_rp_n:
358
0
            case MVM_OP_param_op_n:
359
0
                if (arg_flag == MVM_CALLSITE_ARG_NUM) {
360
0
                    pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_n);
361
0
                }
362
0
                else {
363
0
                    pos_unbox(tc, g, pos_bb[i], pos_ins[i], MVM_op_get_op(MVM_OP_unbox_n));
364
0
                    pos_added[i]++;
365
0
                    if (args[i].o)
366
0
                        add_guards_and_facts(tc, g, i, args[i].o, pos_ins[i]);
367
0
                }
368
0
                break;
369
3.54k
            case MVM_OP_param_rp_s:
370
3.54k
            case MVM_OP_param_op_s:
371
3.54k
                if (arg_flag == MVM_CALLSITE_ARG_STR) {
372
3.39k
                    pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_s);
373
3.39k
                }
374
148
                else {
375
148
                    pos_unbox(tc, g, pos_bb[i], pos_ins[i], MVM_op_get_op(MVM_OP_unbox_s));
376
148
                    pos_added[i]++;
377
148
                    if (args[i].o)
378
148
                        add_guards_and_facts(tc, g, i, args[i].o, pos_ins[i]);
379
148
                }
380
3.54k
                break;
381
26.9k
            case MVM_OP_param_rp_o:
382
26.9k
            case MVM_OP_param_op_o:
383
26.9k
                if (arg_flag == MVM_CALLSITE_ARG_OBJ) {
384
25.4k
                    pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_o);
385
25.4k
                    if (args[i].o)
386
25.4k
                        add_guards_and_facts(tc, g, i, args[i].o, pos_ins[i]);
387
25.4k
                }
388
1.45k
                else if (arg_flag == MVM_CALLSITE_ARG_INT) {
389
714
                    pos_box(tc, g, pos_bb[i], pos_ins[i],
390
714
                        MVM_op_get_op(MVM_OP_hllboxtype_i), MVM_op_get_op(MVM_OP_box_i),
391
714
                        MVM_op_get_op(MVM_OP_sp_getarg_i), MVM_reg_int64);
392
714
                    pos_added[i] += 2;
393
714
                }
394
744
                else if (arg_flag == MVM_CALLSITE_ARG_NUM) {
395
11
                    pos_box(tc, g, pos_bb[i], pos_ins[i],
396
11
                        MVM_op_get_op(MVM_OP_hllboxtype_n), MVM_op_get_op(MVM_OP_box_n),
397
11
                        MVM_op_get_op(MVM_OP_sp_getarg_n), MVM_reg_num64);
398
11
                    pos_added[i] += 2;
399
11
                }
400
733
                else if (arg_flag == MVM_CALLSITE_ARG_STR) {
401
733
                    pos_box(tc, g, pos_bb[i], pos_ins[i],
402
733
                        MVM_op_get_op(MVM_OP_hllboxtype_s), MVM_op_get_op(MVM_OP_box_s),
403
733
                        MVM_op_get_op(MVM_OP_sp_getarg_s), MVM_reg_str);
404
733
                    pos_added[i] += 2;
405
733
                }
406
26.9k
                break;
407
0
            default:
408
0
                break;
409
32.4k
            }
410
32.4k
            pos_ins[i]->operands[1].lit_i16 = (MVMint16)i;
411
32.4k
        }
412
16.6k
413
16.6k
        /* Now consider any optionals. */
414
16.6k
        if (opt_min >= 0) {
415
7.47k
            for (i = opt_min; i <= opt_max; i++) {
416
3.73k
                MVMuint8 passed = i < cs->num_pos;
417
3.73k
                if (passed) {
418
1.13k
                    /* If we know the argument has been passed, then add a goto
419
1.13k
                     * to the "passed" code. */
420
1.13k
                    MVMSpeshIns *after = pos_ins[i];
421
2.00k
                    while (pos_added[i]--)
422
868
                        after = after->next;
423
1.13k
                    MVM_spesh_manipulate_insert_goto(tc, g, pos_bb[i], after,
424
1.13k
                        pos_ins[i]->operands[2].ins_bb);
425
1.13k
426
1.13k
                    /* Inserting an unconditional goto makes the linear_next BB
427
1.13k
                    * unreachable, so we remove it from the succ list. */
428
1.13k
                    MVM_spesh_manipulate_remove_successor(tc, pos_bb[i],
429
1.13k
                        pos_bb[i]->linear_next);
430
2.59k
                } else {
431
2.59k
                    /* If we didn't pass this, just fall through the original
432
2.59k
                    * operation and we'll get the default value set. */
433
2.59k
                    MVM_spesh_manipulate_delete_ins(tc, g, pos_bb[i], pos_ins[i]);
434
2.59k
                    MVM_spesh_manipulate_remove_successor(tc, pos_bb[i],
435
2.59k
                        pos_ins[i]->operands[2].ins_bb);
436
2.59k
                }
437
3.73k
            }
438
3.73k
        }
439
16.6k
440
16.6k
        /* Now consider any nameds. */
441
20.2k
        for (i = 0; i < num_named; i++) {
442
3.56k
            /* See if the arg was passed. */
443
3.56k
            MVMString *arg_name      = MVM_spesh_get_string(tc, g, named_ins[i]->operands[1]);
444
3.56k
            MVMint32   passed_nameds = (cs->arg_count - cs->num_pos) / 2;
445
3.56k
            MVMint32   cs_flags      = cs->num_pos + passed_nameds;
446
3.56k
            MVMint32   cur_idx       = 0;
447
3.56k
            MVMint32   cur_named     = 0;
448
3.56k
            MVMuint8   found_flag    = 0;
449
3.56k
            MVMint32   found_idx     = -1;
450
3.56k
            MVMint32   j;
451
12.4k
            for (j = 0; j < cs_flags; j++) {
452
10.5k
                if (cs->arg_flags[j] & MVM_CALLSITE_ARG_NAMED) {
453
2.75k
                    if (MVM_string_equal(tc, arg_name, cs->arg_names[cur_named])) {
454
1.67k
                        /* Found it. */
455
1.67k
                        found_flag = cs->arg_flags[j];
456
1.67k
                        found_idx  = cur_idx;
457
1.67k
                        break;
458
1.67k
                    }
459
1.07k
                    cur_idx += 2;
460
1.07k
                    cur_named++;
461
1.07k
                }
462
7.76k
                else {
463
7.76k
                    cur_idx++;
464
7.76k
                }
465
10.5k
            }
466
3.56k
467
3.56k
            /* Now go by instruction. */
468
3.56k
            switch (named_ins[i]->info->opcode) {
469
0
            case MVM_OP_param_rn_i:
470
0
                if (found_idx == -1)
471
0
                    goto cleanup;
472
0
                if (found_flag & MVM_CALLSITE_ARG_INT) {
473
0
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_i);
474
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
475
0
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i], cur_named);
476
0
                }
477
0
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
478
0
                        && prim_spec(tc, args[found_idx].o) == MVM_STORAGE_SPEC_BP_INT) {
479
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
480
0
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_i));
481
0
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i]->next, cur_named);
482
0
                }
483
0
                named_used++;
484
0
                break;
485
0
            case MVM_OP_param_rn_n:
486
0
                if (found_idx == -1)
487
0
                    goto cleanup;
488
0
                if (found_flag & MVM_CALLSITE_ARG_NUM) {
489
0
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_n);
490
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
491
0
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i], cur_named);
492
0
                }
493
0
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
494
0
                        && prim_spec(tc, args[found_idx].o) == MVM_STORAGE_SPEC_BP_NUM) {
495
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
496
0
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_n));
497
0
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i]->next, cur_named);
498
0
                }
499
0
                named_used++;
500
0
                break;
501
181
            case MVM_OP_param_rn_s:
502
181
                if (found_idx == -1)
503
0
                    goto cleanup;
504
181
                if (found_flag & MVM_CALLSITE_ARG_STR) {
505
92
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_s);
506
92
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
507
92
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i], cur_named);
508
92
                }
509
89
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
510
89
                        && prim_spec(tc, args[found_idx].o) == MVM_STORAGE_SPEC_BP_STR) {
511
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
512
0
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_s));
513
0
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i]->next, cur_named);
514
0
                }
515
181
                named_used++;
516
181
                break;
517
231
            case MVM_OP_param_rn_o:
518
231
                if (found_idx == -1)
519
0
                    goto cleanup;
520
231
                if (found_flag & MVM_CALLSITE_ARG_OBJ) {
521
172
                    MVMuint16 arg_idx = found_idx + 1;
522
172
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_o);
523
172
                    named_ins[i]->operands[1].lit_i16 = arg_idx;
524
172
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i], cur_named);
525
172
                    if (args[arg_idx].o)
526
172
                        add_guards_and_facts(tc, g, arg_idx, args[arg_idx].o, named_ins[i]);
527
172
                }
528
59
                else if (found_flag & (MVM_CALLSITE_ARG_INT | MVM_CALLSITE_ARG_NUM | MVM_CALLSITE_ARG_STR)) {
529
59
                    MVMuint16 arg_idx = found_idx + 1;
530
59
                    named_ins[i]->operands[1].lit_i16 = arg_idx;
531
59
                    if (found_flag & MVM_CALLSITE_ARG_INT)
532
56
                        pos_box(tc, g, named_bb[i], named_ins[i],
533
56
                            MVM_op_get_op(MVM_OP_hllboxtype_i), MVM_op_get_op(MVM_OP_box_i),
534
56
                            MVM_op_get_op(MVM_OP_sp_getarg_i), MVM_reg_int64);
535
3
                    else if (found_flag & MVM_CALLSITE_ARG_NUM)
536
1
                        pos_box(tc, g, named_bb[i], named_ins[i],
537
1
                            MVM_op_get_op(MVM_OP_hllboxtype_n), MVM_op_get_op(MVM_OP_box_n),
538
1
                            MVM_op_get_op(MVM_OP_sp_getarg_n), MVM_reg_num64);
539
2
                    else if (found_flag & MVM_CALLSITE_ARG_STR)
540
2
                        pos_box(tc, g, named_bb[i], named_ins[i],
541
2
                            MVM_op_get_op(MVM_OP_hllboxtype_s), MVM_op_get_op(MVM_OP_box_s),
542
2
                            MVM_op_get_op(MVM_OP_sp_getarg_s), MVM_reg_str);
543
59
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i]->next->next, cur_named);
544
59
                }
545
231
                named_used++;
546
231
                break;
547
51
            case MVM_OP_param_on_i:
548
51
                if (found_idx == -1) {
549
22
                    MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]);
550
22
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i], named_ins[i]->operands[2].ins_bb);
551
22
                }
552
29
                else if (found_flag & MVM_CALLSITE_ARG_INT) {
553
29
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_i);
554
29
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
555
29
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i],
556
29
                        named_ins[i]->operands[2].ins_bb);
557
29
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i], cur_named);
558
29
                    named_used++;
559
29
                }
560
0
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
561
0
                        && prim_spec(tc, args[found_idx].o) == MVM_STORAGE_SPEC_BP_INT) {
562
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
563
0
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_i));
564
0
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i]->next,
565
0
                        named_ins[i]->operands[2].ins_bb);
566
0
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i]->next, cur_named);
567
0
                    named_used++;
568
0
                }
569
51
                break;
570
0
            case MVM_OP_param_on_n:
571
0
                if (found_idx == -1) {
572
0
                    MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]);
573
0
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i], named_ins[i]->operands[2].ins_bb);
574
0
                }
575
0
                else if (found_flag & MVM_CALLSITE_ARG_NUM) {
576
0
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_n);
577
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
578
0
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i],
579
0
                        named_ins[i]->operands[2].ins_bb);
580
0
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i], cur_named);
581
0
                    named_used++;
582
0
                }
583
0
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
584
0
                        && prim_spec(tc, args[found_idx].o) == MVM_STORAGE_SPEC_BP_NUM) {
585
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
586
0
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_n));
587
0
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i]->next,
588
0
                        named_ins[i]->operands[2].ins_bb);
589
0
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i]->next, cur_named);
590
0
                    named_used++;
591
0
                }
592
0
                break;
593
266
            case MVM_OP_param_on_s:
594
266
                if (found_idx == -1) {
595
115
                    MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]);
596
115
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i], named_ins[i]->operands[2].ins_bb);
597
115
                }
598
151
                else if (found_flag & MVM_CALLSITE_ARG_STR) {
599
151
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_s);
600
151
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
601
151
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i],
602
151
                        named_ins[i]->operands[2].ins_bb);
603
151
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i], cur_named);
604
151
                    named_used++;
605
151
                }
606
0
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
607
0
                        && prim_spec(tc, args[found_idx].o) == MVM_STORAGE_SPEC_BP_STR) {
608
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
609
0
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_s));
610
0
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i]->next,
611
0
                        named_ins[i]->operands[2].ins_bb);
612
0
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i]->next, cur_named);
613
0
                    named_used++;
614
0
                }
615
266
                break;
616
2.83k
            case MVM_OP_param_on_o:
617
2.83k
                if (found_idx == -1) {
618
1.75k
                    MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]);
619
1.75k
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i], named_ins[i]->operands[2].ins_bb);
620
1.75k
                }
621
1.08k
                else if (found_flag & MVM_CALLSITE_ARG_OBJ) {
622
580
                    MVMuint16 arg_idx = found_idx + 1;
623
580
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_o);
624
580
                    named_ins[i]->operands[1].lit_i16 = arg_idx;
625
580
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i],
626
580
                        named_ins[i]->operands[2].ins_bb);
627
580
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i], cur_named);
628
580
                    if (args[arg_idx].o)
629
580
                        add_guards_and_facts(tc, g, arg_idx, args[arg_idx].o, named_ins[i]);
630
580
                    named_used++;
631
580
                }
632
504
                else if (found_flag & (MVM_CALLSITE_ARG_INT | MVM_CALLSITE_ARG_NUM | MVM_CALLSITE_ARG_STR)) {
633
504
                    MVMuint16 arg_idx = found_idx + 1;
634
504
                    named_ins[i]->operands[1].lit_i16 = arg_idx;
635
504
                    if (found_flag & MVM_CALLSITE_ARG_INT)
636
386
                        pos_box(tc, g, named_bb[i], named_ins[i],
637
386
                            MVM_op_get_op(MVM_OP_hllboxtype_i), MVM_op_get_op(MVM_OP_box_i),
638
386
                            MVM_op_get_op(MVM_OP_sp_getarg_i), MVM_reg_int64);
639
118
                    else if (found_flag & MVM_CALLSITE_ARG_NUM)
640
66
                        pos_box(tc, g, named_bb[i], named_ins[i],
641
66
                            MVM_op_get_op(MVM_OP_hllboxtype_n), MVM_op_get_op(MVM_OP_box_n),
642
66
                            MVM_op_get_op(MVM_OP_sp_getarg_n), MVM_reg_num64);
643
52
                    else if (found_flag & MVM_CALLSITE_ARG_STR)
644
52
                        pos_box(tc, g, named_bb[i], named_ins[i],
645
52
                            MVM_op_get_op(MVM_OP_hllboxtype_s), MVM_op_get_op(MVM_OP_box_s),
646
52
                            MVM_op_get_op(MVM_OP_sp_getarg_s), MVM_reg_str);
647
504
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i]->next->next,
648
504
                        named_ins[i]->operands[2].ins_bb);
649
504
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i]->next->next, cur_named);
650
504
                    named_used++;
651
504
                }
652
2.83k
                break;
653
0
            default:
654
0
                break;
655
3.56k
            }
656
3.56k
        }
657
16.6k
658
16.6k
        /* If we had no nameds or we used them all, can toss namesused, and we
659
16.6k
         * don't need to mark used after all. */
660
16.6k
        if (paramnamesused_ins && num_named == named_used) {
661
14.6k
            MVM_spesh_manipulate_delete_ins(tc, g, paramnamesused_bb, paramnamesused_ins);
662
15.5k
            for (i = 0; i < num_named; i++)
663
833
                if (used_ins[i])
664
744
                    MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], used_ins[i]);
665
14.6k
        }
666
16.6k
    }
667
17.1k
668
17.1k
  cleanup:
669
17.1k
    MVM_free(pos_ins);
670
17.1k
    MVM_free(pos_bb);
671
17.1k
    MVM_free(pos_added);
672
17.1k
    MVM_free(named_ins);
673
17.1k
    MVM_free(named_bb);
674
17.1k
    MVM_free(used_ins);
675
17.1k
}