[Mono] Fix EnumCompareTo for small integers (#48192)
authorEgor Bogatov <egorbo@gmail.com>
Fri, 12 Feb 2021 15:10:34 +0000 (18:10 +0300)
committerGitHub <noreply@github.com>
Fri, 12 Feb 2021 15:10:34 +0000 (18:10 +0300)
src/mono/mono/mini/interp/transform.c
src/mono/mono/mini/intrinsics.c

index ac50ed6..8446da4 100644 (file)
@@ -2383,34 +2383,46 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas
                        // Save arguments
                        store_local (td, localb);
                        store_local (td, locala);
-                       // (a > b)
                        load_local (td, locala);
                        load_local (td, localb);
-                       if (is_unsigned)
-                               interp_add_ins (td, is_i8 ? MINT_CGT_UN_I8 : MINT_CGT_UN_I4);
-                       else
-                               interp_add_ins (td, is_i8 ? MINT_CGT_I8 : MINT_CGT_I4);
-                       td->sp -= 2;
-                       interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local);
-                       push_simple_type (td, STACK_TYPE_I4);
-                       interp_ins_set_dreg (td->last_ins, td->sp [-1].local);
-                       // (a < b)
-                       load_local (td, locala);
-                       load_local (td, localb);
-                       if (is_unsigned)
-                               interp_add_ins (td, is_i8 ? MINT_CLT_UN_I8 : MINT_CLT_UN_I4);
+
+                       if (t->type >= MONO_TYPE_BOOLEAN && t->type <= MONO_TYPE_U2)
+                       {
+                               interp_add_ins (td, MINT_SUB_I4);
+                               td->sp -= 2;
+                               interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local);
+                               push_simple_type (td, STACK_TYPE_I4);
+                               interp_ins_set_dreg (td->last_ins, td->sp [-1].local);
+                       }
                        else
-                               interp_add_ins (td, is_i8 ? MINT_CLT_I8 : MINT_CLT_I4);
-                       td->sp -= 2;
-                       interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local);
-                       push_simple_type (td, STACK_TYPE_I4);
-                       interp_ins_set_dreg (td->last_ins, td->sp [-1].local);
-                       // (a > b) - (a < b)
-                       interp_add_ins (td, MINT_SUB_I4);
-                       td->sp -= 2;
-                       interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local);
-                       push_simple_type (td, STACK_TYPE_I4);
-                       interp_ins_set_dreg (td->last_ins, td->sp [-1].local);
+                       {
+                               // (a > b)
+                               if (is_unsigned)
+                                       interp_add_ins (td, is_i8 ? MINT_CGT_UN_I8 : MINT_CGT_UN_I4);
+                               else
+                                       interp_add_ins (td, is_i8 ? MINT_CGT_I8 : MINT_CGT_I4);
+                               td->sp -= 2;
+                               interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local);
+                               push_simple_type (td, STACK_TYPE_I4);
+                               interp_ins_set_dreg (td->last_ins, td->sp [-1].local);
+                               // (a < b)
+                               load_local (td, locala);
+                               load_local (td, localb);
+                               if (is_unsigned)
+                                       interp_add_ins (td, is_i8 ? MINT_CLT_UN_I8 : MINT_CLT_UN_I4);
+                               else
+                                       interp_add_ins (td, is_i8 ? MINT_CLT_I8 : MINT_CLT_I4);
+                               td->sp -= 2;
+                               interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local);
+                               push_simple_type (td, STACK_TYPE_I4);
+                               interp_ins_set_dreg (td->last_ins, td->sp [-1].local);
+                               // (a > b) - (a < b)
+                               interp_add_ins (td, MINT_SUB_I4);
+                               td->sp -= 2;
+                               interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local);
+                               push_simple_type (td, STACK_TYPE_I4);
+                               interp_ins_set_dreg (td->last_ins, td->sp [-1].local);
+                       }
                        td->ip += 5;
                        return TRUE;
                } else {
index 52a01b1..13677c2 100644 (file)
@@ -632,11 +632,19 @@ emit_jit_helpers_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSi
                        reg2 = alloc_ireg (cfg);
                        dreg = alloc_ireg (cfg);
 
-                       EMIT_NEW_BIALU (cfg, ins, cmp_op, -1, args [0]->dreg, args [1]->dreg);
-                       EMIT_NEW_UNALU (cfg, ins, cgt_op, reg1, -1);
-                       EMIT_NEW_BIALU (cfg, ins, cmp_op, -1, args [0]->dreg, args [1]->dreg);
-                       EMIT_NEW_UNALU (cfg, ins, clt_op, reg2, -1);
-                       EMIT_NEW_BIALU (cfg, ins, OP_ISUB, dreg, reg1, reg2);
+                       if (t->type >= MONO_TYPE_BOOLEAN && t->type <= MONO_TYPE_U2)
+                       {
+                               // Use "a - b" for small types (smaller than Int32)
+                               EMIT_NEW_BIALU (cfg, ins, OP_ISUB, dreg, args [0]->dreg, args [1]->dreg);
+                       }
+                       else
+                       {
+                               EMIT_NEW_BIALU (cfg, ins, cmp_op, -1, args [0]->dreg, args [1]->dreg);
+                               EMIT_NEW_UNALU (cfg, ins, cgt_op, reg1, -1);
+                               EMIT_NEW_BIALU (cfg, ins, cmp_op, -1, args [0]->dreg, args [1]->dreg);
+                               EMIT_NEW_UNALU (cfg, ins, clt_op, reg2, -1);
+                               EMIT_NEW_BIALU (cfg, ins, OP_ISUB, dreg, reg1, reg2);
+                       }
                }
                return ins;
        }