Thu May 15 11:57:42 CEST 2003 Paolo Molaro <lupus@ximian.com>
authorPaolo Molaro <lupus@oddwiz.org>
Thu, 15 May 2003 11:04:39 +0000 (11:04 -0000)
committerPaolo Molaro <lupus@oddwiz.org>
Thu, 15 May 2003 11:04:39 +0000 (11:04 -0000)
* mini-ops.h, mini.c, inssel.brg: optimize access to 2D arrays.
* jit-icalls.c, exceptions.cs: fixed index out of range checks, added
test case.

svn path=/trunk/mono/; revision=14598

mono/mini/ChangeLog
mono/mini/exceptions.cs
mono/mini/inssel.brg
mono/mini/jit-icalls.c
mono/mini/mini-ops.h
mono/mini/mini.c

index e387b413a3805e166b1bc07ccf9d10b61e0aaabd..7fa629fe0859ce20ef6a3beb96963e24f7785bdb 100644 (file)
@@ -1,3 +1,10 @@
+
+Thu May 15 11:57:42 CEST 2003 Paolo Molaro <lupus@ximian.com>
+
+       * mini-ops.h, mini.c, inssel.brg: optimize access to 2D arrays.
+       * jit-icalls.c, exceptions.cs: fixed index out of range checks, added
+       test case.
+
 2003-05-14  Dietmar Maurer  <dietmar@ximian.com>
 
        * inssel.brg: remove some common pop instructions without side effects
index 9a0eab7e669af976b975d56887305ae214efa18f..1db43de32c8599149d00649bb3a2b1643b9ef2f6 100644 (file)
@@ -1450,4 +1450,44 @@ class Tests {
                        return 0;
                return 4;
        }
+
+       static readonly int[] mul_dim_results = new int[] {
+               0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8,
+               1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8,
+               2, 0, 2, 1, 2, 8, 
+               3, 0, 3, 1, 3, 8, 
+               4, 0, 4, 1, 4, 8, 
+               5, 0, 5, 1, 5, 2, 5, 3, 5, 4, 5, 5, 5, 6, 5, 7, 5, 8,
+               6, 0, 6, 1, 6, 2, 6, 3, 6, 4, 6, 5, 6, 6, 6, 7, 6, 8,
+               7, 0, 7, 1, 7, 2, 7, 3, 7, 4, 7, 5, 7, 6, 7, 7, 7, 8,
+       };
+
+       static int test_0_multi_dim_array_access () {
+               int [,] a = System.Array.CreateInstance (typeof (int),
+                       new int [] {3,6}, new int [] {2,2 }) as int[,];
+                int x, y;
+               int result_idx = 0;
+               for (x = 0; x < 8; ++x) {
+                       for (y = 0; y < 9; ++y) {
+                               bool got_ex = false;
+                               try {
+                                       a [x, y] = 1;
+                               } catch {
+                                       got_ex = true;
+                               }
+                               if (got_ex) {
+                                       if (result_idx >= mul_dim_results.Length)
+                                               return -1;
+                                       if (mul_dim_results [result_idx] != x || mul_dim_results [result_idx + 1] != y) {
+                                               return result_idx + 1;
+                                       }
+                                       result_idx += 2;
+                               }
+                       }
+               }
+               if (result_idx == mul_dim_results.Length)
+                       return 0;
+               return 200;
+       }
 }
+
index c6cd02a2d65bc184452e4ca4ecfaac69889f7b1f..8c2bb98806e8805b10fefd7db5df32aa9fb4e7ad 100644 (file)
@@ -523,6 +523,57 @@ stmt: CEE_STELEM_REF (OP_GROUP (reg, reg), reg) {
        g_assert_not_reached ();
 }
 
+reg: OP_GROUP (reg, reg) {
+       g_assert_not_reached ();
+}
+
+reg: OP_LDELEMA2D (reg, OP_GROUP (reg, reg)) "20" {
+       int bounds_reg = mono_regstate_next_int (s->rs);
+       int add_reg = mono_regstate_next_int (s->rs);
+       int mult_reg = mono_regstate_next_int (s->rs);
+       int mult2_reg = mono_regstate_next_int (s->rs);
+       int low1_reg = mono_regstate_next_int (s->rs);
+       int low2_reg = mono_regstate_next_int (s->rs);
+       int high1_reg = mono_regstate_next_int (s->rs);
+       int high2_reg = mono_regstate_next_int (s->rs);
+       int realidx1_reg = mono_regstate_next_int (s->rs);
+       int realidx2_reg = mono_regstate_next_int (s->rs);
+       int index1, index2;
+       guint32 size = mono_class_array_element_size (tree->klass);
+
+       index1 = state->right->left->reg1;
+       index2 = state->right->right->reg1;
+
+       /* range checking */
+       MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADI4_MEMBASE, bounds_reg, 
+                                      state->left->reg1, G_STRUCT_OFFSET (MonoArray, bounds));
+
+       MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADI4_MEMBASE, low1_reg, 
+                                      bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
+       /*MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, low1_reg, index1);
+       MONO_EMIT_NEW_COND_EXC (s, GT, "IndexOutOfRangeException");*/
+       MONO_EMIT_NEW_BIALU (s, CEE_SUB, realidx1_reg, index1, low1_reg);
+       MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADI4_MEMBASE, high1_reg, 
+                                      bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
+       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, high1_reg, realidx1_reg);
+       MONO_EMIT_NEW_COND_EXC (s, LE_UN, "IndexOutOfRangeException");
+
+       MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADI4_MEMBASE, low2_reg, 
+                                      bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
+       /*MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, low2_reg, index2);
+       MONO_EMIT_NEW_COND_EXC (s, GT, "IndexOutOfRangeException");*/
+       MONO_EMIT_NEW_BIALU (s, CEE_SUB, realidx2_reg, index2, low2_reg);
+       MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADI4_MEMBASE, high2_reg, 
+                                      bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, length));
+       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, high2_reg, realidx2_reg);
+       MONO_EMIT_NEW_COND_EXC (s, LE_UN, "IndexOutOfRangeException");
+
+       MONO_EMIT_NEW_BIALU_IMM (s, OP_MUL_IMM, mult_reg, realidx1_reg, size);
+       MONO_EMIT_NEW_BIALU (s, CEE_MUL, mult2_reg, mult_reg, realidx2_reg);
+       MONO_EMIT_NEW_BIALU (s, CEE_ADD, add_reg, mult2_reg, state->left->reg1);
+       MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, state->reg1, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
+}
+
 #
 # conversions: conv_u can be implemented with AND, also all _ovf conversions?
 #
index 2efdbc2e35222b682d58fec54b9d56c498f78873..f0b150d77ee129fb6d28a548740d699e873e8705 100644 (file)
@@ -274,7 +274,7 @@ ves_array_element_address (MonoArray *this, ...)
 {
        MonoClass *class;
        va_list ap;
-       int i, ind, esize;
+       int i, ind, esize, realidx;
        gpointer ea;
 
        MONO_ARCH_SAVE_REGS;
@@ -285,20 +285,22 @@ ves_array_element_address (MonoArray *this, ...)
 
        class = this->obj.vtable->klass;
 
-       ind = va_arg(ap, int);
        g_assert (this->bounds != NULL);
 
+       esize = mono_array_element_size (class);
        ind -= this->bounds [0].lower_bound;
-       for (i = 1; i < class->rank; i++) {
-               ind = ind*this->bounds [i].length + va_arg(ap, int) -
-                       this->bounds [i].lower_bound;;
+       for (i = 0; i < class->rank; i++) {
+               ind = va_arg(ap, int);
+               realidx = ind - (int)this->bounds [i].lower_bound;
+               if (realidx < 0 || realidx >= this->bounds [i].length)
+                       mono_raise_exception (mono_get_exception_index_out_of_range ());
+               esize *= realidx;
        }
 
        if (ind >= this->max_length)
                mono_raise_exception (mono_get_exception_index_out_of_range ());
 
-       esize = mono_array_element_size (class);
-       ea = (gpointer*)((char*)this->vector + (ind * esize));
+       ea = (gpointer*)((char*)this->vector + esize);
 
        va_end(ap);
 
index 25f989bdc485533d728daf4ffcb51c04e24be6f8..2645ae254b153476d64831e1b3eddf71ceec612c 100644 (file)
@@ -294,6 +294,8 @@ MINI_OP(OP_ATAN,    "atan")
 MINI_OP(OP_SQRT,    "sqrt")
 /* to optimize strings */
 MINI_OP(OP_GETCHR, "getchar")
+/* get adrress of element in a 2D array */
+MINI_OP(OP_LDELEMA2D, "getldelema2")
 
 /* x86 specific */
 MINI_OP(OP_X86_TEST_NULL,          "x86_test_null")
index cc21919b90ce3ce52e1f659cfc8057d1bab7673c..b5a5130c18ccc596764ce0f6b07893d5aff923f8 100644 (file)
@@ -1930,6 +1930,35 @@ mono_method_check_inlining (MonoMethod *method)
        return FALSE;
 }
 
+static MonoInst*
+mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
+{
+       int temp, rank;
+       MonoInst *addr;
+       MonoMethodSignature *esig;
+
+       rank = cmethod->signature->param_count - (is_set? 1: 0);
+       /* 
+        * FIXME: handle TypeMismatch for set or use the slow path
+        * for that.
+        */
+       if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
+               MonoInst *indexes;
+               NEW_GROUP (cfg, indexes, sp [1], sp [2]);
+               MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
+               addr->inst_left = sp [0];
+               addr->inst_right = indexes;
+               addr->cil_code = ip;
+               addr->type = STACK_MP;
+               addr->klass = cmethod->klass;
+               return addr;
+       }
+       esig = mono_get_element_address_signature (rank);
+       temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
+       NEW_TEMPLOAD (cfg, addr, temp);
+       return addr;
+}
+
 static MonoInst*
 mini_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
@@ -2717,14 +2746,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
                                        
                        } else if (array_rank) {
-                               MonoMethodSignature *esig;
                                MonoInst *addr;
 
                                if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
-                                       esig = mono_get_element_address_signature (fsig->param_count - 1);
-                                       
-                                       temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
-                                       NEW_TEMPLOAD (cfg, addr, temp);
+                                       addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
                                        NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
                                        ins->cil_code = ip;
                                        if (ins->opcode == CEE_STOBJ) {
@@ -2734,21 +2759,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        }
 
                                } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
-                                       esig = mono_get_element_address_signature (fsig->param_count);
-
-                                       temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
-                                       NEW_TEMPLOAD (cfg, addr, temp);
+                                       addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
                                        NEW_INDLOAD (cfg, ins, addr, fsig->ret);
                                        ins->cil_code = ip;
 
                                        *sp++ = ins;
                                } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
-                                       /* implement me */
-                                       esig = mono_get_element_address_signature (fsig->param_count);
-
-                                       temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
-                                       NEW_TEMPLOAD (cfg, *sp, temp);
-                                       sp++;
+                                       addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
+                                       *sp++ = addr;
                                } else {
                                        g_assert_not_reached ();
                                }