Wed May 14 12:40:31 CEST 2003 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / inssel-x86.brg
1 %%
2
3 #
4 # inssel-x86.brg: burg file for special x86 instructions
5 #
6 # Author:
7 #   Dietmar Maurer (dietmar@ximian.com)
8 #   Paolo Molaro (lupus@ximian.com)
9 #
10 # (C) 2002 Ximian, Inc.
11 #
12
13 stmt: CEE_STIND_I8 (OP_REGVAR, lreg) {
14         /* this should only happen for methods returning a long */
15         MONO_EMIT_NEW_UNALU (s, OP_MOVE, X86_EAX, state->right->reg1);
16         MONO_EMIT_NEW_UNALU (s, OP_MOVE, X86_EDX, state->right->reg2);
17 }
18
19 lreg: OP_LNEG (lreg) "3" {
20         int tmpr = mono_regstate_next_int (s->rs);
21         MONO_EMIT_NEW_UNALU (s, CEE_NEG, state->reg1, state->left->reg1);
22         MONO_EMIT_BIALU_IMM (s, tree, OP_ADC_IMM, tmpr, state->left->reg2, 0);
23         MONO_EMIT_NEW_UNALU (s, CEE_NEG, state->reg2, tmpr);
24 }
25
26 freg: OP_LCONV_TO_R8 (lreg) {
27         MONO_EMIT_NEW_UNALU (s, OP_X86_PUSH, -1, state->left->reg2);
28         MONO_EMIT_NEW_UNALU (s, OP_X86_PUSH, -1, state->left->reg1);
29         tree->opcode = OP_X86_FP_LOAD_I8;
30         tree->inst_basereg = X86_ESP;
31         tree->inst_offset = 0;
32         mono_bblock_add_inst (s->cbb, tree);
33         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, X86_ESP, X86_ESP, 8);
34 }
35
36 freg: OP_LCONV_TO_R4 (lreg) {
37         MONO_EMIT_NEW_UNALU (s, OP_X86_PUSH, -1, state->left->reg2);
38         MONO_EMIT_NEW_UNALU (s, OP_X86_PUSH, -1, state->left->reg1);
39         tree->opcode = OP_X86_FP_LOAD_I8;
40         tree->inst_basereg = X86_ESP;
41         tree->inst_offset = 0;
42         mono_bblock_add_inst (s->cbb, tree);
43         /* change precision */
44         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER4_MEMBASE_REG, X86_ESP, 0, state->reg1);
45         MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADR4_MEMBASE, state->reg1, X86_ESP, 0);
46         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, X86_ESP, X86_ESP, 8);
47 }
48
49 freg: CEE_CONV_R_UN (reg) {
50         MONO_EMIT_NEW_BIALU_IMM (s, OP_X86_PUSH_IMM, -1, -1, 0);
51         MONO_EMIT_NEW_UNALU (s, OP_X86_PUSH, -1, state->left->reg1);
52         tree->opcode = OP_X86_FP_LOAD_I8;
53         tree->inst_basereg = X86_ESP;
54         tree->inst_offset = 0;
55         mono_bblock_add_inst (s->cbb, tree);
56         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, X86_ESP, X86_ESP, 8);
57 }
58
59 cflags: OP_COMPARE (CEE_LDIND_I4 (base), reg) {
60         tree->opcode = OP_X86_COMPARE_MEMBASE_REG;
61         tree->inst_basereg = state->left->left->tree->inst_basereg;
62         tree->inst_offset = state->left->left->tree->inst_offset;
63         tree->sreg2 = state->right->reg1;
64         mono_bblock_add_inst (s->cbb, tree);
65 }
66
67 cflags: OP_COMPARE (CEE_LDIND_I4 (base), OP_ICONST) {
68         tree->opcode = OP_X86_COMPARE_MEMBASE_IMM;
69         tree->inst_basereg = state->left->left->tree->inst_basereg;
70         tree->inst_offset = state->left->left->tree->inst_offset;
71         tree->inst_imm = state->right->tree->inst_c0;
72         mono_bblock_add_inst (s->cbb, tree);
73 }
74
75 cflags: OP_COMPARE (reg, CEE_LDIND_I4 (base)) {
76         tree->opcode = OP_X86_COMPARE_REG_MEMBASE;
77         tree->sreg2 = state->right->left->tree->inst_basereg;
78         tree->inst_offset = state->right->left->tree->inst_offset;
79         tree->sreg1 = state->left->reg1;
80         mono_bblock_add_inst (s->cbb, tree);
81 }
82
83 reg: OP_LOCALLOC (OP_ICONST) {
84         if (tree->flags & MONO_INST_INIT) {
85                 /* microcoded in mini-x86.c */
86                 tree->sreg1 = mono_regstate_next_int (s->rs);
87                 MONO_EMIT_NEW_ICONST (s, tree->sreg1, state->left->tree->inst_c0);
88                 mono_bblock_add_inst (s->cbb, tree);
89         } else {
90                 MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, state->left->tree->inst_c0);
91                 MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, X86_ESP);
92         }
93 }
94
95 reg: OP_LOCALLOC (reg) {
96         mono_bblock_add_inst (s->cbb, tree);
97 }
98
99 stmt: OP_SETRET (reg) {
100         tree->opcode = OP_MOVE;
101         tree->sreg1 = state->left->reg1;
102         tree->dreg = X86_EAX;
103         mono_bblock_add_inst (s->cbb, tree);
104 }
105
106 stmt: OP_SETRET (lreg) {
107         MONO_EMIT_NEW_UNALU (s, OP_MOVE, X86_EDX, state->left->reg2);
108         tree->opcode = OP_MOVE;
109         tree->sreg1 = state->left->reg1;
110         tree->dreg = X86_EAX;
111         mono_bblock_add_inst (s->cbb, tree);
112 }
113
114 stmt: OP_SETRET (CEE_LDIND_REF (OP_REGVAR)) {
115         tree->opcode = OP_MOVE;
116         tree->sreg1 = state->left->left->tree->dreg;
117         tree->dreg = X86_EAX;
118         mono_bblock_add_inst (s->cbb, tree);
119 }
120
121 stmt: OP_SETRET (freg) {
122         /* nothing to do */
123 }
124
125 stmt: OP_SETRET (OP_ICONST) {
126         tree->opcode = OP_ICONST;
127         tree->inst_c0 = state->left->tree->inst_c0;
128         tree->dreg = X86_EAX;
129         mono_bblock_add_inst (s->cbb, tree);
130 }
131
132 stmt: OP_OUTARG (reg) {
133         tree->opcode = OP_X86_PUSH;
134         tree->sreg1 = state->left->reg1;
135         mono_bblock_add_inst (s->cbb, tree);
136 }
137
138 # we need to reduce this code duplication with some burg syntax extension
139 stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)) {
140         tree->opcode = OP_X86_PUSH;
141         tree->sreg1 = state->left->left->tree->dreg;
142         mono_bblock_add_inst (s->cbb, tree);
143 }
144
145 stmt: OP_OUTARG (CEE_LDIND_I4 (OP_REGVAR)) {
146         tree->opcode = OP_X86_PUSH;
147         tree->sreg1 = state->left->left->tree->dreg;
148         mono_bblock_add_inst (s->cbb, tree);
149 }
150
151 stmt: OP_OUTARG (CEE_LDIND_U4 (OP_REGVAR)) {
152         tree->opcode = OP_X86_PUSH;
153         tree->sreg1 = state->left->left->tree->dreg;
154         mono_bblock_add_inst (s->cbb, tree);
155 }
156
157 stmt: OP_OUTARG (CEE_LDIND_I (OP_REGVAR)) {
158         tree->opcode = OP_X86_PUSH;
159         tree->sreg1 = state->left->left->tree->dreg;
160         mono_bblock_add_inst (s->cbb, tree);
161 }
162
163 stmt: OP_OUTARG (lreg) {
164         MONO_EMIT_NEW_UNALU (s, OP_X86_PUSH, -1, state->left->reg2);
165         tree->opcode = OP_X86_PUSH;
166         tree->sreg1 = state->left->reg1;
167         mono_bblock_add_inst (s->cbb, tree);
168 }
169
170 stmt: OP_OUTARG (CEE_LDIND_I8 (base)) {
171         MonoInst *ins;
172         ins = mono_mempool_alloc0 (s->mempool, sizeof (MonoInst));
173         ins->opcode = OP_X86_PUSH_MEMBASE;
174         ins->inst_basereg = state->left->left->tree->inst_basereg;
175         ins->inst_offset = state->left->left->tree->inst_offset + 4;
176         mono_bblock_add_inst (s->cbb, ins);
177
178         tree->opcode = OP_X86_PUSH_MEMBASE;
179         tree->inst_basereg = state->left->left->tree->inst_basereg;
180         tree->inst_offset = state->left->left->tree->inst_offset;
181         mono_bblock_add_inst (s->cbb, tree);
182 }
183
184 stmt: OP_OUTARG (OP_ICONST) {
185         tree->opcode = OP_X86_PUSH_IMM;
186         tree->inst_imm = state->left->tree->inst_c0;
187         mono_bblock_add_inst (s->cbb, tree);
188 }
189
190 stmt: OP_OUTARG (CEE_LDIND_I4 (base)) {
191         tree->opcode = OP_X86_PUSH_MEMBASE;
192         tree->inst_basereg = state->left->left->tree->inst_basereg;
193         tree->inst_offset = state->left->left->tree->inst_offset;
194         mono_bblock_add_inst (s->cbb, tree);
195 }
196
197 stmt: OP_OUTARG (CEE_LDIND_U4 (base)) {
198         tree->opcode = OP_X86_PUSH_MEMBASE;
199         tree->inst_basereg = state->left->left->tree->inst_basereg;
200         tree->inst_offset = state->left->left->tree->inst_offset;
201         mono_bblock_add_inst (s->cbb, tree);
202 }
203
204 stmt: OP_OUTARG (CEE_LDIND_I (base)) {
205         tree->opcode = OP_X86_PUSH_MEMBASE;
206         tree->inst_basereg = state->left->left->tree->inst_basereg;
207         tree->inst_offset = state->left->left->tree->inst_offset;
208         mono_bblock_add_inst (s->cbb, tree);
209 }
210
211 stmt: OP_OUTARG (CEE_LDIND_REF (base)) {
212         tree->opcode = OP_X86_PUSH_MEMBASE;
213         tree->inst_basereg = state->left->left->tree->inst_basereg;
214         tree->inst_offset = state->left->left->tree->inst_offset;
215         mono_bblock_add_inst (s->cbb, tree);
216 }
217
218 stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)) {
219         tree->opcode = OP_X86_PUSH;
220         tree->sreg1 = state->left->left->tree->dreg;
221         mono_bblock_add_inst (s->cbb, tree);
222 }
223
224 stmt: OP_OUTARG (CEE_LDOBJ (reg)) {
225         tree->opcode = OP_X86_PUSH;
226         tree->sreg1 = state->left->reg1;
227         mono_bblock_add_inst (s->cbb, tree);
228 }
229
230 stmt: OP_OUTARG (freg) {
231         MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, 8);
232         tree->opcode = OP_STORER8_MEMBASE_REG;
233         tree->sreg1 = state->left->reg1;
234         tree->inst_destbasereg = X86_ESP;
235         tree->inst_offset = 0;
236         mono_bblock_add_inst (s->cbb, tree);
237 }
238
239 stmt: OP_OUTARG_R4 (freg) {
240         MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, 4);
241         tree->opcode = OP_STORER4_MEMBASE_REG;
242         tree->sreg1 = state->left->reg1;
243         tree->inst_destbasereg = X86_ESP;
244         tree->inst_offset = 0;
245         mono_bblock_add_inst (s->cbb, tree);
246 }
247
248 stmt: OP_OUTARG_R8 (freg) {
249         MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, X86_ESP, X86_ESP, 8);
250         tree->opcode = OP_STORER8_MEMBASE_REG;
251         tree->sreg1 = state->left->reg1;
252         tree->inst_destbasereg = X86_ESP;
253         tree->inst_offset = 0;
254         mono_bblock_add_inst (s->cbb, tree);
255 }
256
257 stmt: OP_OUTARG_VT (CEE_LDOBJ (base)) {
258         MonoInst *vt = state->left->left->tree;
259         //g_print ("vt size: %d at R%d + %d\n", tree->inst_imm, vt->inst_basereg, vt->inst_offset);
260         if (tree->inst_imm <= 4) {
261                 tree->opcode = OP_X86_PUSH_MEMBASE;
262                 tree->inst_basereg = vt->inst_basereg;
263                 tree->inst_offset = vt->inst_offset;
264                 mono_bblock_add_inst (s->cbb, tree);
265         } else {
266                 tree->opcode = OP_X86_PUSH_OBJ;
267                 tree->inst_basereg = vt->inst_basereg;
268                 tree->inst_offset = vt->inst_offset;
269                 mono_bblock_add_inst (s->cbb, tree);
270         }
271 }
272
273 stmt: OP_OUTARG_VT (OP_ICONST) {
274         tree->opcode = OP_X86_PUSH_IMM;
275         tree->inst_imm = state->left->tree->inst_c0;
276         mono_bblock_add_inst (s->cbb, tree);
277 }
278
279 reg: CEE_LDELEMA (reg, reg) "15" {
280         int length_reg = mono_regstate_next_int (s->rs);
281         guint32 size = mono_class_array_element_size (tree->klass);
282         
283         MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADI4_MEMBASE, length_reg, 
284                                        state->left->reg1, G_STRUCT_OFFSET (MonoArray, max_length));
285         MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, length_reg, state->right->reg1);
286         MONO_EMIT_NEW_COND_EXC (s, LE_UN, "IndexOutOfRangeException");
287
288         if (size == 1 || size == 2 || size == 4 || size == 8) {
289                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
290                 tree->opcode = OP_X86_LEA;
291                 tree->dreg = state->reg1;
292                 tree->sreg1 = state->left->reg1;
293                 tree->sreg2 = state->right->reg1;
294                 tree->inst_imm = G_STRUCT_OFFSET (MonoArray, vector);
295                 tree->unused = fast_log2 [size];
296                 mono_bblock_add_inst (s->cbb, tree);
297         } else {
298                 int mult_reg = mono_regstate_next_int (s->rs);
299                 int add_reg = mono_regstate_next_int (s->rs);
300                 MONO_EMIT_NEW_BIALU_IMM (s, OP_MUL_IMM, mult_reg, state->right->reg1, size);
301                 MONO_EMIT_NEW_BIALU (s, CEE_ADD, add_reg, mult_reg, state->left->reg1);
302                 MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, state->reg1, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
303         }
304 }
305
306 stmt: CEE_STIND_R8 (OP_REGVAR, freg) {
307         /* nothing to do: the value is already on the FP stack */
308 }
309
310 stmt: CEE_STIND_I4 (base, CEE_ADD (CEE_LDIND_I4 (base), OP_ICONST)) {
311         int con = state->right->right->tree->inst_c0;   
312
313         if (con == 1) {
314                 tree->opcode = OP_X86_INC_MEMBASE;
315         } else {
316                 tree->opcode = OP_X86_ADD_MEMBASE_IMM;
317                 tree->inst_imm = con;
318         }
319
320         tree->inst_basereg = state->left->tree->inst_basereg;
321         tree->inst_offset = state->left->tree->inst_offset;
322         mono_bblock_add_inst (s->cbb, tree);
323 } cost {
324         MBTREE_TYPE *t1 = state->right->left->left->tree;
325         MBTREE_TYPE *t2 = state->left->tree;
326         MBCOND (t1->inst_basereg == t2->inst_basereg &&
327                 t1->inst_offset == t2->inst_offset);
328         return 2;
329 }
330
331 stmt: CEE_STIND_I4 (base, CEE_SUB (CEE_LDIND_I4 (base), OP_ICONST)) {
332         int con = state->right->right->tree->inst_c0;   
333
334         if (con == 1) {
335                 tree->opcode = OP_X86_DEC_MEMBASE;
336         } else {
337                 tree->opcode = OP_X86_SUB_MEMBASE_IMM;
338                 tree->inst_imm = con;
339         }
340
341         tree->inst_basereg = state->left->tree->inst_basereg;
342         tree->inst_offset = state->left->tree->inst_offset;
343         mono_bblock_add_inst (s->cbb, tree);
344 } cost {
345         MBTREE_TYPE *t1 = state->right->left->left->tree;
346         MBTREE_TYPE *t2 = state->left->tree;
347         MBCOND (t1->inst_basereg == t2->inst_basereg &&
348                 t1->inst_offset == t2->inst_offset);
349         return 2;
350 }
351
352 #
353 # this rules is incorrect, it needs to do an indirect inc (inc_membase)
354 #stmt: CEE_STIND_I4 (reg, CEE_ADD (reg, OP_ICONST)) {
355 #       tree->opcode = OP_X86_INC_REG;
356 #       tree->dreg = state->left->reg1;
357 #       mono_bblock_add_inst (s->cbb, tree);
358 #} cost {
359 #       MBState *s1 = state->left;
360 #       MBState *s2 = state->right->left;
361 #       int con = state->right->right->tree->inst_c0;   
362 #       MBCOND (con == 1 && s1->reg1 == s2->reg1);
363 #       return 1;
364 #}
365
366 stmt: CEE_STIND_I4 (OP_REGVAR, CEE_SUB (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)) {
367         int con = state->right->right->tree->inst_c0;   
368         int dreg = state->left->tree->dreg;
369         int sreg = state->right->left->left->tree->dreg;
370
371         if (con == 1) {
372                 if (dreg != sreg)
373                         MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, sreg);
374                 tree->opcode = OP_X86_DEC_REG;
375                 tree->dreg = tree->sreg1 = dreg;
376         } else if (con == -1) {
377                 if (dreg != sreg)
378                         MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, sreg);
379                 tree->opcode = OP_X86_INC_REG;
380                 tree->dreg = tree->sreg1 = dreg;
381         } else {
382                 tree->opcode = OP_SUB_IMM;
383                 tree->inst_imm = con;
384                 tree->sreg1 = sreg;
385                 tree->dreg = dreg;
386         }
387         mono_bblock_add_inst (s->cbb, tree);
388 }
389
390 stmt: CEE_STIND_I4 (OP_REGVAR, CEE_ADD (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST)) {
391         int con = state->right->right->tree->inst_c0;
392         int dreg = state->left->tree->dreg;
393         int sreg = state->right->left->left->tree->dreg;
394
395         if (con == 1) {
396                 if (dreg != sreg)
397                         MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, sreg);
398                 tree->opcode = OP_X86_INC_REG;
399                 tree->dreg = tree->sreg1 = dreg;
400         } else if (con == -1) {
401                 if (dreg != sreg)
402                         MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, sreg);
403                 tree->opcode = OP_X86_DEC_REG;
404                 tree->dreg = tree->sreg1 = dreg;
405         } else {
406                 tree->opcode = OP_ADD_IMM;
407                 tree->inst_imm = con;
408                 tree->sreg1 = sreg;
409                 tree->dreg = dreg;
410         }
411         mono_bblock_add_inst (s->cbb, tree);
412 }
413
414 # on x86, fp compare overwrites EAX, so we must
415 # either improve the local register allocator or
416 # emit coarse opcodes which saves EAX for us.
417
418 reg: OP_CEQ (OP_COMPARE (freg, freg)) { 
419         MONO_EMIT_BIALU (s, tree, OP_FCEQ, state->reg1, state->left->left->reg1,
420                          state->left->right->reg1);
421 }
422
423 reg: OP_CLT (OP_COMPARE (freg, freg)) { 
424         MONO_EMIT_BIALU (s, tree, OP_FCLT, state->reg1, state->left->left->reg1,
425                          state->left->right->reg1);
426 }
427
428 reg: OP_CLT_UN (OP_COMPARE (freg, freg)) {      
429         MONO_EMIT_BIALU (s, tree, OP_FCLT_UN, state->reg1, state->left->left->reg1,
430                          state->left->right->reg1);
431 }
432
433 reg: OP_CGT (OP_COMPARE (freg, freg)) { 
434         MONO_EMIT_BIALU (s, tree, OP_FCGT, state->reg1, state->left->left->reg1,
435                          state->left->right->reg1);
436 }
437
438 reg: OP_CGT_UN (OP_COMPARE (freg, freg)) {      
439         MONO_EMIT_BIALU (s, tree, OP_FCGT_UN, state->reg1, state->left->left->reg1,
440                          state->left->right->reg1);
441 }
442
443 # fpcflags overwrites EAX, but this does not matter for statements
444 # because we are the last operation in the tree.
445  
446 stmt: CEE_BNE_UN (fpcflags) {
447         tree->opcode = OP_FBNE_UN;
448         mono_bblock_add_inst (s->cbb, tree);
449 }
450
451 stmt: CEE_BEQ (fpcflags) {
452         tree->opcode = OP_FBEQ;
453         mono_bblock_add_inst (s->cbb, tree);
454 }
455
456 stmt: CEE_BLT (fpcflags) {
457         tree->opcode = OP_FBLT;
458         mono_bblock_add_inst (s->cbb, tree);
459 }
460
461 stmt: CEE_BLT_UN (fpcflags) {
462         tree->opcode = OP_FBLT_UN;
463         mono_bblock_add_inst (s->cbb, tree);
464 }
465
466 stmt: CEE_BGT (fpcflags) {
467         tree->opcode = OP_FBGT;
468         mono_bblock_add_inst (s->cbb, tree);
469 }
470
471 stmt: CEE_BGT_UN (fpcflags) {
472         tree->opcode = OP_FBGT_UN;
473         mono_bblock_add_inst (s->cbb, tree);
474 }
475
476 stmt: CEE_BGE  (fpcflags) {
477         tree->opcode = OP_FBGE;
478         mono_bblock_add_inst (s->cbb, tree);
479 }
480
481 stmt: CEE_BGE_UN (fpcflags) {
482         tree->opcode = OP_FBGE_UN;
483         mono_bblock_add_inst (s->cbb, tree);
484 }
485
486 stmt: CEE_BLE  (fpcflags) {
487         tree->opcode = OP_FBLE;
488         mono_bblock_add_inst (s->cbb, tree);
489 }
490
491 stmt: CEE_BLE_UN (fpcflags) {
492         tree->opcode = OP_FBLE_UN;
493         mono_bblock_add_inst (s->cbb, tree);
494 }
495
496 stmt: CEE_POP (freg) "0" {
497         /* we need to pop the value from the x86 FP stack */
498         MONO_EMIT_UNALU (s, tree, OP_X86_FPOP, -1, state->left->reg1);  
499 }     
500
501 %%