/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 | } |