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