2008-08-22 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / inssel-hppa.brg
1 %%
2
3 #
4 # inssel-hppa.brg: burg file for special hppa instructions
5 #
6 # Copyright (c) 2007 Randolph Chung
7 #
8 # Permission is hereby granted, free of charge, to any person obtaining a copy
9 # of this software and associated documentation files (the "Software"), to deal
10 # in the Software without restriction, including without limitation the rights
11 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 # copies of the Software, and to permit persons to whom the Software is
13 # furnished to do so, subject to the following conditions:
14 #
15 # The above copyright notice and this permission notice shall be included in
16 # all copies or substantial portions of the Software.
17 #
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 # THE SOFTWARE.
25 #
26
27 # Load/store operations
28 reg: CEE_LDIND_I1 (OP_REGVAR) {
29         MONO_EMIT_UNALU (s, tree, CEE_CONV_I1, state->reg1, state->left->tree->dreg);
30 }
31
32 reg: CEE_LDIND_I2 (OP_REGVAR) {
33         MONO_EMIT_UNALU (s, tree, CEE_CONV_I2, state->reg1, state->left->tree->dreg);
34 }
35
36 reg: CEE_LDIND_REF (OP_REGVAR),
37 reg: CEE_LDIND_I (OP_REGVAR),
38 reg: CEE_LDIND_I4 (OP_REGVAR),
39 reg: CEE_LDIND_U4 (OP_REGVAR) "0" {
40         state->reg1 = state->left->tree->dreg;
41         tree->dreg = state->reg1;
42 }
43
44 lreg: CEE_LDIND_I8 (OP_REGVAR) {
45         /* reg2 contains the most significant word */
46         MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->reg2, state->left->tree->dreg);
47         tree->opcode = OP_MOVE;
48         tree->dreg = state->reg1;
49         tree->sreg1 = state->left->tree->dreg + 1;
50         mono_bblock_add_inst (s->cbb, tree);
51 }
52
53 freg: CEE_LDIND_R4 (OP_REGVAR) {
54         MONO_EMIT_UNALU (s, tree, OP_FMOVE, state->reg1, state->left->tree->dreg);
55 }
56
57 freg: CEE_LDIND_R8 (OP_REGVAR) {
58         MONO_EMIT_UNALU (s, tree, OP_FMOVE, state->reg1, state->left->tree->dreg);
59 }
60
61 stmt: CEE_STIND_I8 (OP_REGVAR, reg) {
62         MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->left->tree->dreg, state->right->reg1);
63 }
64
65 stmt: CEE_STIND_I8 (OP_REGVAR, lreg) {
66         /* this should only happen for methods returning a long */
67         MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->left->tree->dreg, state->right->reg1);
68         MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->left->tree->dreg + 1, state->right->reg2);
69 }
70
71 # Outputing arguments
72 stmt: OP_OUTARG (reg) {
73         MonoCallInst *call = tree->inst_call;
74         MonoHPPAArgInfo *ai = tree->backend.data;
75
76         tree->opcode = OP_MOVE;
77         tree->dreg = mono_regstate_next_int (s->rs);
78         tree->sreg1 = state->left->reg1;
79         mono_bblock_add_inst (s->cbb, tree);
80         mono_call_inst_add_outarg_reg (s, call, tree->dreg, ai->reg, FALSE);
81 }
82
83 stmt: OP_HPPA_OUTARG_REGOFFSET (base) {
84         MonoCallInst *call = tree->inst_call;
85
86         tree->inst_basereg = state->left->tree->inst_basereg;
87         tree->inst_offset = state->left->tree->inst_offset;
88         tree->dreg = mono_regstate_next_int (s->rs);
89         mono_bblock_add_inst (s->cbb, tree);
90         
91         mono_call_inst_add_outarg_reg (s, call, tree->dreg, hppa_r28, FALSE);
92 }
93
94 stmt: OP_OUTARG (OP_REGVAR) {
95         MonoCallInst *call = tree->inst_call;
96         MonoHPPAArgInfo *ai = tree->backend.data;
97
98         tree->opcode = OP_MOVE;
99         tree->dreg = mono_regstate_next_int (s->rs);
100         tree->sreg1 = state->left->tree->dreg;
101         mono_bblock_add_inst (s->cbb, tree);
102         mono_call_inst_add_outarg_reg (s, call, tree->dreg, ai->reg, FALSE);
103 }
104
105 stmt: OP_OUTARG (lreg) {
106         MonoCallInst *call = tree->inst_call;
107         MonoHPPAArgInfo *ai = tree->backend.data;
108         int tdreg = mono_regstate_next_int (s->rs);
109
110         MONO_EMIT_NEW_UNALU (s, OP_MOVE, tdreg, state->left->reg2);
111         mono_call_inst_add_outarg_reg (s, call, tdreg, ai->reg, FALSE);
112         tree->opcode = OP_MOVE;
113         tree->dreg = mono_regstate_next_int (s->rs);
114         tree->sreg1 = state->left->reg1;
115         mono_bblock_add_inst (s->cbb, tree);
116         mono_call_inst_add_outarg_reg (s, call, tree->dreg, ai->reg + 1, FALSE);
117 }
118
119 stmt: OP_OUTARG (OP_ICONST) {
120         MonoCallInst *call = tree->inst_call;
121         MonoHPPAArgInfo *ai = tree->backend.data;
122
123         tree->opcode = OP_ICONST;
124         tree->dreg = mono_regstate_next_int (s->rs);
125         tree->inst_c0 = state->left->tree->inst_c0;
126         mono_bblock_add_inst (s->cbb, tree);
127         mono_call_inst_add_outarg_reg (s, call, tree->dreg, ai->reg, FALSE);
128 }
129
130 stmt: OP_OUTARG (CEE_LDIND_REF (OP_REGVAR)) {
131         MonoCallInst *call = tree->inst_call;
132         MonoHPPAArgInfo *ai = tree->backend.data;
133
134         tree->opcode = OP_MOVE;
135         tree->dreg = mono_regstate_next_int (s->rs);
136         tree->sreg1 = state->left->left->tree->dreg;
137         mono_bblock_add_inst (s->cbb, tree);
138         mono_call_inst_add_outarg_reg (s, call, tree->dreg, ai->reg, FALSE);
139 }
140
141 stmt: OP_OUTARG_VT (CEE_LDOBJ (base)) "0" {
142         MonoCallInst *call = tree->inst_call;
143         MonoHPPAArgInfo *ai = tree->backend.data;
144         int start_reg = ai->reg;
145         int size = ai->size;
146         int nregs = (size + (sizeof (gpointer) - 1)) / sizeof (gpointer);
147         int i, tmpr, soffset, dreg;
148         MonoInst *vt = state->left->left->tree;
149         soffset = vt->inst_offset;
150
151         if (ai->pass_in_reg) {
152                 for (i = 0; i < nregs; ++i) {
153                         tmpr = mono_regstate_next_int (s->rs);
154                         MONO_EMIT_NEW_LOAD_MEMBASE (s, tmpr, vt->inst_basereg, soffset);
155                         dreg = mono_regstate_next_int (s->rs);
156                         if (size < sizeof (gpointer))
157                                 MONO_EMIT_NEW_BIALU_IMM (s, OP_SHR_IMM, dreg, tmpr, (sizeof (gpointer) - size) * 8);
158                         else
159                                 MONO_EMIT_NEW_UNALU (s, OP_MOVE, dreg, tmpr);
160                         mono_call_inst_add_outarg_reg (s, call, dreg, start_reg + i, FALSE);
161                         soffset += sizeof (gpointer);
162                         size -= sizeof (gpointer);
163                 }
164         }
165         else {
166                 mini_emit_memcpy (s, hppa_sp, ai->offset, vt->inst_basereg, soffset, size, 0);
167         }
168 }
169
170 stmt: OP_OUTARG_R4 (freg) {
171         MonoCallInst *call = tree->inst_call;
172
173         tree->opcode = OP_HPPA_SETF4REG;
174         tree->dreg = mono_regstate_next_float (s->rs);
175         tree->sreg1 = state->left->reg1;
176         mono_bblock_add_inst (s->cbb, tree);
177         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE);
178 }
179
180 stmt: OP_OUTARG_R4 (OP_R4CONST) {
181         MonoCallInst *call = tree->inst_call;
182
183         tree->opcode = OP_HPPA_OUTARG_R4CONST;
184         tree->dreg = mono_regstate_next_float (s->rs);
185         tree->inst_p0 = state->left->tree->inst_p0;
186         mono_bblock_add_inst (s->cbb, tree);
187         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE);
188 }
189
190 stmt: OP_OUTARG_R8 (freg),
191 stmt: OP_OUTARG (freg) {
192         MonoCallInst *call = tree->inst_call;
193
194         tree->opcode = OP_FMOVE;
195         tree->dreg = mono_regstate_next_float (s->rs);
196         tree->sreg1 = state->left->reg1;
197         mono_bblock_add_inst (s->cbb, tree);
198         mono_call_inst_add_outarg_reg (s, call, tree->dreg, tree->backend.reg3, TRUE);
199 }
200
201 stmt: OP_OUTARG_MEMBASE (reg) {
202         MonoHPPAArgInfo *ai = tree->backend.data;
203         switch (ai->size)
204         {
205         case 1:
206                 MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI1_MEMBASE_REG, hppa_sp, ai->offset, state->left->reg1);
207                 break;
208         case 2:
209                 MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI2_MEMBASE_REG, hppa_sp, ai->offset, state->left->reg1);
210                 break;
211         case 4:
212                 MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, hppa_sp, ai->offset, state->left->reg1);
213                 break;
214         default:
215                 g_assert_not_reached ();
216         }
217 }
218
219 stmt: OP_OUTARG_MEMBASE (OP_ICONST) {
220         MonoHPPAArgInfo *ai = tree->backend.data;
221         switch (ai->size)
222         {
223         case 1:
224                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (s, OP_STOREI1_MEMBASE_IMM, hppa_sp, ai->offset, state->left->tree->inst_c0);
225                 break;
226         case 2:
227                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (s, OP_STOREI2_MEMBASE_IMM, hppa_sp, ai->offset, state->left->tree->inst_c0);
228                 break;
229         case 4:
230                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (s, OP_STORE_MEMBASE_IMM, hppa_sp, ai->offset, state->left->tree->inst_c0);
231                 break;
232         default:
233                 g_assert_not_reached ();
234         }
235 }
236
237 stmt: OP_OUTARG_MEMBASE (lreg) {
238         MonoHPPAArgInfo *ai = tree->backend.data;
239         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, hppa_sp, ai->offset, state->left->reg2);
240         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, hppa_sp, ai->offset + 4, state->left->reg1);
241 }
242
243 stmt: OP_OUTARG_MEMBASE (freg) {
244         MonoHPPAArgInfo *ai = tree->backend.data;
245         if (ai->size == 4)
246                 MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER4_MEMBASE_REG, hppa_sp, ai->offset, state->left->reg1);
247         else
248                 MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORER8_MEMBASE_REG, hppa_sp, ai->offset, state->left->reg1);
249 }
250
251 stmt: OP_OUTARG_MEMBASE (OP_R4CONST) {
252         MonoHPPAArgInfo *ai = tree->backend.data;
253         unsigned int constaddr = mono_regstate_next_int (s->rs);
254         unsigned int tmp = mono_regstate_next_float (s->rs);
255         MONO_EMIT_NEW_ICONST (s, constaddr, (unsigned int)state->left->tree->inst_p0);
256         MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_HPPA_LOADR4_LEFT, tmp, constaddr, 0);
257         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_HPPA_STORER4_LEFT, hppa_sp, ai->offset, tmp);
258 }
259
260 reg: OP_LOCALLOC (OP_ICONST) {
261         tree->sreg1 = mono_regstate_next_int (s->rs);
262         tree->dreg = state->reg1;
263         MONO_EMIT_NEW_ICONST (s, tree->sreg1, state->left->tree->inst_c0);
264         mono_bblock_add_inst (s->cbb, tree);
265 }
266
267 reg: OP_LOCALLOC (reg) {
268         tree->dreg = state->reg1;
269         tree->sreg1 = state->left->reg1;
270         mono_bblock_add_inst (s->cbb, tree);
271 }
272
273 stmt: OP_SETRET (reg) {
274         tree->opcode = OP_MOVE;
275         tree->sreg1 = state->left->reg1;
276         tree->dreg = hppa_r28;
277         mono_bblock_add_inst (s->cbb, tree);
278 }
279
280 stmt: OP_SETRET (lreg) {
281         tree->opcode = OP_SETLRET;
282         tree->sreg1 = state->left->reg1;
283         tree->sreg2 = state->left->reg2;
284         tree->dreg = hppa_r28;
285         mono_bblock_add_inst (s->cbb, tree);
286 }
287
288 stmt: OP_SETRET (freg) {
289         if (mono_method_signature (s->method)->ret->type == MONO_TYPE_R4) {
290                 tree->opcode = OP_HPPA_SETF4REG;
291         } else {
292                 tree->opcode = OP_FMOVE;
293         }
294
295         tree->sreg1 = state->left->reg1;
296         tree->dreg = hppa_fr4;
297         mono_bblock_add_inst (s->cbb, tree);
298 }
299
300 # Comparision rules: hppa does not have an addressable status register, so
301 # we have to do compare-and-branch in a single step
302
303 # Override the cost of the rule in the base inssel.brg so that this is preferred
304 # We are using this so that all the combinations of OP_COMPARE(reg, OP_ICONST)
305 # will get folded into OP_COMPARE(reg, reg) to simplify our compare-and-branch
306 # rules.
307 # FIXME: this is ugly, we should expand the rules here, or try to refactor
308 # the rules in the base set
309 reg: OP_ICONST "0" {
310         tree->dreg = state->reg1;
311         MONO_EMIT_NEW_ICONST (s, state->reg1, tree->inst_c0);
312 }
313
314 stmt: OP_SWITCH (reg) {
315         MonoInst *label, *inst;
316         int n = GPOINTER_TO_INT (tree->klass);
317         int sreg = mono_regstate_next_int (s->rs);
318         
319         MONO_NEW_LABEL (s, label);
320
321         MONO_EMIT_NEW_ICONST (s, sreg, n);
322
323         MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK(s, CEE_BGE_UN, state->left->reg1, sreg, tree->inst_many_bb [n]);
324         mono_bblock_add_inst (s->cbb, label);
325         mono_create_jump_table (s, label, tree->inst_many_bb, n);
326         /* the backend code will deal with aot vs normal case */
327         tree->sreg1 = state->left->reg1;
328         mono_bblock_add_inst (s->cbb, tree);
329 }
330
331 stmt: CEE_BEQ (OP_COMPARE(reg, reg)),
332 stmt: CEE_BNE_UN (OP_COMPARE(reg, reg)),
333 stmt: CEE_BGE (OP_COMPARE(reg, reg)),
334 stmt: CEE_BGE_UN (OP_COMPARE(reg, reg)),
335 stmt: CEE_BGT (OP_COMPARE(reg, reg)),
336 stmt: CEE_BGT_UN (OP_COMPARE(reg, reg)),
337 stmt: CEE_BLE (OP_COMPARE(reg, reg)),
338 stmt: CEE_BLE_UN (OP_COMPARE(reg, reg)),
339 stmt: CEE_BLT (OP_COMPARE(reg, reg)),
340 stmt: CEE_BLT_UN (OP_COMPARE(reg, reg)) "0" {
341         tree->opcode = OP_HPPA_BEQ + (tree->opcode - CEE_BEQ);
342         tree->sreg1 = state->left->left->reg1;
343         tree->sreg2 = state->left->right->reg1;
344         tree->inst_offset = state->left->left->tree->inst_offset;
345         mono_bblock_add_inst (s->cbb, tree);
346 }
347
348 reg: OP_CEQ (OP_COMPARE (reg, reg)),
349 reg: OP_CGT (OP_COMPARE (reg, reg)),
350 reg: OP_CGT_UN (OP_COMPARE (reg, reg)),
351 reg: OP_CLT (OP_COMPARE (reg, reg)),
352 reg: OP_CLT_UN (OP_COMPARE (reg, reg)) "0" {
353         MONO_EMIT_BIALU (s, tree, OP_HPPA_CEQ + (tree->opcode - OP_CEQ), state->reg1, state->left->left->reg1, state->left->right->reg1);
354 }
355
356 reg: OP_CEQ (OP_COMPARE_IMM (reg, OP_ICONST)),
357 reg: OP_CLT (OP_COMPARE_IMM (reg, OP_ICONST)),
358 reg: OP_CLT_UN (OP_COMPARE_IMM (reg, OP_ICONST)),
359 reg: OP_CGT (OP_COMPARE_IMM (reg, OP_ICONST)),
360 reg: OP_CGT_UN (OP_COMPARE_IMM (reg, OP_ICONST)) "0" {
361         MONO_EMIT_BIALU_IMM (s, tree, OP_HPPA_CEQ_IMM + (tree->opcode - OP_CEQ), state->reg1, state->left->left->reg1, state->left->right->reg1);
362 }
363
364 # Floating point versions of the compare functions
365 stmt: CEE_BEQ (OP_COMPARE (freg, freg)),
366 stmt: CEE_BNE_UN (OP_COMPARE (freg, freg)),
367 stmt: CEE_BLT (OP_COMPARE (freg, freg)),
368 stmt: CEE_BLT_UN (OP_COMPARE (freg, freg)),
369 stmt: CEE_BGT (OP_COMPARE (freg, freg)),
370 stmt: CEE_BGT_UN (OP_COMPARE (freg, freg)),
371 stmt: CEE_BGE  (OP_COMPARE (freg, freg)),
372 stmt: CEE_BGE_UN (OP_COMPARE (freg, freg)),
373 stmt: CEE_BLE  (OP_COMPARE (freg, freg)),
374 stmt: CEE_BLE_UN (OP_COMPARE (freg, freg)) "0" {
375         tree->opcode = OP_FBEQ + (tree->opcode - CEE_BEQ);
376         tree->sreg1 = state->left->left->reg1;
377         tree->sreg2 = state->left->right->reg1;
378         mono_bblock_add_inst (s->cbb, tree);
379 }
380
381 reg: OP_CEQ (OP_COMPARE (freg, freg)),
382 reg: OP_CGT (OP_COMPARE (freg, freg)),
383 reg: OP_CGT_UN (OP_COMPARE (freg, freg)),
384 reg: OP_CLT (OP_COMPARE (freg, freg)),
385 reg: OP_CLT_UN (OP_COMPARE (freg, freg)) "0" {
386         tree->opcode = OP_FCEQ + (tree->opcode - OP_CEQ);
387         tree->sreg1 = state->left->left->reg1;
388         tree->sreg2 = state->left->right->reg1;
389         tree->dreg = state->reg1;
390         mono_bblock_add_inst (s->cbb, tree);
391 }
392
393 # ALU operations
394 reg: CEE_ADD_OVF (reg, reg),
395 reg: CEE_ADD_OVF_UN (reg, reg) "0" {
396         tree->backend.reg3 = tree->opcode;
397         tree->opcode = OP_HPPA_ADD_OVF;
398         tree->sreg1 = state->left->reg1;
399         tree->sreg2 = state->right->reg1;
400         tree->dreg = state->reg1;
401         mono_bblock_add_inst (s->cbb, tree);
402 }
403
404 lreg: OP_LADD_OVF (lreg, lreg),
405 lreg: OP_LADD_OVF_UN (lreg, lreg) "0" {
406         MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg1, state->left->reg1, state->right->reg1);
407         tree->backend.reg3 = tree->opcode;
408         tree->opcode = OP_HPPA_ADDC_OVF;
409         tree->sreg1 = state->left->reg2;
410         tree->sreg2 = state->right->reg2;
411         tree->dreg = state->reg2;
412         mono_bblock_add_inst (s->cbb, tree);
413 }
414
415 reg: CEE_SUB_OVF (reg, reg),
416 reg: CEE_SUB_OVF_UN (reg, reg) "0" {
417         MONO_EMIT_NEW_BIALU (s, OP_SUBCC, state->reg1, state->left->reg1, state->right->reg1);
418         tree->backend.reg3 = tree->opcode;
419         tree->opcode = OP_HPPA_SUB_OVF;
420         tree->sreg1 = state->left->reg1;
421         tree->sreg2 = state->right->reg1;
422         tree->dreg = state->reg1;
423         mono_bblock_add_inst (s->cbb, tree);
424 }
425
426 lreg: OP_LSUB_OVF (lreg, lreg),
427 lreg: OP_LSUB_OVF_UN (lreg, lreg) "0" {
428         MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg1, state->left->reg1, state->right->reg1);
429         tree->backend.reg3 = tree->opcode;
430         tree->opcode = OP_HPPA_SUBB_OVF;
431         tree->sreg1 = state->left->reg2;
432         tree->sreg2 = state->right->reg2;
433         tree->dreg = state->reg2;
434         mono_bblock_add_inst (s->cbb, tree);
435 }
436
437 lreg: OP_LNEG (lreg) "2" {
438         MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg1, hppa_r0, state->left->reg1);
439         MONO_EMIT_BIALU (s, tree, OP_SBB, state->reg2, hppa_r0, state->left->reg2);
440 }
441
442 reg: CEE_MUL (reg, reg),
443 reg: CEE_MUL_OVF (reg, reg),
444 reg: CEE_MUL_OVF_UN (reg, reg) "0" {
445         guint32 sreg1 = state->left->reg1;
446         guint32 sreg2 = state->right->reg1;
447         guint32 dreg = state->reg1;
448         guint32 freg1, freg2, freg3;
449
450         freg1 = mono_regstate_next_float (s->rs);
451         freg2 = mono_regstate_next_float (s->rs);
452         freg3 = mono_regstate_next_float (s->rs);
453
454         /* TODO: this scribbles on 4-bytes past the end of the stack; need
455          * to figure out how to properly "reserve" a temp stack slot for
456          * this
457          */
458         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, hppa_sp, 0, sreg1);
459         MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_HPPA_LOADR4_LEFT, freg1, hppa_sp, 0);
460         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, hppa_sp, 0, sreg2);
461         MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_HPPA_LOADR4_LEFT, freg2, hppa_sp, 0);
462         MONO_EMIT_NEW_BIALU (s, OP_HPPA_XMPYU, freg3, freg1, freg2);
463         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_HPPA_STORER4_RIGHT, hppa_sp, 0, freg3);
464         MONO_EMIT_LOAD_MEMBASE (s, tree, dreg, hppa_sp, 0);
465 }
466
467 reg: CEE_MUL(reg, OP_ICONST),
468 reg: OP_MUL_IMM(reg, OP_ICONST),
469 reg: CEE_MUL_OVF (reg, OP_ICONST),
470 reg: CEE_MUL_OVF_UN (reg, OP_ICONST) "0" {
471         guint32 sreg1 = state->left->reg1;
472         gssize imm = state->right->tree->inst_c0;
473         guint32 dreg = state->reg1;
474         guint32 freg1, freg2, freg3;
475
476         freg1 = mono_regstate_next_float (s->rs);
477         freg2 = mono_regstate_next_float (s->rs);
478         freg3 = mono_regstate_next_float (s->rs);
479
480         /* TODO: this scribbles on 4-bytes past the end of the stack; need
481          * to figure out how to properly "reserve" a temp stack slot for
482          * this
483          */
484         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STORE_MEMBASE_REG, hppa_sp, 0, sreg1);
485         MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADR4_MEMBASE, freg1, hppa_sp, 0);
486         MONO_EMIT_NEW_STORE_MEMBASE_IMM (s, OP_STORE_MEMBASE_IMM, hppa_sp, 0, imm);
487         MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADR4_MEMBASE, freg2, hppa_sp, 0);
488         MONO_EMIT_NEW_BIALU (s, OP_HPPA_XMPYU, freg3, freg1, freg2);
489         MONO_EMIT_NEW_STORE_MEMBASE (s, OP_HPPA_STORER4_RIGHT, hppa_sp, 0, freg3);
490         MONO_EMIT_LOAD_MEMBASE (s, tree, dreg, hppa_sp, 0);
491 }
492
493 # Floating point ALU ops
494 freg: OP_FNEG (freg) "0" {
495         extern double hppa_zero;
496         MonoInst *inst = mono_mempool_alloc0 (s->mempool, sizeof (MonoInst));
497         inst->opcode = OP_R8CONST;
498         inst->dreg = mono_regstate_next_float (s->rs);
499         inst->inst_p0 = (gpointer)&hppa_zero;
500         mono_bblock_add_inst (s->cbb, inst);
501         MONO_EMIT_BIALU (s, tree, OP_FSUB, state->reg1, inst->dreg, state->left->reg1);
502 }
503
504 # Conversion operations
505 lreg: CEE_CONV_I8 (reg) "0" {
506         int tmpreg = mono_regstate_next_int (s->rs);
507         int negone = mono_regstate_next_int (s->rs);
508         
509         /* branchless code:
510          * low = reg;
511          * tmp = low > -1 ? 1: 0;
512          * high = tmp - 1; if low is zero or pos high becomes 0, else -1
513          */
514         MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->reg1, state->left->reg1);
515         MONO_EMIT_NEW_ICONST (s, negone, -1);
516         MONO_EMIT_NEW_BIALU (s, OP_HPPA_CGT, tmpreg, state->reg1, negone);
517         MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, state->reg2, tmpreg, 1);
518 }
519
520 freg: OP_LCONV_TO_R8 (lreg) {
521         tree->sreg1 = state->left->reg1;
522         tree->dreg = state->reg1;
523         mono_bblock_add_inst (s->cbb, tree);
524 }
525
526 freg: OP_LCONV_TO_R8 (lreg) {
527         /* Dummy rule */
528 }
529
530 freg: OP_LCONV_TO_R4 (lreg) {
531         tree->sreg1 = state->left->reg1;
532         tree->dreg = state->reg1;
533         mono_bblock_add_inst (s->cbb, tree);
534 }
535
536 reg: OP_LCONV_TO_OVF_I (lreg),
537 reg: OP_LCONV_TO_OVF_I4 (lreg) "0" {
538         int tmp_reg = mono_regstate_next_int (s->rs);
539
540         /* Overflows if reg2 != sign extension of reg1 */
541         MONO_EMIT_BIALU_IMM (s, tree, OP_SHR_IMM, tmp_reg, state->left->reg1, 31);
542
543         MONO_EMIT_NEW_COMPARE_EXC (s, NE_UN, state->left->reg2, tmp_reg, "OverflowException");
544         MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->reg1, state->left->reg1);
545 }
546
547
548 # Exception handling
549 stmt: OP_START_HANDLER {
550         MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
551         tree->inst_left = spvar;
552         mono_bblock_add_inst (s->cbb, tree);
553 }
554
555 stmt: OP_ENDFINALLY {
556         MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
557         tree->inst_left = spvar;
558         mono_bblock_add_inst (s->cbb, tree);
559 }
560
561 stmt: OP_ENDFILTER (reg) {
562         MonoInst *spvar = mono_find_spvar_for_region (s, s->cbb->region);
563         tree->inst_left = spvar;
564         tree->sreg1 = state->left->reg1;
565         mono_bblock_add_inst (s->cbb, tree);
566 }
567
568 %%