e960a796bc438b67e081c1b4878ad7069d87c91f
[mono.git] / mono / mini / inssel-amd64.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
41 %%
42
43 #
44 # inssel-x86.brg: burg file for special x86 instructions
45 #
46 # Author:
47 #   Dietmar Maurer (dietmar@ximian.com)
48 #   Paolo Molaro (lupus@ximian.com)
49 #
50 # (C) 2002 Ximian, Inc.
51 #
52
53 stmt: OP_START_HANDLER {
54         MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
55         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, spvar->inst_basereg, spvar->inst_offset, X86_ESP);
56 }
57
58 stmt: CEE_ENDFINALLY {
59         MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
60         MONO_EMIT_NEW_LOAD_MEMBASE (s, X86_ESP, spvar->inst_basereg, spvar->inst_offset); 
61         tree->opcode = CEE_RET;
62         mono_bblock_add_inst (s->cbb, tree);
63 }
64
65 stmt: OP_ENDFILTER (reg) {
66         MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
67         MONO_EMIT_NEW_UNALU (s, OP_MOVE, X86_EAX, state->left->reg1);
68         MONO_EMIT_NEW_LOAD_MEMBASE (s, X86_ESP, spvar->inst_basereg, spvar->inst_offset); 
69         tree->opcode = CEE_RET;
70         mono_bblock_add_inst (s->cbb, tree);
71 }
72
73 stmt: CEE_STIND_I8 (OP_REGVAR, reg) {
74         /* this should only happen for methods returning a long */
75         MONO_EMIT_NEW_UNALU (s, OP_MOVE, X86_EAX, state->right->reg1);
76         MONO_EMIT_NEW_UNALU (s, OP_MOVE, X86_EDX, state->right->reg2);
77 }
78
79 freg: OP_LCONV_TO_R8 (reg) {
80         tree->sreg1 = state->left->reg1;
81         tree->dreg = state->reg1;
82         mono_bblock_add_inst (s->cbb, tree);
83 }
84
85 freg: OP_LCONV_TO_R4 (reg) {
86         tree->sreg1 = state->left->reg1;
87         tree->dreg = state->reg1;
88         mono_bblock_add_inst (s->cbb, tree);
89 }
90
91 freg: CEE_CONV_R_UN (reg) {
92         MONO_EMIT_NEW_BIALU_IMM (s, OP_X86_PUSH_IMM, -1, -1, 0);
93         MONO_EMIT_NEW_UNALU (s, OP_X86_PUSH, -1, state->left->reg1);
94         tree->opcode = OP_X86_FP_LOAD_I8;
95         tree->inst_basereg = X86_ESP;
96         tree->inst_offset = 0;
97         mono_bblock_add_inst (s->cbb, tree);
98         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, X86_ESP, X86_ESP, 8);
99 }
100
101 cflags: OP_COMPARE (CEE_LDIND_I4 (base), reg) {
102         tree->opcode = OP_AMD64_ICOMPARE_MEMBASE_REG;
103         tree->inst_basereg = state->left->left->tree->inst_basereg;
104         tree->inst_offset = state->left->left->tree->inst_offset;
105         tree->sreg2 = state->right->reg1;
106         mono_bblock_add_inst (s->cbb, tree);
107 }
108
109 cflags: OP_COMPARE (CEE_LDIND_I4 (base), OP_ICONST) {
110         tree->opcode = OP_AMD64_ICOMPARE_MEMBASE_IMM;
111         tree->inst_basereg = state->left->left->tree->inst_basereg;
112         tree->inst_offset = state->left->left->tree->inst_offset;
113         tree->inst_imm = state->right->tree->inst_c0;
114         mono_bblock_add_inst (s->cbb, tree);
115 }
116
117 cflags: OP_COMPARE (reg, CEE_LDIND_I4 (base)) {
118         tree->opcode = OP_AMD64_ICOMPARE_REG_MEMBASE;
119         tree->sreg2 = state->right->left->tree->inst_basereg;
120         tree->inst_offset = state->right->left->tree->inst_offset;
121         tree->sreg1 = state->left->reg1;
122         mono_bblock_add_inst (s->cbb, tree);
123 }
124
125 stmt: CEE_STIND_I1 (base, OP_CEQ (cflags)) {
126         tree->opcode = OP_X86_SETEQ_MEMBASE;
127         tree->inst_offset = state->left->tree->inst_offset;
128         tree->inst_basereg = state->left->tree->inst_basereg;
129         mono_bblock_add_inst (s->cbb, tree);
130 }
131
132 reg: OP_LOCALLOC (OP_ICONST) {
133         if (tree->flags & MONO_INST_INIT) {
134                 /* microcoded in mini-x86.c */
135                 tree->sreg1 = mono_regstate_next_int (s->rs);
136                 MONO_EMIT_NEW_ICONST (s, tree->sreg1, state->left->tree->inst_c0);
137                 mono_bblock_add_inst (s->cbb, tree);
138         } else {
139                 MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, state->left->tree->inst_c0);
140                 MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, X86_ESP);
141         }
142 }
143
144 reg: OP_LOCALLOC (reg) {
145         tree->sreg1 = state->left->tree->dreg;
146         mono_bblock_add_inst (s->cbb, tree);
147 }
148
149 stmt: OP_SETRET (reg) {
150         tree->opcode = OP_MOVE;
151         tree->sreg1 = state->left->reg1;
152         tree->dreg = X86_EAX;
153         mono_bblock_add_inst (s->cbb, tree);
154 }
155
156 stmt: OP_SETRET (reg) {
157         MONO_EMIT_NEW_UNALU (s, OP_MOVE, X86_EDX, state->left->reg2);
158         tree->opcode = OP_MOVE;
159         tree->sreg1 = state->left->reg1;
160         tree->dreg = X86_EAX;
161         mono_bblock_add_inst (s->cbb, tree);
162 }
163
164 stmt: OP_SETRET (CEE_LDIND_REF (OP_REGVAR)) {
165         tree->opcode = OP_MOVE;
166         tree->sreg1 = state->left->left->tree->dreg;
167         tree->dreg = X86_EAX;
168         mono_bblock_add_inst (s->cbb, tree);
169 }
170
171 stmt: OP_SETRET (freg) {
172         tree->opcode = OP_AMD64_SET_XMMREG;
173         tree->sreg1 = state->left->reg1;
174         tree->dreg = 0; /* %xmm0 */
175         mono_bblock_add_inst (s->cbb, tree);    
176         /* nothing to do */
177 }
178
179 stmt: OP_SETRET (OP_ICONST) {
180         tree->opcode = OP_ICONST;
181         tree->inst_c0 = state->left->tree->inst_c0;
182         tree->dreg = X86_EAX;
183         mono_bblock_add_inst (s->cbb, tree);
184 }
185
186 stmt: OP_OUTARG (reg) {
187         tree->opcode = OP_X86_PUSH;
188         tree->sreg1 = state->left->reg1;
189         mono_bblock_add_inst (s->cbb, tree);
190 }
191
192 stmt: OP_OUTARG_REG (reg) {
193         tree->opcode = OP_SETREG;
194         tree->sreg1 = state->left->reg1;
195         tree->dreg = tree->unused;
196         mono_bblock_add_inst (s->cbb, tree);
197 }
198
199 # we need to reduce this code duplication with some burg syntax extension
200 stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)) {
201         tree->opcode = OP_X86_PUSH;
202         tree->sreg1 = state->left->left->tree->dreg;
203         mono_bblock_add_inst (s->cbb, tree);
204 }
205
206 stmt: OP_OUTARG (CEE_LDIND_I4 (OP_REGVAR)) {
207         tree->opcode = OP_X86_PUSH;
208         tree->sreg1 = state->left->left->tree->dreg;
209         mono_bblock_add_inst (s->cbb, tree);
210 }
211
212 stmt: OP_OUTARG (CEE_LDIND_U4 (OP_REGVAR)) {
213         tree->opcode = OP_X86_PUSH;
214         tree->sreg1 = state->left->left->tree->dreg;
215         mono_bblock_add_inst (s->cbb, tree);
216 }
217
218 stmt: OP_OUTARG (CEE_LDIND_I (OP_REGVAR)) {
219         tree->opcode = OP_X86_PUSH;
220         tree->sreg1 = state->left->left->tree->dreg;
221         mono_bblock_add_inst (s->cbb, tree);
222 }
223
224 stmt: OP_OUTARG (reg) {
225         MONO_EMIT_NEW_UNALU (s, OP_X86_PUSH, -1, state->left->reg2);
226         tree->opcode = OP_X86_PUSH;
227         tree->sreg1 = state->left->reg1;
228         mono_bblock_add_inst (s->cbb, tree);
229 }
230
231 stmt: OP_OUTARG (CEE_LDIND_I8 (base)) {
232         MonoInst *ins;
233         ins = mono_mempool_alloc0 (s->mempool, sizeof (MonoInst));
234         ins->opcode = OP_X86_PUSH_MEMBASE;
235         ins->inst_basereg = state->left->left->tree->inst_basereg;
236         ins->inst_offset = state->left->left->tree->inst_offset + 4;
237         mono_bblock_add_inst (s->cbb, ins);
238
239         tree->opcode = OP_X86_PUSH_MEMBASE;
240         tree->inst_basereg = state->left->left->tree->inst_basereg;
241         tree->inst_offset = state->left->left->tree->inst_offset;
242         mono_bblock_add_inst (s->cbb, tree);
243 }
244
245 stmt: OP_OUTARG (OP_ICONST) {
246         tree->opcode = OP_X86_PUSH_IMM;
247         tree->inst_imm = state->left->tree->inst_c0;
248         mono_bblock_add_inst (s->cbb, tree);
249 } cost {
250         MBCOND (sizeof (gpointer) == 4);
251
252         return 0;
253 }
254
255 stmt: OP_OUTARG (CEE_LDIND_I4 (base)) {
256         tree->opcode = OP_X86_PUSH_MEMBASE;
257         tree->inst_basereg = state->left->left->tree->inst_basereg;
258         tree->inst_offset = state->left->left->tree->inst_offset;
259         mono_bblock_add_inst (s->cbb, tree);
260 }
261
262 stmt: OP_OUTARG (CEE_LDIND_U4 (base)) {
263         tree->opcode = OP_X86_PUSH_MEMBASE;
264         tree->inst_basereg = state->left->left->tree->inst_basereg;
265         tree->inst_offset = state->left->left->tree->inst_offset;
266         mono_bblock_add_inst (s->cbb, tree);
267 }
268
269 stmt: OP_OUTARG (CEE_LDIND_I (base)) {
270         tree->opcode = OP_X86_PUSH_MEMBASE;
271         tree->inst_basereg = state->left->left->tree->inst_basereg;
272         tree->inst_offset = state->left->left->tree->inst_offset;
273         mono_bblock_add_inst (s->cbb, tree);
274 }
275
276 stmt: OP_OUTARG (CEE_LDIND_REF (base)) {
277         tree->opcode = OP_X86_PUSH_MEMBASE;
278         tree->inst_basereg = state->left->left->tree->inst_basereg;
279         tree->inst_offset = state->left->left->tree->inst_offset;
280         mono_bblock_add_inst (s->cbb, tree);
281 }
282
283 stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)) {
284         tree->opcode = OP_X86_PUSH;
285         tree->sreg1 = state->left->left->tree->dreg;
286         mono_bblock_add_inst (s->cbb, tree);
287 }
288
289 stmt: OP_OUTARG (CEE_LDOBJ (reg)) {
290         tree->opcode = OP_X86_PUSH;
291         tree->sreg1 = state->left->reg1;
292         mono_bblock_add_inst (s->cbb, tree);
293 }
294
295 stmt: OP_OUTARG (freg) {
296         MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, 8);
297         tree->opcode = OP_STORER8_MEMBASE_REG;
298         tree->sreg1 = state->left->reg1;
299         tree->inst_destbasereg = X86_ESP;
300         tree->inst_offset = 0;
301         mono_bblock_add_inst (s->cbb, tree);
302 }
303
304 stmt: OP_OUTARG_R4 (freg) {
305         MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, 4);
306         tree->opcode = OP_STORER4_MEMBASE_REG;
307         tree->sreg1 = state->left->reg1;
308         tree->inst_destbasereg = X86_ESP;
309         tree->inst_offset = 0;
310         mono_bblock_add_inst (s->cbb, tree);
311 }
312
313 stmt: OP_OUTARG_R8 (freg) {
314         MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, 8);
315         tree->opcode = OP_STORER8_MEMBASE_REG;
316         tree->sreg1 = state->left->reg1;
317         tree->inst_destbasereg = X86_ESP;
318         tree->inst_offset = 0;
319         mono_bblock_add_inst (s->cbb, tree);
320 }
321
322 stmt: OP_AMD64_OUTARG_XMMREG (freg) {
323         tree->opcode = OP_AMD64_SET_XMMREG;
324         tree->sreg1 = state->left->reg1;
325         tree->dreg = tree->unused;
326         mono_bblock_add_inst (s->cbb, tree);
327 }
328
329 stmt: OP_OUTARG_VT (CEE_LDOBJ (base)) {
330         MonoInst *vt = state->left->left->tree;
331         //g_print ("vt size: %d at R%d + %d\n", tree->inst_imm, vt->inst_basereg, vt->inst_offset);
332
333         if (!tree->inst_imm)
334                 return;
335
336         if (tree->inst_imm <= 4) {
337                 tree->opcode = OP_X86_PUSH_MEMBASE;
338                 tree->inst_basereg = vt->inst_basereg;
339                 tree->inst_offset = vt->inst_offset;
340                 mono_bblock_add_inst (s->cbb, tree);
341         } else if (tree->inst_imm <= 20) {
342                 int sz = tree->inst_imm;
343                 sz += 3;
344                 sz &= ~3;
345                 MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, sz);
346                 mini_emit_memcpy (s, X86_ESP, 0, vt->inst_basereg, vt->inst_offset, tree->inst_imm, 0);
347         } else {
348                 tree->opcode = OP_X86_PUSH_OBJ;
349                 tree->inst_basereg = vt->inst_basereg;
350                 tree->inst_offset = vt->inst_offset;
351                 mono_bblock_add_inst (s->cbb, tree);
352         }
353 }
354
355 stmt: OP_OUTARG_VT (OP_ICONST) {
356         tree->opcode = OP_X86_PUSH_IMM;
357         tree->inst_imm = state->left->tree->inst_c0;
358         mono_bblock_add_inst (s->cbb, tree);
359 }
360
361 stmt: OP_OUTARG_VT (reg) {
362         tree->opcode = OP_X86_PUSH;
363         tree->sreg1 = state->left->tree->dreg;
364         mono_bblock_add_inst (s->cbb, tree);
365 }
366
367 reg: OP_LDADDR (OP_REGOFFSET) "1" {
368         if (state->left->tree->inst_offset) {
369                 tree->opcode = OP_X86_LEA_MEMBASE;
370                 tree->sreg1 = state->left->tree->inst_basereg;
371                 tree->inst_imm = state->left->tree->inst_offset;
372                 tree->dreg = state->reg1;
373         } else {
374                 tree->opcode = OP_MOVE;
375                 tree->sreg1 = state->left->tree->inst_basereg;
376                 tree->dreg = state->reg1;
377         }
378         mono_bblock_add_inst (s->cbb, tree);
379 }
380
381 reg: CEE_LDOBJ (OP_REGOFFSET) "1" {
382         if (state->left->tree->inst_offset) {
383                 tree->opcode = OP_X86_LEA_MEMBASE;
384                 tree->sreg1 = state->left->tree->inst_basereg;
385                 tree->inst_imm = state->left->tree->inst_offset;
386                 tree->dreg = state->reg1;
387         } else {
388                 tree->opcode = OP_MOVE;
389                 tree->sreg1 = state->left->tree->inst_basereg;
390                 tree->dreg = state->reg1;
391         }
392         mono_bblock_add_inst (s->cbb, tree);
393 }
394
395 reg: CEE_LDELEMA (reg, reg) "15" {
396         guint32 size = mono_class_array_element_size (tree->klass);
397         
398         MONO_EMIT_BOUNDS_CHECK (s, state->left->reg1, MonoArray, max_length, state->right->reg1);
399
400         if (size == 1 || size == 2 || size == 4 || size == 8) {
401                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
402                 tree->opcode = OP_X86_LEA;
403                 tree->dreg = state->reg1;
404                 tree->sreg1 = state->left->reg1;
405                 tree->sreg2 = state->right->reg1;
406                 tree->inst_imm = G_STRUCT_OFFSET (MonoArray, vector);
407                 tree->unused = fast_log2 [size];
408                 mono_bblock_add_inst (s->cbb, tree);
409         } else {
410                 int mult_reg = mono_regstate_next_int (s->rs);
411                 int add_reg = mono_regstate_next_int (s->rs);
412                 MONO_EMIT_NEW_BIALU_IMM (s, OP_MUL_IMM, mult_reg, state->right->reg1, size);
413                 MONO_EMIT_NEW_BIALU (s, CEE_ADD, add_reg, mult_reg, state->left->reg1);
414                 MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, state->reg1, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
415         }
416 }
417
418 stmt: CEE_STIND_R8 (OP_REGVAR, freg) {
419         /* nothing to do: the value is already on the FP stack */
420 }
421
422 stmt: CEE_STIND_I4 (base, CEE_ADD (CEE_LDIND_I4 (base), OP_ICONST)) {
423         int con = state->right->right->tree->inst_c0;   
424
425         if (con == 1) {
426                 tree->opcode = OP_X86_INC_MEMBASE;
427         } else {
428                 tree->opcode = OP_X86_ADD_MEMBASE_IMM;
429                 tree->inst_imm = con;
430         }
431
432         tree->inst_basereg = state->left->tree->inst_basereg;
433         tree->inst_offset = state->left->tree->inst_offset;
434         mono_bblock_add_inst (s->cbb, tree);
435 } cost {
436         MBTREE_TYPE *t1 = state->right->left->left->tree;
437         MBTREE_TYPE *t2 = state->left->tree;
438         MBCOND (t1->inst_basereg == t2->inst_basereg &&
439                 t1->inst_offset == t2->inst_offset);
440         return 2;
441 }
442
443 stmt: CEE_STIND_I4 (base, CEE_SUB (CEE_LDIND_I4 (base), OP_ICONST)) {
444         int con = state->right->right->tree->inst_c0;   
445
446         if (con == 1) {
447                 tree->opcode = OP_X86_DEC_MEMBASE;
448         } else {
449                 tree->opcode = OP_X86_SUB_MEMBASE_IMM;
450                 tree->inst_imm = con;
451         }
452
453         tree->inst_basereg = state->left->tree->inst_basereg;
454         tree->inst_offset = state->left->tree->inst_offset;
455         mono_bblock_add_inst (s->cbb, tree);
456 } cost {
457         MBTREE_TYPE *t1 = state->right->left->left->tree;
458         MBTREE_TYPE *t2 = state->left->tree;
459         MBCOND (t1->inst_basereg == t2->inst_basereg &&
460                 t1->inst_offset == t2->inst_offset);
461         return 2;
462 }
463
464 #
465 # this rules is incorrect, it needs to do an indirect inc (inc_membase)
466 #stmt: CEE_STIND_I4 (reg, CEE_ADD (reg, OP_ICONST)) {
467 #       tree->opcode = OP_X86_INC_REG;
468 #       tree->dreg = state->left->reg1;
469 #       mono_bblock_add_inst (s->cbb, tree);
470 #} cost {
471 #       MBState *s1 = state->left;
472 #       MBState *s2 = state->right->left;
473 #       int con = state->right->right->tree->inst_c0;   
474 #       MBCOND (con == 1 && s1->reg1 == s2->reg1);
475 #       return 1;
476 #}
477
478 stmt: CEE_STIND_I4 (OP_REGVAR, CEE_SUB (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)) {
479         int con = state->right->right->tree->inst_c0;   
480         int dreg = state->left->tree->dreg;
481         int sreg = state->right->left->left->tree->dreg;
482
483         if (con == 1) {
484                 if (dreg != sreg)
485                         MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, sreg);
486                 tree->opcode = OP_X86_DEC_REG;
487                 tree->dreg = tree->sreg1 = dreg;
488         } else if (con == -1) {
489                 if (dreg != sreg)
490                         MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, sreg);
491                 tree->opcode = OP_X86_INC_REG;
492                 tree->dreg = tree->sreg1 = dreg;
493         } else {
494                 tree->opcode = OP_SUB_IMM;
495                 tree->inst_imm = con;
496                 tree->sreg1 = sreg;
497                 tree->dreg = dreg;
498         }
499         mono_bblock_add_inst (s->cbb, tree);
500 }
501
502 stmt: CEE_STIND_I (OP_REGVAR, CEE_ADD (CEE_LDIND_I (OP_REGVAR), OP_ICONST)),
503 stmt: CEE_STIND_I4 (OP_REGVAR, CEE_ADD (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)) {
504         int con = state->right->right->tree->inst_c0;
505         int dreg = state->left->tree->dreg;
506         int sreg = state->right->left->left->tree->dreg;
507
508         if (con == 1) {
509                 if (dreg != sreg)
510                         MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, sreg);
511                 tree->opcode = OP_X86_INC_REG;
512                 tree->dreg = tree->sreg1 = dreg;
513         } else 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 {
519                 tree->opcode = OP_ADD_IMM;
520                 tree->inst_imm = con;
521                 tree->sreg1 = sreg;
522                 tree->dreg = dreg;
523         }
524         mono_bblock_add_inst (s->cbb, tree);
525 }
526
527 reg: CEE_LDIND_I2 (OP_REGVAR) {
528         MONO_EMIT_UNALU (s, tree, OP_SEXT_I2, state->reg1, state->left->tree->dreg);
529 }
530
531 # on x86, fp compare overwrites EAX, so we must
532 # either improve the local register allocator or
533 # emit coarse opcodes which saves EAX for us.
534
535 reg: OP_CEQ (OP_COMPARE (freg, freg)) { 
536         MONO_EMIT_BIALU (s, tree, OP_FCEQ, state->reg1, state->left->left->reg1,
537                          state->left->right->reg1);
538 }
539
540 reg: OP_CLT (OP_COMPARE (freg, freg)) { 
541         MONO_EMIT_BIALU (s, tree, OP_FCLT, state->reg1, state->left->left->reg1,
542                          state->left->right->reg1);
543 }
544
545 reg: OP_CLT_UN (OP_COMPARE (freg, freg)) {      
546         MONO_EMIT_BIALU (s, tree, OP_FCLT_UN, state->reg1, state->left->left->reg1,
547                          state->left->right->reg1);
548 }
549
550 reg: OP_CGT (OP_COMPARE (freg, freg)) { 
551         MONO_EMIT_BIALU (s, tree, OP_FCGT, state->reg1, state->left->left->reg1,
552                          state->left->right->reg1);
553 }
554
555 reg: OP_CGT_UN (OP_COMPARE (freg, freg)) {      
556         MONO_EMIT_BIALU (s, tree, OP_FCGT_UN, state->reg1, state->left->left->reg1,
557                          state->left->right->reg1);
558 }
559
560 # fpcflags overwrites EAX, but this does not matter for statements
561 # because we are the last operation in the tree.
562  
563 stmt: CEE_BNE_UN (fpcflags) {
564         tree->opcode = OP_FBNE_UN;
565         mono_bblock_add_inst (s->cbb, tree);
566 }
567
568 stmt: CEE_BEQ (fpcflags) {
569         tree->opcode = OP_FBEQ;
570         mono_bblock_add_inst (s->cbb, tree);
571 }
572
573 stmt: CEE_BLT (fpcflags) {
574         tree->opcode = OP_FBLT;
575         mono_bblock_add_inst (s->cbb, tree);
576 }
577
578 stmt: CEE_BLT_UN (fpcflags) {
579         tree->opcode = OP_FBLT_UN;
580         mono_bblock_add_inst (s->cbb, tree);
581 }
582
583 stmt: CEE_BGT (fpcflags) {
584         tree->opcode = OP_FBGT;
585         mono_bblock_add_inst (s->cbb, tree);
586 }
587
588 stmt: CEE_BGT_UN (fpcflags) {
589         tree->opcode = OP_FBGT_UN;
590         mono_bblock_add_inst (s->cbb, tree);
591 }
592
593 stmt: CEE_BGE  (fpcflags) {
594         tree->opcode = OP_FBGE;
595         mono_bblock_add_inst (s->cbb, tree);
596 }
597
598 stmt: CEE_BGE_UN (fpcflags) {
599         tree->opcode = OP_FBGE_UN;
600         mono_bblock_add_inst (s->cbb, tree);
601 }
602
603 stmt: CEE_BLE  (fpcflags) {
604         tree->opcode = OP_FBLE;
605         mono_bblock_add_inst (s->cbb, tree);
606 }
607
608 stmt: CEE_BLE_UN (fpcflags) {
609         tree->opcode = OP_FBLE_UN;
610         mono_bblock_add_inst (s->cbb, tree);
611 }
612
613 stmt: CEE_POP (freg) "0" {
614         /* we need to pop the value from the x86 FP stack */
615         MONO_EMIT_UNALU (s, tree, OP_X86_FPOP, -1, state->left->reg1);  
616 }     
617
618 # override the rules in inssel-float.brg that work for machines with FP registers 
619
620 freg: OP_FCONV_TO_R8 (freg) "0" {
621         /* nothing to do */
622 }
623
624 freg: OP_FCONV_TO_R4 (freg) "0" {
625         /* fixme: nothing to do ??*/
626 }
627
628 reg: CEE_ADD(reg, CEE_LDIND_I4 (base)) {
629         MonoInst *base = state->right->left->tree;
630
631         tree->dreg = state->reg1;
632         tree->sreg1 = state->left->reg1;
633         tree->sreg2 = base->inst_basereg; 
634         tree->inst_offset = base->inst_offset; 
635         tree->opcode = OP_X86_ADD_MEMBASE; 
636         mono_bblock_add_inst (s->cbb, tree);
637
638
639 reg: CEE_SUB(reg, CEE_LDIND_I4 (base)) {
640         MonoInst *base = state->right->left->tree;
641
642         tree->dreg = state->reg1;
643         tree->sreg1 = state->left->reg1;
644         tree->sreg2 = base->inst_basereg; 
645         tree->inst_offset = base->inst_offset; 
646         tree->opcode = OP_X86_SUB_MEMBASE; 
647         mono_bblock_add_inst (s->cbb, tree);
648
649
650 reg: CEE_MUL(reg, CEE_LDIND_I4 (base)) {
651         MonoInst *base = state->right->left->tree;
652
653         tree->dreg = state->reg1;
654         tree->sreg1 = state->left->reg1;
655         tree->sreg2 = base->inst_basereg; 
656         tree->inst_offset = base->inst_offset; 
657         tree->opcode = OP_X86_MUL_MEMBASE; 
658         mono_bblock_add_inst (s->cbb, tree);
659
660
661 reg: OP_LSHL (reg, reg) "0" {
662         MONO_EMIT_BIALU (s, tree, tree->opcode, state->reg1, state->left->reg1, state->right->reg1);
663 }
664
665 reg: OP_LSHL (reg, OP_ICONST) "0" {
666         MONO_EMIT_BIALU_IMM (s, tree, OP_LSHL_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
667 }
668
669 reg: OP_LSHR (reg, reg) "0" {
670         MONO_EMIT_BIALU (s, tree, tree->opcode, state->reg1, state->left->reg1, state->right->reg1);
671 }
672
673 reg: OP_LSHR (reg, OP_ICONST) "0" {
674         MONO_EMIT_BIALU_IMM (s, tree, OP_LSHR_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
675 }
676
677 reg: OP_LSHR_UN (reg, reg) "0" {
678         MONO_EMIT_BIALU (s, tree, tree->opcode, state->reg1, state->left->reg1, state->right->reg1);
679 }
680
681 reg: OP_LSHR_UN (reg, OP_ICONST) "0" {
682         MONO_EMIT_BIALU_IMM (s, tree, OP_LSHR_UN_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
683 }
684 %%