* 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
+
+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
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;
+ }
}
+
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?
#
{
MonoClass *class;
va_list ap;
- int i, ind, esize;
+ int i, ind, esize, realidx;
gpointer ea;
MONO_ARCH_SAVE_REGS;
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);
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")
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)
{
}
} 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) {
}
} 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 ();
}