a few warning fixes
[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_ireg_args = g_slist_append (call->out_ireg_args, (gpointer)(regpair));
211 }
212
213 stmt: OP_OUTARG_REG (OP_I8CONST),
214 stmt: OP_OUTARG_REG (OP_ICONST) {       
215         MonoCallInst *call = (MonoCallInst*)tree->inst_right;
216         guint64 regpair;
217
218         tree->opcode = OP_ICONST;
219         tree->inst_c0 = state->left->tree->inst_c0;
220         tree->dreg = mono_regstate_next_int (s->rs);
221         mono_bblock_add_inst (s->cbb, tree);
222
223         regpair = (((guint64)tree->unused) << 32) + tree->dreg;
224         call->out_ireg_args = g_slist_append (call->out_ireg_args, (gpointer)(regpair));
225 }
226
227 stmt: OP_OUTARG_REG (CEE_LDIND_I (OP_REGVAR)),
228 stmt: OP_OUTARG_REG (CEE_LDIND_I8 (OP_REGVAR)),
229 stmt: OP_OUTARG_REG (CEE_LDIND_I4 (OP_REGVAR)),
230 stmt: OP_OUTARG_REG (CEE_LDIND_U4 (OP_REGVAR)),
231 stmt: OP_OUTARG_REG (CEE_LDIND_REF (OP_REGVAR)) {       
232         MonoCallInst *call = (MonoCallInst*)tree->inst_right;
233         guint64 regpair;
234
235         tree->opcode = OP_SETREG;
236         tree->sreg1 = state->left->left->tree->dreg;
237         tree->dreg = mono_regstate_next_int (s->rs);
238         mono_bblock_add_inst (s->cbb, tree);
239
240         regpair = (((guint64)tree->unused) << 32) + tree->dreg;
241         call->out_ireg_args = g_slist_append (call->out_ireg_args, (gpointer)(regpair));
242 }
243
244 # we need to reduce this code duplication with some burg syntax extension
245 stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)) {
246         tree->opcode = OP_X86_PUSH;
247         tree->sreg1 = state->left->left->tree->dreg;
248         mono_bblock_add_inst (s->cbb, tree);
249 }
250
251 stmt: OP_OUTARG (CEE_LDIND_I4 (OP_REGVAR)) {
252         tree->opcode = OP_X86_PUSH;
253         tree->sreg1 = state->left->left->tree->dreg;
254         mono_bblock_add_inst (s->cbb, tree);
255 }
256
257 stmt: OP_OUTARG (CEE_LDIND_U4 (OP_REGVAR)) {
258         tree->opcode = OP_X86_PUSH;
259         tree->sreg1 = state->left->left->tree->dreg;
260         mono_bblock_add_inst (s->cbb, tree);
261 }
262
263 stmt: OP_OUTARG (CEE_LDIND_I (OP_REGVAR)) {
264         tree->opcode = OP_X86_PUSH;
265         tree->sreg1 = state->left->left->tree->dreg;
266         mono_bblock_add_inst (s->cbb, tree);
267 }
268
269 stmt: OP_OUTARG (CEE_LDIND_I4 (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_U4 (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_I (base)) {
284         tree->opcode = OP_X86_PUSH_MEMBASE;
285         tree->inst_basereg = state->left->left->tree->inst_basereg;
286         tree->inst_offset = state->left->left->tree->inst_offset;
287         mono_bblock_add_inst (s->cbb, tree);
288 }
289
290 stmt: OP_OUTARG (CEE_LDIND_REF (base)) {
291         tree->opcode = OP_X86_PUSH_MEMBASE;
292         tree->inst_basereg = state->left->left->tree->inst_basereg;
293         tree->inst_offset = state->left->left->tree->inst_offset;
294         mono_bblock_add_inst (s->cbb, tree);
295 }
296
297 stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)) {
298         tree->opcode = OP_X86_PUSH;
299         tree->sreg1 = state->left->left->tree->dreg;
300         mono_bblock_add_inst (s->cbb, tree);
301 }
302
303 stmt: OP_OUTARG (CEE_LDOBJ (reg)) {
304         tree->opcode = OP_X86_PUSH;
305         tree->sreg1 = state->left->reg1;
306         mono_bblock_add_inst (s->cbb, tree);
307 }
308
309 stmt: OP_OUTARG (freg) {
310         MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, 8);
311         tree->opcode = OP_STORER8_MEMBASE_REG;
312         tree->sreg1 = state->left->reg1;
313         tree->inst_destbasereg = X86_ESP;
314         tree->inst_offset = 0;
315         mono_bblock_add_inst (s->cbb, tree);
316 }
317
318 stmt: OP_OUTARG_R4 (freg) {
319         MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, 8);
320         tree->opcode = OP_STORER4_MEMBASE_REG;
321         tree->sreg1 = state->left->reg1;
322         tree->inst_destbasereg = X86_ESP;
323         tree->inst_offset = 0;
324         mono_bblock_add_inst (s->cbb, tree);
325 }
326
327 stmt: OP_OUTARG_R8 (freg) {
328         MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, 8);
329         tree->opcode = OP_STORER8_MEMBASE_REG;
330         tree->sreg1 = state->left->reg1;
331         tree->inst_destbasereg = X86_ESP;
332         tree->inst_offset = 0;
333         mono_bblock_add_inst (s->cbb, tree);
334 }
335
336 stmt: OP_AMD64_OUTARG_XMMREG_R4 (freg) {
337         MonoCallInst *call = (MonoCallInst*)tree->inst_right;
338         guint64 regpair;
339
340         tree->opcode = OP_AMD64_SET_XMMREG_R4;
341         tree->sreg1 = state->left->reg1;
342         tree->dreg = mono_regstate_next_float (s->rs);
343         mono_bblock_add_inst (s->cbb, tree);
344
345         regpair = (((guint64)tree->unused) << 32) + tree->dreg;
346         call->out_freg_args = g_slist_append (call->out_freg_args, (gpointer)(regpair));
347 }
348
349 stmt: OP_AMD64_OUTARG_XMMREG_R8 (freg) {
350         MonoCallInst *call = (MonoCallInst*)tree->inst_right;
351         guint64 regpair;
352
353         tree->opcode = OP_AMD64_SET_XMMREG_R8;
354         tree->sreg1 = state->left->reg1;
355         tree->dreg = mono_regstate_next_float (s->rs);
356         mono_bblock_add_inst (s->cbb, tree);
357
358         regpair = (((guint64)tree->unused) << 32) + tree->dreg;
359         call->out_freg_args = g_slist_append (call->out_freg_args, (gpointer)(regpair));
360 }
361
362 stmt: OP_OUTARG_VT (CEE_LDOBJ (base)) {
363         MonoInst *vt = state->left->left->tree;
364         //g_print ("vt size: %d at R%d + %d\n", tree->inst_imm, vt->inst_basereg, vt->inst_offset);
365
366         if (!tree->inst_imm)
367                 return;
368
369         if (tree->inst_imm <= 8) {
370                 tree->opcode = OP_X86_PUSH_MEMBASE;
371                 tree->inst_basereg = vt->inst_basereg;
372                 tree->inst_offset = vt->inst_offset;
373                 mono_bblock_add_inst (s->cbb, tree);
374         } else if (tree->inst_imm <= 20) {
375                 int sz = tree->inst_imm;
376                 sz += 8;
377                 sz &= ~8;
378                 MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, sz);
379                 mini_emit_memcpy (s, X86_ESP, 0, vt->inst_basereg, vt->inst_offset, tree->inst_imm, 0);
380         } else {
381                 tree->opcode = OP_X86_PUSH_OBJ;
382                 tree->inst_basereg = vt->inst_basereg;
383                 tree->inst_offset = vt->inst_offset;
384                 mono_bblock_add_inst (s->cbb, tree);
385         }
386 }
387
388 stmt: OP_OUTARG_VT (OP_ICONST) {
389         tree->opcode = OP_X86_PUSH_IMM;
390         tree->inst_imm = state->left->tree->inst_c0;
391         mono_bblock_add_inst (s->cbb, tree);
392 }
393
394 stmt: OP_OUTARG_VT (reg) {
395         tree->opcode = OP_X86_PUSH;
396         tree->sreg1 = state->left->tree->dreg;
397         mono_bblock_add_inst (s->cbb, tree);
398 }
399
400 stmt: OP_AMD64_OUTARG_ALIGN_STACK {
401         MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, 8);
402 }       
403
404 base: OP_INARG_VT (base) {
405         MONO_EMIT_NEW_LOAD_MEMBASE (s, state->reg1, state->left->tree->inst_basereg, 
406                                         state->left->tree->inst_offset);
407 }
408
409 reg: OP_LDADDR (OP_INARG_VT (base)) {
410         MONO_EMIT_NEW_LOAD_MEMBASE (s, state->reg1, state->left->left->tree->inst_basereg, 
411                                         state->left->left->tree->inst_offset);
412 }
413
414 reg: CEE_LDOBJ (OP_INARG_VT (base)) {
415         MONO_EMIT_NEW_LOAD_MEMBASE (s, state->reg1, state->left->left->tree->inst_basereg, 
416                                         state->left->left->tree->inst_offset);
417 }
418
419 reg: OP_LDADDR (OP_REGOFFSET) "1" {
420         if (state->left->tree->inst_offset) {
421                 tree->opcode = OP_X86_LEA_MEMBASE;
422                 tree->sreg1 = state->left->tree->inst_basereg;
423                 tree->inst_imm = state->left->tree->inst_offset;
424                 tree->dreg = state->reg1;
425         } else {
426                 tree->opcode = OP_MOVE;
427                 tree->sreg1 = state->left->tree->inst_basereg;
428                 tree->dreg = state->reg1;
429         }
430         mono_bblock_add_inst (s->cbb, tree);
431 }
432
433 reg: CEE_LDOBJ (OP_REGOFFSET) "1" {
434         if (state->left->tree->inst_offset) {
435                 tree->opcode = OP_X86_LEA_MEMBASE;
436                 tree->sreg1 = state->left->tree->inst_basereg;
437                 tree->inst_imm = state->left->tree->inst_offset;
438                 tree->dreg = state->reg1;
439         } else {
440                 tree->opcode = OP_MOVE;
441                 tree->sreg1 = state->left->tree->inst_basereg;
442                 tree->dreg = state->reg1;
443         }
444         mono_bblock_add_inst (s->cbb, tree);
445 }
446
447 reg: CEE_LDELEMA (reg, reg) "15" {
448         guint32 size = mono_class_array_element_size (tree->klass);
449         
450         MONO_EMIT_BOUNDS_CHECK (s, state->left->reg1, MonoArray, max_length, state->right->reg1);
451
452         if (size == 1 || size == 2 || size == 4 || size == 8) {
453                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
454                 tree->opcode = OP_X86_LEA;
455                 tree->dreg = state->reg1;
456                 tree->sreg1 = state->left->reg1;
457                 tree->sreg2 = state->right->reg1;
458                 tree->inst_imm = G_STRUCT_OFFSET (MonoArray, vector);
459                 tree->unused = fast_log2 [size];
460                 mono_bblock_add_inst (s->cbb, tree);
461         } else {
462                 int mult_reg = mono_regstate_next_int (s->rs);
463                 int add_reg = mono_regstate_next_int (s->rs);
464                 MONO_EMIT_NEW_BIALU_IMM (s, OP_MUL_IMM, mult_reg, state->right->reg1, size);
465                 MONO_EMIT_NEW_BIALU (s, CEE_ADD, add_reg, mult_reg, state->left->reg1);
466                 MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, state->reg1, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
467         }
468 }
469
470 stmt: CEE_STIND_R8 (OP_REGVAR, freg) {
471         /* nothing to do: the value is already on the FP stack */
472 }
473
474 stmt: CEE_STIND_I4 (base, CEE_ADD (CEE_LDIND_I4 (base), OP_ICONST)) {
475         int con = state->right->right->tree->inst_c0;   
476
477         if (con == 1) {
478                 tree->opcode = OP_X86_INC_MEMBASE;
479         } else {
480                 tree->opcode = OP_X86_ADD_MEMBASE_IMM;
481                 tree->inst_imm = con;
482         }
483
484         tree->inst_basereg = state->left->tree->inst_basereg;
485         tree->inst_offset = state->left->tree->inst_offset;
486         mono_bblock_add_inst (s->cbb, tree);
487 } cost {
488         MBTREE_TYPE *t1 = state->right->left->left->tree;
489         MBTREE_TYPE *t2 = state->left->tree;
490         MBCOND (t1->inst_basereg == t2->inst_basereg &&
491                 t1->inst_offset == t2->inst_offset);
492         return 2;
493 }
494
495 stmt: CEE_STIND_I4 (base, CEE_SUB (CEE_LDIND_I4 (base), OP_ICONST)) {
496         int con = state->right->right->tree->inst_c0;   
497
498         if (con == 1) {
499                 tree->opcode = OP_X86_DEC_MEMBASE;
500         } else {
501                 tree->opcode = OP_X86_SUB_MEMBASE_IMM;
502                 tree->inst_imm = con;
503         }
504
505         tree->inst_basereg = state->left->tree->inst_basereg;
506         tree->inst_offset = state->left->tree->inst_offset;
507         mono_bblock_add_inst (s->cbb, tree);
508 } cost {
509         MBTREE_TYPE *t1 = state->right->left->left->tree;
510         MBTREE_TYPE *t2 = state->left->tree;
511         MBCOND (t1->inst_basereg == t2->inst_basereg &&
512                 t1->inst_offset == t2->inst_offset);
513         return 2;
514 }
515
516 stmt: CEE_STIND_I4 (OP_REGVAR, CEE_SUB (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)) {
517         int con = state->right->right->tree->inst_c0;   
518         int dreg = state->left->tree->dreg;
519         int sreg = state->right->left->left->tree->dreg;
520
521         if (con == 1) {
522                 if (dreg != sreg)
523                         MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, sreg);
524                 tree->opcode = OP_X86_DEC_REG;
525                 tree->dreg = tree->sreg1 = dreg;
526         } else if (con == -1) {
527                 if (dreg != sreg)
528                         MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, sreg);
529                 tree->opcode = OP_X86_INC_REG;
530                 tree->dreg = tree->sreg1 = dreg;
531         } else {
532                 tree->opcode = OP_SUB_IMM;
533                 tree->inst_imm = con;
534                 tree->sreg1 = sreg;
535                 tree->dreg = dreg;
536         }
537         mono_bblock_add_inst (s->cbb, tree);
538 }
539
540 stmt: CEE_STIND_I (OP_REGVAR, CEE_ADD (CEE_LDIND_I (OP_REGVAR), OP_ICONST)),
541 stmt: CEE_STIND_I4 (OP_REGVAR, CEE_ADD (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)) {
542         int con = state->right->right->tree->inst_c0;
543         int dreg = state->left->tree->dreg;
544         int sreg = state->right->left->left->tree->dreg;
545
546         if (con == 1) {
547                 if (dreg != sreg)
548                         MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, sreg);
549                 tree->opcode = OP_X86_INC_REG;
550                 tree->dreg = tree->sreg1 = dreg;
551         } else if (con == -1) {
552                 if (dreg != sreg)
553                         MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, sreg);
554                 tree->opcode = OP_X86_DEC_REG;
555                 tree->dreg = tree->sreg1 = dreg;
556         } else {
557                 tree->opcode = OP_ADD_IMM;
558                 tree->inst_imm = con;
559                 tree->sreg1 = sreg;
560                 tree->dreg = dreg;
561         }
562         mono_bblock_add_inst (s->cbb, tree);
563 }
564
565 reg: CEE_LDIND_I2 (OP_REGVAR) {
566         MONO_EMIT_UNALU (s, tree, OP_SEXT_I2, state->reg1, state->left->tree->dreg);
567 }
568
569 # The XOR rule
570 stmt: CEE_STIND_I8 (OP_REGVAR, OP_ICONST),
571 stmt: CEE_STIND_I4 (OP_REGVAR, OP_ICONST),
572 stmt: CEE_STIND_I2 (OP_REGVAR, OP_ICONST),
573 stmt: CEE_STIND_I1 (OP_REGVAR, OP_ICONST),
574 stmt: CEE_STIND_REF (OP_REGVAR, OP_ICONST),
575 stmt: CEE_STIND_I (OP_REGVAR, OP_ICONST),
576 stmt: CEE_STIND_I8 (OP_REGVAR, OP_I8CONST),
577 stmt: CEE_STIND_I4 (OP_REGVAR, OP_I8CONST),
578 stmt: CEE_STIND_I2 (OP_REGVAR, OP_I8CONST),
579 stmt: CEE_STIND_I1 (OP_REGVAR, OP_I8CONST),
580 stmt: CEE_STIND_REF (OP_REGVAR, OP_I8CONST),
581 stmt: CEE_STIND_I (OP_REGVAR, OP_I8CONST) {
582         int r = state->left->tree->dreg;
583         MONO_EMIT_BIALU (s, tree, CEE_XOR, r, r, r);
584 } cost {
585         MBCOND (!state->right->tree->inst_c0);
586         
587         return 0;
588 }
589
590 # on x86, fp compare overwrites EAX, so we must
591 # either improve the local register allocator or
592 # emit coarse opcodes which saves EAX for us.
593
594 reg: OP_CEQ (OP_COMPARE (freg, freg)) { 
595         MONO_EMIT_BIALU (s, tree, OP_FCEQ, state->reg1, state->left->left->reg1,
596                          state->left->right->reg1);
597 }
598
599 reg: OP_CLT (OP_COMPARE (freg, freg)) { 
600         MONO_EMIT_BIALU (s, tree, OP_FCLT, state->reg1, state->left->left->reg1,
601                          state->left->right->reg1);
602 }
603
604 reg: OP_CLT_UN (OP_COMPARE (freg, freg)) {      
605         MONO_EMIT_BIALU (s, tree, OP_FCLT_UN, state->reg1, state->left->left->reg1,
606                          state->left->right->reg1);
607 }
608
609 reg: OP_CGT (OP_COMPARE (freg, freg)) { 
610         MONO_EMIT_BIALU (s, tree, OP_FCGT, state->reg1, state->left->left->reg1,
611                          state->left->right->reg1);
612 }
613
614 reg: OP_CGT_UN (OP_COMPARE (freg, freg)) {      
615         MONO_EMIT_BIALU (s, tree, OP_FCGT_UN, state->reg1, state->left->left->reg1,
616                          state->left->right->reg1);
617 }
618
619 # fpcflags overwrites EAX, but this does not matter for statements
620 # because we are the last operation in the tree.
621  
622 stmt: CEE_BNE_UN (fpcflags) {
623         tree->opcode = OP_FBNE_UN;
624         mono_bblock_add_inst (s->cbb, tree);
625 }
626
627 stmt: CEE_BEQ (fpcflags) {
628         tree->opcode = OP_FBEQ;
629         mono_bblock_add_inst (s->cbb, tree);
630 }
631
632 stmt: CEE_BLT (fpcflags) {
633         tree->opcode = OP_FBLT;
634         mono_bblock_add_inst (s->cbb, tree);
635 }
636
637 stmt: CEE_BLT_UN (fpcflags) {
638         tree->opcode = OP_FBLT_UN;
639         mono_bblock_add_inst (s->cbb, tree);
640 }
641
642 stmt: CEE_BGT (fpcflags) {
643         tree->opcode = OP_FBGT;
644         mono_bblock_add_inst (s->cbb, tree);
645 }
646
647 stmt: CEE_BGT_UN (fpcflags) {
648         tree->opcode = OP_FBGT_UN;
649         mono_bblock_add_inst (s->cbb, tree);
650 }
651
652 stmt: CEE_BGE  (fpcflags) {
653         tree->opcode = OP_FBGE;
654         mono_bblock_add_inst (s->cbb, tree);
655 }
656
657 stmt: CEE_BGE_UN (fpcflags) {
658         tree->opcode = OP_FBGE_UN;
659         mono_bblock_add_inst (s->cbb, tree);
660 }
661
662 stmt: CEE_BLE  (fpcflags) {
663         tree->opcode = OP_FBLE;
664         mono_bblock_add_inst (s->cbb, tree);
665 }
666
667 stmt: CEE_BLE_UN (fpcflags) {
668         tree->opcode = OP_FBLE_UN;
669         mono_bblock_add_inst (s->cbb, tree);
670 }
671
672 stmt: CEE_POP (freg) "0" {
673         /* we need to pop the value from the x86 FP stack */
674         MONO_EMIT_UNALU (s, tree, OP_X86_FPOP, -1, state->left->reg1);  
675 }     
676
677 # override the rules in inssel-float.brg that work for machines with FP registers 
678
679 freg: OP_FCONV_TO_R8 (freg) "0" {
680         tree->opcode = OP_FMOVE;
681         tree->sreg1 = state->left->reg1;
682         tree->dreg = state->reg1;
683         mono_bblock_add_inst (s->cbb, tree);
684 }
685
686 freg: OP_FCONV_TO_R4 (freg) "0" {
687         tree->opcode = OP_FMOVE;
688         tree->sreg1 = state->left->reg1;
689         tree->dreg = state->reg1;
690         mono_bblock_add_inst (s->cbb, tree);
691 }
692
693 reg: CEE_ADD(reg, CEE_LDIND_I4 (base)) {
694         MonoInst *base = state->right->left->tree;
695
696         tree->dreg = state->reg1;
697         tree->sreg1 = state->left->reg1;
698         tree->sreg2 = base->inst_basereg; 
699         tree->inst_offset = base->inst_offset; 
700         tree->opcode = OP_X86_ADD_MEMBASE; 
701         mono_bblock_add_inst (s->cbb, tree);
702
703
704 reg: CEE_SUB(reg, CEE_LDIND_I4 (base)) {
705         MonoInst *base = state->right->left->tree;
706
707         tree->dreg = state->reg1;
708         tree->sreg1 = state->left->reg1;
709         tree->sreg2 = base->inst_basereg; 
710         tree->inst_offset = base->inst_offset; 
711         tree->opcode = OP_X86_SUB_MEMBASE; 
712         mono_bblock_add_inst (s->cbb, tree);
713
714
715 reg: CEE_MUL(reg, CEE_LDIND_I4 (base)) {
716         MonoInst *base = state->right->left->tree;
717
718         tree->dreg = state->reg1;
719         tree->sreg1 = state->left->reg1;
720         tree->sreg2 = base->inst_basereg; 
721         tree->inst_offset = base->inst_offset; 
722         tree->opcode = OP_X86_MUL_MEMBASE; 
723         mono_bblock_add_inst (s->cbb, tree);
724
725
726 reg: OP_LSHL (reg, reg) "0" {
727         MONO_EMIT_BIALU (s, tree, tree->opcode, state->reg1, state->left->reg1, state->right->reg1);
728 }
729
730 reg: OP_LSHL (reg, OP_ICONST) "0" {
731         MONO_EMIT_BIALU_IMM (s, tree, OP_LSHL_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
732 }
733
734 reg: OP_LSHR (reg, reg) "0" {
735         MONO_EMIT_BIALU (s, tree, tree->opcode, state->reg1, state->left->reg1, state->right->reg1);
736 }
737
738 reg: OP_LSHR (reg, OP_ICONST) "0" {
739         MONO_EMIT_BIALU_IMM (s, tree, OP_LSHR_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
740 }
741
742 reg: OP_LSHR_UN (reg, reg) "0" {
743         MONO_EMIT_BIALU (s, tree, tree->opcode, state->reg1, state->left->reg1, state->right->reg1);
744 }
745
746 reg: OP_LSHR_UN (reg, OP_ICONST) "0" {
747         MONO_EMIT_BIALU_IMM (s, tree, OP_LSHR_UN_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
748 }
749
750 reg: OP_X86_TLS_GET {
751         tree->dreg = state->reg1;
752         mono_bblock_add_inst (s->cbb, tree);
753 }
754
755 %%