+static int
+mono_emit_vector_ldelema (MonoCompile *cfg, MonoType *array_type, MonoInst *arr, MonoInst *index, gboolean check_bounds)
+{
+ MonoInst *ins;
+ guint32 size;
+ int mult_reg, add_reg, array_reg, index_reg, index2_reg, index3_reg;
+
+ size = mono_array_element_size (mono_class_from_mono_type (array_type));
+ mult_reg = alloc_preg (cfg);
+ array_reg = arr->dreg;
+ index_reg = index->dreg;
+
+#if SIZEOF_VOID_P == 8
+ /* The array reg is 64 bits but the index reg is only 32 */
+ index2_reg = alloc_preg (cfg);
+ MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
+#else
+ index2_reg = index_reg;
+#endif
+ index3_reg = alloc_preg (cfg);
+
+ if (check_bounds) {
+ MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PADD_IMM, index3_reg, index2_reg, 16 / size - 1);
+ MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index3_reg);
+ }
+
+ add_reg = alloc_preg (cfg);
+
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
+ MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
+ NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
+ ins->type = STACK_PTR;
+ MONO_ADD_INS (cfg->cbb, ins);
+
+ return add_reg;
+}
+
+static MonoInst*
+emit_array_extension_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+{
+ if (!strcmp ("GetVector", cmethod->name) || !strcmp ("GetVectorAligned", cmethod->name)) {
+ MonoInst *load;
+ int addr = mono_emit_vector_ldelema (cfg, fsig->params [0], args [0], args [1], TRUE);
+
+ MONO_INST_NEW (cfg, load, !strcmp ("GetVectorAligned", cmethod->name) ? OP_LOADX_ALIGNED_MEMBASE : OP_LOADX_MEMBASE );
+ load->klass = cmethod->klass;
+ load->sreg1 = addr;
+ load->type = STACK_VTYPE;
+ load->dreg = alloc_ireg (cfg);
+ MONO_ADD_INS (cfg->cbb, load);
+
+ return load;
+ }
+ if (!strcmp ("SetVector", cmethod->name) || !strcmp ("SetVectorAligned", cmethod->name)) {
+ MonoInst *store;
+ int vreg = get_simd_vreg (cfg, cmethod, args [1]);
+ int addr = mono_emit_vector_ldelema (cfg, fsig->params [0], args [0], args [2], TRUE);
+
+ MONO_INST_NEW (cfg, store, !strcmp ("SetVectorAligned", cmethod->name) ? OP_STOREX_ALIGNED_MEMBASE_REG : OP_STOREX_MEMBASE);
+ store->klass = cmethod->klass;
+ store->dreg = addr;
+ store->sreg1 = vreg;
+ MONO_ADD_INS (cfg->cbb, store);
+
+ return store;
+ }
+ if (!strcmp ("IsAligned", cmethod->name)) {
+ MonoInst *ins;
+ int addr = mono_emit_vector_ldelema (cfg, fsig->params [0], args [0], args [1], FALSE);
+
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, addr, addr, 15);
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, addr, 0);
+ NEW_UNALU (cfg, ins, OP_CEQ, addr, -1);
+ MONO_ADD_INS (cfg->cbb, ins);
+
+ return ins;
+ }
+ return NULL;
+}
+