[jit] Add mini_emit_memory_store and use it for STOBJ.
[mono.git] / mono / mini / memory-access.c
1 /**
2  * Emit memory access for the front-end.
3  *
4  */
5
6 #include <config.h>
7 #include <mono/utils/mono-compiler.h>
8
9 #ifndef DISABLE_JIT
10
11 #include <mono/utils/mono-memory-model.h>
12
13 #include "mini.h"
14 #include "ir-emit.h"
15
16 void 
17 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
18 {
19         int val_reg;
20
21         g_assert (val == 0);
22
23         if (align == 0)
24                 align = 4;
25
26         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
27                 switch (size) {
28                 case 1:
29                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
30                         return;
31                 case 2:
32                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
33                         return;
34                 case 4:
35                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
36                         return;
37 #if SIZEOF_REGISTER == 8
38                 case 8:
39                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
40                         return;
41 #endif
42                 }
43         }
44
45         val_reg = alloc_preg (cfg);
46
47         if (SIZEOF_REGISTER == 8)
48                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
49         else
50                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
51
52         if (align < 4) {
53                 /* This could be optimized further if neccesary */
54                 while (size >= 1) {
55                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
56                         offset += 1;
57                         size -= 1;
58                 }
59                 return;
60         }       
61
62         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
63                 if (offset % 8) {
64                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
65                         offset += 4;
66                         size -= 4;
67                 }
68                 while (size >= 8) {
69                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
70                         offset += 8;
71                         size -= 8;
72                 }
73         }       
74
75         while (size >= 4) {
76                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
77                 offset += 4;
78                 size -= 4;
79         }
80         while (size >= 2) {
81                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
82                 offset += 2;
83                 size -= 2;
84         }
85         while (size >= 1) {
86                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
87                 offset += 1;
88                 size -= 1;
89         }
90 }
91
92 void 
93 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
94 {
95         int cur_reg;
96
97         if (align == 0)
98                 align = 4;
99
100         /*FIXME arbitrary hack to avoid unbound code expansion.*/
101         g_assert (size < 10000);
102
103         if (align < 4) {
104                 /* This could be optimized further if neccesary */
105                 while (size >= 1) {
106                         cur_reg = alloc_preg (cfg);
107                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
108                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
109                         doffset += 1;
110                         soffset += 1;
111                         size -= 1;
112                 }
113         }
114
115         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
116                 while (size >= 8) {
117                         cur_reg = alloc_preg (cfg);
118                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
119                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
120                         doffset += 8;
121                         soffset += 8;
122                         size -= 8;
123                 }
124         }       
125
126         while (size >= 4) {
127                 cur_reg = alloc_preg (cfg);
128                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
129                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
130                 doffset += 4;
131                 soffset += 4;
132                 size -= 4;
133         }
134         while (size >= 2) {
135                 cur_reg = alloc_preg (cfg);
136                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
137                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
138                 doffset += 2;
139                 soffset += 2;
140                 size -= 2;
141         }
142         while (size >= 1) {
143                 cur_reg = alloc_preg (cfg);
144                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
145                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
146                 doffset += 1;
147                 soffset += 1;
148                 size -= 1;
149         }
150 }
151
152 MonoInst*
153 mini_emit_memory_load (MonoCompile *cfg, MonoType *type, MonoInst *src, int offset, int ins_flag)
154 {
155         MonoInst *ins;
156
157         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, type, src->dreg, offset);
158         ins->flags |= ins_flag;
159
160         if (ins_flag & MONO_INST_VOLATILE) {
161                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
162                 mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
163         }
164
165         return ins;
166 }
167
168
169 void
170 mini_emit_memory_store (MonoCompile *cfg, MonoType *type, MonoInst *dest, MonoInst *value, int ins_flag)
171 {
172         MonoInst *ins;
173
174         if (ins_flag & MONO_INST_VOLATILE) {
175                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
176                 mini_emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
177         }
178         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
179
180         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, type, dest->dreg, 0, value->dreg);
181         ins->flags |= ins_flag;
182         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
183                 mini_type_is_reference (type) && !MONO_INS_IS_PCONST_NULL (value)) {
184                 /* insert call to write barrier */
185                 mini_emit_write_barrier (cfg, dest, value);
186         }
187 }
188
189 #endif