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
  
  
  


Reply via email to