/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 | 53.9k | #define MAX_POS_ARGS 8 |
5 | | |
6 | | /* Maximum number of named args we'll consider for optimization purposes. */ |
7 | 23.5k | #define MAX_NAMED_ARGS 8 |
8 | | |
9 | | /* Adds facts for an object arg. */ |
10 | | static void add_facts(MVMThreadContext *tc, MVMSpeshGraph *g, MVMint32 slot, |
11 | 15.4k | MVMSpeshStatsType type_tuple_entry, MVMSpeshIns *arg_ins) { |
12 | 15.4k | /* Add appropriate facts from the arg type tuple. */ |
13 | 15.4k | MVMint16 orig = arg_ins->operands[0].reg.orig; |
14 | 15.4k | MVMint16 i = arg_ins->operands[0].reg.i; |
15 | 15.4k | MVMObject *type = type_tuple_entry.type; |
16 | 15.4k | g->facts[orig][i].type = type; |
17 | 15.4k | g->facts[orig][i].flags |= MVM_SPESH_FACT_KNOWN_TYPE; |
18 | 15.4k | if (type_tuple_entry.type_concrete) { |
19 | 13.7k | g->facts[orig][i].flags |= MVM_SPESH_FACT_CONCRETE; |
20 | 13.7k | if (!type->st->container_spec) |
21 | 13.7k | g->facts[orig][i].flags |= MVM_SPESH_FACT_DECONTED; |
22 | 13.7k | } |
23 | 1.71k | else { |
24 | 1.71k | g->facts[orig][i].flags |= MVM_SPESH_FACT_TYPEOBJ | MVM_SPESH_FACT_DECONTED; |
25 | 1.71k | } |
26 | 15.4k | |
27 | 15.4k | /* Add any decontainerized type info. */ |
28 | 15.4k | if (type_tuple_entry.decont_type) { |
29 | 0 | g->facts[orig][i].decont_type = type_tuple_entry.decont_type; |
30 | 0 | g->facts[orig][i].flags |= MVM_SPESH_FACT_KNOWN_DECONT_TYPE; |
31 | 0 | if (type_tuple_entry.decont_type_concrete) |
32 | 0 | g->facts[orig][i].flags |= MVM_SPESH_FACT_DECONT_CONCRETE; |
33 | 0 | else |
34 | 0 | g->facts[orig][i].flags |= MVM_SPESH_FACT_DECONT_TYPEOBJ; |
35 | 0 | if (type_tuple_entry.rw_cont) |
36 | 0 | g->facts[orig][i].flags |= MVM_SPESH_FACT_RW_CONT; |
37 | 0 | } |
38 | 15.4k | } |
39 | | |
40 | | /* Handles a pos arg that needs unboxing. */ |
41 | | static void pos_unbox(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, |
42 | 0 | MVMSpeshIns *ins, const MVMOpInfo *unbox_op) { |
43 | 0 | MVMSpeshOperand temp = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_obj); |
44 | 0 | MVMSpeshIns *unbox = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns)); |
45 | 0 | unbox->info = unbox_op; |
46 | 0 | unbox->operands = MVM_spesh_alloc(tc, g, 2 * sizeof(MVMSpeshOperand)); |
47 | 0 | unbox->operands[0] = ins->operands[0]; |
48 | 0 | unbox->operands[1] = temp; |
49 | 0 | ins->info = MVM_op_get_op(MVM_OP_sp_getarg_o); |
50 | 0 | ins->operands[0] = temp; |
51 | 0 | MVM_spesh_manipulate_insert_ins(tc, bb, ins, unbox); |
52 | 0 | MVM_spesh_manipulate_release_temp_reg(tc, g, temp); |
53 | 0 | } |
54 | | |
55 | | /* Handles a pos arg that needs boxing. */ |
56 | | static void pos_box(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, |
57 | | MVMSpeshIns *ins, const MVMOpInfo *hlltype_op, const MVMOpInfo *box_op, |
58 | 906 | const MVMOpInfo *arg_op, MVMuint8 kind) { |
59 | 906 | MVMSpeshOperand temp_bt, temp_arg; |
60 | 906 | MVMSpeshIns *hlltype, *box; |
61 | 906 | |
62 | 906 | /* Add HLL type op. */ |
63 | 906 | temp_bt = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_obj); |
64 | 906 | hlltype = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns)); |
65 | 906 | hlltype->info = hlltype_op; |
66 | 906 | hlltype->operands = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshOperand)); |
67 | 906 | hlltype->operands[0] = temp_bt; |
68 | 906 | MVM_spesh_manipulate_insert_ins(tc, bb, ins, hlltype); |
69 | 906 | |
70 | 906 | /* Add box op. */ |
71 | 906 | temp_arg = MVM_spesh_manipulate_get_temp_reg(tc, g, kind); |
72 | 906 | box = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns)); |
73 | 906 | box->info = box_op; |
74 | 906 | box->operands = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand)); |
75 | 906 | box->operands[0] = ins->operands[0]; |
76 | 906 | box->operands[1] = temp_arg; |
77 | 906 | box->operands[2] = temp_bt; |
78 | 906 | MVM_spesh_manipulate_insert_ins(tc, bb, hlltype, box); |
79 | 906 | |
80 | 906 | /* Update instruction to receive unboxed arg. */ |
81 | 906 | ins->info = arg_op; |
82 | 906 | ins->operands[0] = temp_arg; |
83 | 906 | |
84 | 906 | /* Release temporary registers. */ |
85 | 906 | MVM_spesh_manipulate_release_temp_reg(tc, g, temp_bt); |
86 | 906 | MVM_spesh_manipulate_release_temp_reg(tc, g, temp_arg); |
87 | 906 | } |
88 | | |
89 | | /* Gets the primitive boxed by a type. */ |
90 | 181 | static MVMuint16 prim_spec(MVMThreadContext *tc, MVMSpeshStatsType *type_tuple, MVMint32 i) { |
91 | 0 | MVMObject *type = type_tuple ? type_tuple[i].type : NULL; |
92 | 181 | return type |
93 | 0 | ? REPR(type)->get_storage_spec(tc, STABLE(type))->boxed_primitive |
94 | 181 | : 0; |
95 | 181 | } |
96 | | |
97 | | /* Puts a single named argument into a slurpy hash, boxing if needed. */ |
98 | | static void slurp_named_arg(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, |
99 | 72 | MVMSpeshIns *hash_ins, MVMint32 named_idx) { |
100 | 72 | MVMSpeshIns *key_ins; |
101 | 72 | |
102 | 72 | /* Look up arg flags and name, and compute index. */ |
103 | 72 | MVMCallsiteFlags flags = g->cs->arg_flags[g->cs->num_pos + named_idx]; |
104 | 72 | MVMString *name = g->cs->arg_names[named_idx]; |
105 | 72 | MVMuint16 arg_idx = g->cs->num_pos + 2 * named_idx + 1; |
106 | 72 | |
107 | 72 | /* Allocate temporary registers for the key and value. */ |
108 | 72 | MVMSpeshOperand key_temp = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_str); |
109 | 72 | MVMSpeshOperand value_temp = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_obj); |
110 | 72 | |
111 | 72 | /* Insert bind key instruction after slurpy hash creation instruction (we |
112 | 72 | * do it first as below we prepend instructions to obtain the key and the |
113 | 72 | * value. */ |
114 | 72 | MVMSpeshIns *bindkey_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns)); |
115 | 72 | bindkey_ins->info = MVM_op_get_op(MVM_OP_bindkey_o); |
116 | 72 | bindkey_ins->operands = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand)); |
117 | 72 | bindkey_ins->operands[0] = hash_ins->operands[0]; |
118 | 72 | bindkey_ins->operands[1] = key_temp; |
119 | 72 | bindkey_ins->operands[2] = value_temp; |
120 | 72 | MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, bindkey_ins); |
121 | 72 | |
122 | 72 | /* Instruction to get value depends on argument type. */ |
123 | 72 | if ((flags & MVM_CALLSITE_ARG_MASK) == MVM_CALLSITE_ARG_OBJ) { |
124 | 50 | /* It's already a boxed object, so just fetch it into the value |
125 | 50 | * register. */ |
126 | 50 | MVMSpeshIns *fetch_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns)); |
127 | 50 | fetch_ins->info = MVM_op_get_op(MVM_OP_sp_getarg_o); |
128 | 50 | fetch_ins->operands = MVM_spesh_alloc(tc, g, 2 * sizeof(MVMSpeshOperand)); |
129 | 50 | fetch_ins->operands[0] = value_temp; |
130 | 50 | fetch_ins->operands[1].lit_ui16 = arg_idx; |
131 | 50 | MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, fetch_ins); |
132 | 50 | } |
133 | 22 | else { |
134 | 22 | MVMSpeshIns *box_ins, *hlltype_ins, *fetch_ins; |
135 | 22 | |
136 | 22 | /* We need to box it. Get a temporary register to box into. To |
137 | 22 | * only use one extra register, we will re-use the temp value |
138 | 22 | * one to load the box type into, and only add a temporary for. */ |
139 | 22 | MVMSpeshOperand unboxed_temp; |
140 | 22 | MVMuint16 box_op; |
141 | 22 | MVMuint16 hlltype_op; |
142 | 22 | MVMuint16 fetch_op; |
143 | 22 | switch (flags & MVM_CALLSITE_ARG_MASK) { |
144 | 20 | case MVM_CALLSITE_ARG_INT: |
145 | 20 | unboxed_temp = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_int64); |
146 | 20 | box_op = MVM_OP_box_i; |
147 | 20 | hlltype_op = MVM_OP_hllboxtype_i; |
148 | 20 | fetch_op = MVM_OP_sp_getarg_i; |
149 | 20 | break; |
150 | 0 | case MVM_CALLSITE_ARG_NUM: |
151 | 0 | unboxed_temp = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_num64); |
152 | 0 | box_op = MVM_OP_box_n; |
153 | 0 | hlltype_op = MVM_OP_hllboxtype_n; |
154 | 0 | fetch_op = MVM_OP_sp_getarg_n; |
155 | 0 | break; |
156 | 2 | case MVM_CALLSITE_ARG_STR: |
157 | 2 | unboxed_temp = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_str); |
158 | 2 | box_op = MVM_OP_box_s; |
159 | 2 | hlltype_op = MVM_OP_hllboxtype_s; |
160 | 2 | fetch_op = MVM_OP_sp_getarg_s; |
161 | 2 | break; |
162 | 0 | default: |
163 | 0 | MVM_panic(1, "Spesh args: unexpected named argument type %d", flags); |
164 | 22 | } |
165 | 22 | |
166 | 22 | /* Emit instruction to box value. */ |
167 | 22 | box_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns)); |
168 | 22 | box_ins->info = MVM_op_get_op(box_op); |
169 | 22 | box_ins->operands = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand)); |
170 | 22 | box_ins->operands[0] = value_temp; |
171 | 22 | box_ins->operands[1] = unboxed_temp; |
172 | 22 | box_ins->operands[2] = value_temp; |
173 | 22 | MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, box_ins); |
174 | 22 | |
175 | 22 | /* Prepend the instruction get box type. */ |
176 | 22 | hlltype_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns)); |
177 | 22 | hlltype_ins->info = MVM_op_get_op(hlltype_op); |
178 | 22 | hlltype_ins->operands = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshOperand)); |
179 | 22 | hlltype_ins->operands[0] = value_temp; |
180 | 22 | MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, hlltype_ins); |
181 | 22 | |
182 | 22 | /* Prepend fetch instruction. */ |
183 | 22 | fetch_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns)); |
184 | 22 | fetch_ins->info = MVM_op_get_op(fetch_op); |
185 | 22 | fetch_ins->operands = MVM_spesh_alloc(tc, g, 2 * sizeof(MVMSpeshOperand)); |
186 | 22 | fetch_ins->operands[0] = unboxed_temp; |
187 | 22 | fetch_ins->operands[1].lit_ui16 = arg_idx; |
188 | 22 | MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, fetch_ins); |
189 | 22 | |
190 | 22 | /* Can release the temporary register now. */ |
191 | 22 | MVM_spesh_manipulate_release_temp_reg(tc, g, unboxed_temp); |
192 | 22 | } |
193 | 72 | |
194 | 72 | /* Insert key fetching instruciton; we just store the string in a spesh |
195 | 72 | * slot. */ |
196 | 72 | key_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns)); |
197 | 72 | key_ins->info = MVM_op_get_op(MVM_OP_sp_getspeshslot); |
198 | 72 | key_ins->operands = MVM_spesh_alloc(tc, g, 2 * sizeof(MVMSpeshOperand)); |
199 | 72 | key_ins->operands[0] = key_temp; |
200 | 72 | key_ins->operands[1].lit_i16 = MVM_spesh_add_spesh_slot(tc, g, (MVMCollectable *)name); |
201 | 72 | MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, key_ins); |
202 | 72 | |
203 | 72 | /* Release temporary registers after. */ |
204 | 72 | MVM_spesh_manipulate_release_temp_reg(tc, g, key_temp); |
205 | 72 | MVM_spesh_manipulate_release_temp_reg(tc, g, value_temp); |
206 | 72 | } |
207 | | |
208 | | /* Takes information about the incoming callsite and arguments, and performs |
209 | | * various optimizations based on that information. */ |
210 | | void MVM_spesh_args(MVMThreadContext *tc, MVMSpeshGraph *g, MVMCallsite *cs, |
211 | 11.0k | MVMSpeshStatsType *type_tuple) { |
212 | 11.0k | /* We need to identify the various arg-related instructions in the graph, |
213 | 11.0k | * then manipulate them as a whole. */ |
214 | 11.0k | MVMSpeshIns *checkarity_ins = NULL; |
215 | 11.0k | MVMSpeshBB *checkarity_bb = NULL; |
216 | 11.0k | MVMSpeshIns *paramnamesused_ins = NULL; |
217 | 11.0k | MVMSpeshBB *paramnamesused_bb = NULL; |
218 | 11.0k | MVMSpeshIns *param_sn_ins = NULL; |
219 | 11.0k | MVMSpeshBB *param_sn_bb = NULL; |
220 | 11.0k | |
221 | 11.0k | MVMSpeshIns **pos_ins = MVM_calloc(MAX_POS_ARGS, sizeof(MVMSpeshIns *)); |
222 | 11.0k | MVMSpeshBB **pos_bb = MVM_calloc(MAX_POS_ARGS, sizeof(MVMSpeshBB *)); |
223 | 11.0k | MVMuint8 *pos_added = MVM_calloc(MAX_POS_ARGS, sizeof(MVMuint8)); |
224 | 11.0k | MVMSpeshIns **named_ins = MVM_calloc(MAX_NAMED_ARGS, sizeof(MVMSpeshIns *)); |
225 | 11.0k | MVMSpeshBB **named_bb = MVM_calloc(MAX_NAMED_ARGS, sizeof(MVMSpeshBB *)); |
226 | 11.0k | MVMint32 req_max = -1; |
227 | 11.0k | MVMint32 opt_min = -1; |
228 | 11.0k | MVMint32 opt_max = -1; |
229 | 11.0k | MVMint32 num_named = 0; |
230 | 11.0k | MVMint32 named_used = 0; |
231 | 11.0k | MVMint32 named_passed = (cs->arg_count - cs->num_pos) / 2; |
232 | 11.0k | MVMint32 cs_flags = cs->num_pos + named_passed; |
233 | 11.0k | MVMint32 cur_ins = 0; |
234 | 11.0k | |
235 | 11.0k | /* We use a bit field to track named argument use; on deopt we will put it |
236 | 11.0k | * into the deoptimized frame. */ |
237 | 11.0k | MVMuint64 named_used_bit_field = 0; |
238 | 11.0k | |
239 | 11.0k | MVMSpeshBB *bb = g->entry; |
240 | 11.0k | g->cs = cs; |
241 | 11.0k | |
242 | 11.0k | /* Walk through the graph, looking for arg related instructions. */ |
243 | 451k | while (bb) { |
244 | 440k | MVMSpeshIns *ins = bb->first_ins; |
245 | 2.55M | while (ins) { |
246 | 2.11M | switch (ins->info->opcode) { |
247 | 11.0k | case MVM_OP_checkarity: |
248 | 11.0k | if (checkarity_ins) |
249 | 0 | goto cleanup; /* Dupe; weird; bail out! */ |
250 | 11.0k | checkarity_ins = ins; |
251 | 11.0k | checkarity_bb = bb; |
252 | 11.0k | break; |
253 | 19.3k | case MVM_OP_param_rp_i: |
254 | 19.3k | case MVM_OP_param_rp_n: |
255 | 19.3k | case MVM_OP_param_rp_s: |
256 | 19.3k | case MVM_OP_param_rp_o: { |
257 | 19.3k | /* Required positional. */ |
258 | 19.3k | MVMint16 idx = ins->operands[1].lit_i16; |
259 | 19.3k | if (idx < 0 || idx >= MAX_POS_ARGS) |
260 | 0 | goto cleanup; |
261 | 19.3k | if (pos_ins[idx]) /* Dupe; weird. */ |
262 | 0 | goto cleanup; |
263 | 19.3k | pos_ins[idx] = ins; |
264 | 19.3k | pos_bb[idx] = bb; |
265 | 19.3k | if (idx > req_max) |
266 | 19.3k | req_max = idx; |
267 | 19.3k | break; |
268 | 19.3k | } |
269 | 1.65k | case MVM_OP_param_op_i: |
270 | 1.65k | case MVM_OP_param_op_n: |
271 | 1.65k | case MVM_OP_param_op_s: |
272 | 1.65k | case MVM_OP_param_op_o: { |
273 | 1.65k | /* Optional Positional int/num/string/object */ |
274 | 1.65k | MVMint16 idx = ins->operands[1].lit_i16; |
275 | 1.65k | if (idx < 0 || idx >= MAX_POS_ARGS) |
276 | 0 | goto cleanup; |
277 | 1.65k | if (pos_ins[idx]) /* Dupe; weird. */ |
278 | 0 | goto cleanup; |
279 | 1.65k | pos_ins[idx] = ins; |
280 | 1.65k | pos_bb[idx] = bb; |
281 | 1.65k | if (idx > opt_max) |
282 | 1.65k | opt_max = idx; |
283 | 1.65k | if (opt_min == -1 || idx < opt_min) |
284 | 1.65k | opt_min = idx; |
285 | 1.65k | break; |
286 | 1.65k | } |
287 | 1.57k | case MVM_OP_param_on_i: |
288 | 1.57k | case MVM_OP_param_on_n: |
289 | 1.57k | case MVM_OP_param_on_s: |
290 | 1.57k | case MVM_OP_param_on_o: |
291 | 1.57k | case MVM_OP_param_rn_i: |
292 | 1.57k | case MVM_OP_param_rn_n: |
293 | 1.57k | case MVM_OP_param_rn_s: |
294 | 1.57k | case MVM_OP_param_rn_o: |
295 | 1.57k | /* Named (optional or required). */ |
296 | 1.57k | if (num_named == MAX_NAMED_ARGS) |
297 | 0 | goto cleanup; |
298 | 1.57k | named_ins[num_named] = ins; |
299 | 1.57k | named_bb[num_named] = bb; |
300 | 1.57k | num_named++; |
301 | 1.57k | break; |
302 | 158 | case MVM_OP_param_sp: |
303 | 158 | break; |
304 | 266 | case MVM_OP_param_sn: |
305 | 266 | param_sn_ins = ins; |
306 | 266 | param_sn_bb = bb; |
307 | 266 | break; |
308 | 0 | case MVM_OP_usecapture: |
309 | 0 | case MVM_OP_savecapture: |
310 | 0 | /* Require full args processing context for now; bail. */ |
311 | 0 | goto cleanup; |
312 | 10.7k | case MVM_OP_paramnamesused: |
313 | 10.7k | if (paramnamesused_ins) |
314 | 0 | goto cleanup; /* Dupe; weird; bail out! */ |
315 | 10.7k | paramnamesused_ins = ins; |
316 | 10.7k | paramnamesused_bb = bb; |
317 | 10.7k | break; |
318 | 0 | case MVM_OP_param_rn2_i: |
319 | 0 | case MVM_OP_param_rn2_n: |
320 | 0 | case MVM_OP_param_rn2_s: |
321 | 0 | case MVM_OP_param_rn2_o: |
322 | 0 | case MVM_OP_param_on2_i: |
323 | 0 | case MVM_OP_param_on2_n: |
324 | 0 | case MVM_OP_param_on2_s: |
325 | 0 | case MVM_OP_param_on2_o: |
326 | 0 | case MVM_OP_param_rp_u: |
327 | 0 | case MVM_OP_param_op_u: |
328 | 0 | case MVM_OP_param_rn_u: |
329 | 0 | case MVM_OP_param_on_u: |
330 | 0 | case MVM_OP_param_rn2_u: |
331 | 0 | case MVM_OP_param_on2_u: |
332 | 0 | /* Don't understand how to specialize these yet. */ |
333 | 0 | goto cleanup; |
334 | 2.06M | default: |
335 | 2.06M | break; |
336 | 2.11M | } |
337 | 2.11M | cur_ins++; |
338 | 2.11M | ins = ins->next; |
339 | 2.11M | } |
340 | 440k | bb = bb->linear_next; |
341 | 440k | } |
342 | 11.0k | |
343 | 11.0k | /* If we didn't find a checkarity instruction, bail. */ |
344 | 11.0k | if (!checkarity_ins) |
345 | 0 | goto cleanup; |
346 | 11.0k | |
347 | 11.0k | /* If required and optional aren't contiguous, bail. */ |
348 | 11.0k | if (opt_min >= 0 && req_max + 1 != opt_min) |
349 | 0 | goto cleanup; |
350 | 11.0k | |
351 | 11.0k | /* If the number of passed args is in range... */ |
352 | 11.0k | if (cs->num_pos >= req_max + 1 && (opt_max < 0 || cs->num_pos <= opt_max + 1)) { |
353 | 11.0k | /* Ensure we've got all the arg fetch instructions we need, and that |
354 | 11.0k | * types match or it's a box/unbox. */ |
355 | 11.0k | MVMint32 i; |
356 | 30.8k | for (i = 0; i < cs->num_pos; i++) { |
357 | 20.1k | MVMCallsiteEntry arg_flag = cs->arg_flags[i]; |
358 | 20.1k | if (!pos_ins[i]) |
359 | 102 | goto cleanup; |
360 | 20.0k | switch (pos_ins[i]->info->opcode) { |
361 | 1.19k | case MVM_OP_param_rp_i: |
362 | 1.19k | case MVM_OP_param_op_i: |
363 | 1.19k | if (arg_flag != MVM_CALLSITE_ARG_INT) |
364 | 146 | if (arg_flag != MVM_CALLSITE_ARG_OBJ || |
365 | 146 | prim_spec(tc, type_tuple, i) != MVM_STORAGE_SPEC_BP_INT) |
366 | 146 | goto cleanup; |
367 | 1.05k | break; |
368 | 0 | case MVM_OP_param_rp_n: |
369 | 0 | case MVM_OP_param_op_n: |
370 | 0 | if (arg_flag != MVM_CALLSITE_ARG_NUM) |
371 | 0 | if (arg_flag != MVM_CALLSITE_ARG_OBJ || |
372 | 0 | prim_spec(tc, type_tuple, i) != MVM_STORAGE_SPEC_BP_NUM) |
373 | 0 | goto cleanup; |
374 | 0 | break; |
375 | 1.73k | case MVM_OP_param_rp_s: |
376 | 1.73k | case MVM_OP_param_op_s: |
377 | 1.73k | if (arg_flag != MVM_CALLSITE_ARG_STR) |
378 | 25 | if (arg_flag != MVM_CALLSITE_ARG_OBJ || |
379 | 25 | prim_spec(tc, type_tuple, i) != MVM_STORAGE_SPEC_BP_STR) |
380 | 25 | goto cleanup; |
381 | 1.71k | break; |
382 | 17.1k | case MVM_OP_param_rp_o: |
383 | 17.1k | case MVM_OP_param_op_o: |
384 | 17.1k | if (arg_flag != MVM_CALLSITE_ARG_OBJ && arg_flag != MVM_CALLSITE_ARG_INT && |
385 | 543 | arg_flag != MVM_CALLSITE_ARG_NUM && arg_flag != MVM_CALLSITE_ARG_STR) |
386 | 0 | goto cleanup; |
387 | 17.1k | break; |
388 | 0 | default: |
389 | 0 | break; |
390 | 20.0k | } |
391 | 20.0k | } |
392 | 11.0k | |
393 | 11.0k | /* We can optimize. Toss checkarity. */ |
394 | 10.7k | MVM_spesh_manipulate_delete_ins(tc, g, checkarity_bb, checkarity_ins); |
395 | 10.7k | |
396 | 10.7k | /* Re-write the passed required positionals to spesh ops, and add any |
397 | 10.7k | * facts. */ |
398 | 30.2k | for (i = 0; i < cs->num_pos; i++) { |
399 | 19.5k | MVMCallsiteEntry arg_flag = cs->arg_flags[i]; |
400 | 19.5k | switch (pos_ins[i]->info->opcode) { |
401 | 1.05k | case MVM_OP_param_rp_i: |
402 | 1.05k | case MVM_OP_param_op_i: |
403 | 1.05k | if (arg_flag == MVM_CALLSITE_ARG_INT) { |
404 | 1.05k | pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_i); |
405 | 1.05k | } |
406 | 0 | else { |
407 | 0 | pos_unbox(tc, g, pos_bb[i], pos_ins[i], MVM_op_get_op(MVM_OP_unbox_i)); |
408 | 0 | pos_added[i]++; |
409 | 0 | if (type_tuple && type_tuple[i].type) |
410 | 0 | add_facts(tc, g, i, type_tuple[i], pos_ins[i]); |
411 | 0 | } |
412 | 1.05k | break; |
413 | 0 | case MVM_OP_param_rp_n: |
414 | 0 | case MVM_OP_param_op_n: |
415 | 0 | if (arg_flag == MVM_CALLSITE_ARG_NUM) { |
416 | 0 | pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_n); |
417 | 0 | } |
418 | 0 | else { |
419 | 0 | pos_unbox(tc, g, pos_bb[i], pos_ins[i], MVM_op_get_op(MVM_OP_unbox_n)); |
420 | 0 | pos_added[i]++; |
421 | 0 | if (type_tuple && type_tuple[i].type) |
422 | 0 | add_facts(tc, g, i, type_tuple[i], pos_ins[i]); |
423 | 0 | } |
424 | 0 | break; |
425 | 1.67k | case MVM_OP_param_rp_s: |
426 | 1.67k | case MVM_OP_param_op_s: |
427 | 1.67k | if (arg_flag == MVM_CALLSITE_ARG_STR) { |
428 | 1.67k | pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_s); |
429 | 1.67k | } |
430 | 0 | else { |
431 | 0 | pos_unbox(tc, g, pos_bb[i], pos_ins[i], MVM_op_get_op(MVM_OP_unbox_s)); |
432 | 0 | pos_added[i]++; |
433 | 0 | if (type_tuple && type_tuple[i].type) |
434 | 0 | add_facts(tc, g, i, type_tuple[i], pos_ins[i]); |
435 | 0 | } |
436 | 1.67k | break; |
437 | 16.7k | case MVM_OP_param_rp_o: |
438 | 16.7k | case MVM_OP_param_op_o: |
439 | 16.7k | if (arg_flag == MVM_CALLSITE_ARG_OBJ) { |
440 | 16.0k | pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_o); |
441 | 16.0k | if (type_tuple && type_tuple[i].type) { |
442 | 15.1k | add_facts(tc, g, i, type_tuple[i], pos_ins[i]); |
443 | 15.1k | if (i == 0) |
444 | 10.1k | g->specialized_on_invocant = 1; |
445 | 15.1k | } |
446 | 16.0k | } |
447 | 731 | else if (arg_flag == MVM_CALLSITE_ARG_INT) { |
448 | 188 | pos_box(tc, g, pos_bb[i], pos_ins[i], |
449 | 188 | MVM_op_get_op(MVM_OP_hllboxtype_i), MVM_op_get_op(MVM_OP_box_i), |
450 | 188 | MVM_op_get_op(MVM_OP_sp_getarg_i), MVM_reg_int64); |
451 | 188 | pos_added[i] += 2; |
452 | 188 | } |
453 | 543 | else if (arg_flag == MVM_CALLSITE_ARG_NUM) { |
454 | 8 | pos_box(tc, g, pos_bb[i], pos_ins[i], |
455 | 8 | MVM_op_get_op(MVM_OP_hllboxtype_n), MVM_op_get_op(MVM_OP_box_n), |
456 | 8 | MVM_op_get_op(MVM_OP_sp_getarg_n), MVM_reg_num64); |
457 | 8 | pos_added[i] += 2; |
458 | 8 | } |
459 | 535 | else if (arg_flag == MVM_CALLSITE_ARG_STR) { |
460 | 535 | pos_box(tc, g, pos_bb[i], pos_ins[i], |
461 | 535 | MVM_op_get_op(MVM_OP_hllboxtype_s), MVM_op_get_op(MVM_OP_box_s), |
462 | 535 | MVM_op_get_op(MVM_OP_sp_getarg_s), MVM_reg_str); |
463 | 535 | pos_added[i] += 2; |
464 | 535 | } |
465 | 16.7k | break; |
466 | 0 | default: |
467 | 0 | break; |
468 | 19.5k | } |
469 | 19.5k | pos_ins[i]->operands[1].lit_i16 = (MVMint16)i; |
470 | 19.5k | } |
471 | 10.7k | |
472 | 10.7k | /* Now consider any optionals. */ |
473 | 10.7k | if (opt_min >= 0) { |
474 | 3.22k | for (i = opt_min; i <= opt_max; i++) { |
475 | 1.61k | MVMuint8 passed = i < cs->num_pos; |
476 | 1.61k | if (passed) { |
477 | 746 | /* If we know the argument has been passed, then add a goto |
478 | 746 | * to the "passed" code. */ |
479 | 746 | MVMSpeshIns *after = pos_ins[i]; |
480 | 926 | while (pos_added[i]--) |
481 | 180 | after = after->next; |
482 | 746 | MVM_spesh_manipulate_insert_goto(tc, g, pos_bb[i], after, |
483 | 746 | pos_ins[i]->operands[2].ins_bb); |
484 | 746 | |
485 | 746 | /* Inserting an unconditional goto makes the linear_next BB |
486 | 746 | * unreachable, so we remove it from the succ list. */ |
487 | 746 | MVM_spesh_manipulate_remove_successor(tc, pos_bb[i], |
488 | 746 | pos_bb[i]->linear_next); |
489 | 864 | } else { |
490 | 864 | /* If we didn't pass this, just fall through the original |
491 | 864 | * operation and we'll get the default value set. */ |
492 | 864 | MVM_spesh_manipulate_delete_ins(tc, g, pos_bb[i], pos_ins[i]); |
493 | 864 | MVM_spesh_manipulate_remove_successor(tc, pos_bb[i], |
494 | 864 | pos_ins[i]->operands[2].ins_bb); |
495 | 864 | } |
496 | 1.61k | } |
497 | 1.61k | } |
498 | 10.7k | |
499 | 10.7k | /* Now consider any nameds. */ |
500 | 12.2k | for (i = 0; i < num_named; i++) { |
501 | 1.52k | /* See if the arg was passed. */ |
502 | 1.52k | MVMString *arg_name = MVM_spesh_get_string(tc, g, named_ins[i]->operands[1]); |
503 | 1.52k | MVMint32 cur_idx = 0; |
504 | 1.52k | MVMint32 cur_named = 0; |
505 | 1.52k | MVMuint8 found_flag = 0; |
506 | 1.52k | MVMint32 found_idx = -1; |
507 | 1.52k | MVMint32 found_flag_idx = -1; |
508 | 1.52k | MVMint32 j; |
509 | 4.99k | for (j = 0; j < cs_flags; j++) { |
510 | 4.07k | if (cs->arg_flags[j] & MVM_CALLSITE_ARG_NAMED) { |
511 | 985 | if (MVM_string_equal(tc, arg_name, cs->arg_names[cur_named])) { |
512 | 602 | /* Found it. */ |
513 | 602 | found_flag_idx = j; |
514 | 602 | found_flag = cs->arg_flags[j]; |
515 | 602 | found_idx = cur_idx; |
516 | 602 | break; |
517 | 602 | } |
518 | 383 | cur_idx += 2; |
519 | 383 | cur_named++; |
520 | 383 | } |
521 | 3.09k | else { |
522 | 3.09k | cur_idx++; |
523 | 3.09k | } |
524 | 4.07k | } |
525 | 1.52k | |
526 | 1.52k | /* Now go by instruction. */ |
527 | 1.52k | switch (named_ins[i]->info->opcode) { |
528 | 0 | case MVM_OP_param_rn_i: |
529 | 0 | if (found_idx == -1) |
530 | 0 | goto cleanup; |
531 | 0 | if (found_flag & MVM_CALLSITE_ARG_INT) { |
532 | 0 | named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_i); |
533 | 0 | named_ins[i]->operands[1].lit_i16 = found_idx + 1; |
534 | 0 | named_used_bit_field |= (MVMuint64)1 << cur_named; |
535 | 0 | } |
536 | 0 | else if (found_flag & MVM_CALLSITE_ARG_OBJ |
537 | 0 | && prim_spec(tc, type_tuple, found_flag_idx) == MVM_STORAGE_SPEC_BP_INT) { |
538 | 0 | named_ins[i]->operands[1].lit_i16 = found_idx + 1; |
539 | 0 | pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_i)); |
540 | 0 | named_used_bit_field |= (MVMuint64)1 << cur_named; |
541 | 0 | } |
542 | 0 | named_used++; |
543 | 0 | break; |
544 | 0 | case MVM_OP_param_rn_n: |
545 | 0 | if (found_idx == -1) |
546 | 0 | goto cleanup; |
547 | 0 | if (found_flag & MVM_CALLSITE_ARG_NUM) { |
548 | 0 | named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_n); |
549 | 0 | named_ins[i]->operands[1].lit_i16 = found_idx + 1; |
550 | 0 | named_used_bit_field |= (MVMuint64)1 << cur_named; |
551 | 0 | } |
552 | 0 | else if (found_flag & MVM_CALLSITE_ARG_OBJ |
553 | 0 | && prim_spec(tc, type_tuple, found_flag_idx) == MVM_STORAGE_SPEC_BP_NUM) { |
554 | 0 | named_ins[i]->operands[1].lit_i16 = found_idx + 1; |
555 | 0 | pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_n)); |
556 | 0 | named_used_bit_field |= (MVMuint64)1 << cur_named; |
557 | 0 | } |
558 | 0 | named_used++; |
559 | 0 | break; |
560 | 44 | case MVM_OP_param_rn_s: |
561 | 44 | if (found_idx == -1) |
562 | 0 | goto cleanup; |
563 | 44 | if (found_flag & MVM_CALLSITE_ARG_STR) { |
564 | 34 | named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_s); |
565 | 34 | named_ins[i]->operands[1].lit_i16 = found_idx + 1; |
566 | 34 | named_used_bit_field |= (MVMuint64)1 << cur_named; |
567 | 34 | } |
568 | 10 | else if (found_flag & MVM_CALLSITE_ARG_OBJ |
569 | 10 | && prim_spec(tc, type_tuple, found_flag_idx) == MVM_STORAGE_SPEC_BP_STR) { |
570 | 0 | named_ins[i]->operands[1].lit_i16 = found_idx + 1; |
571 | 0 | pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_s)); |
572 | 0 | named_used_bit_field |= (MVMuint64)1 << cur_named; |
573 | 0 | } |
574 | 44 | named_used++; |
575 | 44 | break; |
576 | 62 | case MVM_OP_param_rn_o: |
577 | 62 | if (found_idx == -1) |
578 | 0 | goto cleanup; |
579 | 62 | if (found_flag & MVM_CALLSITE_ARG_OBJ) { |
580 | 57 | MVMuint16 arg_idx = found_idx + 1; |
581 | 57 | named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_o); |
582 | 57 | named_ins[i]->operands[1].lit_i16 = arg_idx; |
583 | 57 | named_used_bit_field |= (MVMuint64)1 << cur_named; |
584 | 57 | if (type_tuple && type_tuple[found_flag_idx].type) |
585 | 57 | add_facts(tc, g, arg_idx, type_tuple[found_flag_idx], named_ins[i]); |
586 | 57 | } |
587 | 5 | else if (found_flag & (MVM_CALLSITE_ARG_INT | MVM_CALLSITE_ARG_NUM | MVM_CALLSITE_ARG_STR)) { |
588 | 5 | MVMuint16 arg_idx = found_idx + 1; |
589 | 5 | named_ins[i]->operands[1].lit_i16 = arg_idx; |
590 | 5 | if (found_flag & MVM_CALLSITE_ARG_INT) |
591 | 5 | pos_box(tc, g, named_bb[i], named_ins[i], |
592 | 5 | MVM_op_get_op(MVM_OP_hllboxtype_i), MVM_op_get_op(MVM_OP_box_i), |
593 | 5 | MVM_op_get_op(MVM_OP_sp_getarg_i), MVM_reg_int64); |
594 | 0 | else if (found_flag & MVM_CALLSITE_ARG_NUM) |
595 | 0 | pos_box(tc, g, named_bb[i], named_ins[i], |
596 | 0 | MVM_op_get_op(MVM_OP_hllboxtype_n), MVM_op_get_op(MVM_OP_box_n), |
597 | 0 | MVM_op_get_op(MVM_OP_sp_getarg_n), MVM_reg_num64); |
598 | 0 | else if (found_flag & MVM_CALLSITE_ARG_STR) |
599 | 0 | pos_box(tc, g, named_bb[i], named_ins[i], |
600 | 0 | MVM_op_get_op(MVM_OP_hllboxtype_s), MVM_op_get_op(MVM_OP_box_s), |
601 | 0 | MVM_op_get_op(MVM_OP_sp_getarg_s), MVM_reg_str); |
602 | 5 | named_used_bit_field |= (MVMuint64)1 << cur_named; |
603 | 5 | } |
604 | 62 | named_used++; |
605 | 62 | break; |
606 | 220 | case MVM_OP_param_on_i: |
607 | 220 | if (found_idx == -1) { |
608 | 161 | MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]); |
609 | 161 | MVM_spesh_manipulate_remove_successor(tc, named_bb[i], named_ins[i]->operands[2].ins_bb); |
610 | 161 | } |
611 | 59 | else if (found_flag & MVM_CALLSITE_ARG_INT) { |
612 | 59 | named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_i); |
613 | 59 | named_ins[i]->operands[1].lit_i16 = found_idx + 1; |
614 | 59 | MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i], |
615 | 59 | named_ins[i]->operands[2].ins_bb); |
616 | 59 | MVM_spesh_manipulate_remove_successor(tc, named_bb[i], |
617 | 59 | named_bb[i]->linear_next); |
618 | 59 | named_used_bit_field |= (MVMuint64)1 << cur_named; |
619 | 59 | named_used++; |
620 | 59 | } |
621 | 0 | else if (found_flag & MVM_CALLSITE_ARG_OBJ |
622 | 0 | && prim_spec(tc, type_tuple, found_flag_idx) == MVM_STORAGE_SPEC_BP_INT) { |
623 | 0 | named_ins[i]->operands[1].lit_i16 = found_idx + 1; |
624 | 0 | pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_i)); |
625 | 0 | MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i]->next, |
626 | 0 | named_ins[i]->operands[2].ins_bb); |
627 | 0 | MVM_spesh_manipulate_remove_successor(tc, named_bb[i], |
628 | 0 | named_bb[i]->linear_next); |
629 | 0 | named_used_bit_field |= (MVMuint64)1 << cur_named; |
630 | 0 | named_used++; |
631 | 0 | } |
632 | 220 | break; |
633 | 0 | case MVM_OP_param_on_n: |
634 | 0 | if (found_idx == -1) { |
635 | 0 | MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]); |
636 | 0 | MVM_spesh_manipulate_remove_successor(tc, named_bb[i], named_ins[i]->operands[2].ins_bb); |
637 | 0 | } |
638 | 0 | else if (found_flag & MVM_CALLSITE_ARG_NUM) { |
639 | 0 | named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_n); |
640 | 0 | named_ins[i]->operands[1].lit_i16 = found_idx + 1; |
641 | 0 | MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i], |
642 | 0 | named_ins[i]->operands[2].ins_bb); |
643 | 0 | MVM_spesh_manipulate_remove_successor(tc, named_bb[i], |
644 | 0 | named_bb[i]->linear_next); |
645 | 0 | named_used_bit_field |= (MVMuint64)1 << cur_named; |
646 | 0 | named_used++; |
647 | 0 | } |
648 | 0 | else if (found_flag & MVM_CALLSITE_ARG_OBJ |
649 | 0 | && prim_spec(tc, type_tuple, found_flag_idx) == MVM_STORAGE_SPEC_BP_NUM) { |
650 | 0 | named_ins[i]->operands[1].lit_i16 = found_idx + 1; |
651 | 0 | pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_n)); |
652 | 0 | MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i]->next, |
653 | 0 | named_ins[i]->operands[2].ins_bb); |
654 | 0 | MVM_spesh_manipulate_remove_successor(tc, named_bb[i], |
655 | 0 | named_bb[i]->linear_next); |
656 | 0 | named_used_bit_field |= (MVMuint64)1 << cur_named; |
657 | 0 | named_used++; |
658 | 0 | } |
659 | 0 | break; |
660 | 86 | case MVM_OP_param_on_s: |
661 | 86 | if (found_idx == -1) { |
662 | 53 | MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]); |
663 | 53 | MVM_spesh_manipulate_remove_successor(tc, named_bb[i], named_ins[i]->operands[2].ins_bb); |
664 | 53 | } |
665 | 33 | else if (found_flag & MVM_CALLSITE_ARG_STR) { |
666 | 33 | named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_s); |
667 | 33 | named_ins[i]->operands[1].lit_i16 = found_idx + 1; |
668 | 33 | MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i], |
669 | 33 | named_ins[i]->operands[2].ins_bb); |
670 | 33 | MVM_spesh_manipulate_remove_successor(tc, named_bb[i], |
671 | 33 | named_bb[i]->linear_next); |
672 | 33 | named_used_bit_field |= (MVMuint64)1 << cur_named; |
673 | 33 | named_used++; |
674 | 33 | } |
675 | 0 | else if (found_flag & MVM_CALLSITE_ARG_OBJ |
676 | 0 | && prim_spec(tc, type_tuple, found_flag_idx) == MVM_STORAGE_SPEC_BP_STR) { |
677 | 0 | named_ins[i]->operands[1].lit_i16 = found_idx + 1; |
678 | 0 | pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_s)); |
679 | 0 | MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i]->next, |
680 | 0 | named_ins[i]->operands[2].ins_bb); |
681 | 0 | MVM_spesh_manipulate_remove_successor(tc, named_bb[i], |
682 | 0 | named_bb[i]->linear_next); |
683 | 0 | named_used_bit_field |= (MVMuint64)1 << cur_named; |
684 | 0 | named_used++; |
685 | 0 | } |
686 | 86 | break; |
687 | 1.10k | case MVM_OP_param_on_o: |
688 | 1.10k | if (found_idx == -1) { |
689 | 704 | MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]); |
690 | 704 | MVM_spesh_manipulate_remove_successor(tc, named_bb[i], named_ins[i]->operands[2].ins_bb); |
691 | 704 | } |
692 | 404 | else if (found_flag & MVM_CALLSITE_ARG_OBJ) { |
693 | 234 | MVMuint16 arg_idx = found_idx + 1; |
694 | 234 | named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_o); |
695 | 234 | named_ins[i]->operands[1].lit_i16 = arg_idx; |
696 | 234 | MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i], |
697 | 234 | named_ins[i]->operands[2].ins_bb); |
698 | 234 | MVM_spesh_manipulate_remove_successor(tc, named_bb[i], |
699 | 234 | named_bb[i]->linear_next); |
700 | 234 | named_used_bit_field |= (MVMuint64)1 << cur_named; |
701 | 234 | if (type_tuple && type_tuple[found_flag_idx].type) |
702 | 224 | add_facts(tc, g, arg_idx, type_tuple[found_flag_idx], named_ins[i]); |
703 | 234 | named_used++; |
704 | 234 | } |
705 | 170 | else if (found_flag & (MVM_CALLSITE_ARG_INT | MVM_CALLSITE_ARG_NUM | MVM_CALLSITE_ARG_STR)) { |
706 | 170 | MVMuint16 arg_idx = found_idx + 1; |
707 | 170 | named_ins[i]->operands[1].lit_i16 = arg_idx; |
708 | 170 | if (found_flag & MVM_CALLSITE_ARG_INT) |
709 | 126 | pos_box(tc, g, named_bb[i], named_ins[i], |
710 | 126 | MVM_op_get_op(MVM_OP_hllboxtype_i), MVM_op_get_op(MVM_OP_box_i), |
711 | 126 | MVM_op_get_op(MVM_OP_sp_getarg_i), MVM_reg_int64); |
712 | 44 | else if (found_flag & MVM_CALLSITE_ARG_NUM) |
713 | 25 | pos_box(tc, g, named_bb[i], named_ins[i], |
714 | 25 | MVM_op_get_op(MVM_OP_hllboxtype_n), MVM_op_get_op(MVM_OP_box_n), |
715 | 25 | MVM_op_get_op(MVM_OP_sp_getarg_n), MVM_reg_num64); |
716 | 19 | else if (found_flag & MVM_CALLSITE_ARG_STR) |
717 | 19 | pos_box(tc, g, named_bb[i], named_ins[i], |
718 | 19 | MVM_op_get_op(MVM_OP_hllboxtype_s), MVM_op_get_op(MVM_OP_box_s), |
719 | 19 | MVM_op_get_op(MVM_OP_sp_getarg_s), MVM_reg_str); |
720 | 170 | MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i]->next->next, |
721 | 170 | named_ins[i]->operands[2].ins_bb); |
722 | 170 | MVM_spesh_manipulate_remove_successor(tc, named_bb[i], |
723 | 170 | named_bb[i]->linear_next); |
724 | 170 | named_used_bit_field |= (MVMuint64)1 << cur_named; |
725 | 170 | named_used++; |
726 | 170 | } |
727 | 1.10k | break; |
728 | 0 | default: |
729 | 0 | break; |
730 | 1.52k | } |
731 | 1.52k | } |
732 | 10.7k | |
733 | 10.7k | /* If we have an instruction to check all nameds were used... */ |
734 | 10.7k | if (paramnamesused_ins) { |
735 | 10.4k | /* Delete it if they were. */ |
736 | 10.4k | if (named_passed == named_used) { |
737 | 10.4k | MVM_spesh_manipulate_delete_ins(tc, g, paramnamesused_bb, paramnamesused_ins); |
738 | 10.4k | } |
739 | 10.4k | |
740 | 10.4k | /* Otherwise, we have unexpected named arguments. Turn it into an |
741 | 10.4k | * error. */ |
742 | 0 | else { |
743 | 0 | MVMuint16 i; |
744 | 0 | for (i = 0; i < named_passed; i++) { |
745 | 0 | if (!(named_used_bit_field & ((MVMuint64)1 << i))) { |
746 | 0 | paramnamesused_ins->info = MVM_op_get_op(MVM_OP_sp_paramnamesused); |
747 | 0 | paramnamesused_ins->operands = MVM_spesh_alloc(tc, |
748 | 0 | g, sizeof(MVMSpeshOperand)); |
749 | 0 | paramnamesused_ins->operands[0].lit_i16 = MVM_spesh_add_spesh_slot(tc, |
750 | 0 | g, (MVMCollectable *)g->cs->arg_names[i]); |
751 | 0 | break; |
752 | 0 | } |
753 | 0 | } |
754 | 0 | } |
755 | 10.4k | } |
756 | 10.7k | |
757 | 10.7k | /* If we have a slurpy hash... */ |
758 | 10.7k | if (param_sn_ins) { |
759 | 232 | /* Construct it as a hash. */ |
760 | 232 | MVMObject *hash_type = g->sf->body.cu->body.hll_config->slurpy_hash_type; |
761 | 232 | if (REPR(hash_type)->ID == MVM_REPR_ID_MVMHash) { |
762 | 232 | MVMSpeshOperand target = param_sn_ins->operands[0]; |
763 | 232 | param_sn_ins->info = MVM_op_get_op(MVM_OP_sp_fastcreate); |
764 | 232 | param_sn_ins->operands = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand)); |
765 | 232 | param_sn_ins->operands[0] = target; |
766 | 232 | param_sn_ins->operands[1].lit_i16 = sizeof(MVMHash); |
767 | 232 | param_sn_ins->operands[2].lit_i16 = MVM_spesh_add_spesh_slot(tc, g, |
768 | 232 | (MVMCollectable *)STABLE(hash_type)); |
769 | 232 | } |
770 | 0 | else { |
771 | 0 | MVM_oops(tc, "Arg spesh: slurpy hash type was not a VMHash as expected"); |
772 | 0 | } |
773 | 232 | |
774 | 232 | /* Populate it with unused named args, if needed, boxing them on |
775 | 232 | * the way. */ |
776 | 232 | if (named_passed > named_used) |
777 | 176 | for (i = 0; i < named_passed; i++) |
778 | 108 | if (!(named_used_bit_field & ((MVMuint64)1 << i))) |
779 | 72 | slurp_named_arg(tc, g, param_sn_bb, param_sn_ins, i); |
780 | 232 | } |
781 | 10.7k | |
782 | 10.7k | /* Stash the named used bit field in the graph; will need to make it |
783 | 10.7k | * into the candidate and all the way to deopt. */ |
784 | 10.7k | g->deopt_named_used_bit_field = named_used_bit_field; |
785 | 10.7k | } |
786 | 11.0k | |
787 | 11.0k | cleanup: |
788 | 11.0k | MVM_free(pos_ins); |
789 | 11.0k | MVM_free(pos_bb); |
790 | 11.0k | MVM_free(pos_added); |
791 | 11.0k | MVM_free(named_ins); |
792 | 11.0k | MVM_free(named_bb); |
793 | 11.0k | } |