Author: leo
Date: Thu Apr 28 04:46:37 2005
New Revision: 7936

Added:
   trunk/ops/pic.ops
Modified:
   trunk/MANIFEST
   trunk/imcc/pbc.c
   trunk/include/parrot/mmd.h
   trunk/include/parrot/pic.h
   trunk/ops/ops.num
   trunk/src/interpreter.c
   trunk/src/mmd.c
   trunk/src/packdump.c
   trunk/src/packfile.c
   trunk/src/pdump.c
   trunk/src/pic.c
Log:
PIC 2 - infix_p_p and inline_sub_p_p

Experimental PIC support, mainly to show the potential for perfomance.

* only the inplace infix_ic_p_p opcode
* one inline variant sub_p_p for the MOPS benchmark

The inline variant is about 2,5 times faster then all other run cores and
even faster then native integer MOPS with the function core.

---

* fix pdump utility


Modified: trunk/MANIFEST
==============================================================================
--- trunk/MANIFEST      (original)
+++ trunk/MANIFEST      Thu Apr 28 04:46:37 2005
@@ -1541,6 +1541,7 @@
 ops/object.ops                                    []
 ops/obscure.ops                                   []
 ops/ops.num                                       [devel]
+ops/pic.ops                                       []
 ops/pmc.ops                                       []
 ops/python.ops                                    []
 ops/rx.ops                                        []

Modified: trunk/imcc/pbc.c
==============================================================================
--- trunk/imcc/pbc.c    (original)
+++ trunk/imcc/pbc.c    Thu Apr 28 04:46:37 2005
@@ -59,6 +59,7 @@
     struct cs_t *prev;                  /* previous code segment */
     struct cs_t *next;                  /* next code segment */
     SymReg * key_consts[HASH_SIZE];     /* cached key constants for this seg */
+    int pic_idx;                        /* next index of PIC */
 };
 
 static struct globals {
@@ -1056,14 +1057,24 @@
         constant_folding(interpreter, unit);
         store_sub_size(code_size, ins_size);
         bytes = (oldsize + code_size) * sizeof(opcode_t);
+        /*
+         * allocate code and pic_index
+         *
+         * pic_index is half the size of the code, as one PIC-cachable opcode
+         * is at least two opcodes wide - see below how to further decrease
+         * this storage
+         */
         if (interpreter->code->base.data) {
             interpreter->code->base.data =
                 mem_sys_realloc(interpreter->code->base.data, bytes);
+            interpreter->code->pic_index->data =
+                mem_sys_realloc(interpreter->code->pic_index->data, bytes/2);
         } else {
-            interpreter->code->base.data =
-                mem_sys_allocate(bytes);
+            interpreter->code->base.data = mem_sys_allocate(bytes);
+            interpreter->code->pic_index->data = mem_sys_allocate(bytes/2);
         }
         interpreter->code->base.size = oldsize + code_size;
+        interpreter->code->pic_index->size = (oldsize + code_size)/2;
         pc = (opcode_t*) interpreter->code->base.data + oldsize;
         npc = 0;
         /* add debug if necessary */
@@ -1131,8 +1142,23 @@
         if (debug_seg) {
             debug_seg->base.data[ins_line++] = (opcode_t) ins->line;
         }
+        op = (opcode_t)ins->opnum;
+        /* add PIC idx */
+        if (parrot_PIC_op_is_cached(interpreter, op)) {
+            size_t offs = pc - interpreter->code->base.data;
+            /*
+             * for pic_idx fitting into a short, we could
+             * further reduce the size by storing shorts
+             * the relation code_size / pic_index_size could
+             * indicate the used storage
+             *
+             * drawback: if we reach 0xffff, we'd have to resize again
+             */
+            interpreter->code->pic_index->data[offs / 2] =
+                ++globals.cs->pic_idx;
+        }
         /* Start generating the bytecode */
-        *pc++ = op = (opcode_t)ins->opnum;
+        *pc++ = op;
         /* Get the info for that opcode */
         op_info = &interpreter->op_info_table[op];
         IMCC_debug(interpreter, DEBUG_PBC, "%d %s", npc, op_info->full_name);

Modified: trunk/include/parrot/mmd.h
==============================================================================
--- trunk/include/parrot/mmd.h  (original)
+++ trunk/include/parrot/mmd.h  Thu Apr 28 04:46:37 2005
@@ -28,6 +28,19 @@
 /* compare */
 INTVAL mmd_dispatch_i_pp(Parrot_Interp, PMC *, PMC *, INTVAL);
 
+/* function typedefs */
+typedef PMC*    (*mmd_f_p_ppp)(Interp *, PMC *, PMC *, PMC *);
+typedef PMC*    (*mmd_f_p_pip)(Interp *, PMC *, INTVAL, PMC *);
+typedef PMC*    (*mmd_f_p_pnp)(Interp *, PMC *, FLOATVAL, PMC *);
+typedef PMC*    (*mmd_f_p_psp)(Interp *, PMC *, STRING *, PMC *);
+
+typedef void    (*mmd_f_v_pp)(Interp *, PMC *, PMC *);
+typedef void    (*mmd_f_v_pi)(Interp *, PMC *, INTVAL);
+typedef void    (*mmd_f_v_pn)(Interp *, PMC *, FLOATVAL);
+typedef void    (*mmd_f_v_ps)(Interp *, PMC *, STRING *);
+
+typedef INTVAL  (*mmd_f_i_pp) (Interp *, PMC *, PMC *);
+
 void mmd_add_by_class(Parrot_Interp, INTVAL, STRING *, STRING *, funcptr_t);
 void mmd_register(Parrot_Interp, INTVAL, INTVAL, INTVAL, funcptr_t);
 void mmd_register_sub(Parrot_Interp, INTVAL, INTVAL, INTVAL, PMC*);

Modified: trunk/include/parrot/pic.h
==============================================================================
--- trunk/include/parrot/pic.h  (original)
+++ trunk/include/parrot/pic.h  Thu Apr 28 04:46:37 2005
@@ -57,7 +57,7 @@
     struct Parrot_pic_store_t *prev;   /* prev pic_store */
     size_t usable;                     /* size of usable memory: */
     Parrot_PIC *pic;                   /* from rear */
-    Parrot_MIC **mic;                  /* idx access to allocated MICs */
+    Parrot_MIC *mic;                   /* idx access to allocated MICs */
     size_t n_mics;                     /* range check, debugging mainly */
 } Parrot_PIC_store;
 
@@ -69,6 +69,10 @@
 Parrot_MIC* parrot_PIC_alloc_mic(Interp*, size_t n);
 Parrot_PIC* parrot_PIC_alloc_pic(Interp*);
 
+void parrot_pic_find_infix_v_pp(Interp *, PMC *left, PMC *right,
+                Parrot_MIC *mic, opcode_t *cur_opcode);
+void * parrot_pic_opcode(Interp *, int op);
+
 #endif /* PARROT_PIC_H_GUARD */
 
 /*

Modified: trunk/ops/ops.num
==============================================================================
--- trunk/ops/ops.num   (original)
+++ trunk/ops/ops.num   Thu Apr 28 04:46:37 2005
@@ -1328,3 +1328,5 @@
 find_name_p_s                  1298
 find_name_p_sc                 1299
 backtrace                      1300
+pic_infix___ic_p_p             1301
+pic_inline_sub___ic_p_p        1302

Added: trunk/ops/pic.ops
==============================================================================
--- (empty file)
+++ trunk/ops/pic.ops   Thu Apr 28 04:46:37 2005
@@ -0,0 +1,141 @@
+/*
+** pic.ops
+*/
+
+#define DEPRECATED internal_exception(UNIMPLEMENTED, "you shouldn't see this")
+
+#include "parrot/oplib/ops.h"
+
+VERSION = PARROT_VERSION;
+
+=head1 NAME
+
+pic.ops - PIC (Polymorphic Inline Cache) opcode variants
+
+=cut
+
+=head1 DESCRIPTION
+
+During predereferencing opcodes that allow caching are rewritten so that
+equivalent opcodes in this file are used. User code MUST never emit these
+opcodes directly.
+
+###############################################################################
+
+=head2 General infix operations
+
+These operations take an infix operation number and PMC arguments.
+
+=over 4
+
+########################################
+
+=cut
+
+=item C<pic_infix__(inconst INT, in PMC, in PMC)>
+
+One for fun and MOPS.
+
+=cut
+
+inline op pic_infix__(inconst INT, in PMC, in PMC) :pic {
+    Parrot_MIC *mic;
+    Parrot_PIC_lru *lru;
+    PMC *left, *right;
+    INTVAL lr_types;
+
+    mic = (Parrot_MIC *) cur_opcode[1];
+    left = $2;
+    right = $3;
+    lru = &mic->lru;
+    lr_types = (left->vtable->base_type << 16) | right->vtable->base_type;
+    if (lru->lr_type == lr_types) {
+runit_v_pp:
+       ((mmd_f_v_pp)lru->f.real_function)(interpreter, left, right);
+       goto NEXT();
+    }
+    if (mic->pic) {
+       lru = mic->pic->lru;
+       if (lru->lr_type == lr_types)
+           goto runit_v_pp;
+       if (++lru->lr_type == lr_types)
+           goto runit_v_pp;
+       if (++lru->lr_type == lr_types)
+           goto runit_v_pp;
+       mic->pic->miss_count++;
+       /*
+        * TODO if we got too often here just do a dynamic lookup
+        */
+    }
+    parrot_pic_find_infix_v_pp(interpreter, left, right, mic, cur_opcode);
+    /* rerun this opcode */
+    goto OFFSET(0);
+}
+
+=item C<pic_inline_sub__(inconst INT, in PMC, in PMC)>
+
+And for more fun an inlined variant too.
+
+=cut
+
+inline op pic_inline_sub__(inconst INT, in PMC, in PMC) :pic {
+    Parrot_MIC *mic;
+    Parrot_PIC_lru *lru;
+    PMC *left, *right;
+    INTVAL lr_types, lt, rt;
+
+    left = $2;
+    mic = (Parrot_MIC *) cur_opcode[1];
+    lt = left->vtable->base_type;
+    right = $3;
+    lru = &mic->lru;
+    rt = right->vtable->base_type;
+    lr_types = (lt << 16) | rt;
+    if (lru->lr_type == lr_types) {
+       INTVAL a = lt == enum_class_Integer ? PMC_int_val(left) :
+           VTABLE_get_integer(interpreter, left);
+       INTVAL b = rt == enum_class_Integer ? PMC_int_val(right) :
+           VTABLE_get_integer(interpreter, right);
+       INTVAL c = a - b;
+       if ((c^a) >= 0 || (c^~b) >= 0) {
+           if (lt == enum_class_Integer)
+               PMC_int_val(left) = c;
+           else
+               VTABLE_set_integer_native(interpreter, left, c);
+       }
+       else {
+           if (PARROT_ERRORS_test(interpreter,PARROT_ERRORS_OVERFLOW_FLAG)) {
+               real_exception(interpreter, NULL, ERR_OVERFLOW,
+                       "Integer overflow");
+           }
+           /* TODO preserve type system */
+           VTABLE_morph(interpreter, left, enum_class_BigInt);
+           VTABLE_set_integer_native(interpreter, left, a);
+           mmd_dispatch_p_pip(interpreter, left, b, left, MMD_SUBTRACT);
+       }
+    }
+    else {
+        ((void**)cur_opcode)[0] =
+            parrot_pic_opcode(interpreter, PARROT_OP_pic_infix___ic_p_p);
+       goto OFFSET(0);
+    }
+    goto NEXT();
+}
+
+
+=back
+
+=cut
+
+###############################################################################
+
+=head1 COPYRIGHT
+
+Copyright (C) 2005 The Perl Foundation.  All rights reserved.
+
+=head1 LICENSE
+
+This program is free software. It is subject to the same license
+as the Parrot interpreter itself.
+
+=cut

Modified: trunk/src/interpreter.c
==============================================================================
--- trunk/src/interpreter.c     (original)
+++ trunk/src/interpreter.c     Thu Apr 28 04:46:37 2005
@@ -337,8 +337,10 @@
     load_prederef(interpreter, which);
     if (!interpreter->code->prederef.code) {
         size_t N = interpreter->code->base.size;
-        size_t i;
+        opcode_t *pc = interpreter->code->base.data;
+        size_t i, n, n_pics;
         void *pred_func;
+        op_info_t *opinfo;
 /* Parrot_memalign_if_possible in OpenBSD allocates 256 if you ask for 312
    -- Need to verify this, it may have been a bug elsewhere. If it works now,
    we can remove the mem_sys_allocate_zeroed line below. */
@@ -355,11 +357,23 @@
         else
             pred_func = ((void **)
                     interpreter->op_lib->op_func_table)[CORE_OPS_prederef__];
-        for (i = 0; i < N; i++) {
+        for (i = n_pics = 0; i < N; ) {
+            opinfo = &interpreter->op_info_table[*pc];
             temp[i] = pred_func;
+            n = opinfo->arg_count;
+            pc += n;
+            i += n;
+            /* count ops that need a PIC */
+            if (parrot_PIC_op_is_cached(interpreter, *pc))
+                n_pics++;
         }
 
         interpreter->code->prederef.code = temp;
+        /* allocate pic store */
+        if (n_pics) {
+            /* pic_index is starting from 1 */
+            parrot_PIC_alloc_store(interpreter, interpreter->code, n_pics + 1);
+        }
     }
 }
 

Modified: trunk/src/mmd.c
==============================================================================
--- trunk/src/mmd.c     (original)
+++ trunk/src/mmd.c     Thu Apr 28 04:46:37 2005
@@ -47,18 +47,6 @@
 static void mmd_create_builtin_multi_meth_2(Interp *,
         INTVAL func_nr, INTVAL type, INTVAL right, funcptr_t func_ptr);
 
-typedef PMC*    (*mmd_f_p_ppp)(Interp *, PMC *, PMC *, PMC *);
-typedef PMC*    (*mmd_f_p_pip)(Interp *, PMC *, INTVAL, PMC *);
-typedef PMC*    (*mmd_f_p_pnp)(Interp *, PMC *, FLOATVAL, PMC *);
-typedef PMC*    (*mmd_f_p_psp)(Interp *, PMC *, STRING *, PMC *);
-
-typedef void    (*mmd_f_v_pp)(Interp *, PMC *, PMC *);
-typedef void    (*mmd_f_v_pi)(Interp *, PMC *, INTVAL);
-typedef void    (*mmd_f_v_pn)(Interp *, PMC *, FLOATVAL);
-typedef void    (*mmd_f_v_ps)(Interp *, PMC *, STRING *);
-
-typedef INTVAL  (*mmd_f_i_pp) (Interp *, PMC *, PMC *);
-
 #ifndef NDEBUG
 static void
 dump_mmd(Interp *interpreter, INTVAL function)

Modified: trunk/src/packdump.c
==============================================================================
--- trunk/src/packdump.c        (original)
+++ trunk/src/packdump.c        Thu Apr 28 04:46:37 2005
@@ -109,7 +109,7 @@
             STRING *a_key = const_string(interpreter, "(keyed)");
             STRING *null = const_string(interpreter, "(null)");
             opcode_t *code_start =
-                interpreter->code->cur_cs->base.data;
+                interpreter->code->base.data;
             switch (pmc->vtable->base_type) {
                 case enum_class_Sub:
                 case enum_class_Coroutine:

Modified: trunk/src/packfile.c
==============================================================================
--- trunk/src/packfile.c        (original)
+++ trunk/src/packfile.c        Thu Apr 28 04:46:37 2005
@@ -1217,6 +1217,10 @@
     cur_cs->const_table = (struct PackFile_ConstTable*) seg;
     cur_cs->const_table->code = cur_cs;
 
+    seg = create_seg(interpreter, &pf->directory,
+            PF_UNKNOWN_SEG, "PIC_idx", file_name, add);
+    cur_cs->pic_index = seg;
+
     return cur_cs;
 }
 /*

Modified: trunk/src/pdump.c
==============================================================================
--- trunk/src/pdump.c   (original)
+++ trunk/src/pdump.c   Thu Apr 28 04:46:37 2005
@@ -263,13 +263,13 @@
         FILE *fp;
 
         size = PackFile_pack_size(interpreter,
-                interpreter->code) * sizeof(opcode_t);
+                interpreter->code->base.pf) * sizeof(opcode_t);
         pack = (opcode_t*) mem_sys_allocate(size);
         if (!pack) {
             printf("out of mem\n");
             exit(1);
         }
-        PackFile_pack(interpreter, interpreter->code, pack);
+        PackFile_pack(interpreter, interpreter->code->base.pf, pack);
         if (strcmp (file, "-") == 0)
             fp = stdout;
         else if ((fp = fopen(file, "wb")) == 0) {

Modified: trunk/src/pic.c
==============================================================================
--- trunk/src/pic.c     (original)
+++ trunk/src/pic.c     Thu Apr 28 04:46:37 2005
@@ -12,11 +12,60 @@
 prederefed run cores. Additionally opcodes that do some kind of lookup
 like C<new_p_sc> are changed to faster variants.
 
-TODO For non-prederefed run-cores there's a less efficient variant which
+For non-prederefed run-cores there's a less efficient variant which
 is basically:
 
- * the bytecode segment has an index per cached opcode
+ * the bytecode segment has an index per cached opcode (code->pic_index)
  * this index points into pic_store
+ * TODO use the cache in opcodes
+
+=head1 OPERATION SCHEME
+
+Given this bytecode:
+
+    0               1              2    3    4                5
+  +--------------+---------------+----+----+-----------------+----------+
+  | infix_ic_p_p | .MMD_SUBTRACT | P5 | P6 | callmethodcc_sc | "method" |
+  +--------------+---------------+----+----+-----------------+----------+
+
+In init_prederef the opcodes are replaced with prederef__, operands are
+replaced with their addresses:
+
+    0               1              2    3    4                5
+  +--------------+---------------+----+----+-----------------+----------+
+  | prederef__   |&.MMD_SUBTRACT | &P5| &P6| prederef__      |&"method" |
+  +--------------+---------------+----+----+-----------------+----------+
+
+we have code->pic_index with an index into pic_store - the pic_index is
+half the size of the bytecode and addressed with pc_offset/2:
+
+    0   1   2
+  +---+---+---+
+  | 1 |   | 2 |
+  +---+---+---+
+
+During predereferencing the opcode gets rewritten to the PIC variant,
+the constant infix operation number is replaced with a pointer to the MIC
+in the pic_store at the index pic_index:
+
+    0                    1     2    3
+  +--------------------+-----+----+----+-----------------------+-----+
+  | pic_infix___ic_p_p | MIC1|&P5 |&P6 | pic_callmethodcc___sc | MIC2|
+  +--------------------+-----+----+----+-----------------------+-----+
+
+This can be further optimized due to static inlining:
+
+    0                    1     2    3
+  +--------------------+-----+----+----+-----------------------+-----+
+  | pic_inline_sub_p_p | MIC1|&P5 |&P6 | pic_callmethodcc___sc | MIC2|
+  +--------------------+-----+----+----+-----------------------+-----+
+
+The opcode is an opcode number for the switched core or the actual code address
+for the direct-threaded CGP core. With a little help of the JIT system we could
+also dynamicall create inlined code.
+
+Runcores with r/o (mmaped) bytecode can't be rewritten in this way, the
+lookup of the cache has to be done in the opcode itself.
 
 =head2 Functions
 
@@ -29,10 +78,24 @@
 #include "parrot/parrot.h"
 #include "parrot/oplib/ops.h"
 #include <assert.h>
+#ifdef HAVE_COMPUTED_GOTO
+#  include "parrot/oplib/core_ops_cgp.h"
+#endif
+
+/* needs a Makefile dependency */
+/* #include "../classes/pmc_integer.h" */
+
+extern void Parrot_Integer_i_subtract_Integer(Interp* , PMC* pmc, PMC* value);
 
 #define OP_AS_OFFS(o) (_reg_base + ((opcode_t*)cur_opcode)[o])
 
 /*
+ * hack to turn on inlining - just sub_p_p for mops done
+ */
+
+#define ENABLE_INLINING 1
+
+/*
 
 =item C<void parrot_PIC_alloc_store(Interp *, struct PackFile_ByteCode *, 
size_t n);>
 
@@ -73,7 +136,7 @@
 
     store->pic    = (Parrot_PIC*)((char *)store + size);
     store->usable = poly;
-    store->mic    = (Parrot_MIC**)((char*)store + sizeof(Parrot_PIC_store));
+    store->mic    = (Parrot_MIC*)((char*)store + sizeof(Parrot_PIC_store));
     store->n_mics = n;
 }
 
@@ -101,6 +164,9 @@
 int
 parrot_PIC_op_is_cached(Interp *interpreter, int op_code)
 {
+    switch (op_code) {
+        case PARROT_OP_infix_ic_p_p: return 1;
+    }
     return 0;
 }
 /*
@@ -123,7 +189,7 @@
 
     store = interpreter->code->pic_store;
     assert(n < store->n_mics);
-    return store->mic[n];
+    return store->mic + n;
 }
 
 Parrot_PIC*
@@ -168,6 +234,22 @@
 */
 
 
+void *
+parrot_pic_opcode(Interp *interpreter, int op)
+{
+    int core = interpreter->run_core;
+    op_lib_t *cg_lib;
+
+    if (core == PARROT_SWITCH_CORE)
+        return (void*) op;
+#ifdef HAVE_COMPUTED_GOTO
+    cg_lib = PARROT_CORE_CGP_OPLIB_INIT(1);
+    return ((void**)cg_lib->op_func_table)[op];
+#else
+    return NULL;
+#endif
+}
+
 #define N_STATIC_TYPES 500
 static INTVAL pmc_type_numbers[N_STATIC_TYPES];
 
@@ -206,9 +288,26 @@
                 op = PARROT_OP_new_p_ic;
             }
             break;
+        case PARROT_OP_infix_ic_p_p:
+            {
+                Parrot_MIC *mic;
+                size_t n;
+                struct PackFile_ByteCode *cs = interpreter->code;
+
+                n = cur_opcode - (opcode_t*)cs->prederef.code;
+                /*
+                 * pic_index is half the size of the code
+                 */
+                n = cs->pic_index->data[n / 2];
+                mic = parrot_PIC_alloc_mic(interpreter, n);
+                mic->m.func_nr = *(INTVAL*) cur_opcode[1];
+                pc_pred[1] = (void*) mic;
+                op = PARROT_OP_pic_infix___ic_p_p;
+            }
+            break;
     }
     /*
-     * else set default prederef code address
+     * rewrite opcode
      */
     if (core == PARROT_SWITCH_CORE)
         *pc_pred = (void**) op;
@@ -216,6 +315,88 @@
         *pc_pred = ((void **)prederef_op_func)[op];
 }
 
+static void
+parrot_pic_move(Interp* interpreter, Parrot_MIC *mic)
+{
+    Parrot_PIC* pic;
+
+    /*
+     * MIC slot is empty - use it
+     */
+    if (!mic->lru.lr_type)
+        return;
+    /*
+     * need more cache slots - allocate one PIC
+     */
+    if (!mic->pic) {
+        mic->pic = parrot_PIC_alloc_pic(interpreter);
+    }
+    else {
+        /*
+         * PIC was already used - shift slots up
+         */
+        pic = mic->pic;
+        pic->lru[2].lr_type = pic->lru[1].lr_type;
+        pic->lru[2].f.sub = pic->lru[1].f.sub;
+        pic->lru[1].lr_type = pic->lru[0].lr_type;
+        pic->lru[1].f.sub = pic->lru[0].f.sub;
+        pic->lru[0].lr_type = mic->lru.lr_type;
+        pic->lru[0].f.sub = mic->lru.f.sub;
+        mic->lru.lr_type = 0;
+    }
+}
+
+void
+parrot_pic_find_infix_v_pp(Interp *interpreter, PMC *left, PMC *right,
+                Parrot_MIC *mic, opcode_t *cur_opcode)
+{
+    funcptr_t func;
+    int is_pmc;
+    INTVAL left_type, right_type;
+    /*
+     * if 2 threads are entering here, there is a chance
+     * that one moves the lru structure under the other thread
+     * and vv - just lock in case
+     *
+     * TODO
+     *
+     * if (TRY_LOCK_INTERPRETER(i) == EBUSY)
+     *      return;  - reexec
+     */
+    LOCK_INTERPRETER(interpreter);
+    /*
+ * move entries back and set topmost entry
+ */
+    parrot_pic_move(interpreter, mic);
+    /*
+     * get real dispatch function
+     */
+    left_type = left->vtable->base_type;
+    right_type = right->vtable->base_type;
+    func = get_mmd_dispatch_type(interpreter,
+            mic->m.func_nr, left_type, right_type, &is_pmc);
+    if (is_pmc) {
+        /* set prederef code address to orig slot for now
+         */
+        ((void**)cur_opcode)[0] =
+            parrot_pic_opcode(interpreter, PARROT_OP_infix_ic_p_p);
+        mic->lru.f.sub = (PMC*)F2DPTR(func);
+    }
+    else {
+        int op = PARROT_OP_pic_infix___ic_p_p;
+
+#if ENABLE_INLINING
+        if (func == (funcptr_t)Parrot_Integer_i_subtract_Integer && !mic->pic)
+            op = PARROT_OP_pic_inline_sub___ic_p_p;
+#endif
+        ((void**)cur_opcode)[0] =
+            parrot_pic_opcode(interpreter, op);
+        mic->lru.f.real_function = func;
+    }
+    mic->lru.lr_type = (left_type << 16) | right_type;
+    UNLOCK_INTERPRETER(interpreter);
+}
+
 /*
 
 =back
@@ -227,7 +408,7 @@
 =head1 SEE ALSO
 
 F<src/mmd.c>, F<src/object.c>, F<src/interpreter.c>, F<ops/core_ops_cgp.c>,
-F<include/parrot/pic.h>
+F<include/parrot/pic.h>, F<ops/pic.ops>
 
 =cut
 

Reply via email to