[jit] Add mini_emit_memory_copy_bytes and mini_emit_memory_init_bytes to be used...
authorRodrigo Kumpera <kumpera@gmail.com>
Tue, 9 May 2017 20:50:30 +0000 (13:50 -0700)
committerRodrigo Kumpera <kumpera@gmail.com>
Tue, 9 May 2017 23:04:31 +0000 (16:04 -0700)
mono/mini/memory-access.c
mono/mini/mini.h

index 76c42e0b04f64a577bc3a17723a49553c74553fb..8974cf4c6e69606645dbad744c59b45bc8c3ddc3 100644 (file)
@@ -13,6 +13,8 @@
 #include "mini.h"
 #include "ir-emit.h"
 
+#define MAX_INLINE_COPIES 10
+
 void 
 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
 {
@@ -149,6 +151,62 @@ mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int so
        }
 }
 
+static void
+mini_emit_memcpy_internal (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoInst *size_ins, int size, int align)
+{
+       /* FIXME: Optimize the case when src/dest is OP_LDADDR */
+
+       /* We can't do copies at a smaller granule than the provided alignment */
+       if (size_ins || ((size / align > MAX_INLINE_COPIES) && !(cfg->opt & MONO_OPT_INTRINS))) {
+               MonoInst *iargs [3];
+               iargs [0] = dest;
+               iargs [1] = src;
+
+               if (!size_ins)
+                       EMIT_NEW_ICONST (cfg, size_ins, size);
+               iargs [2] = size_ins;
+               mono_emit_method_call (cfg, mini_get_memcpy_method (), iargs, NULL);
+       } else {
+               mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, size, align);
+       }
+}
+
+static void
+mini_emit_memset_internal (MonoCompile *cfg, MonoInst *dest, MonoInst *value_ins, int value, MonoInst *size_ins, int size, int align)
+{
+       /* FIXME: Optimize the case when dest is OP_LDADDR */
+
+       /* We can't do copies at a smaller granule than the provided alignment */
+       if (value_ins || size_ins || value != 0 || ((size / align > MAX_INLINE_COPIES) && !(cfg->opt & MONO_OPT_INTRINS))) {
+               MonoInst *iargs [3];
+               iargs [0] = dest;
+
+               if (!value_ins)
+                       EMIT_NEW_ICONST (cfg, value_ins, value);
+               iargs [1] = value_ins;
+
+               if (!size_ins)
+                       EMIT_NEW_ICONST (cfg, size_ins, size);
+               iargs [2] = size_ins;
+
+               mono_emit_method_call (cfg, mini_get_memset_method (), iargs, NULL);
+       } else {
+               mini_emit_memset (cfg, dest->dreg, 0, size, value, align);
+       }
+}
+
+static void
+mini_emit_memcpy_const_size (MonoCompile *cfg, MonoInst *dest, MonoInst *src, int size, int align)
+{
+       mini_emit_memcpy_internal (cfg, dest, src, NULL, size, align);
+}
+
+static void
+mini_emit_memset_const_size (MonoCompile *cfg, MonoInst *dest, int value, int size, int align)
+{
+       mini_emit_memset_internal (cfg, dest, NULL, value, NULL, size, align);
+}
+
 MonoInst*
 mini_emit_memory_load (MonoCompile *cfg, MonoType *type, MonoInst *src, int offset, int ins_flag)
 {
@@ -186,4 +244,55 @@ mini_emit_memory_store (MonoCompile *cfg, MonoType *type, MonoInst *dest, MonoIn
        }
 }
 
+void
+mini_emit_memory_copy_bytes (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoInst *size, int ins_flag)
+{
+       int align = SIZEOF_VOID_P;
+
+       /*
+        * FIXME: It's unclear whether we should be emitting both the acquire
+        * and release barriers for cpblk. It is technically both a load and
+        * store operation, so it seems like that's the sensible thing to do.
+        *
+        * FIXME: We emit full barriers on both sides of the operation for
+        * simplicity. We should have a separate atomic memcpy method instead.
+        */
+       if (ins_flag & MONO_INST_VOLATILE) {
+               /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
+               mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
+       }
+
+       if ((cfg->opt & MONO_OPT_INTRINS) && (size->opcode == OP_ICONST)) {
+               mini_emit_memcpy_const_size (cfg, dest, src, size->inst_c0, align);
+       } else {
+               if (cfg->verbose_level > 3)
+                       printf ("EMITING REGULAR COPY\n");
+               mini_emit_memcpy_internal (cfg, dest, src, size, 0, align);
+       }
+
+       if (ins_flag & MONO_INST_VOLATILE) {
+               /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
+               mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
+       }
+}
+
+void
+mini_emit_memory_init_bytes (MonoCompile *cfg, MonoInst *dest, MonoInst *value, MonoInst *size, int ins_flag)
+{
+       int align = SIZEOF_VOID_P;
+
+       if (ins_flag & MONO_INST_VOLATILE) {
+               /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
+               mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
+       }
+
+       //FIXME unrolled memset only supports zeroing
+       if ((cfg->opt & MONO_OPT_INTRINS) && (size->opcode == OP_ICONST) && (value->opcode == OP_ICONST) && (value->inst_c0 == 0)) {
+               mini_emit_memset_const_size (cfg, dest, value->inst_c0, size->inst_c0, align);
+       } else {
+               mini_emit_memset_internal (cfg, dest, value, 0, size, 0, align);
+       }
+
+}
+
 #endif
index da2c219b42fca1b56013cb457208c78b55495f3c..e86b807375f7a0605c056cec4f41e56d24a59388 100644 (file)
@@ -2641,6 +2641,8 @@ void              mini_emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, Mono
 gboolean          mini_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align);
 MonoInst*         mini_emit_memory_load (MonoCompile *cfg, MonoType *type, MonoInst *src, int offset, int ins_flag);
 void              mini_emit_memory_store (MonoCompile *cfg, MonoType *type, MonoInst *dest, MonoInst *value, int ins_flag);
+void              mini_emit_memory_copy_bytes (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoInst *size, int ins_flag);
+void              mini_emit_memory_init_bytes (MonoCompile *cfg, MonoInst *dest, MonoInst *value, MonoInst *size, int ins_flag);
 
 MonoMethod*       mini_get_memcpy_method (void);
 MonoMethod*       mini_get_memset_method (void);