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