2008-10-17 Marek Safar <marek.safar@gmail.com>
[mono.git] / mono / mini / inssel-sparc.brg
1 %%
2
3 #
4 # inssel-sparc.brg: burg file for special sparc 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, reg) {
14         MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->left->tree->dreg, state->right->reg1);
15 }
16
17 reg: CEE_LDIND_I8 (OP_REGVAR) {
18         MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->reg1, state->left->tree->dreg);
19 }
20
21 stmt: CEE_STIND_I8 (OP_REGVAR, lreg) {
22         /* this should only happen for methods returning a long */
23         MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->left->tree->dreg, state->right->reg2);
24         MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->left->tree->dreg + 1, state->right->reg1);
25 }
26
27 lreg: CEE_LDIND_I8 (OP_REGVAR) {
28         /* reg2 contains the most significant word */
29         MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->reg2, state->left->tree->dreg);
30         tree->opcode = OP_MOVE;
31         tree->dreg = state->reg1;
32         tree->sreg1 = state->left->tree->dreg + 1;
33         mono_bblock_add_inst (s->cbb, tree);
34 }
35
36 freg: OP_LCONV_TO_R8 (lreg) {
37         tree->sreg1 = state->left->reg1;
38         tree->dreg = state->reg1;
39         mono_bblock_add_inst (s->cbb, tree);
40 }
41
42 freg: OP_LCONV_TO_R8 (lreg) {
43         /* Dummy rule */
44 }
45
46 freg: OP_LCONV_TO_R4 (lreg) {
47         tree->sreg1 = state->left->reg1;
48         tree->dreg = state->reg1;
49         mono_bblock_add_inst (s->cbb, tree);
50 }
51
52 freg: CEE_CONV_R_UN (reg) {
53         tree->sreg1 = state->left->reg1;
54         tree->dreg = state->reg1;
55         mono_bblock_add_inst (s->cbb, tree);
56 }
57
58 freg: OP_FCONV_TO_R4 (freg) "0" {
59         /* The conversion is done elsewhere */
60         MONO_EMIT_UNALU (s, tree, OP_FMOVE, state->reg1, state->left->reg1);
61 }
62
63 freg: CEE_LDIND_R8 (OP_REGVAR) {
64         MONO_EMIT_UNALU (s, tree, OP_FMOVE, state->reg1, state->left->tree->dreg);
65 }
66
67 freg: CEE_LDIND_R4 (OP_REGVAR) {
68         MONO_EMIT_UNALU (s, tree, OP_FMOVE, state->reg1, state->left->tree->dreg);
69 }
70
71 reg: OP_LOCALLOC (reg) {
72         tree->sreg1 = state->left->reg1;
73         tree->dreg = state->reg1;
74         mono_bblock_add_inst (s->cbb, tree);
75 }
76
77 base: OP_VTARG_ADDR (base) {
78         MONO_EMIT_NEW_LOAD_MEMBASE (s, state->reg1, state->left->tree->inst_basereg, 
79                                         state->left->tree->inst_offset);
80 }
81
82 reg: OP_LDADDR (OP_VTARG_ADDR (base)) {
83         MONO_EMIT_NEW_LOAD_MEMBASE (s, state->reg1, state->left->left->tree->inst_basereg, 
84                                         state->left->left->tree->inst_offset);
85 }
86
87 reg: CEE_LDOBJ (OP_VTARG_ADDR (base)) {
88         MONO_EMIT_NEW_LOAD_MEMBASE (s, state->reg1, state->left->left->tree->inst_basereg, 
89                                         state->left->left->tree->inst_offset);
90 }
91
92 base: OP_LDADDR (reg) {
93 /*
94         tree->inst_basereg = mono_regstate_next_int (s->rs);
95         tree->inst_offset = 0;
96
97         MONO_EMIT_NEW_LOAD_MEMBASE (s, tree->inst_basereg, state->left->tree->dreg, 0);
98 */
99         tree->inst_basereg = state->left->tree->dreg;
100         tree->inst_offset = 0;
101 }
102
103 stmt: OP_OUTARG (OP_LDADDR (reg)) {
104         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
105
106         tree->opcode = OP_MOVE;
107         tree->dreg = mono_regstate_next_int (s->rs);
108         tree->sreg1 = state->left->left->tree->dreg;
109         mono_bblock_add_inst (s->cbb, tree);
110
111         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
112 }
113
114 stmt: OP_SETRET (reg) {
115         tree->opcode = OP_MOVE;
116         tree->sreg1 = state->left->reg1;
117         tree->dreg = sparc_i0;
118         mono_bblock_add_inst (s->cbb, tree);
119 }
120
121 stmt: OP_SETRET (lreg) {
122         MONO_EMIT_NEW_UNALU (s, OP_MOVE, sparc_i0, state->left->reg2);
123         tree->opcode = OP_MOVE;
124         tree->sreg1 = state->left->reg1;
125         tree->dreg = sparc_i1;
126         mono_bblock_add_inst (s->cbb, tree);
127 }
128
129 stmt: OP_SETRET (freg) {
130         tree->opcode = OP_SETFRET;
131         tree->sreg1 = state->left->reg1;
132         tree->dreg = sparc_f0;
133         mono_bblock_add_inst (s->cbb, tree);
134 }
135
136 stmt: OP_SETRET (OP_ICONST) {
137         tree->opcode = OP_ICONST;
138         tree->inst_c0 = state->left->tree->inst_c0;
139         tree->dreg = sparc_i0;
140         mono_bblock_add_inst (s->cbb, tree);
141 }
142
143 stmt: OP_OUTARG (reg) {
144         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
145
146         tree->opcode = OP_MOVE;
147         tree->dreg = mono_regstate_next_int (s->rs);
148         tree->sreg1 = state->left->reg1;
149         mono_bblock_add_inst (s->cbb, tree);
150
151         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
152 }
153
154 stmt: OP_OUTARG (OP_REGVAR) {
155         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
156
157         tree->opcode = OP_MOVE;
158         tree->dreg = mono_regstate_next_int (s->rs);
159         tree->sreg1 = state->left->tree->dreg;
160         mono_bblock_add_inst (s->cbb, tree);
161
162         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
163 }
164
165 stmt: OP_OUTARG (OP_ICONST) {
166         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
167
168         tree->opcode = OP_ICONST;
169         tree->dreg = mono_regstate_next_int (s->rs);
170         tree->inst_c0 = state->left->tree->inst_c0;
171         mono_bblock_add_inst (s->cbb, tree);
172
173         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
174 }
175
176 stmt: OP_OUTARG (OP_I8CONST) {
177         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
178
179         tree->opcode = OP_ICONST;
180         tree->dreg = mono_regstate_next_int (s->rs);
181         tree->inst_c0 = state->left->tree->inst_c0;
182         mono_bblock_add_inst (s->cbb, tree);
183
184         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
185 } cost {
186         MBCOND (sizeof (gpointer) == 8);
187
188         return 0;
189 }
190
191 stmt: OP_OUTARG (CEE_LDIND_R4 (base)) {
192         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
193
194         tree->opcode = OP_LOADI4_MEMBASE;
195         tree->dreg = mono_regstate_next_int (s->rs);
196         tree->inst_basereg = state->left->left->tree->inst_basereg;
197         tree->inst_offset = state->left->left->tree->inst_offset;
198         mono_bblock_add_inst (s->cbb, tree);
199
200         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
201 }
202
203 stmt: OP_SPARC_OUTARG_FLOAT (freg) {
204         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
205         int dreg = mono_regstate_next_int (s->rs);
206         /* floating-point <-> integer transfer must go through memory */
207         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER4_MEMBASE_REG, tree->inst_right->inst_basereg,
208                                                                 tree->inst_right->inst_imm, state->left->reg1);
209         MONO_EMIT_NEW_LOAD_MEMBASE (s, dreg, tree->inst_right->inst_basereg, tree->inst_right->inst_imm);
210
211         mono_call_inst_add_outarg_reg (s, call, dreg, tree->backend.reg3, FALSE);
212 }
213
214 stmt: OP_SPARC_OUTARG_REGPAIR (lreg) {
215         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
216         int dreg = mono_regstate_next_int (s->rs);
217         int dreg2 = mono_regstate_next_int (s->rs);
218
219         MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, state->left->reg2);
220         tree->opcode = OP_MOVE;
221         tree->dreg = dreg2;
222         tree->sreg1 = state->left->reg1;
223         mono_bblock_add_inst (s->cbb, tree);
224
225         mono_call_inst_add_outarg_reg (s, call, dreg, tree->backend.reg3, FALSE);
226         mono_call_inst_add_outarg_reg (s, call, dreg2, tree->backend.reg3 + 1, FALSE);
227 }
228
229 stmt: OP_SPARC_OUTARG_REGPAIR_FLOAT (freg) {
230         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
231         int dreg = mono_regstate_next_int (s->rs);
232         int dreg2 = mono_regstate_next_int (s->rs);
233
234         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER8_MEMBASE_REG, tree->inst_right->inst_basereg,
235                                                                 tree->inst_right->inst_imm, state->left->reg1);
236         /* floating-point <-> integer transfer must go through memory */
237         /* Load into a register pair */
238         MONO_EMIT_NEW_LOAD_MEMBASE (s, dreg, tree->inst_right->inst_basereg, tree->inst_right->inst_imm);
239         MONO_EMIT_NEW_LOAD_MEMBASE (s, dreg2, tree->inst_right->inst_basereg, tree->inst_right->inst_imm + 4);
240
241         mono_call_inst_add_outarg_reg (s, call, dreg, tree->backend.reg3, FALSE);
242         mono_call_inst_add_outarg_reg (s, call, dreg2, tree->backend.reg3 + 1, FALSE);
243 }
244
245 stmt: OP_SPARC_OUTARG_MEM (reg) {
246         guint32 offset = tree->inst_right->inst_imm;
247         if (mono_sparc_is_sparc64 ()) {
248                 guint32 real_offset = tree->inst_right->inst_imm - MONO_SPARC_STACK_BIAS;
249                 /* Correct for the additions in get_call_info () */
250                 offset = MONO_SPARC_STACK_BIAS + (real_offset & ~(7));
251             tree->opcode = OP_STOREI8_MEMBASE_REG;
252         }
253         else {
254                 if (offset & 0x1)
255                         tree->opcode = OP_STOREI1_MEMBASE_REG;
256                 else if (offset & 0x2)
257                         tree->opcode = OP_STOREI2_MEMBASE_REG;
258                 else
259                         tree->opcode = OP_STOREI4_MEMBASE_REG;
260         }
261         tree->inst_destbasereg = tree->inst_right->inst_basereg;
262         tree->inst_offset = offset;
263         tree->sreg1 = state->left->reg1;
264         mono_bblock_add_inst (s->cbb, tree);
265 }
266
267 stmt: OP_SPARC_OUTARG_MEM (freg) {
268         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER4_MEMBASE_REG, tree->inst_right->inst_basereg,
269                                                                 tree->inst_right->inst_imm, state->left->reg1);
270 }
271
272 stmt: OP_SPARC_OUTARG_MEMPAIR (lreg) {
273         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI4_MEMBASE_REG, tree->inst_right->inst_basereg,
274                                                                 tree->inst_right->inst_imm, state->left->reg2);
275         tree->opcode = OP_STOREI4_MEMBASE_REG;
276         tree->inst_destbasereg = tree->inst_right->inst_basereg;
277         tree->inst_offset = tree->inst_right->inst_imm + 4;
278         tree->sreg1 = state->left->reg1;
279         mono_bblock_add_inst (s->cbb, tree);
280 }
281
282 stmt: OP_SPARC_OUTARG_MEMPAIR (freg) {
283         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER8_MEMBASE_REG, tree->inst_right->inst_basereg,
284                                                                 tree->inst_right->inst_imm, state->left->reg1);
285 }
286
287 stmt: OP_SPARC_OUTARG_SPLIT_REG_STACK (lreg) {
288         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
289
290         int dreg = mono_regstate_next_int (s->rs);
291         MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, state->left->reg2);
292         tree->opcode = OP_STOREI4_MEMBASE_REG;
293         tree->inst_destbasereg = tree->inst_right->inst_basereg;
294         tree->inst_offset = tree->inst_right->inst_imm + 4;
295         tree->sreg1 = state->left->reg1;
296         mono_bblock_add_inst (s->cbb, tree);
297
298         mono_call_inst_add_outarg_reg (s, call, dreg, tree->backend.reg3, FALSE);
299 }
300
301 stmt: OP_SPARC_OUTARG_SPLIT_REG_STACK (freg) {
302         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
303
304         int dreg = mono_regstate_next_int (s->rs);
305         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER8_MEMBASE_REG, tree->inst_right->inst_basereg,
306                                                                 tree->inst_right->inst_imm, state->left->reg1);
307         /* floating-point <-> integer transfer must go through memory */
308         /* Load most significant word into register */
309         MONO_EMIT_NEW_LOAD_MEMBASE (s, dreg, tree->inst_right->inst_basereg, tree->inst_right->inst_imm);
310
311         mono_call_inst_add_outarg_reg (s, call, dreg, tree->backend.reg3, FALSE);
312 }
313
314 stmt: OP_SPARC_OUTARG_FLOAT_REG (freg) {
315         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
316
317         tree->opcode = OP_SPARC_SETFREG_FLOAT;
318         tree->dreg = mono_regstate_next_int (s->rs);
319         tree->sreg1 = state->left->reg1;
320         mono_bblock_add_inst (s->cbb, tree);
321
322         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE);
323 }       
324
325 stmt: OP_SPARC_OUTARG_DOUBLE_REG (freg) {
326         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
327
328         tree->opcode = OP_FMOVE;
329         tree->dreg = mono_regstate_next_int (s->rs);
330         tree->sreg1 = state->left->reg1;
331         mono_bblock_add_inst (s->cbb, tree);
332
333         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE);
334 }       
335
336 # Handles scalar valuetypes like RuntimeTypeHandle
337 reg: OP_OUTARG_VT (OP_ICONST) {
338         MONO_EMIT_NEW_STORE_MEMBASE_IMM (s, OP_STOREI4_MEMBASE_IMM, sparc_sp, tree->inst_c1, state->left->tree->inst_c0);
339         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, state->reg1, sparc_sp, tree->inst_c1);
340 }
341
342 reg: OP_OUTARG_VT (OP_AOTCONST) {
343         MONO_EMIT_NEW_AOTCONST (s, state->reg1, state->left->tree->inst_p0, state->left->tree->inst_c1);
344         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI4_MEMBASE_REG, sparc_sp, tree->inst_c1, state->reg1);
345         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, state->reg1, sparc_sp, tree->inst_c1);
346 }
347
348 # FIXME: Unify this with the previous rule
349 reg: OP_OUTARG_VT (OP_REFANYTYPE (reg)) {
350         MONO_EMIT_NEW_LOAD_MEMBASE (s, state->reg1, state->left->left->reg1, G_STRUCT_OFFSET (MonoTypedRef, type));
351         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI4_MEMBASE_REG, sparc_sp, tree->inst_c1, state->reg1);
352         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, state->reg1, sparc_sp, tree->inst_c1);
353 }       
354
355 reg: OP_OUTARG_VT (base) {
356         int size = tree->backend.size;
357         mini_emit_memcpy (s, sparc_sp, tree->inst_c1, state->left->tree->inst_basereg, state->left->tree->inst_offset, size, 0);
358         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, state->reg1, sparc_sp, tree->inst_c1);
359 }
360
361 stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)) {
362         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
363
364         tree->opcode = OP_MOVE;
365         tree->sreg1 = state->left->left->tree->dreg;
366         tree->dreg = mono_regstate_next_int (s->rs);
367         mono_bblock_add_inst (s->cbb, tree);
368
369         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
370 }
371
372 stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGOFFSET)) {
373         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
374
375         int dreg = mono_regstate_next_int (s->rs);
376         MONO_EMIT_NEW_LOAD_MEMBASE (s, dreg, state->left->left->tree->inst_basereg, 
377                                                                 state->left->left->tree->inst_offset);
378
379         mono_call_inst_add_outarg_reg (s, call, dreg, tree->backend.reg3, FALSE);
380 }
381
382 stmt: OP_OUTARG_VT (OP_ICONST) {
383         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
384
385         tree->opcode = OP_ICONST;
386         tree->dreg = mono_regstate_next_int (s->rs); 
387         tree->inst_imm = state->left->tree->inst_c0;
388         mono_bblock_add_inst (s->cbb, tree);
389
390         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
391 }
392
393 stmt: CEE_STIND_R8 (OP_REGVAR, freg) {
394         /* nothing to do: the value is already on the FP stack */
395 }
396
397 reg: CEE_LDIND_I1 (OP_REGVAR) {
398         MONO_EMIT_UNALU (s, tree, CEE_CONV_I1, state->reg1, state->left->tree->dreg);
399 }
400
401 reg: CEE_LDIND_I2 (OP_REGVAR) {
402         MONO_EMIT_UNALU (s, tree, CEE_CONV_I2, state->reg1, state->left->tree->dreg);
403 }
404
405 stmt: CEE_BNE_UN (fpcflags) {
406         tree->opcode = OP_FBNE_UN;
407         mono_bblock_add_inst (s->cbb, tree);
408 }
409
410 stmt: CEE_BEQ (fpcflags) {
411         tree->opcode = OP_FBEQ;
412         mono_bblock_add_inst (s->cbb, tree);
413 }
414
415 stmt: CEE_BLT (fpcflags) {
416         tree->opcode = OP_FBLT;
417         mono_bblock_add_inst (s->cbb, tree);
418 }
419
420 stmt: CEE_BLT_UN (fpcflags) {
421         tree->opcode = OP_FBLT_UN;
422         mono_bblock_add_inst (s->cbb, tree);
423 }
424
425 stmt: CEE_BGT (fpcflags) {
426         tree->opcode = OP_FBGT;
427         mono_bblock_add_inst (s->cbb, tree);
428 }
429
430 stmt: CEE_BGT_UN (fpcflags) {
431         tree->opcode = OP_FBGT_UN;
432         mono_bblock_add_inst (s->cbb, tree);
433 }
434
435 stmt: CEE_BGE  (fpcflags) {
436         tree->opcode = OP_FBGE;
437         mono_bblock_add_inst (s->cbb, tree);
438 }
439
440 stmt: CEE_BGE_UN (fpcflags) {
441         tree->opcode = OP_FBGE_UN;
442         mono_bblock_add_inst (s->cbb, tree);
443 }
444
445 stmt: CEE_BLE  (fpcflags) {
446         tree->opcode = OP_FBLE;
447         mono_bblock_add_inst (s->cbb, tree);
448 }
449
450 stmt: CEE_BLE_UN (fpcflags) {
451         tree->opcode = OP_FBLE_UN;
452         mono_bblock_add_inst (s->cbb, tree);
453 }
454
455 stmt: CEE_POP (freg) "0" {
456         /* nothing to do */
457 }     
458
459 stmt: OP_START_HANDLER {
460      mono_bblock_add_inst (s->cbb, tree);
461 }
462
463 stmt: OP_ENDFINALLY {
464         //MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
465         //MONO_EMIT_NEW_LOAD_MEMBASE (s, sparc_o7, spvar->inst_basereg, spvar->inst_offset); 
466         mono_bblock_add_inst (s->cbb, tree);
467 }
468
469 stmt: OP_ENDFILTER (reg) {
470         //MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
471         //MONO_EMIT_NEW_LOAD_MEMBASE (s, sparc_o7, spvar->inst_basereg, spvar->inst_offset); 
472         tree->sreg1 = state->left->reg1;
473         mono_bblock_add_inst (s->cbb, tree);
474 }
475
476 stmt: OP_START_HANDLER {
477 }
478
479 stmt: OP_ENDFINALLY {
480         mono_bblock_add_inst (s->cbb, tree);
481 }
482
483 stmt: OP_ENDFILTER (reg) {
484         tree->sreg1 = state->left->reg1;
485         tree->dreg = state->reg1;
486         mono_bblock_add_inst (s->cbb, tree);
487 }
488
489 reg: OP_CEQ (OP_COMPARE (freg, freg)) { 
490         MONO_EMIT_BIALU (s, tree, OP_FCEQ, state->reg1, state->left->left->reg1,
491                          state->left->right->reg1);
492 }
493
494 reg: OP_CLT (OP_COMPARE (freg, freg)) { 
495         MONO_EMIT_BIALU (s, tree, OP_FCLT, state->reg1, state->left->left->reg1,
496                          state->left->right->reg1);
497 }
498
499 reg: OP_CLT_UN (OP_COMPARE (freg, freg)) {      
500         MONO_EMIT_BIALU (s, tree, OP_FCLT_UN, state->reg1, state->left->left->reg1,
501                          state->left->right->reg1);
502 }
503
504 reg: OP_CGT (OP_COMPARE (freg, freg)) { 
505         MONO_EMIT_BIALU (s, tree, OP_FCGT, state->reg1, state->left->left->reg1,
506                          state->left->right->reg1);
507 }
508
509 reg: OP_CGT_UN (OP_COMPARE (freg, freg)) {      
510         MONO_EMIT_BIALU (s, tree, OP_FCGT_UN, state->reg1, state->left->left->reg1,
511                          state->left->right->reg1);
512 }
513
514 reg: OP_LOCALLOC (reg) {
515         tree->sreg1 = state->left->tree->dreg;
516         mono_bblock_add_inst (s->cbb, tree);
517 }
518
519 #
520 # Optimizations
521 #
522
523 reg: CEE_LDIND_REF (OP_REGVAR),
524 reg: CEE_LDIND_I (OP_REGVAR),
525 reg: CEE_LDIND_I4 (OP_REGVAR),
526 reg: CEE_LDIND_U4 (OP_REGVAR) "0" {
527         /* This rule might not work on all archs, hence it is sparc only */
528         state->reg1 = state->left->tree->dreg;
529         tree->dreg = state->reg1;
530 }
531
532 stmt: CEE_STIND_I1 (OP_REGVAR, OP_ICONST) {
533         tree->opcode = OP_ICONST;
534         tree->dreg = state->left->tree->dreg;
535         tree->inst_c0 = state->right->tree->inst_c0;
536         mono_bblock_add_inst (s->cbb, tree);
537 }
538
539 stmt: CEE_STIND_I2 (OP_REGVAR, OP_ICONST) {
540         tree->opcode = OP_ICONST;
541         tree->dreg = state->left->tree->dreg;
542         tree->inst_c0 = state->right->tree->inst_c0;
543         mono_bblock_add_inst (s->cbb, tree);
544 }
545
546 stmt: CEE_STIND_I4 (OP_REGVAR, CEE_ADD (reg, OP_ICONST)) {
547         MONO_EMIT_BIALU_IMM (s, tree, OP_ADD_IMM, state->left->tree->dreg, state->right->left->reg1, state->right->right->tree->inst_c0);
548 }
549
550 stmt: CEE_STIND_REF (OP_REGVAR, CEE_ADD (reg, OP_ICONST)) {
551         MONO_EMIT_BIALU_IMM (s, tree, OP_ADD_IMM, state->left->tree->dreg, state->right->left->reg1, state->right->right->tree->inst_c0);
552 }
553
554 stmt: CEE_STIND_I4 (OP_REGVAR, CEE_SUB (reg, OP_ICONST)) {
555         MONO_EMIT_BIALU_IMM (s, tree, OP_SUB_IMM, state->left->tree->dreg, state->right->left->reg1, state->right->right->tree->inst_c0);
556 }
557
558 stmt: CEE_STIND_REF (OP_REGVAR, CEE_SUB (reg, OP_ICONST)) {
559         MONO_EMIT_BIALU_IMM (s, tree, OP_SUB_IMM, state->left->tree->dreg, state->right->left->reg1, state->right->right->tree->inst_c0);
560 }
561
562 stmt: CEE_STIND_I4 (OP_REGVAR, CEE_ADD (reg, reg)) {
563         MONO_EMIT_BIALU (s, tree, CEE_ADD, state->left->tree->dreg, state->right->left->reg1, state->right->right->reg1);
564 }
565
566 stmt: CEE_STIND_REF (OP_REGVAR, CEE_ADD (reg, reg)) {
567         MONO_EMIT_BIALU (s, tree, CEE_ADD, state->left->tree->dreg, state->right->left->reg1, state->right->right->reg1);
568 }
569
570 stmt: CEE_STIND_I4 (OP_REGVAR, CEE_LDIND_I4(base)) {
571         MONO_EMIT_LOAD_MEMBASE (s, tree, state->left->tree->dreg, state->right->left->tree->inst_basereg, 
572                                 state->right->left->tree->inst_offset); 
573 }
574
575 stmt: CEE_STIND_REF (OP_REGVAR, CEE_LDIND_REF(base)) {
576         MONO_EMIT_LOAD_MEMBASE (s, tree, state->left->tree->dreg, state->right->left->tree->inst_basereg, 
577                                 state->right->left->tree->inst_offset); 
578 }
579
580 stmt: OP_SETRET (CEE_LDIND_I1(base)),
581 stmt: OP_SETRET (CEE_LDIND_U1(base)),
582 stmt: OP_SETRET (CEE_LDIND_I2(base)),
583 stmt: OP_SETRET (CEE_LDIND_U2(base)),
584 stmt: OP_SETRET (CEE_LDIND_I(base)),
585 stmt: OP_SETRET (CEE_LDIND_REF(base)),
586 stmt: OP_SETRET (CEE_LDIND_I4(base)),
587 stmt: OP_SETRET (CEE_LDIND_U4(base)) {
588         MONO_EMIT_LOAD_MEMBASE_OP (s, tree, ldind_to_load_membase (state->left->tree->opcode), 
589                 sparc_i0, state->left->left->tree->inst_basereg, state->left->left->tree->inst_offset); 
590 }
591
592 stmt: OP_SETRET (CEE_LDIND_I4(OP_REGVAR)) {
593         tree->opcode = OP_MOVE;
594         tree->dreg = sparc_i0;
595         tree->sreg1 = state->left->left->tree->dreg;
596         mono_bblock_add_inst (s->cbb, tree);
597 }
598
599 stmt: OP_SETRET (CEE_LDIND_I(OP_REGVAR)) {
600         tree->opcode = OP_MOVE;
601         tree->dreg = sparc_i0;
602         tree->sreg1 = state->left->left->tree->dreg;
603         mono_bblock_add_inst (s->cbb, tree);
604 }
605
606 stmt: OP_OUTARG (CEE_LDIND_I (OP_REGVAR)),
607 stmt: OP_OUTARG (CEE_LDIND_I4 (OP_REGVAR)) {
608         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
609
610         tree->opcode = OP_MOVE;
611         tree->dreg = mono_regstate_next_int (s->rs);
612         tree->sreg1 = state->left->left->tree->dreg;
613         mono_bblock_add_inst (s->cbb, tree);
614
615         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
616 }
617
618 stmt: OP_OUTARG (CEE_LDIND_REF(base)) {
619         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
620
621         int dreg = mono_regstate_next_int (s->rs);
622         MONO_EMIT_LOAD_MEMBASE (s, tree, dreg, state->left->left->tree->inst_basereg, 
623                                 state->left->left->tree->inst_offset);  
624
625         mono_call_inst_add_outarg_reg (s, call, dreg, tree->backend.reg3, FALSE);
626 }
627
628 stmt: OP_OUTARG (CEE_LDIND_I4(base)) {
629         MonoCallInst *call = (MonoCallInst*)tree->inst_right->inst_left;
630
631         int dreg = mono_regstate_next_int (s->rs);
632         MONO_EMIT_LOAD_MEMBASE_OP (s, tree, OP_LOADI4_MEMBASE, dreg, state->left->left->tree->inst_basereg, 
633                                 state->left->left->tree->inst_offset);  
634
635         mono_call_inst_add_outarg_reg (s, call, dreg, tree->backend.reg3, FALSE);
636 }
637
638 reg: OP_LDADDR (OP_REGOFFSET) "1" {
639         if (state->left->tree->inst_offset) {
640                 MONO_EMIT_BIALU_IMM (s, tree, OP_ADD_IMM, state->reg1, state->left->tree->inst_basereg, state->left->tree->inst_offset);
641         } else {
642                 tree->opcode = OP_MOVE;
643                 tree->sreg1 = state->left->tree->inst_basereg;
644                 tree->dreg = state->reg1;
645                mono_bblock_add_inst (s->cbb, tree);
646         }
647 }
648
649 lreg: OP_LNEG (lreg) "3" {
650         /* The one in inssel.brg doesn't work, this one is based on gcc code */
651         MONO_EMIT_NEW_BIALU (s, OP_SUBCC, state->reg1, 0, state->left->reg1);
652         MONO_EMIT_NEW_BIALU (s, OP_SBB, state->reg2, 0, state->left->reg2);
653 }
654
655 # FIXME: This rule was commented out in inssel.brg, why ?
656 reg: CEE_REM (reg, OP_ICONST) {
657         MONO_EMIT_BIALU_IMM (s, tree, OP_REM_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
658 }
659
660 # This one too
661 reg: CEE_DIV (reg, OP_ICONST) {
662         MONO_EMIT_BIALU_IMM (s, tree, OP_DIV_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
663 }
664
665 reg: OP_LOCALLOC (OP_ICONST) {
666         tree->opcode = OP_LOCALLOC_IMM;
667         tree->inst_imm = state->left->tree->inst_c0;
668         tree->dreg = state->reg1;
669         mono_bblock_add_inst (s->cbb, tree);
670 }
671
672 # FIXME: Optimized MEMCPY for copying valuetypes
673
674 # Optimized version for initializing valuetypes on the stack
675 stmt: OP_MEMSET (OP_LDADDR(OP_REGOFFSET)) "0" {
676         int size = tree->backend.memcpy_args->size;
677         int align = tree->backend.memcpy_args->align;
678         int offset = state->left->left->tree->inst_offset;
679         int destreg = state->left->left->tree->inst_basereg;
680         int val_reg;
681
682         if (tree->inst_imm) {
683                 val_reg = mono_regstate_next_int (s->rs);
684                 MONO_EMIT_NEW_ICONST (s, val_reg, tree->inst_imm);
685         }
686         else
687                 val_reg = sparc_g0;
688
689         if (align < 4) {
690                 /* This could be optimized further if neccesary */
691                 while (size >= 1) {
692                         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
693                         offset += 1;
694                         size -= 1;
695                 }
696                 return;
697         }       
698
699         /* Target address must be dword aligned */
700         if ((tree->inst_imm == 0) && (size >= 8) && 
701                 (destreg == sparc_fp) && (((offset - MONO_SPARC_STACK_BIAS) % 8) == 0)) {
702                 if (!mono_sparc_is_v9 ()) {
703                         /* Use STD */
704                         MONO_EMIT_NEW_ICONST (s, sparc_g1, 0);
705
706                         while (size >= 8) {
707                                 MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
708                                 offset += 8;
709                                 size -= 8;
710                         }
711                 }
712                 else {
713                         /* Use STX imm */
714                         while (size >= 8) {
715                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (s, OP_STOREI8_MEMBASE_IMM, destreg, offset, 0);
716                                 offset += 8;
717                                 size -= 8;
718                         }
719                 }
720         }
721                 
722         while (size >= 4) {
723                 MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
724                 offset += 4;
725                 size -= 4;
726         }
727         while (size >= 2) {
728                 MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
729                 offset += 2;
730                 size -= 2;
731         }
732         while (size >= 1) {
733                 MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
734                 offset += 1;
735                 size -= 1;
736         }
737 }               
738
739 stmt: OP_MEMSET (reg) "0" {
740         int size = tree->backend.memcpy_args->size;
741         int align = tree->backend.memcpy_args->align;
742         int offset = 0;
743         int destreg = state->left->reg1;
744         int val_reg;
745
746         if (tree->inst_imm) {
747                 val_reg = mono_regstate_next_int (s->rs);
748                 MONO_EMIT_NEW_ICONST (s, val_reg, tree->inst_imm);
749         }
750         else
751                 val_reg = sparc_g0;
752
753         if (align < 4) {
754                 /* This could be optimized further if neccesary */
755                 while (size >= 1) {
756                         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
757                         offset += 1;
758                         size -= 1;
759                 }
760                 return;
761         }       
762
763         while (size >= 4) {
764                 MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
765                 offset += 4;
766                 size -= 4;
767         }
768         while (size >= 2) {
769                 MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
770                 offset += 2;
771                 size -= 2;
772         }
773         while (size >= 1) {
774                 MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
775                 offset += 1;
776                 size -= 1;
777         }
778 }
779
780
781 stmt: CEE_STIND_R8 (base, OP_R8CONST) {
782         /* fp constants are pricy on SPARC */
783         guint64 d = *(guint64*)state->right->tree->inst_p0;
784
785         if (d == 0) {
786                 if (sizeof (gpointer) == 8) {
787                         MONO_EMIT_STORE_MEMBASE (s, tree, OP_STOREI8_MEMBASE_REG, state->left->tree->inst_basereg, state->left->tree->inst_offset, sparc_g0);
788                 }
789                 else {
790                         /* STOREI8 would write %g1 as well */
791                         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI4_MEMBASE_REG, state->left->tree->inst_basereg, state->left->tree->inst_offset, sparc_g0);
792                         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI4_MEMBASE_REG, state->left->tree->inst_basereg, state->left->tree->inst_offset + 4, sparc_g0);
793                 }
794         }
795         else {
796                 state->right->tree->dreg = state->reg1;
797                 mono_bblock_add_inst (s->cbb, state->right->tree);
798                 MONO_EMIT_STORE_MEMBASE (s, tree, OP_STORER8_MEMBASE_REG, state->left->tree->inst_basereg,
799                                          state->left->tree->inst_offset, state->reg1);
800         }
801 }
802
803 %%