MIPS: Fix IMT binary search code generation in backend
authorDamien Diederen <dd@crosstwine.com>
Mon, 7 Feb 2011 21:47:15 +0000 (22:47 +0100)
committerDamien Diederen <dd@crosstwine.com>
Thu, 10 Feb 2011 23:07:50 +0000 (00:07 +0100)
Imt_emit_ir, in object.c, generates binary search code for sequences
longer than three elements.  It saves the key of the mid item, then
recursively calls itself on the two halves of the segment:

    item->key = sorted_array [middle]->key;
    ...
    imt_emit_ir (sorted_array, start, middle, out_array);
    item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);

Note how the mid item itself is included in the second half: it is to
be handled as part of that subsequence, whose code starts at index
'check_target_index'.

Given such a piece of binary search IR, the MIPS backend currently
generates:

    load_const (temp, item->key);
    slt (temp, temp, IMT_REG);      ; temp = key < searched_for;
    bne (temp, zero, 0);            ; if (temp) jump_target_index ();

This is broken because no jump happens if (key == searched_for).  The
target method won't be found in the first subtree, so the runtime will
end up jumping to its last method instead of the correct one!

This patch causes the following sequence to be emitted:

    load_const (temp, item->key);
    slt (temp, IMT_REG, temp);      ; temp = searched_for < key;
    beq (temp, zero, 0);            ; if (!temp) jump_target_index ();

Commit contributed under the MIT/X11 license.

mono/mini/mini-mips.c

index 12fe7fa36c072e2ae05ad089dbc5223de441d291..c094bd09c9b57f1b8fe340bba113a496c747866f 100644 (file)
@@ -5701,10 +5701,10 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
                        }
                } else {
                        mips_load_const (code, mips_temp, (gulong)item->key);
-                       mips_slt (code, mips_temp, mips_temp, MONO_ARCH_IMT_REG);
+                       mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
 
                        item->jmp_code = code;
-                       mips_bne (code, mips_temp, mips_zero, 0);
+                       mips_beq (code, mips_temp, mips_zero, 0);
                        mips_nop (code);
                }
        }