cvsuser 03/02/14 05:32:22
Modified: . MANIFEST core.ops debug.c interpreter.c jit.c
ops2c.pl
include/parrot jit.h
jit/i386 core.jit jit_emit.h
t/native_pbc number.t
t/op jit.t
Added: docs/dev jit_i386.dev
Log:
cgp_jit: s. the dev doc and the announce on parrot-internal
Revision Changes Path
1.313 +1 -0 parrot/MANIFEST
Index: MANIFEST
===================================================================
RCS file: /cvs/public/parrot/MANIFEST,v
retrieving revision 1.312
retrieving revision 1.313
diff -u -w -r1.312 -r1.313
--- MANIFEST 10 Feb 2003 10:03:52 -0000 1.312
+++ MANIFEST 14 Feb 2003 13:31:58 -0000 1.313
@@ -127,6 +127,7 @@
docs/dev/byteorder.dev
docs/dev/dod.dev
docs/dev/infant.dev
+docs/dev/jit_i386.dev
docs/dev/rx.dev
docs/embed.pod
docs/faq.pod
1.258 +13 -0 parrot/core.ops
Index: core.ops
===================================================================
RCS file: /cvs/public/parrot/core.ops,v
retrieving revision 1.257
retrieving revision 1.258
diff -u -w -r1.257 -r1.258
--- core.ops 10 Feb 2003 19:18:02 -0000 1.257
+++ core.ops 14 Feb 2003 13:31:58 -0000 1.258
@@ -50,12 +50,25 @@
Does nothing other than waste an iota of time and 32 bits of bytecode space.
+=item B<cpu_ret>()
+
+Emit a cpu return instruction. This is used to return from CGP core
+to JIT code.
+
=cut
inline op noop() {
goto NEXT();
}
+inline op cpu_ret() {
+#ifdef __GNUC__
+# ifdef I386
+ asm("ret");
+# endif
+#endif
+ goto NEXT();
+}
=back
1.59 +4 -2 parrot/debug.c
Index: debug.c
===================================================================
RCS file: /cvs/public/parrot/debug.c,v
retrieving revision 1.58
retrieving revision 1.59
diff -u -w -r1.58 -r1.59
--- debug.c 1 Feb 2003 13:33:54 -0000 1.58
+++ debug.c 14 Feb 2003 13:31:58 -0000 1.59
@@ -2,7 +2,7 @@
* debug.c
*
* CVS Info
- * $Id: debug.c,v 1.58 2003/02/01 13:33:54 leo Exp $
+ * $Id: debug.c,v 1.59 2003/02/14 13:31:58 leo Exp $
* Overview:
* Parrot debugger
* History:
@@ -1001,9 +1001,11 @@
{
int size = 0;
int j;
+ char *p;
/* Write the opcode name */
- strcpy(&dest[file->size], full_name ? info->full_name : info->name);
+ p = file ? &dest[file->size] : dest;
+ strcpy(p, full_name ? info->full_name : info->name);
size += strlen(dest);
dest[size++] = ' ';
1.146 +8 -1 parrot/interpreter.c
Index: interpreter.c
===================================================================
RCS file: /cvs/public/parrot/interpreter.c,v
retrieving revision 1.145
retrieving revision 1.146
diff -u -w -r1.145 -r1.146
--- interpreter.c 11 Feb 2003 08:06:56 -0000 1.145
+++ interpreter.c 14 Feb 2003 13:31:58 -0000 1.146
@@ -1,7 +1,7 @@
/* interpreter.c
* Copyright: (When this is determined...it will go here)
* CVS Info
- * $Id: interpreter.c,v 1.145 2003/02/11 08:06:56 leo Exp $
+ * $Id: interpreter.c,v 1.146 2003/02/14 13:31:58 leo Exp $
* Overview:
* The interpreter api handles running the operations
* Data Structure and Algorithms:
@@ -245,6 +245,13 @@
code_start = interpreter->code->byte_code;
code_size = interpreter->code->cur_cs->base.size;
code_end = interpreter->code->byte_code + code_size;
+#ifdef HAVE_COMPUTED_GOTO
+# ifdef __GNUC__
+# ifdef I386
+ init_prederef(interpreter, 1);
+# endif
+# endif
+#endif
jit_code = build_asm(interpreter, pc, code_start, code_end);
interpreter->code->cur_cs->jit_info = interpreter->jit_info;
1.57 +32 -8 parrot/jit.c
Index: jit.c
===================================================================
RCS file: /cvs/public/parrot/jit.c,v
retrieving revision 1.56
retrieving revision 1.57
diff -u -w -r1.56 -r1.57
--- jit.c 22 Jan 2003 15:56:57 -0000 1.56
+++ jit.c 14 Feb 2003 13:31:58 -0000 1.57
@@ -1,7 +1,7 @@
/*
* jit.c
*
- * $Id: jit.c,v 1.56 2003/01/22 15:56:57 leo Exp $
+ * $Id: jit.c,v 1.57 2003/02/14 13:31:58 leo Exp $
*/
#include <parrot/parrot.h>
@@ -159,6 +159,20 @@
/* Move to the next opcode */
cur_op += op_info->arg_count;
}
+ /* now look at fixups, mark all fixup entries as branch target */
+ {
+ struct PackFile_FixupTable *ft = interpreter->code->fixup_table;
+ int i;
+ if (!ft)
+ return;
+ for (i = 0; i < ft->fixup_count; i++) {
+ switch (ft->fixups[i]->type) {
+ case 0:
+ branch[ft->fixups[i]->u.t0.offset] |= JIT_BRANCH_TARGET;
+ break;
+ }
+ }
+ }
}
static void
@@ -233,6 +247,16 @@
}
}
+/*
+ * I386 has JITed vtables, which have the vtable# in extcall.
+ * This Parrot_jit_vtable_n_op() doese use register mappings.
+ */
+#if defined(I386)
+# define EXTCALL(op) (op_jit[*(op)].extcall == 1)
+#else
+# define EXTCALL(op) op_jit[*(op)].extcall
+#endif
+
static void
make_sections(struct Parrot_Interp *interpreter,
Parrot_jit_optimizer_t * optimizer,
@@ -272,16 +296,16 @@
/*
* End a section:
* If this opcode is jitted and next calls a C function */
- if (!op_jit[*cur_op].extcall) {
+ if (!EXTCALL(cur_op)) {
cur_section->jit_op_count++;
- if (next_op < code_end && op_jit[*next_op].extcall)
+ if (next_op < code_end && EXTCALL(next_op))
start_new = 1;
}
else
/* or if current section is not jitted, and the next opcode
* is. */
- if (next_op < code_end && !op_jit[*next_op].extcall)
+ if (next_op < code_end && !EXTCALL(next_op))
start_new = 1;
/* or when the current opcode is a branch source,
@@ -300,7 +324,7 @@
if (start_new) {
/* Set the type, depending on whether the current
* instruction is external or jitted. */
- cur_section->isjit = !op_jit[*cur_op].extcall;
+ cur_section->isjit = !EXTCALL(cur_op);
/* Save the address where the section ends */
cur_section->end = cur_op;
@@ -591,8 +615,8 @@
op_info = &interpreter->op_info_table[*cur_op];
PDB_disassemble_op(interpreter, instr, sizeof(instr),
op_info, cur_op, NULL, code_start, 0);
- PIO_eprintf(interpreter, "\t\tOP%vu: %s\n",
- cur_op - code_start, instr);
+ PIO_eprintf(interpreter, "\t\tOP%vu: ext %3d\t%s\n",
+ cur_op - code_start, op_jit[*cur_op].extcall, instr);
#if JIT_DEBUG > 1
PIO_eprintf(interpreter, "\t\t\tmap_branch: ");
for (i = 0; i < op_info->arg_count; i++)
@@ -613,7 +637,7 @@
t = types[typ];
PIO_eprintf(interpreter, "\t%c registers used:\t%i\n",
t, ru[typ].registers_used);
- if (1 || ru[typ].registers_used) {
+ if (ru[typ].registers_used) {
PIO_eprintf(interpreter, "\t%c register count:\t", t);
for (i = 0; i < NUM_REGISTERS; i++)
PIO_eprintf(interpreter, "%i ", ru[typ].reg_count[i]);
1.41 +12 -2 parrot/ops2c.pl
Index: ops2c.pl
===================================================================
RCS file: /cvs/public/parrot/ops2c.pl,v
retrieving revision 1.40
retrieving revision 1.41
diff -u -w -r1.40 -r1.41
--- ops2c.pl 9 Feb 2003 16:55:44 -0000 1.40
+++ ops2c.pl 14 Feb 2003 13:31:58 -0000 1.41
@@ -5,7 +5,7 @@
# Generate a C header and source file from the operation definitions in
# an .ops file, using a supplied transform.
#
-# $Id: ops2c.pl,v 1.40 2003/02/09 16:55:44 leo Exp $
+# $Id: ops2c.pl,v 1.41 2003/02/14 13:31:58 leo Exp $
#
use strict;
@@ -155,8 +155,14 @@
print SOURCE <<END_C;
opcode_t *
-$cg_func$base(opcode_t *cur_opcode, struct Parrot_Interp *interpreter)
+$cg_func$base(opcode_t *cur_op, struct Parrot_Interp *interpreter)
{
+#ifdef __GNUC__
+ register opcode_t *cur_opcode asm ("esi") = cur_op;
+#else
+ opcode_t *cur_opcode = cur_op;
+#endif
+
static void *ops_addr[] = {
END_C
@@ -251,6 +257,10 @@
if (cur_opcode == 0)
return (opcode_t *)ops_addr;
#ifdef __GNUC__
+# ifdef I386
+ else if (cur_opcode == (opcode_t *) 1)
+ asm ("jmp *4(%ebp)"); /* jump to ret addr, used by JIT */
+# endif
else
_check();
#endif
1.1 parrot/docs/dev/jit_i386.dev
Index: jit_i386.dev
===================================================================
#
# This file is in POD format; if you're not used to reading POD,
# you can run the file through "perldoc" for a plain text version.
=head1 TITLE
Parrot JIT i386/gcc
=head1 VERSION
=head2 CURRENT
14.02.2003 by Leopold Toetsch
=head1 ABSTRACT
This PDD describes the i386 gcc JIT implementation.
=head1 DESCRIPTION
JIT i386/gcc is a combination of unrolled assembly instructions and
the Computed CGoto Prederefed (CGP) run loop. For branch instructions
the function implementation in the standard core is called.
Another difference of JIT/i386 is, that most vtable functions are
JITed instructions which use register mappings.
For a better understanding of the control flow between these basically
3 run loop cores, an example shows the gory details.
=head1 EXAMPLE
Given the following PASM program, the right 3 colums show, where which
opcode gets executed:
PASM JIT ops Normal CGP ops
(call cgp_core) (jmp back)
set I0, 10 set_i_ic
print I0 (call) print_i
print "\n" print_sc
bsr inc (call) bsr_ic cpu_ret
end (jmp) HALT end (ret)
end (ret)
inc:
inc I0 inc_i
new P0, .PerlString new_p_ic
set P0, I0 set_p_i
print P0 (call) print_p
print "\n" print_sc
ret (call) ret cpu_ret
=head2 Startup sequence
In B<runops_jit> a prederefed copy of the opcode stream is built by
B<init_prederef>. Then B<build_asm> generates the assembler code
seqence as usual. This generated code (shown as B<runops_jit> in
B<ddd>) then is executed.
Generate minimal stack frame, save %ebx
0x812c510 <jit_func>: push %ebp
0x812c511 <jit_func+1>: mov %esp,%ebp
0x812c513 <jit_func+3>: push %ebx
Get the program counter to %ebx
0x812c514 <jit_func+4>: mov 0xc(%ebp),%ebx
Push B<interpreter> and B<(opcode_t*) 1> and call B<cgp_core>
0x812c517 <jit_func+7>: push $0x8113db8
0x812c51c <jit_func+12>: push $0x1
0x812c521 <jit_func+17>: mov $0x1,%eax
0x812c526 <jit_func+22>: call 0x80b5830 <cgp_core>
In B<cgp_core> all callee saved registers are saved.
0x80b5830 <cgp_core>: push %ebp
0x80b5831 <cgp_core+1>: mov %esp,%ebp
0x80b5833 <cgp_core+3>: sub $0xdc,%esp
0x80b5839 <cgp_core+9>: lea 0x8(%ebp),%eax
0x80b583c <cgp_core+12>: push %edi
0x80b583d <cgp_core+13>: push %esi
0x80b583e <cgp_core+14>: push %ebx
In B<%eax> the init flag is set to B<-1>
0x80b583f <cgp_core+15>: mov %eax,0xfffffff
The parameter B<*cur_op> (the program counter) is put into B<%esi> and ...
0x80b5842 <cgp_core+18>: mov 0x8(%ebp),%esi
0x80b5845 <cgp_core+21>: test %esi,%esi
0x80b5847 <cgp_core+23>: jne 0x80b5853 <cgp_core+35>
0x80b5849 <cgp_core+25>: mov $0x810ca60,%eax
0x80b584e <cgp_core+30>: jmp 0x80bb470 <cgp_core+23616>
... compared to B<1>
0x80b5853 <cgp_core+35>: cmp $0x1,%esi
0x80b5856 <cgp_core+38>: jne 0x80b5860 <cgp_core+48>
and, if yes, the program jumps to the return address of above function
call, i.e. it jumps back again to JIT code.
0x80b5858 <cgp_core+40>: jmp *0x4(%ebp)
Back again in JIT code, the init flag is checked
0x812c52b <jit_func+27>: test %eax,%eax
0x812c52d <jit_func+29>: jne 0x812c536 <jit_func+38>
... and if zero, the function would be left.
[ 0x812c52f <jit_func+31>: pop %ebx ]
[ 0x812c531 <jit_func+33>: mov %ebp,%esp ]
[ 0x812c533 <jit_func+35>: pop %ebp ]
[ 0x812c535 <jit_func+37>: ret ]
When coming from the init sequence program flow continues with
checking the B<resume_offset> and jumping to the desired instruction
0x812c536 <jit_func+38>: mov %ebx,%eax
0x812c538 <jit_func+40>: sub $0x400140c0,%eax
0x812c53e <jit_func+46>: mov $0x812c4a8,%edx
0x812c543 <jit_func+51>: jmp *(%edx,%eax,1)
B<set I0, 10> and save_registers
0x812c546 <jit_func+54>: mov $0xa,%ebx
0x812c54b <jit_func+59>: mov %ebx,0x8113db8
Now non-JITed code follows, get the address from the prederefed
op_func_table and call it:
0x812c551 <jit_func+65>: mov $0x812ac0c,%esi
0x812c556 <jit_func+70>: call *(%esi)
inline op print(in INT) {
printf(INTVAL_FMT, (INTVAL)$1);
goto NEXT();
}
where the B<goto NEXT()> is a simple:
0x80b5b49 <cgp_core+793>: jmp *(%esi)
op print(in STR) {
...
goto NEXT();
}
As the last instruction of the non JITed code sequence is a branch,
this is not executed in CGP, but the opcode:
inline op cpu_ret() {
#ifdef __GNUC__
# ifdef I386
asm("ret")
is executed. This opcode is patched into the prederefed code stream
by Parrot_jit_normal_op at the end of a non JITed code sequence. This
returns to JIT code again, where the next instruction gets called as a
function in the standard core ...
0x812c558 <jit_func+72>: push $0x8113db8
0x812c55d <jit_func+77>: push $0x400140dc
0x812c562 <jit_func+82>: call 0x805be60 <Parrot_bsr_ic>
0x812c567 <jit_func+87>: add $0x8,%esp
... and from the return result in B<%eax> the new code position in JIT
is calculated and gets jumped to
0x812c56a <jit_func+90>: sub $0x400140c0,%eax
0x812c570 <jit_func+96>: mov $0x812c4a8,%edx
0x812c575 <jit_func+101>: jmp *(%edx,%eax,1)
Now in the subroutine B<inc>:
0x812c580 <jit_func+112>: mov 0x8113db8,%ebx
0x812c586 <jit_func+118>: inc %ebx
Save register and arguments and call B<pmc_new_noinit>
0x812c587 <jit_func+119>: push %edx
0x812c588 <jit_func+120>: push $0x11
0x812c58d <jit_func+125>: push $0x8113db8
0x812c592 <jit_func+130>: call 0x806fc60 <pmc_new_noinit>
put the PMC* into parrots registeer
0x812c597 <jit_func+135>: mov %eax,0x8113fb8
and prepare arguments for a VTABLE call
0x812c59d <jit_func+141>: push %eax
0x812c59e <jit_func+142>: push $0x8113db8
0x812c5a3 <jit_func+147>: mov 0x10(%eax),%eax
0x812c5a6 <jit_func+150>: call *0x18(%eax)
0x812c5a9 <jit_func+153>: add $0x10,%esp
0x812c5ac <jit_func+156>: pop %edx
and another one
0x812c5ae <jit_func+158>: push %edx
here with the mapped register in B<%ebx>, push B<I0>, the PMC and the
interpreter
0x812c5af <jit_func+159>: push %ebx
0x812c5b0 <jit_func+160>: mov 0x8113fb8,%eax
0x812c5b6 <jit_func+166>: push %eax
0x812c5b7 <jit_func+167>: push $0x8113db8
and call the vtable
0x812c5bc <jit_func+172>: mov 0x10(%eax),%eax
0x812c5bf <jit_func+175>: call *0xdc(%eax)
0x812c5c5 <jit_func+181>: add $0xc,%esp
0x812c5c8 <jit_func+184>: pop %edx
As this ends the JITed section, used registers are saved back to
parrots register
0x812c5ca <jit_func+186>: mov %ebx,0x8113db8
and again the code in B<cgp_core> gets called
0x812c5d0 <jit_func+192>: mov $0x812ac48,%esi
0x812c5d5 <jit_func+197>: call *(%esi)
which after executing the B<print> returns back here in JIT, where the
B<ret> is called
0x812c5d7 <jit_func+199>: push $0x8113db8
0x812c5dc <jit_func+204>: push $0x40014118
0x812c5e1 <jit_func+209>: call 0x805d5e0 <Parrot_ret>
0x812c5e6 <jit_func+214>: add $0x8,%esp
and from the returned PC a JIT address is calculated, which gets
executed then:
0x812c5e9 <jit_func+217>: sub $0x400140c0,%eax
0x812c5ef <jit_func+223>: mov $0x812c4a8,%edx
0x812c5f4 <jit_func+228>: jmp *(%edx,%eax,1)
Now at the B<end> opcode, the CGP code for HALT() gets jumped to:
0x812c578 <jit_func+104>: mov $0x80b5877,%esi
0x812c57d <jit_func+109>: jmp *%esi
which is:
inline op end() {
HALT();
}
or, set return result
0x80b8b6f <cgp_core+13119>: xor %eax,%eax
...
and clean up stack frame and ret:
0x80bb470 <cgp_core+23616>: lea 0xffffff18(%ebp),%esp
0x80bb476 <cgp_core+23622>: pop %ebx
0x80bb477 <cgp_core+23623>: pop %esi
0x80bb478 <cgp_core+23624>: pop %edi
0x80bb479 <cgp_core+23625>: mov %ebp,%esp
0x80bb47b <cgp_core+23627>: pop %ebp
0x80bb47c <cgp_core+23628>: ret
This returns after the position, where B<cgp_core> was called during
the init sequence, but now the return value B<%eax> is zero and the..
0x812c52b <jit_func+27>: test %eax,%eax
0x812c52d <jit_func+29>: jne 0x812c536 <jit_func+38>
0x812c52f <jit_func+31>: pop %ebx
0x812c531 <jit_func+33>: mov %ebp,%esp
0x812c533 <jit_func+35>: pop %ebp
0x812c535 <jit_func+37>: ret
... whole story ends here, we are back again in B<runops_jit>.
So this is rather simple once it gets going.
=head1 BUGS
The register <%edx> above was preserved over the vtable calls, though
it's unused. The floating point registers do not get saved to
parrots, this assumes, that external routines do preserve the FP stack
pointer and don't use more the 4 floating point registers at once.
=head1 AUTHOR
Leopold Toetsch <[EMAIL PROTECTED]>
1.33 +4 -2 parrot/include/parrot/jit.h
Index: jit.h
===================================================================
RCS file: /cvs/public/parrot/include/parrot/jit.h,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -w -r1.32 -r1.33
--- jit.h 21 Jan 2003 10:10:41 -0000 1.32
+++ jit.h 14 Feb 2003 13:32:06 -0000 1.33
@@ -1,7 +1,7 @@
/*
* jit.h
*
- * $Id: jit.h,v 1.32 2003/01/21 10:10:41 leo Exp $
+ * $Id: jit.h,v 1.33 2003/02/14 13:32:06 leo Exp $
*/
#ifndef JIT_H_GUARD
@@ -121,7 +121,9 @@
unsigned int op_count;
ptrdiff_t load_size;
char isjit;
- char dummy[3]; /* For alignment */
+ char done;
+ char ins_count;
+ char dummy; /* For alignment */
int block;
Parrot_jit_optimizer_section_ptr branch_target;
Parrot_jit_optimizer_section_ptr prev;
1.40 +3 -3 parrot/jit/i386/core.jit
Index: core.jit
===================================================================
RCS file: /cvs/public/parrot/jit/i386/core.jit,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -w -r1.39 -r1.40
--- core.jit 11 Feb 2003 20:21:30 -0000 1.39
+++ core.jit 14 Feb 2003 13:32:11 -0000 1.40
@@ -1,7 +1,7 @@
;
; i386/core.jit
;
-; $Id: core.jit,v 1.39 2003/02/11 20:21:30 leo Exp $
+; $Id: core.jit,v 1.40 2003/02/14 13:32:11 leo Exp $
;
# TODO complete this
@@ -1102,7 +1102,7 @@
push_<typ2>(2);
push_<typ1>(1);
emitm_pushl_i(NATIVECODE, interpreter);
- emitm_calll(NATIVECODE, (char*)string_compare - NATIVECODE - 4);
+ call_func(jit_info, (void*)string_compare);
emitm_addb_i_r(NATIVECODE, 12, emit_ESP);
jit_emit_test_r_i(NATIVECODE, emit_EAX);
jit_emit_jcc(jit_info, <op>, *INT_CONST[3]);
@@ -1216,7 +1216,7 @@
# define push_c(i) emitm_pushl_i(NATIVECODE, CONST(i)->u.string)
push_<typ>(1);
- emitm_calll(NATIVECODE, (char*)string_bool - NATIVECODE - 4);
+ call_func(jit_info, (void*)string_bool);
emitm_addb_i_r(NATIVECODE, 4, emit_ESP);
jit_emit_test_r_i(NATIVECODE, emit_EAX);
jit_emit_jcc(jit_info, <op>, *INT_CONST[2]);
1.52 +244 -49 parrot/jit/i386/jit_emit.h
Index: jit_emit.h
===================================================================
RCS file: /cvs/public/parrot/jit/i386/jit_emit.h,v
retrieving revision 1.51
retrieving revision 1.52
diff -u -w -r1.51 -r1.52
--- jit_emit.h 11 Feb 2003 15:09:34 -0000 1.51
+++ jit_emit.h 14 Feb 2003 13:32:11 -0000 1.52
@@ -3,11 +3,15 @@
*
* i386
*
- * $Id: jit_emit.h,v 1.51 2003/02/11 15:09:34 leo Exp $
+ * $Id: jit_emit.h,v 1.52 2003/02/14 13:32:11 leo Exp $
*/
#include <assert.h>
+#ifdef __GNUC__
+# define JIT_CGP
+#endif
+
/* #define NEG_MINUS_ZERO */
#define NEG_ZERO_SUB
@@ -1383,7 +1387,6 @@
emitm_fstp(pc, (r1+1)); \
}
-/* TODO config option, if fcomi* is available */
/* compare ST(r) <-> mem */
# define jit_emit_cmp_rm_n(pc, r, mem) { \
jit_emit_fload_m_n(pc, mem); \
@@ -1594,10 +1597,9 @@
{
/* This calculates (INDEX into op_map * 4) */
emitm_subl_i_r(jit_info->native_ptr,interpreter->code->byte_code,emit_EAX);
-
- /* This jumps to the address in op_map[EBP + sizeof(void *) * INDEX] */
- *jit_info->native_ptr++ = 0x3e; /* DS:0(EBP, EAX, 1) */
- emitm_jumpm(jit_info->native_ptr, emit_EBP, emit_EAX,
+ /* This jumps to the address in op_map[EDX + sizeof(void *) * INDEX] */
+ jit_emit_mov_ri_i(jit_info->native_ptr, emit_EDX, jit_info->arena.op_map);
+ emitm_jumpm(jit_info->native_ptr, emit_EDX, emit_EAX,
sizeof(*jit_info->arena.op_map) / 4, 0);
}
@@ -1611,10 +1613,15 @@
emitm_popl_r(pc, emit_EBP); \
} while(0)
+static void call_func(Parrot_jit_info_t *jit_info, void *addr);
+
+
+#ifndef JIT_CGP
void
Parrot_jit_begin(Parrot_jit_info_t *jit_info,
struct Parrot_Interp * interpreter)
{
+
/* the generated code gets called as:
* (jit_code)(interpreter, pc)
* jumping to pc is the same code as used in Parrot_jit_cpcf_op()
@@ -1643,22 +1650,10 @@
/* get the pc from stack: mov 12(%ebp), %eax */
emitm_movl_m_r(jit_info->native_ptr, emit_EAX, emit_EBP, emit_None, 1, 12);
- /* Point EBP to the opcode-native code map array - this destroy above
- * stack frame. If we have debugging, we should change this */
- jit_emit_mov_ri_i(jit_info->native_ptr, emit_EBP, jit_info->arena.op_map);
-
/* jump to restart pos or first op */
Parrot_emit_jump_to_eax(jit_info, interpreter);
}
-
-# define jit_emit_end(pc) { \
- jit_emit_add_ri_i(pc, emit_ESP, 4); \
- emitm_popl_r(pc, emit_EDI); \
- emitm_popl_r(pc, emit_EBX); \
- emitm_popl_r(pc, emit_ESI); \
- emitm_popl_r(pc, emit_EBP); \
- emitm_ret(pc); \
-}
+#endif
void
@@ -1730,7 +1725,7 @@
# undef Parrot_jit_vtable_2231_op
# undef Parrot_jit_vtable_1r223_op
-# undef Parrot_jit_vtable_1r322_op
+# undef Parrot_jit_vtable_1r332_op
# undef Parrot_jit_vtable_ifp_op
# undef Parrot_jit_vtable_unlessp_op
@@ -1739,6 +1734,7 @@
/* emit a call to a vtable func
* $X->vtable(interp, $X [, $Y...] )
*/
+#define MAP(i) jit_info->optimizer->map_branch[jit_info->op_i + (i)]
static void
Parrot_jit_vtable_n_op(Parrot_jit_info_t *jit_info,
struct Parrot_Interp * interpreter, int n, int bp, int *args)
@@ -1747,8 +1743,17 @@
size_t offset;
op_info_t *op_info = &interpreter->op_info_table[*jit_info->cur_op];
int p[PARROT_MAX_ARGS];
- int idx, i;
+ int idx, i, j;
int st = 0; /* stack pop correction */
+ int saved = 0;
+ Parrot_jit_register_usage_t *ru = jit_info->optimizer->cur_section->ru;
+ /* this is not callee saved, 3 is the # of emit_EDX in intval_map
+ * should also save floating regs back?
+ */
+ if (ru[0].reg_dir[ru[0].reg_usage[3]]) {
+ emitm_pushl_r(jit_info->native_ptr, emit_EDX);
+ saved = 1;
+ }
if (bp) {
jit_emit_stack_frame_enter(jit_info->native_ptr);
jit_emit_sub_ri_i(jit_info->native_ptr, emit_ESP, sizeof(INTVAL));
@@ -1762,16 +1767,11 @@
i = args[idx-1];
p[i] = *(jit_info->cur_op + i);
switch (op_info->types[i]) {
- case PARROT_ARG_I:
case PARROT_ARG_S:
case PARROT_ARG_P:
assert(p[i] >= 0 && p[i] < NUM_REGISTERS);
/* get $i to EAX */
switch (op_info->types[i]) {
- case PARROT_ARG_I:
- jit_emit_mov_rm_i(jit_info->native_ptr, emit_EAX,
- &INT_REG(p[i]));
- break;
case PARROT_ARG_S:
jit_emit_mov_rm_i(jit_info->native_ptr, emit_EAX,
&STR_REG(p[i]));
@@ -1788,11 +1788,23 @@
*/
emitm_pushl_r(jit_info->native_ptr, emit_EAX);
break;
+ case PARROT_ARG_I:
+ if (MAP(i))
+ emitm_pushl_r(jit_info->native_ptr, MAP(i));
+ else {
+ jit_emit_mov_rm_i(jit_info->native_ptr, emit_EAX,
+ &INT_REG(p[i]));
+ emitm_pushl_r(jit_info->native_ptr, emit_EAX);
+ }
+ break;
case PARROT_ARG_KI:
+ if (MAP(i))
+ jit_emit_mov_mr_i(jit_info->native_ptr, &INT_REG(p[i]),
+ MAP(i));
emitm_pushl_i(jit_info->native_ptr, &INT_REG(p[i]));
break;
case PARROT_ARG_KIC:
- /* XXX INTVAL_SIZE, make automatic var, push address */
+ /* XXX INTVAL_SIZE, make auto var, push address */
/* mov key, -4(%ebp) */
emitm_movl_i_m(jit_info->native_ptr, p[i], emit_EBP, 0, 1, -4);
/* lea -4(%bp), eax */
@@ -1807,6 +1819,10 @@
break;
case PARROT_ARG_N:
/* push num on st(0) */
+ if (MAP(i)) {
+ emitm_fld(jit_info->native_ptr, MAP(i));
+ }
+ else
jit_emit_fload_m_n(jit_info->native_ptr, &NUM_REG(p[i]));
goto store;
case PARROT_ARG_NC:
@@ -1834,9 +1850,20 @@
break;
case PARROT_ARG_KC:
+ {
+ /* a key constant may have multiple integer arguments,
+ * so save mapped regs back to parrot regs */
+ for (j = 0; j < ru[0].registers_used; j++) {
+ int us = ru[0].reg_usage[j];
+ jit_emit_mov_mr_i(jit_info->native_ptr,
+ &INT_REG(us),
+ jit_info->intval_map[j]);
+ }
+
emitm_pushl_i(jit_info->native_ptr,
interpreter->code->const_table->
constants[p[i]]->u.key);
+ }
break;
default:
@@ -1858,17 +1885,8 @@
else
emitm_addb_i_r(jit_info->native_ptr,
st+sizeof(void*)*(n+1), emit_ESP);
-}
-
-/* emit a call to a vtable func
- * $1->vtable(interp, $1)
- */
-static void
-Parrot_jit_vtable1_op(Parrot_jit_info_t *jit_info,
- struct Parrot_Interp * interpreter)
-{
- int a[] = { 1 };
- Parrot_jit_vtable_n_op(jit_info, interpreter, 1, 0, a);
+ if (saved)
+ emitm_popl_r(jit_info->native_ptr, emit_EDX);
}
static void
@@ -1882,6 +1900,10 @@
switch (op_info->types[1]) {
case PARROT_ARG_I:
/* XXX INTVAL_SIZE */
+ if (MAP(1)) {
+ jit_emit_mov_rr_i(jit_info->native_ptr, MAP(1), emit_EAX);
+ }
+ else
jit_emit_mov_mr_i(jit_info->native_ptr, &INT_REG(p1), emit_EAX);
break;
case PARROT_ARG_S:
@@ -1891,7 +1913,10 @@
jit_emit_mov_mr_i(jit_info->native_ptr, &PMC_REG(p1), emit_EAX);
break;
case PARROT_ARG_N:
- /* pop num from st(0) and mov to reg */
+ if (MAP(1)) {
+ emitm_fstp(jit_info->native_ptr, (1 + MAP(1)));
+ }
+ else
jit_emit_fstore_m_n(jit_info->native_ptr, &NUM_REG(p1));
break;
default:
@@ -1901,6 +1926,17 @@
}
/* emit a call to a vtable func
+ * $1->vtable(interp, $1)
+ */
+static void
+Parrot_jit_vtable1_op(Parrot_jit_info_t *jit_info,
+ struct Parrot_Interp * interpreter)
+{
+ int a[] = { 1 };
+ Parrot_jit_vtable_n_op(jit_info, interpreter, 1, 0, a);
+}
+
+/* emit a call to a vtable func
* $1 = $2->vtable(interp, $2)
*/
static void
@@ -1940,7 +1976,7 @@
* $1 = $3->vtable(interp, $3, $2)
*/
static void
-Parrot_jit_vtable_1r322_op(Parrot_jit_info_t *jit_info,
+Parrot_jit_vtable_1r332_op(Parrot_jit_info_t *jit_info,
struct Parrot_Interp * interpreter)
{
int a[] = { 3 , 2};
@@ -2053,6 +2089,15 @@
op_info_t *op_info = &interpreter->op_info_table[*jit_info->cur_op];
size_t offset = offsetof(struct _vtable, init);
int nvtable = op_jit[*jit_info->cur_op].extcall;
+ int saved = 0;
+ Parrot_jit_register_usage_t *ru = jit_info->optimizer->cur_section->ru;
+ /* this is not callee saved, 3 is the # of emit_EDX in intval_map
+ * should also save floating regs back?
+ */
+ if (ru[0].reg_dir[ru[0].reg_usage[3]]) {
+ emitm_pushl_r(jit_info->native_ptr, emit_EDX);
+ saved = 1;
+ }
assert(nvtable == 0); /* vtable->init */
assert(op_info->types[1] == PARROT_ARG_P);
@@ -2078,10 +2123,156 @@
emitm_callm(jit_info->native_ptr, emit_EAX, emit_None, emit_None, offset);
/* adjust 4 args pushed */
emitm_addb_i_r(jit_info->native_ptr, 16, emit_ESP);
+ if (saved)
+ emitm_popl_r(jit_info->native_ptr, emit_EDX);
}
# endif /* NO_JIT_VTABLE_OPS */
+# ifdef JIT_CGP
+
+#include <parrot/oplib/core_ops_cgp.h>
+/*
+ * This is the somewhat complicated program flow
+ *
+ * JIT code prederef code
+ * 1) jit_begin
+ * stack_enter
+ * call cgp_core --> set stack frame
+ * jump to retaddr
+ * test EAX, 0 <-- also from HALT
+ * jnz code_start
+ * stack_leave
+ * ret
+ * code_start: of JIT code
+ * jit code
+ * ....
+ *
+ * 2) normal_op
+ * mov prederef_code_ptr, esi
+ * call *(esi) ----> prederefed (non JITted code)
+ * ....
+ * .... <---- ret
+ * jit_code
+ * ....
+ * 3) HALT == jit_end
+ * mov prederefed_op_func[0], esi
+ * jump *esi -----> cleanup prederef stack frame
+ * xor eax,eax ; return 0
+ * ret (--> after call cgp_core in 1)
+ *
+ */
+
+void
+Parrot_jit_begin(Parrot_jit_info_t *jit_info,
+ struct Parrot_Interp * interpreter)
+{
+
+ jit_emit_stack_frame_enter(jit_info->native_ptr);
+ emitm_pushl_r(jit_info->native_ptr, emit_EBX);
+ /* get the pc from stack: mov 12(%ebp), %ebx */
+ emitm_movl_m_r(jit_info->native_ptr, emit_EBX, emit_EBP, emit_None, 1, 12);
+ /* emit cgp_core(1, interpreter) */
+ emitm_pushl_i(jit_info->native_ptr, interpreter);
+ emitm_pushl_i(jit_info->native_ptr, 1);
+ /* use EAX as flag, when jumping back on init, EAX==1 */
+ jit_emit_mov_ri_i(jit_info->native_ptr, emit_EAX, 1);
+ /* TODO restart code */
+ call_func(jit_info, (void (*)(void))cgp_core);
+ /* when cur_opcode == 1, cgp_core jumps back here
+ * when EAX == 0, the official return from HALT was called */
+ jit_emit_test_r_i(jit_info->native_ptr, emit_EAX);
+ emitm_jxs(jit_info->native_ptr, emitm_jnz, 7);
+ emitm_popl_r(jit_info->native_ptr, emit_EBX);
+ jit_emit_stack_frame_leave(jit_info->native_ptr);
+ emitm_ret(jit_info->native_ptr);
+ /* get PC = ebx to eax, jump there */
+ jit_emit_mov_rr_i(jit_info->native_ptr, emit_EAX, emit_EBX);
+ Parrot_emit_jump_to_eax(jit_info, interpreter);
+
+/* code_start: */
+}
+
+void
+Parrot_jit_normal_op(Parrot_jit_info_t *jit_info,
+ struct Parrot_Interp * interpreter)
+{
+ Parrot_jit_optimizer_section_ptr cur_section =
+ jit_info->optimizer->cur_section;
+ int last_is_branch = 0;
+ void ** offset;
+
+ assert(op_jit[*jit_info->cur_op].extcall == 1);
+ if (cur_section->done == 1)
+ return;
+ else if (cur_section->done == -1 && --cur_section->ins_count > 0)
+ return;
+ /* check, where section ends
+ */
+ if (interpreter->op_info_table[*cur_section->end].jump)
+ last_is_branch = 1;
+ else if (cur_section->next && !cur_section->next->isjit)
+ last_is_branch = 1;
+ /* if more then 1 op, then jump to CGP, branches are never
+ * executed in CGP, they are handled below */
+ if (cur_section->done >= 0 &&
+ (INTVAL)cur_section->op_count >= 2 + last_is_branch) {
+ int saved = 0;
+ offset = (jit_info->cur_op - interpreter->code->byte_code) +
+ interpreter->code->cur_cs->prederef_code;
+
+ jit_emit_mov_ri_i(jit_info->native_ptr, emit_ESI, offset);
+ emitm_callm(jit_info->native_ptr, emit_ESI, 0, 0, 0);
+ /* now patch a B<cpu_ret> opcode after the end of the
+ * prederefed (non JIT) section
+ */
+ if (last_is_branch) {
+ offset = (cur_section->end - interpreter->code->byte_code) +
+ interpreter->code->cur_cs->prederef_code;
+ cur_section->done = -1;
+ /* ins to skip */
+ cur_section->ins_count = cur_section->op_count - 1;
+ }
+ else {
+ /* There must be a next section: either we have a B<end>
+ * or a JITed branch,
+ * when the branch is non JIT, we are in the above case
+ */
+ offset = (cur_section->next->begin - interpreter->code->byte_code) +
+ interpreter->code->cur_cs->prederef_code;
+ cur_section->done = 1;
+ }
+ *offset = ((op_func_t*)interpreter->op_lib->op_func_table)[2];
+ }
+ else {
+ /* else call normal funtion */
+ emitm_pushl_i(jit_info->native_ptr, interpreter);
+ emitm_pushl_i(jit_info->native_ptr, jit_info->cur_op);
+ call_func(jit_info,
+ (void (*)(void))interpreter->op_func_table[*(jit_info->cur_op)]);
+ emitm_addb_i_r(jit_info->native_ptr, 8, emit_ESP);
+ /* when this was a branch, then EAX is now the offset
+ * in the byte_code
+ */
+ }
+}
+
+# define jit_emit_end(pc) { \
+ jit_emit_mov_ri_i(pc, emit_ESI,
(ptrcast_t)((op_func_t*)interpreter->op_lib->op_func_table) [0]); \
+ emitm_jumpr(pc, emit_ESI); \
+}
+
+# else
+
+# define jit_emit_end(pc) { \
+ jit_emit_add_ri_i(pc, emit_ESP, 4); \
+ emitm_popl_r(pc, emit_EDI); \
+ emitm_popl_r(pc, emit_EBX); \
+ emitm_popl_r(pc, emit_ESI); \
+ emitm_popl_r(pc, emit_EBP); \
+ emitm_ret(pc); \
+}
+
void
Parrot_jit_normal_op(Parrot_jit_info_t *jit_info,
struct Parrot_Interp * interpreter)
@@ -2093,6 +2284,8 @@
emitm_addb_i_r(jit_info->native_ptr, 4, emit_ESP);
}
+# endif
+
static void Parrot_end_jit(Parrot_jit_info_t *, struct Parrot_Interp * );
void
@@ -2128,7 +2321,9 @@
jit_info->native_ptr = sav_ptr;
Parrot_emit_jump_to_eax(jit_info, interpreter);
}
-
+/*
+ * TODO if this is called from an JITed op it has to use MAPs
+ */
void *
Parrot_jit_build_call_func(struct Parrot_Interp *interpreter, PMC *pmc_nci,
String *signature)
@@ -2327,7 +2522,7 @@
* if jit_emit_noop is defined, it does align a jump target
* to 1 << JUMP_ALIGN (it should emit exactly 1 byte)
*
- * s. also info gcc /malign-jump
+ * s. also info gcc /align-jump
*/
#define jit_emit_noop(pc) *pc++ = 0x90;
1.3 +5 -2 parrot/t/native_pbc/number.t
Index: number.t
===================================================================
RCS file: /cvs/public/parrot/t/native_pbc/number.t,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -w -r1.2 -r1.3
--- number.t 31 Jan 2003 07:47:30 -0000 1.2
+++ number.t 14 Feb 2003 13:32:18 -0000 1.3
@@ -25,7 +25,10 @@
EOC
use Parrot::Test tests => 2;
-use Test::More;
+use Test::More qw(skip);
+
+SKIP: {
+skip("core ops changes", Test::Builder->expected_tests());
output_is(<<CODE, <<OUTPUT, "i386 double float 32 bit opcode_t");
# number_1.pbc
@@ -103,4 +106,4 @@
281474976710656.000000
1125899906842620.000000
OUTPUT
-
+}
1.2 +212 -1 parrot/t/op/jit.t
Index: jit.t
===================================================================
RCS file: /cvs/public/parrot/t/op/jit.t,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -w -r1.1 -r1.2
--- jit.t 19 Nov 2002 15:47:27 -0000 1.1
+++ jit.t 14 Feb 2003 13:32:22 -0000 1.2
@@ -1,6 +1,6 @@
#! perl -w
# test WRT JIT register allocation
-use Parrot::Test tests => 28;
+use Parrot::Test tests => 42;
output_is(<<'CODE', <<'OUTPUT', "add_i_i_i 1,2,3 mapped");
set I0,0
@@ -540,3 +540,214 @@
00
OUTPUT
+# tests for JIT CGP
+output_is(<<'CODE', <<'OUTPUT', "1 non jit");
+ set I0, 16
+ print "ok 1\n"
+ end
+CODE
+ok 1
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "2 non jit");
+ print "ok 1\n"
+ print "ok 2\n"
+ end
+CODE
+ok 1
+ok 2
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "2 non jit");
+ set I0, 16
+ print "ok 1\n"
+ print "ok 2\n"
+ end
+CODE
+ok 1
+ok 2
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "2 non jit, JITed branch to JIT");
+ set I0, 42
+ print I0
+ print "\n"
+ eq I0, 42, sub
+ret:
+ end
+sub:
+ set I0, 43
+ print I0
+ print "\n"
+ branch ret
+CODE
+42
+43
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "2 non jit, non JITed branch to JIT");
+ set I0, 42
+ print I0
+ print "\n"
+ bsr sub
+ end
+sub:
+ set I0, 43
+ print I0
+ print "\n"
+ ret
+CODE
+42
+43
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "2 non jit, JITed branch to non JIT");
+ set I0, 42
+ print I0
+ print "\n"
+ eq I0, 42, sub
+ret:
+ end
+sub:
+ print "ok\n"
+ branch ret
+CODE
+42
+ok
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "2 non jit, non JITed branch to non JIT");
+ set I0, 42
+ print I0
+ print "\n"
+ bsr sub
+ end
+sub:
+ print "ok\n"
+ ret
+CODE
+42
+ok
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "set_addr");
+ set_addr I1, FOO
+ jump I1
+ print "Jump failed\n"
+ end
+
+FOO: print "Jump succeeded\n"
+ end
+CODE
+Jump succeeded
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "jsr");
+ set_addr I1, FOO
+ jsr I1
+ print "and back again\n"
+ end
+
+FOO: print "There "
+ ret
+
+CODE
+There and back again
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "last is branch");
+ print "ok 1\n"
+ branch l2
+l1:
+ print "ok 3\n"
+ end
+l2:
+ print "ok 2\n"
+ branch l1
+CODE
+ok 1
+ok 2
+ok 3
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "last is branch");
+ print "ok 1\n"
+ branch l2
+l1:
+ print "ok 4\n"
+ end
+l2:
+ print "ok 2\n"
+ print "ok 3\n"
+ branch l1
+CODE
+ok 1
+ok 2
+ok 3
+ok 4
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "last is JIT branch");
+ print "ok 1\n"
+ branch l2
+l1:
+ print "ok 3\n"
+ end
+l2:
+ print "ok 2\n"
+ eq I0, 0, l1
+CODE
+ok 1
+ok 2
+ok 3
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "last is JIT branch");
+ print "ok 1\n"
+ branch l2
+l1:
+ print "ok 4\n"
+ end
+l2:
+ print "ok 2\n"
+ print "ok 3\n"
+ eq I0, 0, l1
+CODE
+ok 1
+ok 2
+ok 3
+ok 4
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "t/op/arithmetic_26: non jit seq w. branch");
+new P0, 15
+set N0, 4000
+set P0, 123
+div P0, P0, N0
+
+save N0
+save N1
+save N2
+
+set N0, P0
+set N1, 0.03074969250307496925
+sub N2, N1,N0
+abs N2, N2
+gt N2, 0.000001, local__fp_eq__FPEQNOK__1
+
+restore N2
+restore N1
+restore N0
+branch EQ1
+local__fp_eq__FPEQNOK__1:
+restore N2
+restore N1
+restore N0
+print P0
+print "not "
+EQ1: print "ok 1"
+print "\n"
+end
+CODE
+ok 1
+OUTPUT