Commits

Mark Shannon committed 087c67d Draft

Add verisons of BINARY_OP taking constants as left or right operand.

Comments (0)

Files changed (14)

HotPy/gen_format_code.py

     'K', 'kkK', 'r', 'rr', 'rrr', 'E', 'rrK',
     'o', 'oo', 'ro', 'rro', 'rrro', 'oK', 'rK', 'rrk',
     'rKE', 'rKKE', 'roK', 'rroK', 'rok', 'rrkkk',
-    'rE', 'rrE', 'rroE', 'rrroE',
+    'rE', 'rrE', 'rroE', 'rrroE', 'rokk',
     'rokkkE', 'rrok', 'p', 'oKKK',
     'rrooE', 'rroooE', 'rroo', 'roo',
     'oKE', 'roKE', 'rrKE', 'rroKE', 'rrrKE', 'rrrokE'

HotPy/trace_makeopcodetargets.py

                  'const_to_register', 'exit_if_false', 'exit_if_true',
                  'ensure_type', 'ensure_value', 'ensure_slot',
                  'value_from_object_dict_or_exit_const', 'setup_block',
-                 'poly_type_exit', 'two_move', 'copy_move', 'fast_load_global' ]
+                 'poly_type_exit', 'two_move', 'copy_move', 'fast_load_global',
+                 'binary_op_kv', 'binary_op_vk' ]
 
 ops = [ '' ] * 256
 op_used = [ False ] * 256

Include/optimiser.h

     void (*leave_frame)(HotPyOptimiser*);
     void (*leave_gen_frame)(HotPyOptimiser*);
     void (*binary_op)(HotPyOptimiser*, int, PyObject*);
+    void (*binary_op_kv)(HotPyOptimiser*, int, PyObject*, PyObject*);
+    void (*binary_op_vk)(HotPyOptimiser*, int, PyObject*, PyObject*);
     void (*tuple_concat)(HotPyOptimiser*);
     void (*pick)(HotPyOptimiser*, int);
     void (*bind_callable)(HotPyOptimiser*, PyTypeObject*);

Include/register_macros.h

 #define FORMAT_ID_roK 15
 #define FORMAT_ID_roKE 16
 #define FORMAT_ID_rok 17
-#define FORMAT_ID_rokkkE 18
-#define FORMAT_ID_roo 19
-#define FORMAT_ID_rr 20
-#define FORMAT_ID_rrE 21
-#define FORMAT_ID_rrK 22
-#define FORMAT_ID_rrKE 23
-#define FORMAT_ID_rrk 24
-#define FORMAT_ID_rrkkk 25
-#define FORMAT_ID_rro 26
-#define FORMAT_ID_rroE 27
-#define FORMAT_ID_rroK 28
-#define FORMAT_ID_rroKE 29
-#define FORMAT_ID_rrok 30
-#define FORMAT_ID_rroo 31
-#define FORMAT_ID_rrooE 32
-#define FORMAT_ID_rroooE 33
-#define FORMAT_ID_rrr 34
-#define FORMAT_ID_rrrKE 35
-#define FORMAT_ID_rrro 36
-#define FORMAT_ID_rrroE 37
-#define FORMAT_ID_rrrokE 38
+#define FORMAT_ID_rokk 18
+#define FORMAT_ID_rokkkE 19
+#define FORMAT_ID_roo 20
+#define FORMAT_ID_rr 21
+#define FORMAT_ID_rrE 22
+#define FORMAT_ID_rrK 23
+#define FORMAT_ID_rrKE 24
+#define FORMAT_ID_rrk 25
+#define FORMAT_ID_rrkkk 26
+#define FORMAT_ID_rro 27
+#define FORMAT_ID_rroE 28
+#define FORMAT_ID_rroK 29
+#define FORMAT_ID_rroKE 30
+#define FORMAT_ID_rrok 31
+#define FORMAT_ID_rroo 32
+#define FORMAT_ID_rrooE 33
+#define FORMAT_ID_rroooE 34
+#define FORMAT_ID_rrr 35
+#define FORMAT_ID_rrrKE 36
+#define FORMAT_ID_rrro 37
+#define FORMAT_ID_rrroE 38
+#define FORMAT_ID_rrrokE 39
 
 #define FORMAT_E \
     int e0; \
     k0 = (instruction_word >> 24); \
     assert(consistent_format(next_instr[-1] & 255, "rok"))
 
+#define FORMAT_rokk \
+    int r0, r1, k0, k1; \
+    r0 = (instruction_word >> 8) & 255; \
+    r1 = (instruction_word >> 16) & 255; \
+    k0 = (instruction_word >> 24); \
+    instruction_word = *next_instr++; \
+    k1 = instruction_word & 255; \
+    assert(consistent_format(next_instr[-2] & 255, "rokk"))
+
 #define FORMAT_rokkkE \
     int r0, r1, k0, k1, k2, e0; \
     r0 = (instruction_word >> 8) & 255; \

Include/register_write_functions.h

 }
 
 static void
+write_rokk(HotPyOptimiser *x, int op, int k0, int k1)
+{
+    int r0 = pop_as_register(x, 0);
+    int out0;
+    assert(k0 >= 0);
+    assert(k1 >= 0);
+    out0 = choose_register(x);
+    assert(consistent_format(op, "rokk"));
+    write_word_1111(x, op, r0, out0, k0);
+    write_word_1111(x, k1, 0, 0, 0);
+    push_register(x, out0);
+}
+
+static void
 write_rokkkE(HotPyOptimiser *x, int op, int k0, int k1, int k2, int exit)
 {
     int r0 = pop_as_register(x, 0);
 }
 
 void
+print_rokk(FILE* out, uint32_t **instr_ptr)
+{
+    uint32_t *next_instr = *instr_ptr;
+    uint32_t instruction_word = *next_instr++;
+    int op = instruction_word & 255;
+    FORMAT_rokk;
+    *instr_ptr = next_instr;
+    fprintf(out, "%s r%d o%d k%d k%d\n", _HotPy_Instruction_Names[op], r0, r1, k0, k1);
+}
+
+void
 print_rokkkE(FILE* out, uint32_t **instr_ptr)
 {
     uint32_t *next_instr = *instr_ptr;
 }
 
 static uint32_t *
+defuses_for_rokk(uint32_t *next_instr, int *defs, int *uses)
+{
+    uint32_t instruction_word = *next_instr++;
+    FORMAT_rokk;
+    *uses++ = r0;
+    *defs++ = r1;
+    (void)k0;
+    (void)k1;
+    *defs++ = -1;
+    *uses++ = -1;
+    return next_instr;
+}
+
+static uint32_t *
 defuses_for_rokkkE(uint32_t *next_instr, int *defs, int *uses)
 {
     uint32_t instruction_word = *next_instr++;
 }
 
 static uint32_t *
+relabel_uses_rokk(uint32_t *next_instr, unsigned char *relabel_table)
+{
+    int reg;
+    uint32_t instruction_word = *next_instr++;
+    (void)instruction_word; /* Stop compiler complaining */
+    reg = (instruction_word >> 8) & 255; \
+    instruction_word = (instruction_word & 0xffff00ff) | (relabel_table[reg] << 8);
+    next_instr[-1] = instruction_word;
+    instruction_word = *next_instr++;
+    next_instr[-1] = instruction_word;
+    return next_instr;
+}
+
+static uint32_t *
 relabel_uses_rokkkE(uint32_t *next_instr, unsigned char *relabel_table)
 {
     int reg;
 }
 
 static uint32_t *
+relabel_defs_rokk(uint32_t *next_instr, unsigned char *relabel_table)
+{
+    int reg;
+    uint32_t instruction_word = *next_instr++;
+    (void)instruction_word; /* Stop compiler complaining */
+    reg = (instruction_word >> 16) & 255; \
+    instruction_word = (instruction_word & 0xff00ffff) | (relabel_table[reg] << 16);
+    next_instr[-1] = instruction_word;
+    instruction_word = *next_instr++;
+    next_instr[-1] = instruction_word;
+    return next_instr;
+}
+
+static uint32_t *
 relabel_defs_rokkkE(uint32_t *next_instr, unsigned char *relabel_table)
 {
     int reg;
 }
 
 static HotPyContext *
+get_exit_context_rokk(uint32_t *instr, PyObject *exits)
+{
+   return NULL;
+}
+
+static HotPyContext *
 get_exit_context_rokkkE(uint32_t *instr, PyObject *exits)
 {
     uint32_t instruction_word = *instr++;

Include/trace_opcode.h

 #define TWO_MOVE 212
 #define COPY_MOVE 213
 #define FAST_LOAD_GLOBAL 214
-/* Opcode 215 unused */
-/* Opcode 216 unused */
+#define BINARY_OP_KV 215
+#define BINARY_OP_VK 216
 /* Opcode 217 unused */
 /* Opcode 218 unused */
 /* Opcode 219 unused */
 "TWO_MOVE",
 "COPY_MOVE",
 "FAST_LOAD_GLOBAL",
-NULL,
-NULL,
+"BINARY_OP_KV",
+"BINARY_OP_VK",
 NULL,
 NULL,
 NULL,
 extern char *_HotPy_Instruction_Names[];
 #endif
 
-#define USED_OPCODES 213
+#define USED_OPCODES 217
 

Python/register_interpreter.c

             SET_REGISTER(r2, x);
             DISPATCH();
 
+        /* Should this have an exit? */
+        TARGET(BINARY_OP_KV)
+            FORMAT_rokk;
+            PyObject *l = CONSTANT(k1);
+            PyObject *r = registers[r0];
+            PyObject *x = _PyCallBinaryFastFunction(k0, l, r);
+            if (x == NULL) {
+                goto on_error;
+            }
+            SET_REGISTER(r1, x);
+            DISPATCH();
+
+        /* Should this have an exit? */
+        TARGET(BINARY_OP_VK)
+            FORMAT_rokk;
+            PyObject *l = registers[r0];
+            PyObject *r = CONSTANT(k1);
+            PyObject *x = _PyCallBinaryFastFunction(k0, l, r);
+            if (x == NULL) {
+                goto on_error;
+            }
+            SET_REGISTER(r1, x);
+            DISPATCH();
+
         TARGET(SET_LASTI)
             FORMAT_K;
             f->f_lasti = k0;

Python/register_opcode_targets.h

 &&TARGET_TWO_MOVE,
 &&TARGET_COPY_MOVE,
 &&TARGET_FAST_LOAD_GLOBAL,
-&&_unknown_opcode,
-&&_unknown_opcode,
+&&TARGET_BINARY_OP_KV,
+&&TARGET_BINARY_OP_VK,
 &&_unknown_opcode,
 &&_unknown_opcode,
 &&_unknown_opcode,

Python/trace_D_O_C.c

 }
 
 static void
+binary_op_kv(HotPyOptimiser *x, int func, PyObject *k, PyObject *res)
+{
+    /* This is just for completeness, don't bother optimising */
+    HotPy_DOC *opt = (HotPy_DOC *)x;
+    PyObject *v = POP();
+    materialise(x, v);
+    x->next->binary_op_kv(x->next, func, k, res);
+    PUSH(real_value());
+    return;
+}
+
+static void
+binary_op_vk(HotPyOptimiser *x, int func, PyObject *k, PyObject *res)
+{
+    /* This is just for completeness, don't bother optimising */
+    HotPy_DOC *opt = (HotPy_DOC *)x;
+    PyObject *v = POP();
+    materialise(x, v);
+    x->next->binary_op_vk(x->next, func, k, res);
+    PUSH(real_value());
+    return;
+}
+
+static void
 binary_op(HotPyOptimiser *x, int func, PyObject *res)
 {
     HotPy_DOC *opt = (HotPy_DOC *)x;
     PyObject *v = POP();
     PyObject *w = POP();
-    if (KIND(v) == DK_CONSTANT && KIND(w) == DK_CONSTANT &&
-        is_pure(func, VALUE(w),VALUE(v))) {
+    if (KIND(v) == DK_CONSTANT) {
+        if (KIND(w) == DK_CONSTANT && is_pure(func, VALUE(w),VALUE(v))) {
 #ifdef Py_DEBUG
-        PyObject *x = _PyCallBinaryFastFunction(func, VALUE(w), VALUE(v));
-        assert(PyObject_RichCompareBool(res, x, Py_EQ) == 1);
+            PyObject *x = _PyCallBinaryFastFunction(func, VALUE(w), VALUE(v));
+            assert(PyObject_RichCompareBool(res, x, Py_EQ) == 1);
 #endif
-        Py_DECREF(v);
-        Py_DECREF(w);
-        PUSH(get_constant(opt, res));
+            Py_DECREF(v);
+            Py_DECREF(w);
+            PUSH(get_constant(opt, res));
+        }
+        else {
+            materialise(x, w);
+            x->next->binary_op_vk(x->next, func, VALUE(v), res);
+            Py_DECREF(v);
+            PUSH(real_value());
+        }
     }
     else {
-        materialise(x, w);
-        materialise(x, v);
-        x->next->binary_op(x->next, func, res);
+        if (KIND(w) == DK_CONSTANT) {
+            materialise(x, v);
+            x->next->binary_op_kv(x->next, func, VALUE(w), res);
+            Py_DECREF(w);
+        }
+        else {
+            materialise(x, w);
+            materialise(x, v);
+            x->next->binary_op(x->next, func, res);
+        }
         PUSH(real_value());
     }
     SHOW_STACK();
     x->opt_base.unrolling = unrolling;
     x->opt_base.fail = fail;
     x->opt_base.binary_op = binary_op;
+    x->opt_base.binary_op_kv = binary_op_kv;
+    x->opt_base.binary_op_vk = binary_op_vk;
     x->opt_base.load_fast = load_fast;
     x->opt_base.store_fast = store_fast;
     x->opt_base.delete_fast = delete_fast;

Python/trace_logger.c

     x->next->binary_op(x->next, func, res);
 }
 
+static void
+binary_op_vk(HotPyOptimiser *x, int func, PyObject *k, PyObject *res)
+{
+    fprintf(OUT, "%sbinary op vk %d (right=", INDENT, func);
+    print_str(OUT, k);
+    fprintf(OUT, ")->");
+    print_str(OUT, (PyObject *)Py_TYPE(res));
+    fprintf(OUT, "\n");
+    x->next->binary_op_vk(x->next, func, k, res);
+}
+
+static void
+binary_op_kv(HotPyOptimiser *x, int func, PyObject *k, PyObject *res)
+{
+    fprintf(OUT, "%sbinary op kv %d (left=", INDENT, func);
+    print_str(OUT, k);
+    fprintf(OUT, ")->");
+    print_str(OUT, (PyObject *)Py_TYPE(res));
+    fprintf(OUT, "\n");
+    x->next->binary_op_kv(x->next, func, k, res);
+}
+
 static HotPyContext*
 from_object_dict_fast(HotPyOptimiser *x, int dict_offset,
                       PyDictKeysObject *keys, PyObject *key)
     x->opt_base.leave_frame = leave_frame;
     x->opt_base.leave_gen_frame = leave_gen_frame;
     x->opt_base.binary_op = binary_op;
+    x->opt_base.binary_op_kv = binary_op_kv;
+    x->opt_base.binary_op_vk = binary_op_vk;
     x->opt_base.tuple_concat = tuple_concat;
     x->opt_base.setup_block = setup_block;
     x->opt_base.pick = pick;

Python/trace_opcode_targets.h

 &&_unknown_opcode, /* TWO_MOVE */
 &&_unknown_opcode, /* COPY_MOVE */
 &&_unknown_opcode, /* FAST_LOAD_GLOBAL */
-&&_unknown_opcode,
-&&_unknown_opcode,
+&&_unknown_opcode, /* BINARY_OP_KV */
+&&_unknown_opcode, /* BINARY_OP_VK */
 &&_unknown_opcode,
 &&_unknown_opcode,
 &&_unknown_opcode,

Python/trace_recorder_register.c

         case BINARY_OP:
             print_rrok(out, &code);
             break;
+        case BINARY_OP_KV: case BINARY_OP_VK:
+            print_rokk(out, &code);
+            break;
         case SET_LASTI:
             print_K(out, &code);
             break;
         case ENSURE_TYPE: case ENSURE_VALUE: case POLY_EXIT:
         case POLY_TYPE_EXIT: case  GEN_CHECK_OR_EXIT:
         case ENSURE_SLOT: case BINARY_OP:
+        case BINARY_OP_KV: case BINARY_OP_VK:
         case LOAD_FROM_GLOBAL_AND_BUILTINS:
         case HAS_SPECIAL: case BUILD_SLICE: case OVERRIDES:
         case VALUE_FROM_OBJECT_DICT_OR_EXIT_CONST:
         case ENSURE_TYPE: case ENSURE_VALUE: case POLY_EXIT:
         case POLY_TYPE_EXIT: case  GEN_CHECK_OR_EXIT:
         case ENSURE_SLOT: case BINARY_OP:
+        case BINARY_OP_KV: case BINARY_OP_VK:
         case LOAD_FROM_GLOBAL_AND_BUILTINS:
         case HAS_SPECIAL: case BUILD_SLICE: case OVERRIDES:
         case VALUE_FROM_OBJECT_DICT_OR_EXIT_CONST:
 }
 
 static void
+binary_op_vk(HotPyOptimiser *x, int func, PyObject *k, PyObject *res)
+{
+    HotPyTraceRecorder *opt = (HotPyTraceRecorder *)x;
+    int index = index_for_constant(opt, k);
+    write_rokk(x, BINARY_OP_VK, func, index);
+    CONSISTENT(x);
+}
+
+static void
+binary_op_kv(HotPyOptimiser *x, int func, PyObject *k, PyObject *res)
+{
+    HotPyTraceRecorder *opt = (HotPyTraceRecorder *)x;
+    int index = index_for_constant(opt, k);
+    write_rokk(x, BINARY_OP_KV, func, index);
+    CONSISTENT(x);
+}
+
+static void
 set_lasti(HotPyOptimiser *x, int lasti)
 {
     write_K(x, SET_LASTI, lasti);
     x->opt_base.leave_gen_frame = leave_frame;
     x->opt_base.leave_frame = leave_frame;
     x->opt_base.binary_op = binary_op;
+    x->opt_base.binary_op_kv = binary_op_kv;
+    x->opt_base.binary_op_vk = binary_op_vk;
     x->opt_base.tuple_concat = tuple_concat;
     x->opt_base.pick = pick;
     x->opt_base.bind_callable = bind_callable;
         return defuses_for_E(instr, defs, uses);
     case BINARY_OP:
         return defuses_for_rrok(instr, defs, uses);
+    case BINARY_OP_KV: case BINARY_OP_VK:
+         return defuses_for_rokk(instr, defs, uses);
     case SET_LASTI:
         return defuses_for_K(instr, defs, uses);
     case CONST_TO_REGISTER: case PICK: case LOAD_FAST: case BUILD_SET:
         return relabel_uses_E(instr, relabel_uses_table);
     case BINARY_OP:
         return relabel_uses_rrok(instr, relabel_uses_table);
+    case BINARY_OP_KV: case BINARY_OP_VK:
+        return relabel_uses_rokk(instr, relabel_uses_table);
     case SET_LASTI:
         return relabel_uses_K(instr, relabel_uses_table);
     case CONST_TO_REGISTER: case PICK: case LOAD_FAST: case BUILD_SET:
         return relabel_defs_E(instr, relabel_defs_table);
     case BINARY_OP:
         return relabel_defs_rrok(instr, relabel_defs_table);
+    case BINARY_OP_KV: case BINARY_OP_VK:
+        return relabel_defs_rokk(instr, relabel_defs_table);
     case SET_LASTI:
         return relabel_defs_K(instr, relabel_defs_table);
     case CONST_TO_REGISTER: case PICK: case LOAD_FAST: case BUILD_SET:
         return get_exit_context_E(instr, exits);
     case BINARY_OP:
         return get_exit_context_rrok(instr, exits);
+    case BINARY_OP_KV: case BINARY_OP_VK:
+        return get_exit_context_rokk(instr, exits);
     case SET_LASTI:
         return get_exit_context_K(instr, exits);
     case CONST_TO_REGISTER: case PICK: case LOAD_FAST: case BUILD_SET:

Python/trace_recorder_stack.c

 }
 
 static void
+binary_op_kv(HotPyOptimiser *x, int func, PyObject *k, PyObject *res)
+{
+    push_constant(x, k);
+    opcode(x, ROT_TWO);
+    opcode_with_arg(x, BINARY_OP, func);
+}
+
+static void
+binary_op_vk(HotPyOptimiser *x, int func, PyObject *k, PyObject *res)
+{
+    push_constant(x, k);
+    opcode_with_arg(x, BINARY_OP, func);
+}
+
+static void
 set_lasti(HotPyOptimiser *x, int line)
 {
     opcode_with_arg(x, SET_LASTI, line);
     x->opt_base.leave_gen_frame = leave_frame;
     x->opt_base.leave_frame = leave_frame;
     x->opt_base.binary_op = binary_op;
+    x->opt_base.binary_op_kv = binary_op_kv;
+    x->opt_base.binary_op_vk = binary_op_vk;
     x->opt_base.tuple_concat = tuple_concat;
     x->opt_base.pick = pick;
     x->opt_base.bind_callable = bind_callable;

Python/trace_specialiser.c

 }
 
 static void
+binary_op_kv(HotPyOptimiser *x, int func, PyObject *k, PyObject *res)
+{
+    /* This is just for completeness, don't bother optimising */
+    HotPySpecialiser *opt = (HotPySpecialiser *)x;
+    DROP();
+    x->next->binary_op_kv(x->next, func, k, res);
+    PUSH(new_unknown());
+    return;
+}
+
+static void
+binary_op_vk(HotPyOptimiser *x, int func, PyObject *k, PyObject *res)
+{
+    /* This is just for completeness, don't bother optimising */
+    HotPySpecialiser *opt = (HotPySpecialiser *)x;
+    DROP();
+    x->next->binary_op_vk(x->next, func, k, res);
+    PUSH(new_unknown());
+    return;
+}
+
+static void
 load_clear_register(HotPyOptimiser *x, int index)
 {
     HotPySpecialiser *opt = (HotPySpecialiser *)x;
         /* XXX - Check keys */
         DROP();
         DROP();
-       break;
+        break;
+    }
     case EXIT:
         break;
     case POP_EXIT_IF_FALSE:
     x->opt_base.unrolling = unrolling;
     x->opt_base.fail = fail;
     x->opt_base.binary_op = binary_op;
+    x->opt_base.binary_op_kv = binary_op_kv;
+    x->opt_base.binary_op_vk = binary_op_vk;
     x->opt_base.load_fast = load_fast;
     x->opt_base.store_fast = store_fast;
     x->opt_base.delete_fast = delete_fast;