2008-09-07 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / inssel-ia64.brg
1
2 %%
3
4 #
5 # inssel-ia64.brg: burg file for special IA64 instructions
6 #
7 # Author:
8 #   Zoltan Varga (vargaz@gmail.com)
9 #
10 # (C) 2002 Ximian, Inc.
11 #
12
13 reg: CEE_LDIND_I8 (OP_REGVAR) {
14         state->reg1 = state->left->tree->dreg;
15 }
16
17 stmt: CEE_STIND_I8 (OP_REGVAR, reg) {
18         MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->left->tree->dreg, state->right->reg1);
19 }
20
21 reg: CEE_LDIND_I1 (OP_REGVAR) {
22         MONO_EMIT_UNALU (s, tree, OP_SEXT_I1, state->reg1, state->left->tree->dreg);}
23
24 reg: CEE_LDIND_I2 (OP_REGVAR) {
25         MONO_EMIT_UNALU (s, tree, OP_SEXT_I2, state->reg1, state->left->tree->dreg);}
26
27 stmt: CEE_BEQ (fpcflags) {
28         tree->opcode = OP_FBEQ;
29         mono_bblock_add_inst (s->cbb, tree);
30 }
31
32 stmt: CEE_BNE_UN (fpcflags) {
33         tree->opcode = OP_FBNE_UN;
34         mono_bblock_add_inst (s->cbb, tree);
35 }
36
37 stmt: CEE_BLT (fpcflags) {
38         tree->opcode = OP_FBLT;
39         mono_bblock_add_inst (s->cbb, tree);
40 }
41
42 stmt: CEE_BLT_UN (fpcflags) {
43         tree->opcode = OP_FBLT_UN;
44         mono_bblock_add_inst (s->cbb, tree);
45 }
46
47 stmt: CEE_BGT (fpcflags) {
48         tree->opcode = OP_FBGT;
49         mono_bblock_add_inst (s->cbb, tree);
50 }
51
52 stmt: CEE_BGT_UN (fpcflags) {
53         tree->opcode = OP_FBGT_UN;
54         mono_bblock_add_inst (s->cbb, tree);
55 }
56
57 stmt: CEE_BGE  (fpcflags) {
58         tree->opcode = OP_FBGE;
59         mono_bblock_add_inst (s->cbb, tree);
60 }
61
62 stmt: CEE_BGE_UN (fpcflags) {
63         tree->opcode = OP_FBGE_UN;
64         mono_bblock_add_inst (s->cbb, tree);
65 }
66
67 stmt: CEE_BLE  (fpcflags) {
68         tree->opcode = OP_FBLE;
69         mono_bblock_add_inst (s->cbb, tree);
70 }
71
72 stmt: CEE_BLE_UN (fpcflags) {
73         tree->opcode = OP_FBLE_UN;
74         mono_bblock_add_inst (s->cbb, tree);
75 }
76
77 fpcflags: OP_COMPARE (freg, freg) {
78         tree->opcode = OP_FCOMPARE;
79         mono_bblock_add_inst (s->cbb, tree);
80 }
81
82 reg: OP_CEQ (fpcflags) {        
83         tree->dreg = state->reg1;
84         tree->opcode = OP_FCEQ;
85         mono_bblock_add_inst (s->cbb, tree);
86 }
87
88 reg: OP_CLT (fpcflags) {        
89         tree->dreg = state->reg1;
90         tree->opcode = OP_FCLT;
91         mono_bblock_add_inst (s->cbb, tree);
92 }
93
94 reg: OP_CLT_UN (fpcflags) {     
95         tree->dreg = state->reg1;
96         tree->opcode = OP_FCLT_UN;
97         mono_bblock_add_inst (s->cbb, tree);
98 }
99
100 reg: OP_CGT (fpcflags) {        
101         tree->dreg = state->reg1;
102         tree->opcode = OP_FCGT;
103         mono_bblock_add_inst (s->cbb, tree);
104 }
105
106 reg: OP_CGT_UN (fpcflags) {     
107         tree->dreg = state->reg1;
108         tree->opcode = OP_FCGT_UN;
109         mono_bblock_add_inst (s->cbb, tree);
110 }
111
112 freg: OP_LCONV_TO_R8 (reg) {
113         /* FIXME: Move this inssel-long.brg */
114         tree->sreg1 = state->left->reg1;
115         tree->dreg = state->reg1;
116         mono_bblock_add_inst (s->cbb, tree);
117 }
118
119 freg: OP_LCONV_TO_R4 (reg) {
120         /* FIXME: Move this inssel-long.brg */
121         tree->sreg1 = state->left->reg1;
122         tree->dreg = state->reg1;
123         mono_bblock_add_inst (s->cbb, tree);
124 }
125
126 stmt: OP_OUTARG_REG (reg) {     
127         /* FIXME: Move this to inssel.brg */
128         MonoCallInst *call = (MonoCallInst*)tree->inst_right;
129
130         tree->opcode = OP_MOVE;
131         tree->sreg1 = state->left->reg1;
132         tree->dreg = mono_regstate_next_int (s->rs);
133         mono_bblock_add_inst (s->cbb, tree);
134
135         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
136 }
137
138 stmt: OP_OUTARG_REG (CEE_LDIND_I (base)),
139 stmt: OP_OUTARG_REG (CEE_LDIND_REF (base)),
140 stmt: OP_OUTARG_REG (CEE_LDIND_I1 (base)),
141 stmt: OP_OUTARG_REG (CEE_LDIND_U1 (base)),
142 stmt: OP_OUTARG_REG (CEE_LDIND_I2 (base)),
143 stmt: OP_OUTARG_REG (CEE_LDIND_U2 (base)),
144 stmt: OP_OUTARG_REG (CEE_LDIND_I4 (base)),
145 stmt: OP_OUTARG_REG (CEE_LDIND_U4 (base)),
146 stmt: OP_OUTARG_REG (CEE_LDIND_I8 (base)) {
147         /* FIXME: Move this to inssel.brg or inssel-long.brg */
148         MonoCallInst *call = (MonoCallInst*)tree->inst_right;
149         guint32 dreg;
150         MonoInst *base = state->left->left->tree;
151
152         dreg = mono_regstate_next_int (s->rs);
153         MONO_EMIT_LOAD_MEMBASE_OP (s, tree, ldind_to_load_membase (state->left->tree->opcode),
154                                         dreg, base->inst_basereg, base->inst_offset);
155
156         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
157 }
158
159 stmt: OP_OUTARG_REG (OP_I8CONST),
160 stmt: OP_OUTARG_REG (OP_ICONST) {
161         /* FIXME: Move this to inssel.brg or inssel-long.brg */
162         MonoCallInst *call = (MonoCallInst*)tree->inst_right;
163
164         tree->opcode = OP_ICONST;
165         tree->inst_c0 = state->left->tree->inst_c0;
166         tree->dreg = mono_regstate_next_int (s->rs);
167         mono_bblock_add_inst (s->cbb, tree);
168
169         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
170 }
171
172 stmt: OP_OUTARG_REG (CEE_LDIND_I (OP_REGVAR)),
173 stmt: OP_OUTARG_REG (CEE_LDIND_I8 (OP_REGVAR)),
174 stmt: OP_OUTARG_REG (CEE_LDIND_I4 (OP_REGVAR)),
175 stmt: OP_OUTARG_REG (CEE_LDIND_U4 (OP_REGVAR)),
176 stmt: OP_OUTARG_REG (CEE_LDIND_REF (OP_REGVAR)) {       
177         MonoCallInst *call = (MonoCallInst*)tree->inst_right;
178
179         tree->opcode = OP_MOVE;
180         tree->sreg1 = state->left->left->tree->dreg;
181         tree->dreg = mono_regstate_next_int (s->rs);
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 }
186
187 stmt: OP_OUTARG_FREG (freg) {
188         MonoCallInst *call = (MonoCallInst*)tree->inst_right;
189
190         tree->opcode = OP_FMOVE;
191         tree->sreg1 = state->left->reg1;
192         tree->dreg = mono_regstate_next_float (s->rs);
193         mono_bblock_add_inst (s->cbb, tree);
194
195         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE);
196 }
197
198 stmt: OP_OUTARG_FREG_R4 (freg) {
199         MonoCallInst *call = (MonoCallInst*)tree->inst_right;
200
201         tree->opcode = OP_FCONV_TO_R4;
202         tree->sreg1 = state->left->reg1;
203         tree->dreg = mono_regstate_next_float (s->rs);
204         mono_bblock_add_inst (s->cbb, tree);
205
206         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE);
207 }
208
209 stmt: OP_OUTARG (reg) {
210         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI8_MEMBASE_REG, IA64_SP, tree->inst_imm, state->left->reg1);
211 }
212
213 stmt: OP_OUTARG (freg) {
214         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER8_MEMBASE_REG, IA64_SP, tree->inst_imm, state->left->reg1);
215 }
216
217 stmt: OP_OUTARG_R4 (freg) {
218         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER4_MEMBASE_REG, IA64_SP, tree->inst_imm, state->left->reg1);
219 }
220
221 stmt: OP_OUTARG_REG (OP_LDADDR (OP_REGOFFSET)),
222 stmt: OP_OUTARG_REG (CEE_LDOBJ (OP_REGOFFSET)) {
223         /* FIXME: Move this to inssel.brg */
224         MonoCallInst *call = (MonoCallInst*)tree->inst_right;
225
226         tree->opcode = OP_ADD_IMM;
227         tree->sreg1 = state->left->left->tree->inst_basereg;
228         tree->inst_imm = state->left->left->tree->inst_offset;
229         tree->dreg = mono_regstate_next_int (s->rs);
230         mono_bblock_add_inst (s->cbb, tree);
231
232         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
233 }
234
235 stmt: OP_SETRET (reg) {
236         tree->opcode = OP_MOVE;
237         tree->sreg1 = state->left->reg1;
238         tree->dreg = MONO_ARCH_RETREG1;
239         mono_bblock_add_inst (s->cbb, tree);
240 }
241
242 stmt: OP_SETRET (freg) {
243         tree->opcode = OP_FMOVE;
244         tree->sreg1 = state->left->reg1;
245         tree->dreg = MONO_ARCH_FRETREG1;
246         mono_bblock_add_inst (s->cbb, tree);
247 }
248
249 # Optimized call instructions
250 reg: OP_LCALL_REG (OP_ICONST),
251 reg: OP_LCALL_REG (OP_I8CONST) {
252         /* FIXME: Move this to inssel-long.brg */
253         tree->opcode = OP_LCALL;
254         ((MonoCallInst*)tree)->fptr = state->left->tree->inst_p0;
255         tree->dreg = state->reg1;
256         mono_bblock_add_inst (s->cbb, tree);
257 }
258
259 stmt: OP_OUTARG_VT (CEE_LDOBJ (base), base) {
260         MonoInst *vt = state->left->left->tree;
261         MonoInst *stack_addr = state->right->tree;
262         int sz = stack_addr->inst_imm;
263
264         if (!sz)
265                 return;
266
267         mini_emit_memcpy (s, stack_addr->inst_basereg, stack_addr->inst_offset, vt->inst_basereg, vt->inst_offset, sz, 0);
268 }
269
270 # This handles trees like outarg_vt (refanytype)
271 stmt: OP_OUTARG_VT (reg, base) {
272         MonoInst *stack_addr = state->right->tree;
273
274         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI8_MEMBASE_REG, stack_addr->inst_basereg, stack_addr->inst_offset, state->left->reg1);
275 }
276
277 stmt: OP_START_HANDLER {
278      mono_bblock_add_inst (s->cbb, tree);
279 }
280
281 stmt: OP_ENDFINALLY {
282      mono_bblock_add_inst (s->cbb, tree);
283 }
284
285 stmt: OP_ENDFILTER (reg) {
286         tree->sreg1 = state->left->reg1;
287         mono_bblock_add_inst (s->cbb, tree);
288 }
289
290 reg: OP_LOCALLOC (reg) {
291         tree->sreg1 = state->left->reg1;
292         tree->dreg = state->reg1;
293         mono_bblock_add_inst (s->cbb, tree);
294 }
295
296 reg: CEE_LDIND_REF (OP_REGVAR),
297 reg: CEE_LDIND_I (OP_REGVAR),
298 reg: CEE_LDIND_I8 (OP_REGVAR),
299 reg: CEE_LDIND_I4 (OP_REGVAR),
300 reg: CEE_LDIND_U4 (OP_REGVAR) "0" {
301         state->reg1 = state->left->tree->dreg;
302         tree->dreg = state->reg1;
303 }
304
305 reg: OP_ATOMIC_ADD_NEW_I4 (base, OP_ICONST),
306 reg: OP_ATOMIC_ADD_NEW_I8 (base, OP_ICONST) {
307         tree->opcode = tree->opcode == OP_ATOMIC_ADD_NEW_I4 ? OP_ATOMIC_ADD_IMM_NEW_I4 : OP_ATOMIC_ADD_IMM_NEW_I8;
308         tree->dreg = state->reg1;
309         tree->inst_imm = state->right->tree->inst_imm;
310         tree->inst_basereg = state->left->tree->inst_basereg; 
311         tree->inst_offset = state->left->tree->inst_offset; 
312     
313         mono_bblock_add_inst (s->cbb, tree);
314 } cost {
315         int imm = state->right->tree->inst_imm;
316
317         MBCOND (imm == 1 || imm == 4 || imm == 8 || imm == 16 || imm == -1 || imm == -4 || imm == -8 || imm == -16);
318         return 1;
319 }
320
321 reg: OP_ATOMIC_EXCHANGE_I4 (base, reg),
322 reg: OP_ATOMIC_EXCHANGE_I8 (base, reg),
323 reg: OP_ATOMIC_ADD_NEW_I4 (base, reg),
324 reg: OP_ATOMIC_ADD_NEW_I8 (base, reg) {
325         tree->opcode = tree->opcode;
326         tree->dreg = state->reg1;
327         tree->sreg2 = state->right->reg1;
328         tree->inst_basereg = state->left->tree->inst_basereg; 
329         tree->inst_offset = state->left->tree->inst_offset; 
330     
331         mono_bblock_add_inst (s->cbb, tree);
332 }
333
334 reg: OP_ATOMIC_ADD_IMM_NEW_I4 (base),
335 reg: OP_ATOMIC_ADD_IMM_NEW_I8 (base) {
336         tree->opcode = tree->opcode;
337         tree->dreg = state->reg1;
338         tree->inst_basereg = state->left->tree->inst_basereg; 
339         tree->inst_offset = state->left->tree->inst_offset; 
340     
341         mono_bblock_add_inst (s->cbb, tree);
342 }
343
344 # Optimized memset implementation
345 stmt: OP_MEMSET (base) "0" {
346         int dest_reg, dest_reg2, val_reg, unit, align;
347         int size = tree->backend.memcpy_args->size;
348
349         dest_reg = mono_regstate_next_int (s->rs);
350
351         if (state->left->tree->inst_basereg == s->frame_reg)
352                 /* Aligned by mono_allocate_stack_slots */
353                 align = 8;
354         else
355                 align = 4;
356
357         if (tree->inst_imm == 0)
358                 val_reg = IA64_R0;
359         else {
360                 val_reg = mono_regstate_next_int (s->rs);
361
362                 MONO_EMIT_NEW_ICONST (s, val_reg, tree->inst_imm);
363         }
364
365         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, dest_reg, state->left->tree->inst_basereg, state->left->tree->inst_offset);     
366
367         for (unit = align; unit >= 1; unit = unit >> 1) {
368                 dest_reg2 = mono_regstate_next_int (s->rs);
369
370                 /* Use two destination regs to increase paralellism */
371                 if (size >= 2 * unit) {
372                         int diff = (size / (2 * unit)) * unit;
373                         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, dest_reg2, state->left->tree->inst_basereg, state->left->tree->inst_offset + diff);
374
375                         while (size >= (2 * unit)) {
376                                 MONO_EMIT_NEW_STORE_MEMBASE (s, size_to_ia64_store_membase_inc_reg (unit), dest_reg, 0, val_reg);
377                                 MONO_EMIT_NEW_STORE_MEMBASE (s, size_to_ia64_store_membase_inc_reg (unit), dest_reg2, 0, val_reg);
378                                 size -= 2 * unit;
379                         }
380
381                         if (size > 0)
382                                 MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, dest_reg, dest_reg, diff);
383                 }
384
385                 while (size >= unit) {
386                         if (size == unit)
387                                 MONO_EMIT_NEW_STORE_MEMBASE (s, size_to_store_membase_reg (unit), dest_reg, 0, val_reg);
388                         else
389                                 MONO_EMIT_NEW_STORE_MEMBASE (s, size_to_ia64_store_membase_inc_reg (unit), dest_reg, 0, val_reg);
390                         size -= unit;
391                 }
392         }       
393
394 }
395
396 # Optimized memcpy implementation
397 stmt: OP_MEMCPY (base, base) "0" {
398         int cur_reg, src_reg, dest_reg, unit;
399         int size = tree->backend.memcpy_args->size;
400         int align;
401
402         src_reg = mono_regstate_next_int (s->rs);
403         dest_reg = mono_regstate_next_int (s->rs);
404
405         if ((state->left->tree->inst_basereg == s->frame_reg) &&
406                 (state->right->tree->inst_basereg == s->frame_reg))
407                 /* Aligned by mono_allocate_stack_slots */
408                 align = 8;
409         else
410                 align = 4;
411
412         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, dest_reg, state->left->tree->inst_basereg, state->left->tree->inst_offset);     
413         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, src_reg, state->right->tree->inst_basereg, state->right->tree->inst_offset);
414
415         for (unit = align; unit >= 1; unit = unit >> 1) {
416                 while (size >= unit) {
417                         cur_reg = mono_regstate_next_int (s->rs);
418                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, size_to_ia64_load_u_membase_inc (unit), cur_reg, src_reg, 0);
419                         MONO_EMIT_NEW_STORE_MEMBASE (s, size_to_ia64_store_membase_inc_reg (unit), dest_reg, 0, cur_reg);
420                         size -= unit;
421                 }
422         }       
423 }
424
425 %%
426
427 static int
428 size_to_ia64_load_u_membase_inc (int size)
429 {
430         switch (size) {
431         case 1:
432                 return OP_IA64_LOADU1_MEMBASE_INC;
433         case 2:
434                 return OP_IA64_LOADU2_MEMBASE_INC;
435         case 4:
436                 return OP_IA64_LOADU4_MEMBASE_INC;
437         case 8:
438                 return OP_IA64_LOADI8_MEMBASE_INC;
439         default:
440                 g_assert_not_reached ();
441                 return -1;
442         }
443 }
444
445 static int
446 size_to_store_membase_reg (int size)
447 {
448         switch (size) {
449         case 1:
450                 return OP_STOREI1_MEMBASE_REG;
451         case 2:
452                 return OP_STOREI2_MEMBASE_REG;
453         case 4:
454                 return OP_STOREI4_MEMBASE_REG;
455         case 8:
456                 return OP_STOREI8_MEMBASE_REG;
457         default:
458                 g_assert_not_reached ();
459                 return -1;
460         }
461 }
462
463 static int
464 size_to_ia64_store_membase_inc_reg (int size)
465 {
466         switch (size) {
467         case 1:
468                 return OP_IA64_STOREI1_MEMBASE_INC_REG;
469         case 2:
470                 return OP_IA64_STOREI2_MEMBASE_INC_REG;
471         case 4:
472                 return OP_IA64_STOREI4_MEMBASE_INC_REG;
473         case 8:
474                 return OP_IA64_STOREI8_MEMBASE_INC_REG;
475         default:
476                 g_assert_not_reached ();
477                 return -1;
478         }
479 }