Commits

Mark Shannon  committed 5c3ff2d Draft

Make freeing of registers explicit in register allocator

  • Participants
  • Parent commits b2bf1fb

Comments (0)

Files changed (9)

File HotPy/gen_format_code.py

     outputs = fmt.count('o')
     peek = 'p' in fmt
     for i in reversed(range(inputs)):
-        print ('    int r%d = pop_as_register(x, %d);' % (i+peek, i+peek), file = outfile)
+        print ('    int r%d = pop_as_register(x);' % (i+peek), file = outfile)
+    for i in reversed(range(inputs)):
+        print ('    free_register(x, r%d);' % (i+peek), file = outfile)
     if peek:
         assert fmt.count('p') == 1
         print ('    int r0 = peek_as_register(x);', file = outfile)
     if 'e' in fmt or 'E' in fmt:
         print ('    flush_stack(x);', file = outfile)
     for i in range(outputs):
-        print ('    out%d = choose_register(x);' % i, file = outfile)
+        print ('    out%d = push_as_register(x);' % i, file = outfile)
     print ('    assert(consistent_format(op, "%s"));' % fmt, file = outfile)
     size = 1
     layout = '1'
             parameters.append('0')
             layout += '1'
     write_word(layout, parameters, outfile)
-    for i in range(outputs):
-        print ('    push_register(x, out%d);' % i, file = outfile)
     print ('}\n', file = outfile)
 
 def defuses_function(fmt, outfile):

File HotPy/trace_makeopcodetargets.py

                  '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',
-                 'binary_op_kv', 'binary_op_vk' ]
+                 'binary_op_kv', 'binary_op_vk', 'load_member' ]
 
 ops = [ '' ] * 256
 op_used = [ False ] * 256

File Include/register_write_functions.h

 write_o(HotPyOptimiser *x, int op)
 {
     int out0;
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "o"));
     write_word_1111(x, op, out0, 0, 0);
-    push_register(x, out0);
 }
 
 static void
 {
     int out0;
     assert(k0 >= 0);
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "oK"));
     write_word_112(x, op, out0, k0);
-    push_register(x, out0);
 }
 
 static void
     assert(k0 >= 0);
     assert(exit >= 0);
     flush_stack(x);
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "oKE"));
     write_word_112(x, op, out0, k0);
     write_word_22(x, exit, 0);
-    push_register(x, out0);
 }
 
 static void
     assert(k0 >= 0);
     assert(k1 >= 0);
     assert(k2 >= 0);
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "oKKK"));
     write_word_112(x, op, out0, k0);
     write_word_22(x, k1, k2);
-    push_register(x, out0);
 }
 
 static void
 {
     int out0;
     int out1;
-    out0 = choose_register(x);
-    out1 = choose_register(x);
+    out0 = push_as_register(x);
+    out1 = push_as_register(x);
     assert(consistent_format(op, "oo"));
     write_word_1111(x, op, out0, out1, 0);
-    push_register(x, out0);
-    push_register(x, out1);
 }
 
 static void
 static void
 write_r(HotPyOptimiser *x, int op)
 {
-    int r0 = pop_as_register(x, 0);
+    int r0 = pop_as_register(x);
+    free_register(x, r0);
     assert(consistent_format(op, "r"));
     write_word_1111(x, op, r0, 0, 0);
 }
 static void
 write_rE(HotPyOptimiser *x, int op, int exit)
 {
-    int r0 = pop_as_register(x, 0);
+    int r0 = pop_as_register(x);
+    free_register(x, r0);
     assert(exit >= 0);
     flush_stack(x);
     assert(consistent_format(op, "rE"));
 static void
 write_rK(HotPyOptimiser *x, int op, int k0)
 {
-    int r0 = pop_as_register(x, 0);
+    int r0 = pop_as_register(x);
+    free_register(x, r0);
     assert(k0 >= 0);
     assert(consistent_format(op, "rK"));
     write_word_112(x, op, r0, k0);
 static void
 write_rKE(HotPyOptimiser *x, int op, int k0, int exit)
 {
-    int r0 = pop_as_register(x, 0);
+    int r0 = pop_as_register(x);
+    free_register(x, r0);
     assert(k0 >= 0);
     assert(exit >= 0);
     flush_stack(x);
 static void
 write_rKKE(HotPyOptimiser *x, int op, int k0, int k1, int exit)
 {
-    int r0 = pop_as_register(x, 0);
+    int r0 = pop_as_register(x);
+    free_register(x, r0);
     assert(k0 >= 0);
     assert(k1 >= 0);
     assert(exit >= 0);
 static void
 write_ro(HotPyOptimiser *x, int op)
 {
-    int r0 = pop_as_register(x, 0);
+    int r0 = pop_as_register(x);
+    free_register(x, r0);
     int out0;
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "ro"));
     write_word_1111(x, op, r0, out0, 0);
-    push_register(x, out0);
 }
 
 static void
 write_roK(HotPyOptimiser *x, int op, int k0)
 {
-    int r0 = pop_as_register(x, 0);
+    int r0 = pop_as_register(x);
+    free_register(x, r0);
     int out0;
     assert(k0 >= 0);
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "roK"));
     write_word_1111(x, op, r0, out0, 0);
     write_word_22(x, k0, 0);
-    push_register(x, out0);
 }
 
 static void
 write_roKE(HotPyOptimiser *x, int op, int k0, int exit)
 {
-    int r0 = pop_as_register(x, 0);
+    int r0 = pop_as_register(x);
+    free_register(x, r0);
     int out0;
     assert(k0 >= 0);
     assert(exit >= 0);
     flush_stack(x);
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "roKE"));
     write_word_1111(x, op, r0, out0, 0);
     write_word_22(x, k0, exit);
-    push_register(x, out0);
 }
 
 static void
 write_rok(HotPyOptimiser *x, int op, int k0)
 {
-    int r0 = pop_as_register(x, 0);
+    int r0 = pop_as_register(x);
+    free_register(x, r0);
     int out0;
     assert(k0 >= 0);
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "rok"));
     write_word_1111(x, op, r0, out0, k0);
-    push_register(x, out0);
 }
 
 static void
 write_rokE(HotPyOptimiser *x, int op, int k0, int exit)
 {
-    int r0 = pop_as_register(x, 0);
+    int r0 = pop_as_register(x);
+    free_register(x, r0);
     int out0;
     assert(k0 >= 0);
     assert(exit >= 0);
     flush_stack(x);
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "rokE"));
     write_word_1111(x, op, r0, out0, k0);
     write_word_22(x, exit, 0);
-    push_register(x, out0);
 }
 
 static void
 write_rokk(HotPyOptimiser *x, int op, int k0, int k1)
 {
-    int r0 = pop_as_register(x, 0);
+    int r0 = pop_as_register(x);
+    free_register(x, r0);
     int out0;
     assert(k0 >= 0);
     assert(k1 >= 0);
-    out0 = choose_register(x);
+    out0 = push_as_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);
+    int r0 = pop_as_register(x);
+    free_register(x, r0);
     int out0;
     assert(k0 >= 0);
     assert(k1 >= 0);
     assert(k2 >= 0);
     assert(exit >= 0);
     flush_stack(x);
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "rokkkE"));
     write_word_1111(x, op, r0, out0, k0);
     write_word_112(x, k1, k2, exit);
-    push_register(x, out0);
 }
 
 static void
 write_roo(HotPyOptimiser *x, int op)
 {
-    int r0 = pop_as_register(x, 0);
+    int r0 = pop_as_register(x);
+    free_register(x, r0);
     int out0;
     int out1;
-    out0 = choose_register(x);
-    out1 = choose_register(x);
+    out0 = push_as_register(x);
+    out1 = push_as_register(x);
     assert(consistent_format(op, "roo"));
     write_word_1111(x, op, r0, out0, out1);
-    push_register(x, out0);
-    push_register(x, out1);
 }
 
 static void
 write_rr(HotPyOptimiser *x, int op)
 {
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r1);
+    free_register(x, r0);
     assert(consistent_format(op, "rr"));
     write_word_1111(x, op, r0, r1, 0);
 }
 static void
 write_rrE(HotPyOptimiser *x, int op, int exit)
 {
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r1);
+    free_register(x, r0);
     assert(exit >= 0);
     flush_stack(x);
     assert(consistent_format(op, "rrE"));
 static void
 write_rrK(HotPyOptimiser *x, int op, int k0)
 {
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r1);
+    free_register(x, r0);
     assert(k0 >= 0);
     assert(consistent_format(op, "rrK"));
     write_word_1111(x, op, r0, r1, 0);
 static void
 write_rrKE(HotPyOptimiser *x, int op, int k0, int exit)
 {
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r1);
+    free_register(x, r0);
     assert(k0 >= 0);
     assert(exit >= 0);
     flush_stack(x);
 static void
 write_rrk(HotPyOptimiser *x, int op, int k0)
 {
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r1);
+    free_register(x, r0);
     assert(k0 >= 0);
     assert(consistent_format(op, "rrk"));
     write_word_1111(x, op, r0, r1, k0);
 static void
 write_rrkkk(HotPyOptimiser *x, int op, int k0, int k1, int k2)
 {
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r1);
+    free_register(x, r0);
     assert(k0 >= 0);
     assert(k1 >= 0);
     assert(k2 >= 0);
 static void
 write_rro(HotPyOptimiser *x, int op)
 {
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r1);
+    free_register(x, r0);
     int out0;
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "rro"));
     write_word_1111(x, op, r0, r1, out0);
-    push_register(x, out0);
 }
 
 static void
 write_rroE(HotPyOptimiser *x, int op, int exit)
 {
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r1);
+    free_register(x, r0);
     int out0;
     assert(exit >= 0);
     flush_stack(x);
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "rroE"));
     write_word_1111(x, op, r0, r1, out0);
     write_word_22(x, exit, 0);
-    push_register(x, out0);
 }
 
 static void
 write_rroK(HotPyOptimiser *x, int op, int k0)
 {
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r1);
+    free_register(x, r0);
     int out0;
     assert(k0 >= 0);
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "rroK"));
     write_word_1111(x, op, r0, r1, out0);
     write_word_22(x, k0, 0);
-    push_register(x, out0);
 }
 
 static void
 write_rroKE(HotPyOptimiser *x, int op, int k0, int exit)
 {
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r1);
+    free_register(x, r0);
     int out0;
     assert(k0 >= 0);
     assert(exit >= 0);
     flush_stack(x);
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "rroKE"));
     write_word_1111(x, op, r0, r1, out0);
     write_word_22(x, k0, exit);
-    push_register(x, out0);
 }
 
 static void
 write_rrok(HotPyOptimiser *x, int op, int k0)
 {
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r1);
+    free_register(x, r0);
     int out0;
     assert(k0 >= 0);
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "rrok"));
     write_word_1111(x, op, r0, r1, out0);
     write_word_1111(x, k0, 0, 0, 0);
-    push_register(x, out0);
 }
 
 static void
 write_rroo(HotPyOptimiser *x, int op)
 {
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r1);
+    free_register(x, r0);
     int out0;
     int out1;
-    out0 = choose_register(x);
-    out1 = choose_register(x);
+    out0 = push_as_register(x);
+    out1 = push_as_register(x);
     assert(consistent_format(op, "rroo"));
     write_word_1111(x, op, r0, r1, out0);
     write_word_1111(x, out1, 0, 0, 0);
-    push_register(x, out0);
-    push_register(x, out1);
 }
 
 static void
 write_rrooE(HotPyOptimiser *x, int op, int exit)
 {
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r1);
+    free_register(x, r0);
     int out0;
     int out1;
     assert(exit >= 0);
     flush_stack(x);
-    out0 = choose_register(x);
-    out1 = choose_register(x);
+    out0 = push_as_register(x);
+    out1 = push_as_register(x);
     assert(consistent_format(op, "rrooE"));
     write_word_1111(x, op, r0, r1, out0);
     write_word_112(x, out1, 0, exit);
-    push_register(x, out0);
-    push_register(x, out1);
 }
 
 static void
 write_rroooE(HotPyOptimiser *x, int op, int exit)
 {
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r1);
+    free_register(x, r0);
     int out0;
     int out1;
     int out2;
     assert(exit >= 0);
     flush_stack(x);
-    out0 = choose_register(x);
-    out1 = choose_register(x);
-    out2 = choose_register(x);
+    out0 = push_as_register(x);
+    out1 = push_as_register(x);
+    out2 = push_as_register(x);
     assert(consistent_format(op, "rroooE"));
     write_word_1111(x, op, r0, r1, out0);
     write_word_112(x, out1, out2, exit);
-    push_register(x, out0);
-    push_register(x, out1);
-    push_register(x, out2);
 }
 
 static void
 write_rrr(HotPyOptimiser *x, int op)
 {
-    int r2 = pop_as_register(x, 2);
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r2 = pop_as_register(x);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r2);
+    free_register(x, r1);
+    free_register(x, r0);
     assert(consistent_format(op, "rrr"));
     write_word_1111(x, op, r0, r1, r2);
 }
 static void
 write_rrrE(HotPyOptimiser *x, int op, int exit)
 {
-    int r2 = pop_as_register(x, 2);
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r2 = pop_as_register(x);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r2);
+    free_register(x, r1);
+    free_register(x, r0);
     assert(exit >= 0);
     flush_stack(x);
     assert(consistent_format(op, "rrrE"));
 static void
 write_rrrKE(HotPyOptimiser *x, int op, int k0, int exit)
 {
-    int r2 = pop_as_register(x, 2);
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r2 = pop_as_register(x);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r2);
+    free_register(x, r1);
+    free_register(x, r0);
     assert(k0 >= 0);
     assert(exit >= 0);
     flush_stack(x);
 static void
 write_rrro(HotPyOptimiser *x, int op)
 {
-    int r2 = pop_as_register(x, 2);
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r2 = pop_as_register(x);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r2);
+    free_register(x, r1);
+    free_register(x, r0);
     int out0;
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "rrro"));
     write_word_1111(x, op, r0, r1, r2);
     write_word_1111(x, out0, 0, 0, 0);
-    push_register(x, out0);
 }
 
 static void
 write_rrroE(HotPyOptimiser *x, int op, int exit)
 {
-    int r2 = pop_as_register(x, 2);
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r2 = pop_as_register(x);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r2);
+    free_register(x, r1);
+    free_register(x, r0);
     int out0;
     assert(exit >= 0);
     flush_stack(x);
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "rrroE"));
     write_word_1111(x, op, r0, r1, r2);
     write_word_112(x, out0, 0, exit);
-    push_register(x, out0);
 }
 
 static void
 write_rrrokE(HotPyOptimiser *x, int op, int k0, int exit)
 {
-    int r2 = pop_as_register(x, 2);
-    int r1 = pop_as_register(x, 1);
-    int r0 = pop_as_register(x, 0);
+    int r2 = pop_as_register(x);
+    int r1 = pop_as_register(x);
+    int r0 = pop_as_register(x);
+    free_register(x, r2);
+    free_register(x, r1);
+    free_register(x, r0);
     int out0;
     assert(k0 >= 0);
     assert(exit >= 0);
     flush_stack(x);
-    out0 = choose_register(x);
+    out0 = push_as_register(x);
     assert(consistent_format(op, "rrrokE"));
     write_word_1111(x, op, r0, r1, r2);
     write_word_112(x, out0, k0, exit);
-    push_register(x, out0);
 }
 
 void

File Include/trace_opcode.h

 #define FAST_LOAD_GLOBAL 216
 #define BINARY_OP_KV 217
 #define BINARY_OP_VK 218
-/* Opcode 219 unused */
+#define LOAD_MEMBER 219
 /* Opcode 220 unused */
 /* Opcode 221 unused */
 /* Opcode 222 unused */
 "FAST_LOAD_GLOBAL",
 "BINARY_OP_KV",
 "BINARY_OP_VK",
-NULL,
+"LOAD_MEMBER",
 NULL,
 NULL,
 NULL,
 extern char *_HotPy_Instruction_Names[];
 #endif
 
-#define USED_OPCODES 219
+#define USED_OPCODES 220
 

File Python/register_interpreter.c

             tstate->execution_context = NULL;
             DISPATCH();
 
+        TARGET(LOAD_MEMBER)
+            FORMAT_rokE;
+            PyObject *o = registers[r0];
+            PyObject *d = CONSTANT(k0);
+            exit = GETEXIT(e0);
+            tstate->execution_context = exit->exit_context;
+            PyObject *x = Py_TYPE(d)->tp_descr_get(d, o, (PyObject *)Py_TYPE(o));
+            if (tstate->execution_context == NULL) {
+                if (x)
+                    PUSH_TO_REAL(x);
+                goto materialised;
+            }
+            if (x == NULL)
+                goto error_with_exit;
+            SET_REGISTER(r1, x);
+            tstate->execution_context = NULL;
+            DISPATCH();
+
         TARGET(DESCRIPTOR_GET)
             FORMAT_rro;
             PyObject *v = registers[r0];

File Python/register_opcode_targets.h

 &&TARGET_FAST_LOAD_GLOBAL,
 &&TARGET_BINARY_OP_KV,
 &&TARGET_BINARY_OP_VK,
-&&_unknown_opcode,
+&&TARGET_LOAD_MEMBER,
 &&_unknown_opcode,
 &&_unknown_opcode,
 &&_unknown_opcode,

File Python/trace_D_O_C.c

 
 #define PUSH(v) do { \
     PyObject *_tmp = (v); \
+    assert(Py_TYPE(_tmp) == &DeferredObject_Type); \
     if (_tmp == NULL) { \
         opt->err_occurred = 1; \
         assert(PyErr_Occurred()); \
         write_byte(buffer, DK_REAL);
         return;
     }
+    assert(Py_TYPE(obj) == &DeferredObject_Type);
     k = KIND(obj);
     write_byte(buffer, k);
     switch(k) {

File Python/trace_opcode_targets.h

 &&_unknown_opcode, /* FAST_LOAD_GLOBAL */
 &&_unknown_opcode, /* BINARY_OP_KV */
 &&_unknown_opcode, /* BINARY_OP_VK */
-&&_unknown_opcode,
+&&_unknown_opcode, /* LOAD_MEMBER */
 &&_unknown_opcode,
 &&_unknown_opcode,
 &&_unknown_opcode,

File Python/trace_recorder_register.c

 #include "opcode.h"
 #include "optimiser.h"
 #include "trace_opcode.h"
-#include "trace_opcode.h"
 #include "register_macros.h"
 
 #ifdef Py_DEBUG
     opt->insts[opt->next_inst++] = instruction;
 }
 
-#define PUSH(x) opt->stack[opt->stack_items++] = x
-
 static void flush_stack(HotPyOptimiser *x)
 {
     HotPyTraceRecorder *opt = (HotPyTraceRecorder *)x;
     opt->stack_items = 0;
 }
 
-static int pop_as_register(HotPyOptimiser *x, int def)
-{
-    HotPyTraceRecorder *opt = (HotPyTraceRecorder *)x;
-    if (opt->stack_items) {
-        int reg = opt->stack[--opt->stack_items];
-        opt->used_regs[reg] = 0;
-        return reg;
-    }
-    write_word_1111(x, POP_STACK_TO_REGISTER, def, 0, 0);
-    return def;
-}
-
 static void
 write_move(HotPyOptimiser *x, int from, int to)
 {
         write_word_1111(x, MOVE, from, to, 0);
 }
 
-static void
-store_register(HotPyOptimiser *x, int arg)
-{
-    int from = pop_as_register(x, arg);
-    write_move(x, from, arg);
-}
-
 #ifdef Py_DEBUG
 static int
 consistent_stack(HotPyOptimiser *x)
         used += opt->used_regs[i];
     return used == opt->stack_items;
 }
-#define CONSISTENT(x) consistent_stack(x)
+
+#define CONSISTENT(x) assert(consistent_stack(x))
 #else
 #define CONSISTENT(x) ((void)0)
 #endif
     return chosen;
 }
 
-static void push_register(HotPyOptimiser *x, int reg)
+static int pop_as_register(HotPyOptimiser *x)
+{
+    int reg;
+    HotPyTraceRecorder *opt = (HotPyTraceRecorder *)x;
+    if (opt->stack_items) {
+        reg = opt->stack[--opt->stack_items];
+        return reg;
+    }
+    reg = choose_register(x);
+    write_word_1111(x, POP_STACK_TO_REGISTER, reg, 0, 0);
+    return reg;
+}
+
+static void free_register(HotPyOptimiser *x, int reg)
 {
     HotPyTraceRecorder *opt = (HotPyTraceRecorder *)x;
+    opt->used_regs[reg] = 0;
+}
+
+static int push_as_register(HotPyOptimiser *x)
+{
+    HotPyTraceRecorder *opt = (HotPyTraceRecorder *)x;
+    int reg = choose_register(x);
     assert(reg < HOTPY_STACK_REGISTERS);
     opt->stack[opt->stack_items++] = reg;
+    return reg;
 }
 
 static int peek_as_register(HotPyOptimiser *x)
         return opt->stack[opt->stack_items-1];
     reg = choose_register(x);
     write_word_1111(x, POP_STACK_TO_REGISTER, reg, 0, 0);
-    push_register(x, reg);
+    opt->stack[0] = reg;
+    opt->stack_items = 1;
     return reg;
 }
 
         case LOAD_SLOT:
             print_rok(out, &code);
             break;
-        case LOAD_SLOT_EX:
+        case LOAD_SLOT_EX: case LOAD_MEMBER:
             print_rokE(out, &code);
             break;
         case STORE_TO_GLOBALS:
 }
 
 static void
+store_register(HotPyOptimiser *x, int arg)
+{
+    int from = pop_as_register(x);
+    free_register(x, from);
+    write_move(x, from, arg);
+}
+
+static void
 push_constant(HotPyOptimiser *x, PyObject *value)
 {
     HotPyTraceRecorder *opt = (HotPyTraceRecorder *)x;
 pick(HotPyOptimiser *x, int depth)
 {
     HotPyTraceRecorder *opt = (HotPyTraceRecorder *)x;
-    int reg = choose_register(x);
-    if (opt->stack_items >= depth) {
-        int from = opt->stack[opt->stack_items-depth];
+    int reg = push_as_register(x);
+    if (opt->stack_items > depth) {
+        int from = opt->stack[opt->stack_items-depth-1];
         write_move(x, from, reg);
     }
     else {
         write_word_112(x, PICK, reg, depth - opt->stack_items);
     }
-    push_register(x, reg);
     CONSISTENT(x);
 }
 
 
 static void clear(HotPyOptimiser *x)
 {
+    int i;
     HotPyTraceRecorder *opt = (HotPyTraceRecorder *)x;
     opt->next_inst = 0;
     opt->allocated_insts = 0;
     Py_CLEAR(opt->trace);
     while (opt->keys_count)
         PyDictKeysObject_DecRef(opt->keys[--opt->keys_count]);
+    for (i = 0; i < HOTPY_STACK_REGISTERS; i++)
+        opt->used_regs[i] = 0;
 }
 
 static void
         case VALUE_FROM_OBJECT_DICT_OR_EXIT:
         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 ENSURE_SLOT: case BINARY_OP: case LOAD_MEMBER:
         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:
         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 ENSURE_SLOT: case BINARY_OP: case LOAD_MEMBER:
         case BINARY_OP_KV: case BINARY_OP_VK:
         case LOAD_FROM_GLOBAL_AND_BUILTINS:
         case HAS_SPECIAL: case BUILD_SLICE: case OVERRIDES:
 }
 
 static void
-stack_as_registers(HotPyOptimiser *x, int n)
-{
-    int regs[3];
-    int i;
-    HotPyTraceRecorder *opt = (HotPyTraceRecorder *)x;
-    assert(n <= 3);
-    if (opt->stack_items >= n)
-        return;
-    for (i = n - 1; i >= 0; i--) {
-        if (opt->stack_items)
-            regs[i] = opt->stack[--opt->stack_items];
-        else {
-            regs[i] = choose_register(x);
-            write_word_1111(x, POP_STACK_TO_REGISTER, regs[i], 0, 0);
-        }
-    }
-    for (i = 0; i < n; i++)
-        push_register(x, regs[i]);
-}
-
-static void
 opcode(HotPyOptimiser *x, int op)
 {
     int r0, r1, r2, r3;
     HotPyTraceRecorder *opt = (HotPyTraceRecorder *)x;
     switch(op) {
     case POP_TOP:
-        pop_as_register(x, 0);
+        free_register(x, pop_as_register(x));
         return;
     case ROT_TWO:
-        stack_as_registers(x, 2);
-        r0 = opt->stack[opt->stack_items-2];
-        r1 = opt->stack[opt->stack_items-1];
-        opt->stack[opt->stack_items-2] = r1;
-        opt->stack[opt->stack_items-1] = r0;
+        if (opt->stack_items >= 2) {
+            r0 = opt->stack[opt->stack_items-2];
+            r1 = opt->stack[opt->stack_items-1];
+            opt->stack[opt->stack_items-2] = r1;
+            opt->stack[opt->stack_items-1] = r0;
+        }
+        else {
+            r1 = pop_as_register(x);
+            r0 = pop_as_register(x);
+            r3 = push_as_register(x);
+            write_move(x, r1, r3);
+            r3 = push_as_register(x);
+            write_move(x, r0, r3);
+            free_register(x, r0);
+            free_register(x, r1);
+        }
         return;
     case ROT_THREE:
-        stack_as_registers(x, 3);
-        r0 = opt->stack[opt->stack_items-3];
-        r1 = opt->stack[opt->stack_items-2];
-        r2 = opt->stack[opt->stack_items-1];
-        opt->stack[opt->stack_items-3] = r2;
-        opt->stack[opt->stack_items-2] = r0;
-        opt->stack[opt->stack_items-1] = r1;
+        if (opt->stack_items >= 3) {
+            r0 = opt->stack[opt->stack_items-3];
+            r1 = opt->stack[opt->stack_items-2];
+            r2 = opt->stack[opt->stack_items-1];
+            opt->stack[opt->stack_items-3] = r2;
+            opt->stack[opt->stack_items-2] = r0;
+            opt->stack[opt->stack_items-1] = r1;
+        }
+        else {
+            r2 = pop_as_register(x);
+            r1 = pop_as_register(x);
+            r0 = pop_as_register(x);
+            r3 = push_as_register(x);
+            write_move(x, r2, r3);
+            r3 = push_as_register(x);
+            write_move(x, r0, r3);
+            r3 = push_as_register(x);
+            write_move(x, r1, r3);
+            free_register(x, r0);
+            free_register(x, r1);
+            free_register(x, r2);
+        }
         return;
     case DUP_TOP:
         r0 = peek_as_register(x);
-        r1 = choose_register(x);
+        r1 = push_as_register(x);
         write_move(x, r0, r1);
-        push_register(x, r1);
         return;
     case DUP_TOP_TWO:
-        stack_as_registers(x, 2);
-        r0 = opt->stack[opt->stack_items-2];
-        r1 = opt->stack[opt->stack_items-1];
-        r2 = choose_register(x);
-        r3 = choose_register(x);
+        r1 = pop_as_register(x);
+        r0 = peek_as_register(x);
+        r3 = push_as_register(x);
+        write_move(x, r1, r3);
+        r2 = push_as_register(x);
         write_move(x, r0, r2);
-        push_register(x, r2);
-        write_move(x, r0, r3);
-        push_register(x, r3);
+        r3 = push_as_register(x);
+        write_move(x, r1, r3);
+        free_register(x, r1);
         return;
     case VALUE_NOP: case NOP:
         return;
         /* STORE_MAP would have rrp format, but that is not allowed. */
         r0 = peek_as_register(x);
         write_rrr(x, op);
-        r1 = choose_register(x);
+        r1 = push_as_register(x);
         write_move(x, r0, r1);
-        push_register(x, r1);
         return;
     case GEN_EXIT: case RETURN_VALUE:
         write_r(x, op);
 
 }
 
+#define TEMP_REG 0
+
 static void
 opcode_with_arg(HotPyOptimiser *x, int op, int oparg)
 {
         reg = choose_register(x);
         write_word_112(x, op, reg, oparg);
         for (i = oparg-1; i >= 0; i--) {
-            int item_reg = pop_as_register(x, 0);
+            int item_reg = pop_as_register(x);
+            free_register(x, item_reg);
             /* TUPLE_SET_ITEM has rrk format */
             write_word_1111(x, TUPLE_SET_ITEM, reg, item_reg, i);
         }
-        push_register(x, reg);
+        free_register(x, reg);
+        write_move(x, reg, push_as_register(x));
         return;
     case BUILD_LIST:
         reg = choose_register(x);
         write_word_112(x, op, reg, oparg);
         for (i = oparg-1; i >= 0; i--) {
-            int item_reg = pop_as_register(x, 0);
+            int item_reg = pop_as_register(x);
+            free_register(x, item_reg);
             /* LIST_SET_ITEM has rrk format */
             write_word_1111(x, LIST_SET_ITEM, reg, item_reg, i);
         }
-        push_register(x, reg);
+        free_register(x, reg);
+        write_move(x, reg, push_as_register(x));
         return;
     case BUILD_SET: case BUILD_MAP: case LOAD_CLOSURE:
         write_oK(x, op, oparg);
         write_rrro(x, op);
         return;
     case UNPACK_SEQUENCE:
-        reg = pop_as_register(x, 0);
+        reg = pop_as_register(x);
         flush_stack(x);
+        free_register(x, reg);
         write_word_112(x, op, reg, oparg);
         return;
     case MATERIALISE_FRAME: case STORE_SLOT:
 static void
 load_clear_register(HotPyOptimiser *x, int arg)
 {
-    int r = choose_register(x);
+    int r = push_as_register(x);
     write_move(x, arg, r);
-    push_register(x, r);
     CONSISTENT(x);
 }
 
 static void
 load_register(HotPyOptimiser *x, int arg)
 {
-    int r = choose_register(x);
+    int r = push_as_register(x);
     write_move(x, arg, r);
-    push_register(x, r);
     CONSISTENT(x);
 }
 
     int i;
     int r0, r1, r2, frame_reg;
     int offset0 = offsetof(PyFrameObject, f_localsplus[0])/sizeof(PyObject*);
-    r2 = pop_as_register(x, 2);
-    r1 = pop_as_register(x, 1);
-    r0 = pop_as_register(x, 0);
-    frame_reg = choose_register(x);
+    r2 = pop_as_register(x);
+    r1 = pop_as_register(x);
+    r0 = pop_as_register(x);
+    free_register(x, r1);
+    free_register(x, r2);
     write_word_1111(x, NEW_FRAME, r0, r1, r2);
-    write_word_112(x, frame_reg, 0, 0);
+    write_word_112(x, r0, 0, 0);
     for (i = arg-1; i >= 0; i--) {
-        int reg = pop_as_register(x, 0);
-        write_word_1111(x, STORE_SLOT, frame_reg, reg, offset0 + i);
+        int reg = pop_as_register(x);
+        free_register(x, reg);
+        write_word_1111(x, STORE_SLOT, r0, reg, offset0 + i);
     }
-    push_register(x, frame_reg);
+    free_register(x, r0);
+    frame_reg = push_as_register(x);
+    write_move(x, r0, frame_reg);
     CONSISTENT(x);
 }
 
 static void
 gen_enter(HotPyOptimiser *x, PyCodeObject *code)
 {
-    int r = pop_as_register(x, 0);
+    int r = pop_as_register(x);
     flush_stack(x);
+    free_register(x, r);
     write_word_112(x, GEN_ENTER, r, 0);
     CONSISTENT(x);
 }
 static void
 enter_frame(HotPyOptimiser *x, PyCodeObject *code)
 {
-    int r = pop_as_register(x, 0);
+    int r = pop_as_register(x);
     flush_stack(x);
+    free_register(x, r);
     write_word_112(x, ENTER_FRAME, r, 0);
     CONSISTENT(x);
 }
 {
     HotPyTraceRecorder *opt = (HotPyTraceRecorder *)x;
     PyMemberDef *def = desc->d_member;
-    int slot = def->offset/sizeof(PyObject*);
+    int e, slot = def->offset/sizeof(PyObject*);
     HotPyContext *context = NULL;
     assert(slot < (1 << 8));
     assert(def->offset % sizeof(PyObject*) == 0);
         write_rok(x, LOAD_SLOT, slot);
     }
     else if (def->type == T_OBJECT_EX) {
-        int e;
         context = HotPyContext_New();
         e = new_exit(opt, context);
         if (e < 0)
         write_rokE(x, LOAD_SLOT_EX, slot, e);
     }
     else {
-        assert("Don't support int/float slots yet" && 0);
-        abort();
+        /* Don't support int/float slots efficiently yet */
+        int index = index_for_constant(opt, (PyObject *)desc);
+        context = HotPyContext_New();
+        e = new_exit(opt, context);
+        if (e < 0)
+            return NULL;
+        write_rokE(x, LOAD_MEMBER, index, e);
     }
     CONSISTENT(x);
     return context;
         return defuses_for_o(instr, defs, uses);
     case LOAD_SLOT:
         return defuses_for_rok(instr, defs, uses);
-    case LOAD_SLOT_EX:
+    case LOAD_SLOT_EX: case LOAD_MEMBER:
         return defuses_for_rokE(instr, defs, uses);
     case STORE_TO_GLOBALS:
         return defuses_for_rrK(instr, defs, uses);
         return relabel_uses_o(instr, relabel_uses_table);
     case LOAD_SLOT:
         return relabel_uses_rok(instr, relabel_uses_table);
-    case LOAD_SLOT_EX:
+    case LOAD_SLOT_EX: case LOAD_MEMBER:
         return relabel_uses_rokE(instr, relabel_uses_table);
     case STORE_TO_GLOBALS:
         return relabel_uses_rrK(instr, relabel_uses_table);
         return relabel_defs_o(instr, relabel_defs_table);
     case LOAD_SLOT:
         return relabel_defs_rok(instr, relabel_defs_table);
-    case LOAD_SLOT_EX:
+    case LOAD_SLOT_EX: case LOAD_MEMBER:
         return relabel_defs_rokE(instr, relabel_defs_table);
     case STORE_TO_GLOBALS:
         return relabel_defs_rrK(instr, relabel_defs_table);
         return get_exit_context_o(instr, exits);
     case LOAD_SLOT:
         return get_exit_context_rok(instr, exits);
-    case LOAD_SLOT_EX:
+    case LOAD_SLOT_EX: case LOAD_MEMBER:
         return get_exit_context_rokE(instr, exits);
     case STORE_TO_GLOBALS:
         return get_exit_context_rrK(instr, exits);