New test + update.
[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 (reg) {
199         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI8_MEMBASE_REG, IA64_SP, tree->inst_imm, state->left->reg1);
200 }
201
202 stmt: OP_OUTARG (freg) {
203         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER8_MEMBASE_REG, IA64_SP, tree->inst_imm, state->left->reg1);
204 }
205
206 stmt: OP_OUTARG_R4 (freg) {
207         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER4_MEMBASE_REG, IA64_SP, tree->inst_imm, state->left->reg1);
208 }
209
210 stmt: OP_OUTARG_REG (OP_LDADDR (OP_REGOFFSET)),
211 stmt: OP_OUTARG_REG (CEE_LDOBJ (OP_REGOFFSET)) {
212         /* FIXME: Move this to inssel.brg */
213         MonoCallInst *call = (MonoCallInst*)tree->inst_right;
214
215         tree->opcode = OP_ADD_IMM;
216         tree->sreg1 = state->left->left->tree->inst_basereg;
217         tree->inst_imm = state->left->left->tree->inst_offset;
218         tree->dreg = mono_regstate_next_int (s->rs);
219         mono_bblock_add_inst (s->cbb, tree);
220
221         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, FALSE);
222 }
223
224 stmt: OP_SETRET (reg) {
225         tree->opcode = OP_MOVE;
226         tree->sreg1 = state->left->reg1;
227         tree->dreg = MONO_ARCH_RETREG1;
228         mono_bblock_add_inst (s->cbb, tree);
229 }
230
231 stmt: OP_SETRET (freg) {
232         tree->opcode = OP_FMOVE;
233         tree->sreg1 = state->left->reg1;
234         tree->dreg = MONO_ARCH_FRETREG1;
235         mono_bblock_add_inst (s->cbb, tree);
236 }
237
238 # Optimized call instructions
239 reg: OP_LCALL_REG (OP_ICONST),
240 reg: OP_LCALL_REG (OP_I8CONST) {
241         /* FIXME: Move this to inssel-long.brg */
242         tree->opcode = OP_LCALL;
243         ((MonoCallInst*)tree)->fptr = state->left->tree->inst_p0;
244         tree->dreg = state->reg1;
245         mono_bblock_add_inst (s->cbb, tree);
246 }
247
248 stmt: OP_OUTARG_VT (CEE_LDOBJ (base), base) {
249         MonoInst *vt = state->left->left->tree;
250         MonoInst *stack_addr = state->right->tree;
251         int sz = stack_addr->inst_imm;
252
253         if (!sz)
254                 return;
255
256         mini_emit_memcpy (s, stack_addr->inst_basereg, stack_addr->inst_offset, vt->inst_basereg, vt->inst_offset, sz, 0);
257 }
258
259 # This handles trees like outarg_vt (refanytype)
260 stmt: OP_OUTARG_VT (reg, base) {
261         MonoInst *stack_addr = state->right->tree;
262
263         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI8_MEMBASE_REG, stack_addr->inst_basereg, stack_addr->inst_offset, state->left->reg1);
264 }
265
266 stmt: OP_START_HANDLER {
267      mono_bblock_add_inst (s->cbb, tree);
268 }
269
270 stmt: CEE_ENDFINALLY {
271      mono_bblock_add_inst (s->cbb, tree);
272 }
273
274 stmt: OP_ENDFILTER (reg) {
275         tree->sreg1 = state->left->reg1;
276         mono_bblock_add_inst (s->cbb, tree);
277 }
278
279 reg: OP_LOCALLOC (reg) {
280         tree->sreg1 = state->left->reg1;
281         tree->dreg = state->reg1;
282         mono_bblock_add_inst (s->cbb, tree);
283 }
284
285 reg: CEE_LDIND_REF (OP_REGVAR),
286 reg: CEE_LDIND_I (OP_REGVAR),
287 reg: CEE_LDIND_I8 (OP_REGVAR),
288 reg: CEE_LDIND_I4 (OP_REGVAR),
289 reg: CEE_LDIND_U4 (OP_REGVAR) "0" {
290         state->reg1 = state->left->tree->dreg;
291         tree->dreg = state->reg1;
292 }
293
294 reg: OP_ATOMIC_ADD_NEW_I4 (base, OP_ICONST),
295 reg: OP_ATOMIC_ADD_NEW_I8 (base, OP_ICONST) {
296         tree->opcode = tree->opcode == OP_ATOMIC_ADD_NEW_I4 ? OP_ATOMIC_ADD_IMM_NEW_I4 : OP_ATOMIC_ADD_IMM_NEW_I8;
297         tree->dreg = state->reg1;
298         tree->inst_imm = state->right->tree->inst_imm;
299         tree->inst_basereg = state->left->tree->inst_basereg; 
300         tree->inst_offset = state->left->tree->inst_offset; 
301     
302         mono_bblock_add_inst (s->cbb, tree);
303 } cost {
304         int imm = state->right->tree->inst_imm;
305
306         MBCOND (imm == 1 || imm == 4 || imm == 8 || imm == 16 || imm == -1 || imm == -4 || imm == -8 || imm == -16);
307         return 1;
308 }
309
310 reg: OP_ATOMIC_EXCHANGE_I4 (base, reg),
311 reg: OP_ATOMIC_EXCHANGE_I8 (base, reg),
312 reg: OP_ATOMIC_ADD_NEW_I4 (base, reg),
313 reg: OP_ATOMIC_ADD_NEW_I8 (base, reg) {
314         tree->opcode = tree->opcode;
315         tree->dreg = state->reg1;
316         tree->sreg2 = state->right->reg1;
317         tree->inst_basereg = state->left->tree->inst_basereg; 
318         tree->inst_offset = state->left->tree->inst_offset; 
319     
320         mono_bblock_add_inst (s->cbb, tree);
321 }
322
323 reg: OP_ATOMIC_ADD_IMM_NEW_I4 (base),
324 reg: OP_ATOMIC_ADD_IMM_NEW_I8 (base) {
325         tree->opcode = tree->opcode;
326         tree->dreg = state->reg1;
327         tree->inst_basereg = state->left->tree->inst_basereg; 
328         tree->inst_offset = state->left->tree->inst_offset; 
329     
330         mono_bblock_add_inst (s->cbb, tree);
331 }
332
333 # Optimized memset implementation
334 stmt: OP_MEMSET (base) "0" {
335         int dest_reg, dest_reg2, val_reg, unit, align;
336         int size = tree->backend.size;
337
338         dest_reg = mono_regstate_next_int (s->rs);
339
340         if (state->left->tree->inst_basereg == s->frame_reg)
341                 /* Aligned by mono_allocate_stack_slots */
342                 align = 8;
343         else
344                 align = 4;
345
346         if (tree->inst_imm == 0)
347                 val_reg = IA64_R0;
348         else {
349                 val_reg = mono_regstate_next_int (s->rs);
350
351                 MONO_EMIT_NEW_ICONST (s, val_reg, tree->inst_imm);
352         }
353
354         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, dest_reg, state->left->tree->inst_basereg, state->left->tree->inst_offset);     
355
356         for (unit = align; unit >= 1; unit = unit >> 1) {
357                 dest_reg2 = mono_regstate_next_int (s->rs);
358
359                 /* Use two destination regs to increase paralellism */
360                 if (size >= 2 * unit) {
361                         int diff = (size / (2 * unit)) * unit;
362                         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, dest_reg2, state->left->tree->inst_basereg, state->left->tree->inst_offset + diff);
363
364                         while (size >= (2 * unit)) {
365                                 MONO_EMIT_NEW_STORE_MEMBASE (s, size_to_ia64_store_membase_inc_reg (unit), dest_reg, 0, val_reg);
366                                 MONO_EMIT_NEW_STORE_MEMBASE (s, size_to_ia64_store_membase_inc_reg (unit), dest_reg2, 0, val_reg);
367                                 size -= 2 * unit;
368                         }
369
370                         if (size > 0)
371                                 MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, dest_reg, dest_reg, diff);
372                 }
373
374                 while (size >= unit) {
375                         if (size == unit)
376                                 MONO_EMIT_NEW_STORE_MEMBASE (s, size_to_store_membase_reg (unit), dest_reg, 0, val_reg);
377                         else
378                                 MONO_EMIT_NEW_STORE_MEMBASE (s, size_to_ia64_store_membase_inc_reg (unit), dest_reg, 0, val_reg);
379                         size -= unit;
380                 }
381         }       
382
383 }
384
385 # Optimized memcpy implementation
386 stmt: OP_MEMCPY (base, base) "0" {
387         int cur_reg, src_reg, dest_reg, unit;
388         int size = tree->backend.size;
389         int align;
390
391         src_reg = mono_regstate_next_int (s->rs);
392         dest_reg = mono_regstate_next_int (s->rs);
393
394         if ((state->left->tree->inst_basereg == s->frame_reg) &&
395                 (state->right->tree->inst_basereg == s->frame_reg))
396                 /* Aligned by mono_allocate_stack_slots */
397                 align = 8;
398         else
399                 align = 4;
400
401         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, dest_reg, state->left->tree->inst_basereg, state->left->tree->inst_offset);     
402         MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, src_reg, state->right->tree->inst_basereg, state->right->tree->inst_offset);
403
404         for (unit = align; unit >= 1; unit = unit >> 1) {
405                 while (size >= unit) {
406                         cur_reg = mono_regstate_next_int (s->rs);
407                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, size_to_ia64_load_u_membase_inc (unit), cur_reg, src_reg, 0);
408                         MONO_EMIT_NEW_STORE_MEMBASE (s, size_to_ia64_store_membase_inc_reg (unit), dest_reg, 0, cur_reg);
409                         size -= unit;
410                 }
411         }       
412 }
413
414 %%
415
416 static int
417 size_to_ia64_load_u_membase_inc (int size)
418 {
419         switch (size) {
420         case 1:
421                 return OP_IA64_LOADU1_MEMBASE_INC;
422         case 2:
423                 return OP_IA64_LOADU2_MEMBASE_INC;
424         case 4:
425                 return OP_IA64_LOADU4_MEMBASE_INC;
426         case 8:
427                 return OP_IA64_LOADI8_MEMBASE_INC;
428         default:
429                 g_assert_not_reached ();
430                 return -1;
431         }
432 }
433
434 static int
435 size_to_store_membase_reg (int size)
436 {
437         switch (size) {
438         case 1:
439                 return OP_STOREI1_MEMBASE_REG;
440         case 2:
441                 return OP_STOREI2_MEMBASE_REG;
442         case 4:
443                 return OP_STOREI4_MEMBASE_REG;
444         case 8:
445                 return OP_STOREI8_MEMBASE_REG;
446         default:
447                 g_assert_not_reached ();
448                 return -1;
449         }
450 }
451
452 static int
453 size_to_ia64_store_membase_inc_reg (int size)
454 {
455         switch (size) {
456         case 1:
457                 return OP_IA64_STOREI1_MEMBASE_INC_REG;
458         case 2:
459                 return OP_IA64_STOREI2_MEMBASE_INC_REG;
460         case 4:
461                 return OP_IA64_STOREI4_MEMBASE_INC_REG;
462         case 8:
463                 return OP_IA64_STOREI8_MEMBASE_INC_REG;
464         default:
465                 g_assert_not_reached ();
466                 return -1;
467         }
468 }