* t/pmc/complex.t:
[parrot.git] / src / pic_jit.c
blobefe69e8154bbffc47077cc2366e94894de855fb7
1 /*
2 Copyright (C) 2006-2007, The Perl Foundation.
3 $Id$
5 =head1 NAME
7 src/pic_jit.c - Polymorphic Inline Cache to JIT compilation
9 =head1 DESCRIPTION
11 Some statically known and simple subroutines are replaced by
12 their JITted variants, if
14 - JIT is supported and can JIT subroutines
15 - arguments passing is simple
16 - the code is fully JITtable
17 - and more such checks
19 TODO:
21 - save jit_info in sub
22 - check for multiple calls to the same sub
23 either reuse code or create new
24 - handle void calls/returns
26 =head2 Functions
28 =over 4
30 =cut
34 #include "parrot/parrot.h"
35 #include "parrot/oplib/ops.h"
37 /* HEADERIZER HFILE: include/parrot/pic.h */
39 /* HEADERIZER BEGIN: static */
41 PARROT_WARN_UNUSED_RESULT
42 static int args_match_params(
43 ARGIN(const PMC *sig_args),
44 ARGIN(const PackFile_ByteCode *seg),
45 ARGIN(const opcode_t *start))
46 __attribute__nonnull__(1)
47 __attribute__nonnull__(2)
48 __attribute__nonnull__(3);
50 PARROT_WARN_UNUSED_RESULT
51 static int call_is_safe(ARGIN(const PMC *sub), ARGMOD(opcode_t **set_args))
52 __attribute__nonnull__(1)
53 __attribute__nonnull__(2)
54 FUNC_MODIFIES(*set_args);
56 PARROT_WARN_UNUSED_RESULT
57 static int jit_can_compile_sub(PARROT_INTERP, ARGIN(const PMC *sub))
58 __attribute__nonnull__(1)
59 __attribute__nonnull__(2);
61 PARROT_WARN_UNUSED_RESULT
62 static int ops_jittable(PARROT_INTERP,
63 ARGIN(const PMC *sub),
64 ARGIN(const PMC *sig_results),
65 ARGIN(const PackFile_ByteCode *seg),
66 ARGIN(opcode_t *pc),
67 ARGIN(const opcode_t *end),
68 ARGOUT(int *flags))
69 __attribute__nonnull__(1)
70 __attribute__nonnull__(2)
71 __attribute__nonnull__(3)
72 __attribute__nonnull__(4)
73 __attribute__nonnull__(5)
74 __attribute__nonnull__(6)
75 __attribute__nonnull__(7)
76 FUNC_MODIFIES(*flags);
78 PARROT_WARN_UNUSED_RESULT
79 PARROT_CAN_RETURN_NULL
80 static opcode_t * pic_test_func(PARROT_INTERP,
81 SHIM(INTVAL *sig_bits),
82 ARGOUT(void **args))
83 __attribute__nonnull__(1)
84 __attribute__nonnull__(3)
85 FUNC_MODIFIES(*args);
87 PARROT_WARN_UNUSED_RESULT
88 static int returns_match_results(
89 ARGIN(const PMC *sig_ret),
90 ARGIN(const PMC *sig_result))
91 __attribute__nonnull__(1)
92 __attribute__nonnull__(2);
94 /* HEADERIZER END: static */
97 #ifdef HAVE_COMPUTED_GOTO
98 # include "parrot/oplib/core_ops_cgp.h"
99 #endif
101 #ifdef HAS_JIT
102 # include "parrot/exec.h"
103 # include "jit.h"
105 # ifdef PIC_TEST
107 * just for testing the whole scheme ...
110 .sub main :main
111 .local int i
112 i = 32
113 i = __pic_test(i, 10)
114 print i
115 print "\n"
116 .end
117 .sub __pic_test
118 .param int i
119 .param int j
120 $I0 = i + j
121 .return ($I0)
122 .end
123 ... prints 42, if PIC_TEST is 1, because the C function is called
124 with -C and -S runcores.
129 =item C<static opcode_t * pic_test_func>
131 RT#48260: Not yet documented!!!
133 =cut
137 PARROT_WARN_UNUSED_RESULT
138 PARROT_CAN_RETURN_NULL
139 static opcode_t *
140 pic_test_func(PARROT_INTERP, SHIM(INTVAL *sig_bits), ARGOUT(void **args))
142 INTVAL * const result = (INTVAL*) args[0];
143 INTVAL const i = (INTVAL) args[1];
144 INTVAL const j = (INTVAL) args[2];
146 *result = i + j;
148 return args[3];
150 # endif
154 =item C<static int jit_can_compile_sub>
156 RT#48260: Not yet documented!!!
158 =cut
162 PARROT_WARN_UNUSED_RESULT
163 static int
164 jit_can_compile_sub(PARROT_INTERP, ARGIN(const PMC *sub))
166 const jit_arch_info * const info = Parrot_jit_init(interp);
167 const jit_arch_regs * const regs = info->regs + JIT_CODE_SUB_REGS_ONLY;
168 INTVAL * const n_regs_used = PMC_sub(sub)->n_regs_used;
170 /* if the sub is using more regs than the arch has
171 * we don't JIT it at all
173 if (n_regs_used[REGNO_INT] > regs->n_mapped_I)
174 return 0;
176 if (n_regs_used[REGNO_NUM] > regs->n_mapped_F)
177 return 0;
179 /* if the Sub is using S regs, we can't JIT it yet */
180 if (n_regs_used[REGNO_STR])
181 return 0;
183 /* if the Sub is using more than 1 P reg, we can't JIT it yet
184 * the P reg could be a (recursive) call to a sub
186 if (n_regs_used[REGNO_PMC] > 1)
187 return 0;
189 return 1;
195 =item C<static int args_match_params>
197 RT#48260: Not yet documented!!!
199 =cut
203 PARROT_WARN_UNUSED_RESULT
204 static int
205 args_match_params(ARGIN(const PMC *sig_args), ARGIN(const PackFile_ByteCode *seg),
206 ARGIN(const opcode_t *start))
208 const PMC *sig_params;
209 int n, type;
211 if (*start != PARROT_OP_get_params_pc)
212 return 0;
214 sig_params = seg->const_table->constants[start[1]]->u.key;
216 /* verify that we actually can pass arguments */
217 ASSERT_SIG_PMC(sig_params);
219 n = parrot_pic_check_sig(sig_args, sig_params, &type);
221 /* arg count mismatch */
222 if (n == -1)
223 return 0;
225 /* no args - this would be safe, if the JIT code could already
226 * deal with no args
227 * TODO
229 if (!n)
230 return 0;
232 switch (type & ~PARROT_ARG_CONSTANT) {
233 case PARROT_ARG_INTVAL:
234 case PARROT_ARG_FLOATVAL:
235 return 1;
236 default:
237 return 0;
243 =item C<static int returns_match_results>
245 RT#48260: Not yet documented!!!
247 =cut
251 PARROT_WARN_UNUSED_RESULT
252 static int
253 returns_match_results(ARGIN(const PMC *sig_ret), ARGIN(const PMC *sig_result))
255 int type;
256 const int n = parrot_pic_check_sig(sig_ret, sig_result, &type);
258 /* arg count mismatch */
259 if (n == -1)
260 return 0;
262 /* no args - this would be safe, if the JIT code could already
263 * deal with no args
264 * TODO
266 if (!n)
267 return 0;
269 switch (type & ~PARROT_ARG_CONSTANT) {
270 case PARROT_ARG_INTVAL:
271 case PARROT_ARG_FLOATVAL:
272 return 1;
273 default:
274 return 0;
280 =item C<static int call_is_safe>
282 RT#48260: Not yet documented!!!
284 =cut
288 PARROT_WARN_UNUSED_RESULT
289 static int
290 call_is_safe(ARGIN(const PMC *sub), ARGMOD(opcode_t **set_args))
292 PMC *called, *sig_results;
294 opcode_t * pc = *set_args;
295 PMC * const sig_args =
296 PMC_sub(sub)->seg->const_table->constants[pc[1]]->u.key;
298 /* ignore the signature for now */
299 pc += 2 + SIG_ELEMS(sig_args);
301 if (*pc != PARROT_OP_set_p_pc)
302 return 0;
304 called = PMC_sub(sub)->seg->const_table->constants[pc[2]]->u.key;
306 /* we can JIT just recursive subs for now */
307 if (called != sub)
308 return 0;
310 pc += 3;
312 if (*pc != PARROT_OP_get_results_pc)
313 return 0;
315 sig_results = PMC_sub(sub)->seg->const_table->constants[pc[1]]->u.key;
316 pc += 2 + SIG_ELEMS(sig_results);
318 if (*pc != PARROT_OP_invokecc_p)
319 return 0;
321 pc += 2;
322 *set_args = pc;
324 return 1;
329 =item C<static int ops_jittable>
331 RT#48260: Not yet documented!!!
333 =cut
337 PARROT_WARN_UNUSED_RESULT
338 static int
339 ops_jittable(PARROT_INTERP, ARGIN(const PMC *sub), ARGIN(const PMC *sig_results),
340 ARGIN(const PackFile_ByteCode *seg), ARGIN(opcode_t *pc),
341 ARGIN(const opcode_t *end), ARGOUT(int *flags))
343 while (pc < end) {
344 /* special opcodes which are handled, but not marked as JITtable */
345 int i;
347 const int op = *pc;
348 const op_info_t * const op_info = interp->op_info_table + op;
349 int n = op_info->op_count;
351 switch (op) {
352 case PARROT_OP_returncc:
353 case PARROT_OP_get_params_pc:
354 goto op_is_ok;
355 break;
356 case PARROT_OP_set_returns_pc:
358 const PMC * const sig_ret = seg->const_table->constants[pc[1]]->u.key;
359 if (!returns_match_results(sig_ret, sig_results))
360 return 0;
362 goto op_is_ok;
363 break;
364 case PARROT_OP_set_args_pc:
365 /* verify call, return address after the call */
366 if (!call_is_safe(sub, &pc))
367 return 0;
368 *flags |= JIT_CODE_RECURSIVE;
369 continue;
370 default:
371 /* non-jitted or JITted vtable */
372 if (op_jit[op].extcall != 0)
373 return 0;
374 break;
377 * there are some JITted opcodes like set_s_s, which we can't
378 * handle (yet)
380 for (i = 1; i < n; i++) {
381 const int type = op_info->types[i - 1];
382 switch (type) {
383 case PARROT_ARG_I:
384 case PARROT_ARG_N:
385 case PARROT_ARG_IC:
386 case PARROT_ARG_NC:
387 break;
388 default:
389 return 0;
392 op_is_ok:
393 ADD_OP_VAR_PART(interp, seg, pc, n);
394 pc += n;
396 return 1;
399 #endif /* HAS_JIT */
404 =item C<int parrot_pic_is_safe_to_jit>
406 RT#48260: Not yet documented!!!
408 =cut
412 PARROT_WARN_UNUSED_RESULT
414 parrot_pic_is_safe_to_jit(PARROT_INTERP, ARGIN(const PMC *sub), ARGIN(const PMC *sig_args),
415 ARGIN(const PMC *sig_results), ARGOUT(int *flags))
417 #ifdef HAS_JIT
418 opcode_t *base, *start, *end;
420 *flags = 0;
423 * 0) if runcore setting doesn't contain JIT
424 * forget it
426 if (!(interp->run_core & PARROT_JIT_CORE))
427 return 0;
429 /* 1) if the JIT system can't JIT_CODE_SUB_REGS_ONLY
430 * or the sub is using too many registers
432 if (!jit_can_compile_sub(interp, sub))
433 return 0;
436 * 2) check if get_params is matching set_args
439 base = PMC_sub(sub)->seg->base.data;
440 start = base + PMC_sub(sub)->start_offs;
441 end = base + PMC_sub(sub)->end_offs;
443 if (!args_match_params(sig_args, PMC_sub(sub)->seg, start))
444 return 0;
447 * 3) verify if all opcodes are JITtable, also check set_returns
448 * if it's reached
450 if (!ops_jittable(interp, sub, sig_results,
451 PMC_sub(sub)->seg, start, end, flags))
452 return 0;
454 return 1;
455 #else
456 UNUSED(interp);
457 UNUSED(sub);
458 UNUSED(sig_args);
459 UNUSED(sig_results);
460 UNUSED(flags);
462 return 0;
463 #endif
468 =item C<funcptr_t parrot_pic_JIT_sub>
470 RT#48260: Not yet documented!!!
472 =cut
476 funcptr_t
477 parrot_pic_JIT_sub(PARROT_INTERP, ARGIN(const PMC *sub), int flags)
479 #ifdef HAS_JIT
480 # ifdef PIC_TEST
481 UNUSED(interp);
482 UNUSED(sub);
483 return (funcptr_t) pic_test_func;
484 # else
486 * create JIT code - just a test
488 opcode_t * const base = PMC_sub(sub)->seg->base.data;
489 opcode_t * const start = base + PMC_sub(sub)->start_offs;
490 opcode_t * const end = base + PMC_sub(sub)->end_offs;
491 /* TODO pass Sub */
493 Parrot_jit_info_t * jit_info = parrot_build_asm(interp,
494 start, end, NULL, JIT_CODE_SUB_REGS_ONLY | flags);
496 if (!jit_info)
497 return NULLfunc;
499 return (funcptr_t) jit_info->arena.start;
500 # endif
501 #else
502 UNUSED(interp);
503 UNUSED(sub);
504 UNUSED(flags);
506 return NULLfunc;
507 #endif
513 =back
515 =head1 AUTHOR
517 Leopold Toetsch
519 =head1 SEE ALSO
521 F<src/pic.c>, F<src/jit.c>, F<ops/core_ops_cgp.c>,
522 F<include/parrot/pic.h>, F<ops/pic.ops>
524 =cut
529 * Local variables:
530 * c-file-style: "parrot"
531 * End:
532 * vim: expandtab shiftwidth=4: