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