2008-07-22 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-hppa.h
1 /*
2  * mini-hppa.h: HPPA backend for the Mono code generator
3  *
4  * Copyright (c) 2007 Randolph Chung
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  */
25
26 #ifndef __MONO_MINI_HPPA_H__
27 #define __MONO_MINI_HPPA_H__
28
29 #include <mono/arch/hppa/hppa-codegen.h>
30
31 #include <glib.h>
32
33 #define MONO_ARCH_CPU_SPEC hppa_desc
34
35 /* HPPA's stack grows towards higher addresses */
36 #define MONO_ARCH_STACK_GROWS_UP
37
38 #define MONO_MAX_IREGS 32
39 #define MONO_MAX_FREGS 32
40
41 /* hppa_r20 - hppa_r22 are scratch registers
42  * hppa_r23 - hppa_r26 are the incoming argument registers
43  * hppa_r28, hppa_29 are the return value registers */
44 #define MONO_ARCH_CALLEE_REGS ((0x3f << hppa_r20) | (1 << hppa_r28) | (1 << hppa_r29))
45
46 /* hppa_r3 - hppa_r19, hppa_27, hppa_30 */
47 #define MONO_ARCH_CALLEE_SAVED_REGS ((0x1ffff << hppa_r3) | (1 << hppa_r27) | (1 << hppa_r30))
48
49 /* hppa_fr4 - hppa_fr7 are incoming argument registers
50  * hppa_fr8 - hppa_fr11 are scratch registers 
51  * hppa_fr22 - hppa_fr31 are scratch registers
52  * we reserve hppa_fr31 for code generation */
53 #define MONO_ARCH_CALLEE_FREGS ((0xff << hppa_fr4) | (0x1ff << hppa_fr22))
54
55 /* hppa_fr12 - hppa_fr21 */
56 #define MONO_ARCH_CALLEE_SAVED_FREGS (0x3ff << hppa_fr12)
57
58 #define MONO_ARCH_USE_FPSTACK FALSE
59 #define MONO_ARCH_FPSTACK_SIZE 0
60 #define MONO_ARCH_INST_FIXED_REG(desc) ((desc == 'o') ? hppa_r0 : (desc == 'a') ? hppa_r28 : (desc == 'L') ? hppa_r29 : -1)
61 #define MONO_ARCH_INST_SREG2_MASK(ins) (0)
62
63 #define MONO_ARCH_INST_IS_REGPAIR(desc) ((desc == 'l') || (desc == 'L'))
64 #define MONO_ARCH_INST_REGPAIR_REG2(desc,hreg1) ((desc == 'L') ? hppa_r28 : (desc == 'l') ? ((hreg1)+1) : -1)
65
66 #define MONO_ARCH_FRAME_ALIGNMENT 64
67 #define MONO_ARCH_CODE_ALIGNMENT 32
68 #define HPPA_STACK_LMF_OFFSET   8
69
70 /* r3-r19, r27 */
71 #define MONO_SAVED_GREGS 18
72 #define MONO_SAVED_GREGS_MASK   ((0x1ffff << hppa_r3) | (1 << hppa_r27))
73 /* fr12-fr21 */
74 #define MONO_SAVED_FREGS 10
75 #define MONO_SAVED_FREGS_MASK   (0x003ff000)
76 #define HPPA_IS_SAVED_GREG(i)   ((1 << (i)) & MONO_SAVED_GREGS_MASK)
77 #define HPPA_IS_SAVED_FREG(i)   ((1 << (i)) & MONO_SAVED_FREGS_MASK)
78
79 struct MonoLMF {
80         gpointer    previous_lmf;
81         gpointer    lmf_addr;
82         MonoMethod *method;
83         gpointer    eip; /* pc */
84         gpointer    ebp; /* sp */
85         gulong regs [MONO_SAVED_GREGS];
86         double fregs [MONO_SAVED_FREGS];
87 };
88
89 typedef struct MonoContext {
90         gulong pc;
91         gulong sp;
92         gulong regs [MONO_SAVED_GREGS];
93         double fregs [MONO_SAVED_FREGS];
94 } MonoContext;
95
96 typedef struct MonoCompileArch {
97         gint32 lmf_offset;
98         gint32 localloc_offset;
99 } MonoCompileArch;
100
101 #define MONO_CONTEXT_SET_IP(ctx,_ip) do { (ctx)->pc = (int)(_ip); } while (0) 
102 #define MONO_CONTEXT_SET_BP(ctx,_bp) do { (ctx)->sp = (int)(_bp); } while (0) 
103 #define MONO_CONTEXT_SET_SP(ctx,_sp) do { (ctx)->sp = (int)(_sp); } while (0)
104
105 #define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->pc))
106 #define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->sp))
107 #define MONO_CONTEXT_GET_SP(ctx) ((gpointer)((ctx)->sp))
108
109 #define MONO_INIT_CONTEXT_FROM_FUNC(ctx,start_func) do {        \
110         unsigned long sp;                                       \
111         asm volatile ("copy %%sp, %0\n" : "=r"(sp));            \
112         MONO_CONTEXT_SET_IP ((ctx), (start_func));              \
113         MONO_CONTEXT_SET_BP ((ctx), sp);                        \
114         } while (0)
115
116 #define MONO_ARCH_USE_SIGACTION 1
117
118 #define MONO_ARCH_EMULATE_FCONV_TO_I8   1
119 #define MONO_ARCH_EMULATE_LCONV_TO_R8   1
120 #define MONO_ARCH_EMULATE_LCONV_TO_R4   1
121 #define MONO_ARCH_EMULATE_CONV_R8_UN    1
122 #define MONO_ARCH_EMULATE_LCONV_TO_R8_UN 1
123 #define MONO_ARCH_EMULATE_FREM 1
124 #define MONO_ARCH_EMULATE_DIV 1
125 #define MONO_ARCH_ENABLE_EMIT_STATE_OPT 1
126 #define MONO_ARCH_NEED_DIV_CHECK 1
127
128 /* 
129  * HPPA does not have an addresable "cflags", so all our compare and branch
130  * instructions are combined
131  */
132
133 #define MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK(cfg,op,sr1,sr2,targetbb) \
134         do {    \
135                 MonoInst *inst; \
136                 MonoInst *target_label; \
137                 target_label = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
138                 target_label->opcode = OP_LABEL;        \
139                 target_label->next = (targetbb)->code; \
140                 target_label->inst_c0 = (targetbb)->native_offset; \
141                 (targetbb)->code = target_label; \
142                 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
143                 g_assert (op >= CEE_BEQ && op <= CEE_BLT_UN); \
144                 inst->opcode = OP_HPPA_BEQ + (op - CEE_BEQ); \
145                 (inst)->sreg1 = sr1; \
146                 (inst)->sreg2 = sr2; \
147                 inst->inst_i0 = target_label;   \
148                 inst->flags = MONO_INST_BRLABEL;        \
149                 mono_bblock_add_inst ((cfg)->cbb, inst); \
150         } while (0)
151
152 #define MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK(cfg, cmp_op, sreg1, imm, block) \
153         do { \
154                 guint32 cmp_reg; \
155                 if (!(imm)) { \
156                         cmp_reg = hppa_r0; \
157                 } \
158                 else { \
159                         cmp_reg = hppa_r1; \
160                         MONO_EMIT_NEW_ICONST (cfg, cmp_reg, (imm)); \
161                 } \
162                 MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK(cfg, cmp_op, sreg1, cmp_reg, block); \
163         } while (0)
164
165 #define MONO_EMIT_NEW_COMPARE_BRANCH_LABEL(cfg, cmp_op, sr1, sr2, label) \
166         do { \
167                 MonoInst *inst; \
168                 g_assert (cmp_op >= CEE_BEQ && cmp_op <= CEE_BLT_UN); \
169                 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
170                 inst->opcode = OP_HPPA_BEQ + (cmp_op) - CEE_BEQ; \
171                 inst->sreg1 = sr1;      \
172                 inst->sreg2 = sr2;      \
173                 inst->inst_i0 = label;  \
174                 inst->flags = MONO_INST_BRLABEL;        \
175                 mono_bblock_add_inst ((cfg)->cbb, inst); \
176         } while (0)
177
178 #define MONO_EMIT_NEW_COMPARE_IMM_BRANCH_LABEL(cfg, cmp_op, sreg1, imm, label) \
179         do { \
180                 guint32 cmp_reg; \
181                 if (!(imm)) { \
182                         cmp_reg = hppa_r0; \
183                 } \
184                 else { \
185                         cmp_reg = hppa_r1; \
186                         MONO_EMIT_NEW_ICONST (cfg, cmp_reg, (imm)); \
187                 } \
188                 MONO_EMIT_NEW_COMPARE_BRANCH_LABEL(cfg, cmp_op, sreg1, cmp_reg, label); \
189         } while (0)
190
191 #define MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK_CHAINED(cfg,op,sr1,sr2,targetbb) \
192         MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK(cfg,op,sr1,sr2,targetbb)
193 #define MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK_CHAINED(cfg, cmp_op, sreg1, imm, block) \
194         MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK(cfg, cmp_op, sreg1, imm, block)
195 #define MONO_EMIT_NEW_COMPARE_BRANCH_LABEL_CHAINED(cfg, cmp_op, sr1, sr2, label) \
196         MONO_EMIT_NEW_COMPARE_BRANCH_LABEL(cfg, cmp_op, sr1, sr2, label)
197 #define MONO_EMIT_NEW_COMPARE_IMM_BRANCH_LABEL_CHAINED(cfg, cmp_op, sreg1, imm, label) \
198         MONO_EMIT_NEW_COMPARE_IMM_BRANCH_LABEL(cfg, cmp_op, sreg1, imm, label)
199
200 #define MONO_EMIT_NEW_HPPA_COND_EXC(cfg,cond,sr1,sr2,name) do { \
201                 MonoInst *inst; \
202                 inst = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
203                 inst->opcode = cond;  \
204                 inst->inst_p1 = (char*)name; \
205                 inst->sreg1 = sr1; \
206                 inst->sreg2 = sr2; \
207                 mono_bblock_add_inst ((cfg)->cbb, inst); \
208         } while (0)
209
210 #define MONO_EMIT_NEW_COMPARE_EXC(cfg, cmp_op, sreg1, sreg2, exc) \
211         MONO_EMIT_NEW_HPPA_COND_EXC (cfg, OP_HPPA_COND_EXC_##cmp_op, sreg1, sreg2, exc)
212
213 #define MONO_EMIT_NEW_COMPARE_IMM_EXC(cfg, cmp_op, sreg1, imm, exc) do { \
214                 guint32 cmp_reg; \
215                 if (!(imm)) { \
216                         cmp_reg = hppa_r0; \
217                 } \
218                 else { \
219                         cmp_reg = hppa_r1; \
220                         MONO_EMIT_NEW_ICONST (cfg, cmp_reg, (imm)); \
221                 } \
222                 MONO_EMIT_NEW_COMPARE_EXC (cfg, cmp_op, sreg1, cmp_reg, exc); \
223         } while (0)
224
225 #define MONO_EMIT_NEW_ICOMPARE_IMM_EXC(cfg, cmp_op, sreg1, imm, exc) do { \
226                 MONO_EMIT_NEW_COMPARE_IMM_EXC(cfg, cmp_op, sreg1, imm, exc); \
227         } while (0)
228
229 typedef struct {
230         gint8 reg;
231         gint8 size;
232         gint8 pass_in_reg:1;
233         int vtsize;
234         int offset;
235 } MonoHPPAArgInfo;
236
237
238 void hppa_patch (guint32 *code, const gpointer target);
239
240 #endif /* __MONO_MINI_HPPA_H__ */