Tue Sep 26 11:57:26 CEST 2006 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / inssel-x86.brg
1 #define MONO_EMIT_NEW_X86_COMPARE_MEMBASE_REG(cfg,basereg,offset,operand) do { \
2                 MonoInst *inst; \
3                 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
4                 inst->opcode = OP_X86_COMPARE_MEMBASE_REG; \
5                 inst->inst_basereg = basereg; \
6                 inst->inst_offset = offset; \
7                 inst->sreg2 = operand; \
8                 mono_bblock_add_inst (cfg->cbb, inst); \
9         } while (0)
10
11 #define MONO_EMIT_NEW_X86_COMPARE_MEMBASE_IMM(cfg,basereg,offset,operand) do { \
12                 MonoInst *inst; \
13                 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
14                 inst->opcode = OP_X86_COMPARE_MEMBASE_IMM; \
15                 inst->inst_basereg = basereg; \
16                 inst->inst_offset = offset; \
17                 inst->inst_imm = operand; \
18                 mono_bblock_add_inst (cfg->cbb, inst); \
19         } while (0)
20
21 /* override the arch independant versions with fast x86 versions */
22
23 #undef MONO_EMIT_BOUNDS_CHECK
24 #undef MONO_EMIT_BOUNDS_CHECK_IMM
25
26 #define MONO_EMIT_BOUNDS_CHECK(cfg, array_reg, array_type, array_length_field, index_reg) do { \
27                 if (! (state->tree->flags & MONO_INST_NORANGECHECK)) { \
28                         MONO_EMIT_NEW_X86_COMPARE_MEMBASE_REG (cfg, array_reg, G_STRUCT_OFFSET (array_type, array_length_field), index_reg); \
29                         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \
30                 } \
31         } while (0)
32
33 #define MONO_EMIT_BOUNDS_CHECK_IMM(cfg, array_reg, array_type, array_length_field, index_imm) do { \
34                 if (! (state->tree->flags & MONO_INST_NORANGECHECK)) { \
35                         MONO_EMIT_NEW_X86_COMPARE_MEMBASE_IMM (cfg, array_reg, G_STRUCT_OFFSET (array_type, array_length_field), index_imm); \
36                         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \
37                 } \
38         } while (0)
39
40 int call_reg_to_call_membase (int opcode);
41 int alu_reg_to_alu_imm (int op);
42 int alu_reg_to_alu_membase_imm (int op);
43
44 %%
45
46 #
47 # inssel-x86.brg: burg file for special x86 instructions
48 #
49 # Author:
50 #   Dietmar Maurer (dietmar@ximian.com)
51 #   Paolo Molaro (lupus@ximian.com)
52 #
53 # (C) 2002 Ximian, Inc.
54 #
55
56 stmt: OP_START_HANDLER {
57         MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
58         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, spvar->inst_basereg, spvar->inst_offset, X86_ESP);
59 }
60
61 stmt: CEE_ENDFINALLY {
62         MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
63         MONO_EMIT_NEW_LOAD_MEMBASE (s, X86_ESP, spvar->inst_basereg, spvar->inst_offset); 
64         tree->opcode = CEE_RET;
65         mono_bblock_add_inst (s->cbb, tree);
66 }
67
68 stmt: OP_ENDFILTER (reg) {
69         MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
70         MONO_EMIT_NEW_UNALU (s, OP_MOVE, X86_EAX, state->left->reg1);
71         MONO_EMIT_NEW_LOAD_MEMBASE (s, X86_ESP, spvar->inst_basereg, spvar->inst_offset); 
72         tree->opcode = CEE_RET;
73         mono_bblock_add_inst (s->cbb, tree);
74 }
75
76 stmt: CEE_STIND_I8 (OP_REGVAR, lreg) {
77         /* this should only happen for methods returning a long */
78         MONO_EMIT_NEW_UNALU (s, OP_MOVE, X86_EAX, state->right->reg1);
79         MONO_EMIT_NEW_UNALU (s, OP_MOVE, X86_EDX, state->right->reg2);
80 }
81
82 lreg: OP_LNEG (lreg) "3" {
83         int tmpr = mono_regstate_next_int (s->rs);
84         MONO_EMIT_NEW_UNALU (s, CEE_NEG, state->reg1, state->left->reg1);
85         MONO_EMIT_BIALU_IMM (s, tree, OP_ADC_IMM, tmpr, state->left->reg2, 0);
86         MONO_EMIT_NEW_UNALU (s, CEE_NEG, state->reg2, tmpr);
87 }
88
89 freg: OP_LCONV_TO_R8 (lreg) {
90         MONO_EMIT_NEW_UNALU (s, OP_X86_PUSH, -1, state->left->reg2);
91         MONO_EMIT_NEW_UNALU (s, OP_X86_PUSH, -1, state->left->reg1);
92         tree->opcode = OP_X86_FP_LOAD_I8;
93         tree->inst_basereg = X86_ESP;
94         tree->inst_offset = 0;
95         tree->dreg = state->reg1;
96         mono_bblock_add_inst (s->cbb, tree);
97         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, X86_ESP, X86_ESP, 8);
98 }
99
100 freg: OP_LCONV_TO_R4 (lreg) {
101         MONO_EMIT_NEW_UNALU (s, OP_X86_PUSH, -1, state->left->reg2);
102         MONO_EMIT_NEW_UNALU (s, OP_X86_PUSH, -1, state->left->reg1);
103         tree->opcode = OP_X86_FP_LOAD_I8;
104         tree->inst_basereg = X86_ESP;
105         tree->inst_offset = 0;
106         tree->dreg = state->reg1;
107         mono_bblock_add_inst (s->cbb, tree);
108         /* change precision */
109         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER4_MEMBASE_REG, X86_ESP, 0, state->reg1);
110         MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADR4_MEMBASE, state->reg1, X86_ESP, 0);
111         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, X86_ESP, X86_ESP, 8);
112 }
113
114 freg: CEE_CONV_R_UN (reg) {
115         MONO_EMIT_NEW_BIALU_IMM (s, OP_X86_PUSH_IMM, -1, -1, 0);
116         MONO_EMIT_NEW_UNALU (s, OP_X86_PUSH, -1, state->left->reg1);
117         tree->opcode = OP_X86_FP_LOAD_I8;
118         tree->inst_basereg = X86_ESP;
119         tree->inst_offset = 0;
120         tree->dreg = state->reg1;
121         mono_bblock_add_inst (s->cbb, tree);
122         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, X86_ESP, X86_ESP, 8);
123 }
124
125 cflags: OP_COMPARE (CEE_LDIND_REF (base), reg),
126 cflags: OP_COMPARE (CEE_LDIND_I (base), reg),
127 cflags: OP_COMPARE (CEE_LDIND_I4 (base), reg),
128 cflags: OP_COMPARE (CEE_LDIND_U4 (base), reg) {
129         tree->opcode = OP_X86_COMPARE_MEMBASE_REG;
130         tree->inst_basereg = state->left->left->tree->inst_basereg;
131         tree->inst_offset = state->left->left->tree->inst_offset;
132         tree->sreg2 = state->right->reg1;
133         mono_bblock_add_inst (s->cbb, tree);
134 }
135
136 cflags: OP_COMPARE (CEE_LDIND_REF (base), CEE_LDIND_REF (OP_REGVAR)),
137 cflags: OP_COMPARE (CEE_LDIND_I (base), CEE_LDIND_REF (OP_REGVAR)),
138 cflags: OP_COMPARE (CEE_LDIND_I4 (base), CEE_LDIND_REF (OP_REGVAR)),
139 cflags: OP_COMPARE (CEE_LDIND_U4 (base), CEE_LDIND_REF (OP_REGVAR)) {
140         tree->opcode = OP_X86_COMPARE_MEMBASE_REG;
141         tree->inst_basereg = state->left->left->tree->inst_basereg;
142         tree->inst_offset = state->left->left->tree->inst_offset;
143         tree->sreg2 = state->right->left->tree->dreg;
144         mono_bblock_add_inst (s->cbb, tree);
145 }
146
147 cflags: OP_COMPARE (CEE_LDIND_REF (base), OP_ICONST),
148 cflags: OP_COMPARE (CEE_LDIND_I (base), OP_ICONST),
149 cflags: OP_COMPARE (CEE_LDIND_I4 (base), OP_ICONST),
150 cflags: OP_COMPARE (CEE_LDIND_U4 (base), OP_ICONST) {
151         tree->opcode = OP_X86_COMPARE_MEMBASE_IMM;
152         tree->inst_basereg = state->left->left->tree->inst_basereg;
153         tree->inst_offset = state->left->left->tree->inst_offset;
154         tree->inst_imm = state->right->tree->inst_c0;
155         mono_bblock_add_inst (s->cbb, tree);
156 }
157
158
159 cflags: OP_COMPARE (CEE_LDIND_REF (OP_ICONST), OP_ICONST),
160 cflags: OP_COMPARE (CEE_LDIND_I (OP_ICONST), OP_ICONST),
161 cflags: OP_COMPARE (CEE_LDIND_I4 (OP_ICONST), OP_ICONST),
162 cflags: OP_COMPARE (CEE_LDIND_U4 (OP_ICONST), OP_ICONST) {
163         tree->opcode = OP_X86_COMPARE_MEM_IMM;
164         tree->inst_offset = state->left->left->tree->inst_c0;
165         tree->inst_imm = state->right->tree->inst_c0;
166         mono_bblock_add_inst (s->cbb, tree);
167 }
168
169 cflags: OP_COMPARE (reg, CEE_LDIND_REF (base)),
170 cflags: OP_COMPARE (reg, CEE_LDIND_I (base)),
171 cflags: OP_COMPARE (reg, CEE_LDIND_I4 (base)),
172 cflags: OP_COMPARE (reg, CEE_LDIND_U4 (base)) {
173         tree->opcode = OP_X86_COMPARE_REG_MEMBASE;
174         tree->sreg2 = state->right->left->tree->inst_basereg;
175         tree->inst_offset = state->right->left->tree->inst_offset;
176         tree->sreg1 = state->left->reg1;
177         mono_bblock_add_inst (s->cbb, tree);
178 }
179
180 cflags: OP_COMPARE (CEE_LDIND_REF (OP_REGVAR), CEE_LDIND_REF (base)),
181 cflags: OP_COMPARE (CEE_LDIND_I (OP_REGVAR), CEE_LDIND_I (base)),
182 cflags: OP_COMPARE (CEE_LDIND_I4 (OP_REGVAR), CEE_LDIND_I4 (base)),
183 cflags: OP_COMPARE (CEE_LDIND_U4 (OP_REGVAR), CEE_LDIND_U4 (base)) {
184         tree->opcode = OP_X86_COMPARE_REG_MEMBASE;
185         tree->sreg2 = state->right->left->tree->inst_basereg;
186         tree->inst_offset = state->right->left->tree->inst_offset;
187         tree->sreg1 = state->left->left->tree->dreg;
188         mono_bblock_add_inst (s->cbb, tree);
189 }
190
191 cflags : OP_CEQ (OP_COMPARE (OP_CEQ (cflags), OP_ICONST)) {
192         tree->opcode = OP_CNE;
193         tree->dreg = state->reg1;
194         mono_bblock_add_inst (s->cbb, tree);
195 } cost {
196         MBCOND (!state->left->right->tree->inst_c0);
197         return 1;
198 }
199
200 stmt: CEE_STIND_I1 (base, OP_CEQ (OP_COMPARE (OP_CEQ (cflags), OP_ICONST))) {
201         tree->opcode = OP_X86_SETNE_MEMBASE;
202         tree->inst_offset = state->left->tree->inst_offset;
203         tree->inst_basereg = state->left->tree->inst_basereg;
204         mono_bblock_add_inst (s->cbb, tree);
205 } cost {
206         MBCOND (!state->right->left->right->tree->inst_c0);
207         return 1;
208 }
209
210 stmt: CEE_STIND_I1 (base, OP_CEQ (cflags)) {
211         tree->opcode = OP_X86_SETEQ_MEMBASE;
212         tree->inst_offset = state->left->tree->inst_offset;
213         tree->inst_basereg = state->left->tree->inst_basereg;
214         mono_bblock_add_inst (s->cbb, tree);
215 }
216
217 reg: OP_LOCALLOC (OP_ICONST) {
218         if (tree->flags & MONO_INST_INIT) {
219                 /* microcoded in mini-x86.c */
220                 tree->sreg1 = mono_regstate_next_int (s->rs);
221                 tree->dreg = state->reg1;
222                 MONO_EMIT_NEW_ICONST (s, tree->sreg1, state->left->tree->inst_c0);
223                 mono_bblock_add_inst (s->cbb, tree);
224         } else {
225                 guint32 size = state->left->tree->inst_c0;
226                 size = (size + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~ (MONO_ARCH_FRAME_ALIGNMENT - 1);
227                 MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, size);
228                 MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, X86_ESP);
229         }
230 }
231
232 reg: OP_LOCALLOC (reg) {
233         tree->sreg1 = state->left->tree->dreg;
234         tree->dreg = state->reg1;
235         mono_bblock_add_inst (s->cbb, tree);
236 }
237
238 stmt: OP_SETRET (reg) {
239         MONO_EMIT_UNALU (s, tree, OP_MOVE, X86_EAX, state->left->reg1);
240 }
241
242 stmt: OP_SETRET (lreg) {
243         MONO_EMIT_NEW_UNALU (s, OP_MOVE, X86_EDX, state->left->reg2);
244         MONO_EMIT_UNALU (s, tree, OP_MOVE, X86_EAX, state->left->reg1);
245 }
246
247 stmt: OP_SETRET (CEE_LDIND_REF (OP_REGVAR)),
248 stmt: OP_SETRET (CEE_LDIND_I (OP_REGVAR)),
249 stmt: OP_SETRET (CEE_LDIND_I4 (OP_REGVAR)),
250 stmt: OP_SETRET (CEE_LDIND_U4 (OP_REGVAR)) {
251         MONO_EMIT_UNALU (s, tree, OP_MOVE, X86_EAX, state->left->left->tree->dreg);
252 }
253
254 stmt: OP_SETRET (freg) {
255         /* nothing to do */
256 }
257
258 stmt: OP_SETRET (OP_ICONST) {
259         tree->opcode = OP_ICONST;
260         tree->inst_c0 = state->left->tree->inst_c0;
261         tree->dreg = X86_EAX;
262         mono_bblock_add_inst (s->cbb, tree);
263 }
264
265 stmt: OP_SETRET (i8con) {
266         MONO_EMIT_NEW_ICONST (s, X86_EAX, state->left->tree->inst_ls_word);
267         MONO_EMIT_NEW_ICONST (s, X86_EDX, state->left->tree->inst_ms_word);
268 }
269
270 stmt: OP_OUTARG (reg) {
271         tree->opcode = OP_X86_PUSH;
272         tree->sreg1 = state->left->reg1;
273         mono_bblock_add_inst (s->cbb, tree);
274 }
275
276 stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)),
277 stmt: OP_OUTARG (CEE_LDIND_I4 (OP_REGVAR)),
278 stmt: OP_OUTARG (CEE_LDIND_U4 (OP_REGVAR)),
279 stmt: OP_OUTARG (CEE_LDIND_I (OP_REGVAR)) {
280         tree->opcode = OP_X86_PUSH;
281         tree->sreg1 = state->left->left->tree->dreg;
282         mono_bblock_add_inst (s->cbb, tree);
283 }
284
285 stmt: OP_OUTARG (OP_GOT_ENTRY (CEE_LDIND_I (OP_REGVAR), OP_PATCH_INFO)) {
286         MonoInst *ins;
287         ins = mono_mempool_alloc0 (s->mempool, sizeof (MonoInst));
288         ins->opcode = OP_X86_PUSH_GOT_ENTRY;
289         ins->inst_right = state->left->right->tree;
290         ins->inst_basereg = state->left->left->left->tree->dreg;
291         mono_bblock_add_inst (s->cbb, ins);
292 }
293
294 stmt: OP_OUTARG (lreg) {
295         MONO_EMIT_NEW_UNALU (s, OP_X86_PUSH, -1, state->left->reg2);
296         tree->opcode = OP_X86_PUSH;
297         tree->sreg1 = state->left->reg1;
298         mono_bblock_add_inst (s->cbb, tree);
299 }
300
301 stmt: OP_OUTARG (CEE_LDIND_I8 (base)) {
302         MonoInst *ins;
303         ins = mono_mempool_alloc0 (s->mempool, sizeof (MonoInst));
304         ins->opcode = OP_X86_PUSH_MEMBASE;
305         ins->inst_basereg = state->left->left->tree->inst_basereg;
306         ins->inst_offset = state->left->left->tree->inst_offset + 4;
307         mono_bblock_add_inst (s->cbb, ins);
308
309         tree->opcode = OP_X86_PUSH_MEMBASE;
310         tree->inst_basereg = state->left->left->tree->inst_basereg;
311         tree->inst_offset = state->left->left->tree->inst_offset;
312         mono_bblock_add_inst (s->cbb, tree);
313 }
314
315 stmt: OP_OUTARG (OP_ICONST) {
316         tree->opcode = OP_X86_PUSH_IMM;
317         tree->inst_imm = state->left->tree->inst_c0;
318         mono_bblock_add_inst (s->cbb, tree);
319 }
320
321 stmt: OP_OUTARG (i8con) {
322         MonoInst *ins;
323         ins = mono_mempool_alloc0 (s->mempool, sizeof (MonoInst));
324         ins->opcode = OP_X86_PUSH_IMM;
325         ins->inst_imm = state->left->tree->inst_ms_word;
326         mono_bblock_add_inst (s->cbb, ins);
327
328         tree->opcode = OP_X86_PUSH_IMM;
329         tree->inst_imm = state->left->tree->inst_ls_word;
330         mono_bblock_add_inst (s->cbb, tree);
331 }
332
333 stmt: OP_OUTARG (CEE_LDIND_I4 (base)),
334 stmt: OP_OUTARG (CEE_LDIND_U4 (base)),
335 stmt: OP_OUTARG (CEE_LDIND_I (base)),
336 stmt: OP_OUTARG (CEE_LDIND_REF (base)) {
337         tree->opcode = OP_X86_PUSH_MEMBASE;
338         tree->inst_basereg = state->left->left->tree->inst_basereg;
339         tree->inst_offset = state->left->left->tree->inst_offset;
340         mono_bblock_add_inst (s->cbb, tree);
341 }
342
343 stmt: OP_OUTARG (freg) {
344         MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, 8);
345         tree->opcode = OP_STORER8_MEMBASE_REG;
346         tree->sreg1 = state->left->reg1;
347         tree->inst_destbasereg = X86_ESP;
348         tree->inst_offset = 0;
349         mono_bblock_add_inst (s->cbb, tree);
350 }
351
352 stmt: OP_OUTARG_R4 (freg) {
353         MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, 4);
354         tree->opcode = OP_STORER4_MEMBASE_REG;
355         tree->sreg1 = state->left->reg1;
356         tree->inst_destbasereg = X86_ESP;
357         tree->inst_offset = 0;
358         mono_bblock_add_inst (s->cbb, tree);
359 }
360
361 stmt: OP_OUTARG_R8 (freg) {
362         MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, 8);
363         tree->opcode = OP_STORER8_MEMBASE_REG;
364         tree->sreg1 = state->left->reg1;
365         tree->inst_destbasereg = X86_ESP;
366         tree->inst_offset = 0;
367         mono_bblock_add_inst (s->cbb, tree);
368 }
369
370 stmt: OP_OUTARG_VT (CEE_LDOBJ (base)) {
371         MonoInst *vt = state->left->left->tree;
372         //g_print ("vt size: %d at R%d + %d\n", tree->inst_imm, vt->inst_basereg, vt->inst_offset);
373
374         if (!tree->inst_imm)
375                 return;
376
377         if (tree->inst_imm <= 4) {
378                 tree->opcode = OP_X86_PUSH_MEMBASE;
379                 tree->inst_basereg = vt->inst_basereg;
380                 tree->inst_offset = vt->inst_offset;
381                 mono_bblock_add_inst (s->cbb, tree);
382         } else if (tree->inst_imm <= 20) {
383                 int sz = tree->inst_imm;
384                 sz += 3;
385                 sz &= ~3;
386                 MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, sz);
387                 mini_emit_memcpy (s, X86_ESP, 0, vt->inst_basereg, vt->inst_offset, tree->inst_imm, 0);
388         } else {
389                 tree->opcode = OP_X86_PUSH_OBJ;
390                 tree->inst_basereg = vt->inst_basereg;
391                 tree->inst_offset = vt->inst_offset;
392                 mono_bblock_add_inst (s->cbb, tree);
393         }
394 }
395
396 stmt: OP_OUTARG_VT (OP_ICONST) {
397         tree->opcode = OP_X86_PUSH_IMM;
398         tree->inst_imm = state->left->tree->inst_c0;
399         mono_bblock_add_inst (s->cbb, tree);
400 }
401
402 stmt: OP_OUTARG_VT (reg) {
403         tree->opcode = OP_X86_PUSH;
404         tree->sreg1 = state->left->reg1;
405         mono_bblock_add_inst (s->cbb, tree);
406 }
407
408 stmt: OP_X86_OUTARG_ALIGN_STACK {
409         MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, tree->inst_c0);
410 }       
411
412 reg: OP_LDADDR (OP_REGOFFSET),
413 reg: CEE_LDOBJ (OP_REGOFFSET) {
414         if (state->left->tree->inst_offset) {
415                 tree->opcode = OP_X86_LEA_MEMBASE;
416                 tree->inst_imm = state->left->tree->inst_offset;
417         } else
418                 tree->opcode = OP_MOVE;
419         
420         tree->sreg1 = state->left->tree->inst_basereg;
421         tree->dreg = state->reg1;
422         mono_bblock_add_inst (s->cbb, tree);
423 }
424
425 reg: CEE_LDELEMA (reg, reg) "15" {
426         guint32 size = mono_class_array_element_size (tree->klass);
427         
428         MONO_EMIT_BOUNDS_CHECK (s, state->left->reg1, MonoArray, max_length, state->right->reg1);
429
430         if (size == 1 || size == 2 || size == 4 || size == 8) {
431                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
432                 tree->opcode = OP_X86_LEA;
433                 tree->dreg = state->reg1;
434                 tree->sreg1 = state->left->reg1;
435                 tree->sreg2 = state->right->reg1;
436                 tree->inst_imm = G_STRUCT_OFFSET (MonoArray, vector);
437                 tree->backend.shift_amount = fast_log2 [size];
438                 mono_bblock_add_inst (s->cbb, tree);
439         } else {
440                 int mult_reg = mono_regstate_next_int (s->rs);
441                 int add_reg = mono_regstate_next_int (s->rs);
442                 MONO_EMIT_NEW_BIALU_IMM (s, OP_MUL_IMM, mult_reg, state->right->reg1, size);
443                 MONO_EMIT_NEW_BIALU (s, CEE_ADD, add_reg, mult_reg, state->left->reg1);
444                 MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, state->reg1, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
445         }
446 }
447
448 stmt: CEE_STIND_R8 (OP_REGVAR, freg) {
449         /* nothing to do: the value is already on the FP stack */
450 }
451
452 stmt: CEE_STIND_I4 (base, CEE_AND (CEE_LDIND_U4 (base), OP_ICONST)),
453 stmt: CEE_STIND_I4 (base, CEE_OR (CEE_LDIND_U4 (base), OP_ICONST)),
454 stmt: CEE_STIND_I4 (base, CEE_XOR (CEE_LDIND_U4 (base), OP_ICONST)),
455 stmt: CEE_STIND_I4 (base, CEE_SUB (CEE_LDIND_U4 (base), OP_ICONST)),
456 stmt: CEE_STIND_I4 (base, CEE_ADD (CEE_LDIND_U4 (base), OP_ICONST)),
457 stmt: CEE_STIND_I4 (base, CEE_AND (CEE_LDIND_I4 (base), OP_ICONST)),
458 stmt: CEE_STIND_I4 (base, CEE_OR (CEE_LDIND_I4 (base), OP_ICONST)),
459 stmt: CEE_STIND_I4 (base, CEE_XOR (CEE_LDIND_I4 (base), OP_ICONST)),
460 stmt: CEE_STIND_I4 (base, CEE_SUB (CEE_LDIND_I4 (base), OP_ICONST)),
461 stmt: CEE_STIND_I4 (base, CEE_ADD (CEE_LDIND_I4 (base), OP_ICONST)) {
462         int con = state->right->right->tree->inst_c0;   
463         MBTREE_TYPE *t1 = state->left->tree;
464         MBTREE_TYPE *t2 = state->right->left->left->tree;
465         int op = state->right->tree->opcode;
466
467         /* inst_basereg/offset can't be used for base
468          * operands in cost functions, since they are not set yet,
469          * so we catch all the cases and handle them here.
470          */
471         if (t1->inst_basereg == t2->inst_basereg && t1->inst_offset == t2->inst_offset) {
472                 if (con == 1 && op == CEE_ADD) {
473                         tree->opcode = OP_X86_INC_MEMBASE;
474                 } else if (con == 1 && op == CEE_SUB) {
475                         tree->opcode = OP_X86_DEC_MEMBASE;
476                 } else {
477                         tree->opcode = alu_reg_to_alu_membase_imm (op);
478                         tree->inst_imm = con;
479                 }
480
481                 tree->inst_basereg = state->left->tree->inst_basereg;
482                 tree->inst_offset = state->left->tree->inst_offset;
483                 mono_bblock_add_inst (s->cbb, tree);
484         } else {
485                 /* emit by hand */
486                 int loaded_reg = mono_regstate_next_int (s->rs);
487                 int add_reg = mono_regstate_next_int (s->rs);
488                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADI4_MEMBASE, loaded_reg, t2->inst_basereg, t2->inst_offset);
489                 MONO_EMIT_NEW_BIALU_IMM (s, alu_reg_to_alu_imm (op), add_reg, loaded_reg, con);
490                 MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI4_MEMBASE_REG, t1->inst_basereg, t1->inst_offset, add_reg);
491         }
492 }
493
494 #
495 # this rules is incorrect, it needs to do an indirect inc (inc_membase)
496 #stmt: CEE_STIND_I4 (reg, CEE_ADD (reg, OP_ICONST)) {
497 #       tree->opcode = OP_X86_INC_REG;
498 #       tree->dreg = state->left->reg1;
499 #       mono_bblock_add_inst (s->cbb, tree);
500 #} cost {
501 #       MBState *s1 = state->left;
502 #       MBState *s2 = state->right->left;
503 #       int con = state->right->right->tree->inst_c0;   
504 #       MBCOND (con == 1 && s1->reg1 == s2->reg1);
505 #       return 1;
506 #}
507
508 stmt: CEE_STIND_I4 (OP_REGVAR, CEE_SUB (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)) {
509         int con = state->right->right->tree->inst_c0;   
510         int dreg = state->left->tree->dreg;
511         int sreg = state->right->left->left->tree->dreg;
512
513         if (con == 1) {
514                 if (dreg != sreg)
515                         MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, sreg);
516                 tree->opcode = OP_X86_DEC_REG;
517                 tree->dreg = tree->sreg1 = dreg;
518         } else if (con == -1) {
519                 if (dreg != sreg)
520                         MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, sreg);
521                 tree->opcode = OP_X86_INC_REG;
522                 tree->dreg = tree->sreg1 = dreg;
523         } else {
524                 tree->opcode = OP_SUB_IMM;
525                 tree->inst_imm = con;
526                 tree->sreg1 = sreg;
527                 tree->dreg = dreg;
528         }
529         mono_bblock_add_inst (s->cbb, tree);
530 }
531
532 stmt: CEE_STIND_I (OP_REGVAR, CEE_ADD (CEE_LDIND_I (OP_REGVAR), OP_ICONST)),
533 stmt: CEE_STIND_I4 (OP_REGVAR, CEE_ADD (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)) {
534         int con = state->right->right->tree->inst_c0;
535         int dreg = state->left->tree->dreg;
536         int sreg = state->right->left->left->tree->dreg;
537
538         if (con == 1) {
539                 if (dreg != sreg)
540                         MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, sreg);
541                 tree->opcode = OP_X86_INC_REG;
542                 tree->dreg = tree->sreg1 = dreg;
543         } else if (con == -1) {
544                 if (dreg != sreg)
545                         MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, sreg);
546                 tree->opcode = OP_X86_DEC_REG;
547                 tree->dreg = tree->sreg1 = dreg;
548         } else {
549                 tree->opcode = OP_ADD_IMM;
550                 tree->inst_imm = con;
551                 tree->sreg1 = sreg;
552                 tree->dreg = dreg;
553         }
554         mono_bblock_add_inst (s->cbb, tree);
555 }
556
557 reg: CEE_LDIND_I2 (OP_REGVAR) {
558         MONO_EMIT_UNALU (s, tree, OP_SEXT_I2, state->reg1, state->left->tree->dreg);
559 }
560
561 # The XOR rule
562 stmt: CEE_STIND_I4 (OP_REGVAR, OP_ICONST),
563 stmt: CEE_STIND_I2 (OP_REGVAR, OP_ICONST),
564 stmt: CEE_STIND_I1 (OP_REGVAR, OP_ICONST),
565 stmt: CEE_STIND_REF (OP_REGVAR, OP_ICONST),
566 stmt: CEE_STIND_I (OP_REGVAR, OP_ICONST) {
567         int r = state->left->tree->dreg;
568         MONO_EMIT_BIALU (s, tree, CEE_XOR, r, r, r);
569 } cost {
570         MBCOND (!state->right->tree->inst_c0);
571         
572         return 0;
573 }
574
575 # on x86, fp compare overwrites EAX, so we must
576 # either improve the local register allocator or
577 # emit coarse opcodes which saves EAX for us.
578
579 reg: OP_CEQ (OP_COMPARE (freg, freg)) { 
580         MONO_EMIT_BIALU (s, tree, OP_FCEQ, state->reg1, state->left->left->reg1,
581                          state->left->right->reg1);
582 }
583
584 reg: OP_CLT (OP_COMPARE (freg, freg)) { 
585         MONO_EMIT_BIALU (s, tree, OP_FCLT, state->reg1, state->left->left->reg1,
586                          state->left->right->reg1);
587 }
588
589 reg: OP_CLT_UN (OP_COMPARE (freg, freg)) {      
590         MONO_EMIT_BIALU (s, tree, OP_FCLT_UN, state->reg1, state->left->left->reg1,
591                          state->left->right->reg1);
592 }
593
594 reg: OP_CGT (OP_COMPARE (freg, freg)) { 
595         MONO_EMIT_BIALU (s, tree, OP_FCGT, state->reg1, state->left->left->reg1,
596                          state->left->right->reg1);
597 }
598
599 reg: OP_CGT_UN (OP_COMPARE (freg, freg)) {      
600         MONO_EMIT_BIALU (s, tree, OP_FCGT_UN, state->reg1, state->left->left->reg1,
601                          state->left->right->reg1);
602 }
603
604 # fpcflags overwrites EAX, but this does not matter for statements
605 # because we are the last operation in the tree.
606  
607 stmt: CEE_BNE_UN (fpcflags) {
608         tree->opcode = OP_FBNE_UN;
609         mono_bblock_add_inst (s->cbb, tree);
610 }
611
612 stmt: CEE_BEQ (fpcflags) {
613         tree->opcode = OP_FBEQ;
614         mono_bblock_add_inst (s->cbb, tree);
615 }
616
617 stmt: CEE_BLT (fpcflags) {
618         tree->opcode = OP_FBLT;
619         mono_bblock_add_inst (s->cbb, tree);
620 }
621
622 stmt: CEE_BLT_UN (fpcflags) {
623         tree->opcode = OP_FBLT_UN;
624         mono_bblock_add_inst (s->cbb, tree);
625 }
626
627 stmt: CEE_BGT (fpcflags) {
628         tree->opcode = OP_FBGT;
629         mono_bblock_add_inst (s->cbb, tree);
630 }
631
632 stmt: CEE_BGT_UN (fpcflags) {
633         tree->opcode = OP_FBGT_UN;
634         mono_bblock_add_inst (s->cbb, tree);
635 }
636
637 stmt: CEE_BGE  (fpcflags) {
638         tree->opcode = OP_FBGE;
639         mono_bblock_add_inst (s->cbb, tree);
640 }
641
642 stmt: CEE_BGE_UN (fpcflags) {
643         tree->opcode = OP_FBGE_UN;
644         mono_bblock_add_inst (s->cbb, tree);
645 }
646
647 stmt: CEE_BLE  (fpcflags) {
648         tree->opcode = OP_FBLE;
649         mono_bblock_add_inst (s->cbb, tree);
650 }
651
652 stmt: CEE_BLE_UN (fpcflags) {
653         tree->opcode = OP_FBLE_UN;
654         mono_bblock_add_inst (s->cbb, tree);
655 }
656
657 stmt: CEE_POP (freg) "0" {
658         /* we need to pop the value from the x86 FP stack */
659         MONO_EMIT_UNALU (s, tree, OP_X86_FPOP, -1, state->left->reg1);  
660 }     
661
662 # override the rules in inssel-float.brg that work for machines with FP registers 
663
664 freg: OP_FCONV_TO_R8 (freg) "0" {
665         /* nothing to do */
666 }
667
668 freg: OP_FCONV_TO_R4 (freg) "0" {
669         /* fixme: nothing to do ??*/
670 }
671
672 reg: CEE_ADD(reg, CEE_LDIND_I4 (base)) {
673         MonoInst *base = state->right->left->tree;
674
675         tree->dreg = state->reg1;
676         tree->sreg1 = state->left->reg1;
677         tree->sreg2 = base->inst_basereg; 
678         tree->inst_offset = base->inst_offset; 
679         tree->opcode = OP_X86_ADD_MEMBASE; 
680         mono_bblock_add_inst (s->cbb, tree);
681
682
683 reg: CEE_SUB(reg, CEE_LDIND_I4 (base)) {
684         MonoInst *base = state->right->left->tree;
685
686         tree->dreg = state->reg1;
687         tree->sreg1 = state->left->reg1;
688         tree->sreg2 = base->inst_basereg; 
689         tree->inst_offset = base->inst_offset; 
690         tree->opcode = OP_X86_SUB_MEMBASE; 
691         mono_bblock_add_inst (s->cbb, tree);
692
693
694 reg: CEE_MUL(reg, CEE_LDIND_I4 (base)) {
695         MonoInst *base = state->right->left->tree;
696
697         tree->dreg = state->reg1;
698         tree->sreg1 = state->left->reg1;
699         tree->sreg2 = base->inst_basereg; 
700         tree->inst_offset = base->inst_offset; 
701         tree->opcode = OP_X86_MUL_MEMBASE; 
702         mono_bblock_add_inst (s->cbb, tree);
703
704
705 lreg: OP_LSHL (lreg, reg) "0" {
706         MONO_EMIT_BIALU (s, tree, tree->opcode, state->reg1, state->left->reg1, state->right->reg1);
707 }
708
709 lreg: OP_LSHL (lreg, OP_ICONST) "0" {
710         MONO_EMIT_BIALU_IMM (s, tree, OP_LSHL_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
711 }
712
713 lreg: OP_LSHR (lreg, reg) "0" {
714         MONO_EMIT_BIALU (s, tree, tree->opcode, state->reg1, state->left->reg1, state->right->reg1);
715 }
716
717 lreg: OP_LSHR (lreg, OP_ICONST) "0" {
718         MONO_EMIT_BIALU_IMM (s, tree, OP_LSHR_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
719 }
720
721 lreg: OP_LSHR_UN (lreg, reg) "0" {
722         MONO_EMIT_BIALU (s, tree, tree->opcode, state->reg1, state->left->reg1, state->right->reg1);
723 }
724
725 lreg: OP_LSHR_UN (lreg, OP_ICONST) "0" {
726         MONO_EMIT_BIALU_IMM (s, tree, OP_LSHR_UN_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
727 }
728
729 reg: OP_ATOMIC_ADD_NEW_I4 (base, reg),
730 reg: OP_ATOMIC_ADD_I4 (base, reg) {
731         tree->opcode = tree->opcode;
732         tree->inst_basereg = state->left->tree->inst_basereg; 
733         tree->inst_offset = state->left->tree->inst_offset; 
734         tree->dreg = state->reg1;
735         tree->sreg2 = state->right->reg1;
736     
737         mono_bblock_add_inst (s->cbb, tree);
738 }
739
740 reg: OP_ATOMIC_EXCHANGE_I4 (base, reg) {
741     tree->opcode = OP_ATOMIC_EXCHANGE_I4;
742     tree->dreg = state->reg1;
743     tree->sreg2 = state->right->reg1;
744     tree->inst_basereg = state->left->tree->inst_basereg; 
745     tree->inst_offset = state->left->tree->inst_offset; 
746     
747         mono_bblock_add_inst (s->cbb, tree);
748 }
749
750 # Optimized call instructions
751 # mono_arch_patch_delegate_trampoline depends on these
752 reg: OP_CALL_REG (CEE_LDIND_I (base)),
753 freg: OP_FCALL_REG (CEE_LDIND_I (base)),
754 reg: OP_LCALL_REG (CEE_LDIND_I (base)) {
755         tree->opcode = call_reg_to_call_membase (tree->opcode);
756         tree->inst_basereg = state->left->left->tree->inst_basereg;
757         tree->inst_offset = state->left->left->tree->inst_offset;
758         tree->dreg = state->reg1;
759         mono_bblock_add_inst (s->cbb, tree);
760 }
761
762 lreg: OP_LCALL_REG (CEE_LDIND_I (base)) {
763         tree->opcode = call_reg_to_call_membase (tree->opcode);
764         tree->inst_basereg = state->left->left->tree->inst_basereg;
765         tree->inst_offset = state->left->left->tree->inst_offset;
766         tree->dreg = state->reg1;
767         mono_bblock_add_inst (s->cbb, tree);
768 }
769
770 stmt: OP_VOIDCALL_REG (CEE_LDIND_I (base)) {
771         tree->opcode = call_reg_to_call_membase (tree->opcode);
772         tree->inst_basereg = state->left->left->tree->inst_basereg;
773         tree->inst_offset = state->left->left->tree->inst_offset;
774         mono_bblock_add_inst (s->cbb, tree);
775 }
776
777 stmt: OP_VCALL_REG (CEE_LDIND_I (base), reg) {
778         mono_arch_emit_this_vret_args (s, (MonoCallInst*)tree, -1, -1, state->right->reg1);
779         
780         tree->opcode = call_reg_to_call_membase (tree->opcode);
781         tree->inst_basereg = state->left->left->tree->inst_basereg;
782         tree->inst_offset = state->left->left->tree->inst_offset;
783         tree->dreg = state->reg1;
784         mono_bblock_add_inst (s->cbb, tree);
785 }
786
787 # Optimized ldind(reg) rules
788 reg: CEE_LDIND_REF (OP_REGVAR),
789 reg: CEE_LDIND_I (OP_REGVAR),
790 reg: CEE_LDIND_I4 (OP_REGVAR),
791 reg: CEE_LDIND_U4 (OP_REGVAR) "0" {
792         state->reg1 = state->left->tree->dreg;
793         tree->dreg = state->reg1;
794 }
795
796 reg: OP_STR_CHAR_ADDR (reg, reg) "2" {
797         /*
798          * The corlib functions check for oob already.
799          * MONO_EMIT_BOUNDS_CHECK (s, state->left->reg1, MonoString, length, state->right->reg1);
800          */
801         tree->opcode = OP_X86_LEA;
802         tree->dreg = state->reg1;
803         tree->sreg1 = state->left->reg1;
804         tree->sreg2 = state->right->reg1;
805         tree->inst_imm = G_STRUCT_OFFSET (MonoString, chars);
806         tree->backend.shift_amount = 1; /* shift by two */
807         mono_bblock_add_inst (s->cbb, tree);
808 }
809
810 %%
811
812 int
813 alu_reg_to_alu_imm (int op)
814 {
815         switch (op) {
816         case CEE_ADD:
817                 return OP_ADD_IMM;
818         case CEE_SUB:
819                 return OP_SUB_IMM;
820         case CEE_AND:
821                 return OP_AND_IMM;
822         case CEE_OR:
823                 return OP_OR_IMM;
824         case CEE_XOR:
825                 return OP_XOR_IMM;
826         default:
827                 g_assert_not_reached ();
828         }
829         return -1;
830 }
831
832 int
833 alu_reg_to_alu_membase_imm (int op)
834 {
835         switch (op) {
836         case CEE_ADD:
837                 return OP_X86_ADD_MEMBASE_IMM;
838         case CEE_SUB:
839                 return OP_X86_SUB_MEMBASE_IMM;
840         case CEE_AND:
841                 return OP_X86_AND_MEMBASE_IMM;
842         case CEE_OR:
843                 return OP_X86_OR_MEMBASE_IMM;
844         case CEE_XOR:
845                 return OP_X86_XOR_MEMBASE_IMM;
846         default:
847                 g_assert_not_reached ();
848         }
849         return -1;
850 }
851
852 int
853 call_reg_to_call_membase (int opcode)
854 {
855         switch (opcode) {
856         case OP_CALL_REG:
857                 return OP_CALL_MEMBASE;
858         case OP_FCALL_REG:
859                 return OP_FCALL_MEMBASE;
860         case OP_VCALL_REG:
861                 return OP_VCALL_MEMBASE;
862         case OP_LCALL_REG:
863                 return OP_LCALL_MEMBASE;
864         case OP_VOIDCALL_REG:
865                 return OP_VOIDCALL_MEMBASE;
866         default:
867                 g_assert_not_reached ();
868         }
869
870         return -1;
871 }