root / tcg / tcg-dyngen.c @ c44f945a
History | View | Annotate | Download (15.2 kB)
1 | c896fe29 | bellard | /*
|
---|---|---|---|
2 | c896fe29 | bellard | * Tiny Code Generator for QEMU
|
3 | c896fe29 | bellard | *
|
4 | c896fe29 | bellard | * Copyright (c) 2008 Fabrice Bellard
|
5 | c896fe29 | bellard | *
|
6 | c896fe29 | bellard | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | c896fe29 | bellard | * of this software and associated documentation files (the "Software"), to deal
|
8 | c896fe29 | bellard | * in the Software without restriction, including without limitation the rights
|
9 | c896fe29 | bellard | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | c896fe29 | bellard | * copies of the Software, and to permit persons to whom the Software is
|
11 | c896fe29 | bellard | * furnished to do so, subject to the following conditions:
|
12 | c896fe29 | bellard | *
|
13 | c896fe29 | bellard | * The above copyright notice and this permission notice shall be included in
|
14 | c896fe29 | bellard | * all copies or substantial portions of the Software.
|
15 | c896fe29 | bellard | *
|
16 | c896fe29 | bellard | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | c896fe29 | bellard | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | c896fe29 | bellard | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | c896fe29 | bellard | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | c896fe29 | bellard | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | c896fe29 | bellard | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | c896fe29 | bellard | * THE SOFTWARE.
|
23 | c896fe29 | bellard | */
|
24 | c896fe29 | bellard | #include <assert.h> |
25 | c896fe29 | bellard | #include <stdarg.h> |
26 | c896fe29 | bellard | #include <stdlib.h> |
27 | c896fe29 | bellard | #include <stdio.h> |
28 | c896fe29 | bellard | #include <string.h> |
29 | c896fe29 | bellard | #include <inttypes.h> |
30 | c896fe29 | bellard | |
31 | c896fe29 | bellard | #include "config.h" |
32 | c896fe29 | bellard | #include "osdep.h" |
33 | c896fe29 | bellard | |
34 | c896fe29 | bellard | #include "tcg.h" |
35 | c896fe29 | bellard | |
36 | c896fe29 | bellard | int __op_param1, __op_param2, __op_param3;
|
37 | c896fe29 | bellard | #if defined(__sparc__) || defined(__arm__)
|
38 | c896fe29 | bellard | void __op_gen_label1(){}
|
39 | c896fe29 | bellard | void __op_gen_label2(){}
|
40 | c896fe29 | bellard | void __op_gen_label3(){}
|
41 | c896fe29 | bellard | #else
|
42 | c896fe29 | bellard | int __op_gen_label1, __op_gen_label2, __op_gen_label3;
|
43 | c896fe29 | bellard | #endif
|
44 | c896fe29 | bellard | int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
|
45 | c896fe29 | bellard | |
46 | c896fe29 | bellard | #if 0
|
47 | c896fe29 | bellard | #if defined(__s390__)
|
48 | c896fe29 | bellard | static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
49 | c896fe29 | bellard | {
|
50 | c896fe29 | bellard | }
|
51 | c896fe29 | bellard | #elif defined(__ia64__)
|
52 | c896fe29 | bellard | static inline void flush_icache_range(unsigned long start, unsigned long stop) |
53 | c896fe29 | bellard | { |
54 | c896fe29 | bellard | while (start < stop) {
|
55 | c896fe29 | bellard | asm volatile ("fc %0" :: "r"(start)); |
56 | c896fe29 | bellard | start += 32;
|
57 | c896fe29 | bellard | } |
58 | c896fe29 | bellard | asm volatile (";;sync.i;;srlz.i;;"); |
59 | c896fe29 | bellard | } |
60 | c896fe29 | bellard | #elif defined(__powerpc__)
|
61 | c896fe29 | bellard | |
62 | c896fe29 | bellard | #define MIN_CACHE_LINE_SIZE 8 /* conservative value */ |
63 | c896fe29 | bellard | |
64 | c896fe29 | bellard | static inline void flush_icache_range(unsigned long start, unsigned long stop) |
65 | c896fe29 | bellard | { |
66 | c896fe29 | bellard | unsigned long p; |
67 | c896fe29 | bellard | |
68 | c896fe29 | bellard | start &= ~(MIN_CACHE_LINE_SIZE - 1);
|
69 | c896fe29 | bellard | stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1); |
70 | c896fe29 | bellard | |
71 | c896fe29 | bellard | for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
|
72 | c896fe29 | bellard | asm volatile ("dcbst 0,%0" : : "r"(p) : "memory"); |
73 | c896fe29 | bellard | } |
74 | c896fe29 | bellard | asm volatile ("sync" : : : "memory"); |
75 | c896fe29 | bellard | for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
|
76 | c896fe29 | bellard | asm volatile ("icbi 0,%0" : : "r"(p) : "memory"); |
77 | c896fe29 | bellard | } |
78 | c896fe29 | bellard | asm volatile ("sync" : : : "memory"); |
79 | c896fe29 | bellard | asm volatile ("isync" : : : "memory"); |
80 | c896fe29 | bellard | } |
81 | c896fe29 | bellard | #elif defined(__alpha__)
|
82 | c896fe29 | bellard | static inline void flush_icache_range(unsigned long start, unsigned long stop) |
83 | c896fe29 | bellard | { |
84 | c896fe29 | bellard | asm ("imb"); |
85 | c896fe29 | bellard | } |
86 | c896fe29 | bellard | #elif defined(__sparc__)
|
87 | c896fe29 | bellard | static inline void flush_icache_range(unsigned long start, unsigned long stop) |
88 | c896fe29 | bellard | { |
89 | c896fe29 | bellard | unsigned long p; |
90 | c896fe29 | bellard | |
91 | c896fe29 | bellard | p = start & ~(8UL - 1UL); |
92 | c896fe29 | bellard | stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL); |
93 | c896fe29 | bellard | |
94 | c896fe29 | bellard | for (; p < stop; p += 8) |
95 | c896fe29 | bellard | __asm__ __volatile__("flush\t%0" : : "r" (p)); |
96 | c896fe29 | bellard | } |
97 | c896fe29 | bellard | #elif defined(__arm__)
|
98 | c896fe29 | bellard | static inline void flush_icache_range(unsigned long start, unsigned long stop) |
99 | c896fe29 | bellard | { |
100 | c896fe29 | bellard | register unsigned long _beg __asm ("a1") = start; |
101 | c896fe29 | bellard | register unsigned long _end __asm ("a2") = stop; |
102 | c896fe29 | bellard | register unsigned long _flg __asm ("a3") = 0; |
103 | c896fe29 | bellard | __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); |
104 | c896fe29 | bellard | } |
105 | c896fe29 | bellard | #elif defined(__mc68000)
|
106 | c896fe29 | bellard | |
107 | c896fe29 | bellard | # include <asm/cachectl.h> |
108 | c896fe29 | bellard | static inline void flush_icache_range(unsigned long start, unsigned long stop) |
109 | c896fe29 | bellard | { |
110 | c896fe29 | bellard | cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16);
|
111 | c896fe29 | bellard | } |
112 | c896fe29 | bellard | #elif defined(__mips__)
|
113 | c896fe29 | bellard | |
114 | c896fe29 | bellard | #include <sys/cachectl.h> |
115 | c896fe29 | bellard | static inline void flush_icache_range(unsigned long start, unsigned long stop) |
116 | c896fe29 | bellard | { |
117 | c896fe29 | bellard | _flush_cache ((void *)start, stop - start, BCACHE);
|
118 | c896fe29 | bellard | } |
119 | c896fe29 | bellard | #else
|
120 | c896fe29 | bellard | #error unsupported CPU
|
121 | c896fe29 | bellard | #endif
|
122 | c896fe29 | bellard | |
123 | c896fe29 | bellard | #ifdef __alpha__
|
124 | c896fe29 | bellard | |
125 | c896fe29 | bellard | register int gp asm("$29"); |
126 | c896fe29 | bellard | |
127 | c896fe29 | bellard | static inline void immediate_ldah(void *p, int val) { |
128 | c896fe29 | bellard | uint32_t *dest = p; |
129 | c896fe29 | bellard | long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff; |
130 | c896fe29 | bellard | |
131 | c896fe29 | bellard | *dest &= ~0xffff;
|
132 | c896fe29 | bellard | *dest |= high; |
133 | c896fe29 | bellard | *dest |= 31 << 16; |
134 | c896fe29 | bellard | } |
135 | c896fe29 | bellard | static inline void immediate_lda(void *dest, int val) { |
136 | c896fe29 | bellard | *(uint16_t *) dest = val; |
137 | c896fe29 | bellard | } |
138 | c896fe29 | bellard | void fix_bsr(void *p, int offset) { |
139 | c896fe29 | bellard | uint32_t *dest = p; |
140 | c896fe29 | bellard | *dest &= ~((1 << 21) - 1); |
141 | c896fe29 | bellard | *dest |= (offset >> 2) & ((1 << 21) - 1); |
142 | c896fe29 | bellard | } |
143 | c896fe29 | bellard | |
144 | c896fe29 | bellard | #endif /* __alpha__ */ |
145 | c896fe29 | bellard | |
146 | c896fe29 | bellard | #ifdef __arm__
|
147 | c896fe29 | bellard | |
148 | c896fe29 | bellard | #define ARM_LDR_TABLE_SIZE 1024 |
149 | c896fe29 | bellard | |
150 | c896fe29 | bellard | typedef struct LDREntry { |
151 | c896fe29 | bellard | uint8_t *ptr; |
152 | c896fe29 | bellard | uint32_t *data_ptr; |
153 | c896fe29 | bellard | unsigned type:2; |
154 | c896fe29 | bellard | } LDREntry; |
155 | c896fe29 | bellard | |
156 | c896fe29 | bellard | static LDREntry arm_ldr_table[1024]; |
157 | c896fe29 | bellard | static uint32_t arm_data_table[ARM_LDR_TABLE_SIZE];
|
158 | c896fe29 | bellard | |
159 | c896fe29 | bellard | extern char exec_loop; |
160 | c896fe29 | bellard | |
161 | c896fe29 | bellard | static inline void arm_reloc_pc24(uint32_t *ptr, uint32_t insn, int val) |
162 | c896fe29 | bellard | { |
163 | c896fe29 | bellard | *ptr = (insn & ~0xffffff) | ((insn + ((val - (int)ptr) >> 2)) & 0xffffff); |
164 | c896fe29 | bellard | } |
165 | c896fe29 | bellard | |
166 | c896fe29 | bellard | static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
|
167 | c896fe29 | bellard | LDREntry *ldr_start, LDREntry *ldr_end, |
168 | c896fe29 | bellard | uint32_t *data_start, uint32_t *data_end, |
169 | c896fe29 | bellard | int gen_jmp)
|
170 | c896fe29 | bellard | { |
171 | c896fe29 | bellard | LDREntry *le; |
172 | c896fe29 | bellard | uint32_t *ptr; |
173 | c896fe29 | bellard | int offset, data_size, target;
|
174 | c896fe29 | bellard | uint8_t *data_ptr; |
175 | c896fe29 | bellard | uint32_t insn; |
176 | c896fe29 | bellard | uint32_t mask; |
177 | c896fe29 | bellard | |
178 | c896fe29 | bellard | data_size = (data_end - data_start) << 2;
|
179 | c896fe29 | bellard | |
180 | c896fe29 | bellard | if (gen_jmp) {
|
181 | c896fe29 | bellard | /* generate branch to skip the data */
|
182 | c896fe29 | bellard | if (data_size == 0) |
183 | c896fe29 | bellard | return gen_code_ptr;
|
184 | c896fe29 | bellard | target = (long)gen_code_ptr + data_size + 4; |
185 | c896fe29 | bellard | arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, target);
|
186 | c896fe29 | bellard | gen_code_ptr += 4;
|
187 | c896fe29 | bellard | } |
188 | c896fe29 | bellard | |
189 | c896fe29 | bellard | /* copy the data */
|
190 | c896fe29 | bellard | data_ptr = gen_code_ptr; |
191 | c896fe29 | bellard | memcpy(gen_code_ptr, data_start, data_size); |
192 | c896fe29 | bellard | gen_code_ptr += data_size; |
193 | c896fe29 | bellard | |
194 | c896fe29 | bellard | /* patch the ldr to point to the data */
|
195 | c896fe29 | bellard | for(le = ldr_start; le < ldr_end; le++) {
|
196 | c896fe29 | bellard | ptr = (uint32_t *)le->ptr; |
197 | c896fe29 | bellard | offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) + |
198 | c896fe29 | bellard | (unsigned long)data_ptr - |
199 | c896fe29 | bellard | (unsigned long)ptr - 8; |
200 | c896fe29 | bellard | if (offset < 0) { |
201 | c896fe29 | bellard | fprintf(stderr, "Negative constant pool offset\n");
|
202 | c896fe29 | bellard | tcg_abort(); |
203 | c896fe29 | bellard | } |
204 | c896fe29 | bellard | switch (le->type) {
|
205 | c896fe29 | bellard | case 0: /* ldr */ |
206 | c896fe29 | bellard | mask = ~0x00800fff;
|
207 | c896fe29 | bellard | if (offset >= 4096) { |
208 | c896fe29 | bellard | fprintf(stderr, "Bad ldr offset\n");
|
209 | c896fe29 | bellard | tcg_abort(); |
210 | c896fe29 | bellard | } |
211 | c896fe29 | bellard | break;
|
212 | c896fe29 | bellard | case 1: /* ldc */ |
213 | c896fe29 | bellard | mask = ~0x008000ff;
|
214 | c896fe29 | bellard | if (offset >= 1024 ) { |
215 | c896fe29 | bellard | fprintf(stderr, "Bad ldc offset\n");
|
216 | c896fe29 | bellard | tcg_abort(); |
217 | c896fe29 | bellard | } |
218 | c896fe29 | bellard | break;
|
219 | c896fe29 | bellard | case 2: /* add */ |
220 | c896fe29 | bellard | mask = ~0xfff;
|
221 | c896fe29 | bellard | if (offset >= 1024 ) { |
222 | c896fe29 | bellard | fprintf(stderr, "Bad add offset\n");
|
223 | c896fe29 | bellard | tcg_abort(); |
224 | c896fe29 | bellard | } |
225 | c896fe29 | bellard | break;
|
226 | c896fe29 | bellard | default:
|
227 | c896fe29 | bellard | fprintf(stderr, "Bad pc relative fixup\n");
|
228 | c896fe29 | bellard | tcg_abort(); |
229 | c896fe29 | bellard | } |
230 | c896fe29 | bellard | insn = *ptr & mask; |
231 | c896fe29 | bellard | switch (le->type) {
|
232 | c896fe29 | bellard | case 0: /* ldr */ |
233 | c896fe29 | bellard | insn |= offset | 0x00800000;
|
234 | c896fe29 | bellard | break;
|
235 | c896fe29 | bellard | case 1: /* ldc */ |
236 | c896fe29 | bellard | insn |= (offset >> 2) | 0x00800000; |
237 | c896fe29 | bellard | break;
|
238 | c896fe29 | bellard | case 2: /* add */ |
239 | c896fe29 | bellard | insn |= (offset >> 2) | 0xf00; |
240 | c896fe29 | bellard | break;
|
241 | c896fe29 | bellard | } |
242 | c896fe29 | bellard | *ptr = insn; |
243 | c896fe29 | bellard | } |
244 | c896fe29 | bellard | return gen_code_ptr;
|
245 | c896fe29 | bellard | } |
246 | c896fe29 | bellard | |
247 | c896fe29 | bellard | #endif /* __arm__ */ |
248 | c896fe29 | bellard | |
249 | c896fe29 | bellard | #ifdef __ia64
|
250 | c896fe29 | bellard | |
251 | c896fe29 | bellard | /* Patch instruction with "val" where "mask" has 1 bits. */
|
252 | c896fe29 | bellard | static inline void ia64_patch (uint64_t insn_addr, uint64_t mask, uint64_t val) |
253 | c896fe29 | bellard | { |
254 | c896fe29 | bellard | uint64_t m0, m1, v0, v1, b0, b1, *b = (uint64_t *) (insn_addr & -16);
|
255 | c896fe29 | bellard | # define insn_mask ((1UL << 41) - 1) |
256 | c896fe29 | bellard | unsigned long shift; |
257 | c896fe29 | bellard | |
258 | c896fe29 | bellard | b0 = b[0]; b1 = b[1]; |
259 | c896fe29 | bellard | shift = 5 + 41 * (insn_addr % 16); /* 5 template, 3 x 41-bit insns */ |
260 | c896fe29 | bellard | if (shift >= 64) { |
261 | c896fe29 | bellard | m1 = mask << (shift - 64);
|
262 | c896fe29 | bellard | v1 = val << (shift - 64);
|
263 | c896fe29 | bellard | } else {
|
264 | c896fe29 | bellard | m0 = mask << shift; m1 = mask >> (64 - shift);
|
265 | c896fe29 | bellard | v0 = val << shift; v1 = val >> (64 - shift);
|
266 | c896fe29 | bellard | b[0] = (b0 & ~m0) | (v0 & m0);
|
267 | c896fe29 | bellard | } |
268 | c896fe29 | bellard | b[1] = (b1 & ~m1) | (v1 & m1);
|
269 | c896fe29 | bellard | } |
270 | c896fe29 | bellard | |
271 | c896fe29 | bellard | static inline void ia64_patch_imm60 (uint64_t insn_addr, uint64_t val) |
272 | c896fe29 | bellard | { |
273 | c896fe29 | bellard | ia64_patch(insn_addr, |
274 | c896fe29 | bellard | 0x011ffffe000UL,
|
275 | c896fe29 | bellard | ( ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */ |
276 | c896fe29 | bellard | | ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */)); |
277 | c896fe29 | bellard | ia64_patch(insn_addr - 1, 0x1fffffffffcUL, val >> 18); |
278 | c896fe29 | bellard | } |
279 | c896fe29 | bellard | |
280 | c896fe29 | bellard | static inline void ia64_imm64 (void *insn, uint64_t val) |
281 | c896fe29 | bellard | { |
282 | c896fe29 | bellard | /* Ignore the slot number of the relocation; GCC and Intel
|
283 | c896fe29 | bellard | toolchains differed for some time on whether IMM64 relocs are
|
284 | c896fe29 | bellard | against slot 1 (Intel) or slot 2 (GCC). */
|
285 | c896fe29 | bellard | uint64_t insn_addr = (uint64_t) insn & ~3UL;
|
286 | c896fe29 | bellard | |
287 | c896fe29 | bellard | ia64_patch(insn_addr + 2,
|
288 | c896fe29 | bellard | 0x01fffefe000UL,
|
289 | c896fe29 | bellard | ( ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */ |
290 | c896fe29 | bellard | | ((val & 0x0000000000200000UL) << 0) /* bit 21 -> 21 */ |
291 | c896fe29 | bellard | | ((val & 0x00000000001f0000UL) << 6) /* bit 16 -> 22 */ |
292 | c896fe29 | bellard | | ((val & 0x000000000000ff80UL) << 20) /* bit 7 -> 27 */ |
293 | c896fe29 | bellard | | ((val & 0x000000000000007fUL) << 13) /* bit 0 -> 13 */) |
294 | c896fe29 | bellard | ); |
295 | c896fe29 | bellard | ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22); |
296 | c896fe29 | bellard | } |
297 | c896fe29 | bellard | |
298 | c896fe29 | bellard | static inline void ia64_imm60b (void *insn, uint64_t val) |
299 | c896fe29 | bellard | { |
300 | c896fe29 | bellard | /* Ignore the slot number of the relocation; GCC and Intel
|
301 | c896fe29 | bellard | toolchains differed for some time on whether IMM64 relocs are
|
302 | c896fe29 | bellard | against slot 1 (Intel) or slot 2 (GCC). */
|
303 | c896fe29 | bellard | uint64_t insn_addr = (uint64_t) insn & ~3UL;
|
304 | c896fe29 | bellard | |
305 | c896fe29 | bellard | if (val + ((uint64_t) 1 << 59) >= (1UL << 60)) |
306 | c896fe29 | bellard | fprintf(stderr, "%s: value %ld out of IMM60 range\n",
|
307 | c896fe29 | bellard | __FUNCTION__, (int64_t) val); |
308 | c896fe29 | bellard | ia64_patch_imm60(insn_addr + 2, val);
|
309 | c896fe29 | bellard | } |
310 | c896fe29 | bellard | |
311 | c896fe29 | bellard | static inline void ia64_imm22 (void *insn, uint64_t val) |
312 | c896fe29 | bellard | { |
313 | c896fe29 | bellard | if (val + (1 << 21) >= (1 << 22)) |
314 | c896fe29 | bellard | fprintf(stderr, "%s: value %li out of IMM22 range\n",
|
315 | c896fe29 | bellard | __FUNCTION__, (int64_t)val); |
316 | c896fe29 | bellard | ia64_patch((uint64_t) insn, 0x01fffcfe000UL,
|
317 | c896fe29 | bellard | ( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */ |
318 | c896fe29 | bellard | | ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */ |
319 | c896fe29 | bellard | | ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */ |
320 | c896fe29 | bellard | | ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */)); |
321 | c896fe29 | bellard | } |
322 | c896fe29 | bellard | |
323 | c896fe29 | bellard | /* Like ia64_imm22(), but also clear bits 20-21. For addl, this has
|
324 | c896fe29 | bellard | the effect of turning "addl rX=imm22,rY" into "addl
|
325 | c896fe29 | bellard | rX=imm22,r0". */
|
326 | c896fe29 | bellard | static inline void ia64_imm22_r0 (void *insn, uint64_t val) |
327 | c896fe29 | bellard | { |
328 | c896fe29 | bellard | if (val + (1 << 21) >= (1 << 22)) |
329 | c896fe29 | bellard | fprintf(stderr, "%s: value %li out of IMM22 range\n",
|
330 | c896fe29 | bellard | __FUNCTION__, (int64_t)val); |
331 | c896fe29 | bellard | ia64_patch((uint64_t) insn, 0x01fffcfe000UL | (0x3UL << 20), |
332 | c896fe29 | bellard | ( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */ |
333 | c896fe29 | bellard | | ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */ |
334 | c896fe29 | bellard | | ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */ |
335 | c896fe29 | bellard | | ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */)); |
336 | c896fe29 | bellard | } |
337 | c896fe29 | bellard | |
338 | c896fe29 | bellard | static inline void ia64_imm21b (void *insn, uint64_t val) |
339 | c896fe29 | bellard | { |
340 | c896fe29 | bellard | if (val + (1 << 20) >= (1 << 21)) |
341 | c896fe29 | bellard | fprintf(stderr, "%s: value %li out of IMM21b range\n",
|
342 | c896fe29 | bellard | __FUNCTION__, (int64_t)val); |
343 | c896fe29 | bellard | ia64_patch((uint64_t) insn, 0x11ffffe000UL,
|
344 | c896fe29 | bellard | ( ((val & 0x100000UL) << 16) /* bit 20 -> 36 */ |
345 | c896fe29 | bellard | | ((val & 0x0fffffUL) << 13) /* bit 0 -> 13 */)); |
346 | c896fe29 | bellard | } |
347 | c896fe29 | bellard | |
348 | c896fe29 | bellard | static inline void ia64_nop_b (void *insn) |
349 | c896fe29 | bellard | { |
350 | c896fe29 | bellard | ia64_patch((uint64_t) insn, (1UL << 41) - 1, 2UL << 37); |
351 | c896fe29 | bellard | } |
352 | c896fe29 | bellard | |
353 | c896fe29 | bellard | static inline void ia64_ldxmov(void *insn, uint64_t val) |
354 | c896fe29 | bellard | { |
355 | c896fe29 | bellard | if (val + (1 << 21) < (1 << 22)) |
356 | c896fe29 | bellard | ia64_patch((uint64_t) insn, 0x1fff80fe000UL, 8UL << 37); |
357 | c896fe29 | bellard | } |
358 | c896fe29 | bellard | |
359 | c896fe29 | bellard | static inline int ia64_patch_ltoff(void *insn, uint64_t val, |
360 | c896fe29 | bellard | int relaxable)
|
361 | c896fe29 | bellard | { |
362 | c896fe29 | bellard | if (relaxable && (val + (1 << 21) < (1 << 22))) { |
363 | c896fe29 | bellard | ia64_imm22_r0(insn, val); |
364 | c896fe29 | bellard | return 0; |
365 | c896fe29 | bellard | } |
366 | c896fe29 | bellard | return 1; |
367 | c896fe29 | bellard | } |
368 | c896fe29 | bellard | |
369 | c896fe29 | bellard | struct ia64_fixup {
|
370 | c896fe29 | bellard | struct ia64_fixup *next;
|
371 | c896fe29 | bellard | void *addr; /* address that needs to be patched */ |
372 | c896fe29 | bellard | long value;
|
373 | c896fe29 | bellard | }; |
374 | c896fe29 | bellard | |
375 | c896fe29 | bellard | #define IA64_PLT(insn, plt_index) \
|
376 | c896fe29 | bellard | do { \
|
377 | c896fe29 | bellard | struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \ |
378 | c896fe29 | bellard | fixup->next = plt_fixes; \ |
379 | c896fe29 | bellard | plt_fixes = fixup; \ |
380 | c896fe29 | bellard | fixup->addr = (insn); \ |
381 | c896fe29 | bellard | fixup->value = (plt_index); \ |
382 | c896fe29 | bellard | plt_offset[(plt_index)] = 1; \
|
383 | c896fe29 | bellard | } while (0) |
384 | c896fe29 | bellard | |
385 | c896fe29 | bellard | #define IA64_LTOFF(insn, val, relaxable) \
|
386 | c896fe29 | bellard | do { \
|
387 | c896fe29 | bellard | if (ia64_patch_ltoff(insn, val, relaxable)) { \
|
388 | c896fe29 | bellard | struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \ |
389 | c896fe29 | bellard | fixup->next = ltoff_fixes; \ |
390 | c896fe29 | bellard | ltoff_fixes = fixup; \ |
391 | c896fe29 | bellard | fixup->addr = (insn); \ |
392 | c896fe29 | bellard | fixup->value = (val); \ |
393 | c896fe29 | bellard | } \ |
394 | c896fe29 | bellard | } while (0) |
395 | c896fe29 | bellard | |
396 | c896fe29 | bellard | static inline void ia64_apply_fixes (uint8_t **gen_code_pp, |
397 | c896fe29 | bellard | struct ia64_fixup *ltoff_fixes,
|
398 | c896fe29 | bellard | uint64_t gp, |
399 | c896fe29 | bellard | struct ia64_fixup *plt_fixes,
|
400 | c896fe29 | bellard | int num_plts,
|
401 | c896fe29 | bellard | unsigned long *plt_target, |
402 | c896fe29 | bellard | unsigned int *plt_offset) |
403 | c896fe29 | bellard | { |
404 | c896fe29 | bellard | static const uint8_t plt_bundle[] = { |
405 | c896fe29 | bellard | 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; movl r1=GP */ |
406 | c896fe29 | bellard | 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60, |
407 | c896fe29 | bellard | |
408 | c896fe29 | bellard | 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; brl IP */ |
409 | c896fe29 | bellard | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0 |
410 | c896fe29 | bellard | }; |
411 | c896fe29 | bellard | uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *got_start; |
412 | c896fe29 | bellard | uint64_t *vp; |
413 | c896fe29 | bellard | struct ia64_fixup *fixup;
|
414 | c896fe29 | bellard | unsigned int offset = 0; |
415 | c896fe29 | bellard | struct fdesc {
|
416 | c896fe29 | bellard | long ip;
|
417 | c896fe29 | bellard | long gp;
|
418 | c896fe29 | bellard | } *fdesc; |
419 | c896fe29 | bellard | int i;
|
420 | c896fe29 | bellard | |
421 | c896fe29 | bellard | if (plt_fixes) {
|
422 | c896fe29 | bellard | plt_start = gen_code_ptr; |
423 | c896fe29 | bellard | |
424 | c896fe29 | bellard | for (i = 0; i < num_plts; ++i) { |
425 | c896fe29 | bellard | if (plt_offset[i]) {
|
426 | c896fe29 | bellard | plt_offset[i] = offset; |
427 | c896fe29 | bellard | offset += sizeof(plt_bundle);
|
428 | c896fe29 | bellard | |
429 | c896fe29 | bellard | fdesc = (struct fdesc *) plt_target[i];
|
430 | c896fe29 | bellard | memcpy(gen_code_ptr, plt_bundle, sizeof(plt_bundle));
|
431 | c896fe29 | bellard | ia64_imm64 (gen_code_ptr + 0x02, fdesc->gp);
|
432 | c896fe29 | bellard | ia64_imm60b(gen_code_ptr + 0x12,
|
433 | c896fe29 | bellard | (fdesc->ip - (long) (gen_code_ptr + 0x10)) >> 4); |
434 | c896fe29 | bellard | gen_code_ptr += sizeof(plt_bundle);
|
435 | c896fe29 | bellard | } |
436 | c896fe29 | bellard | } |
437 | c896fe29 | bellard | |
438 | c896fe29 | bellard | for (fixup = plt_fixes; fixup; fixup = fixup->next)
|
439 | c896fe29 | bellard | ia64_imm21b(fixup->addr, |
440 | c896fe29 | bellard | ((long) plt_start + plt_offset[fixup->value]
|
441 | c896fe29 | bellard | - ((long) fixup->addr & ~0xf)) >> 4); |
442 | c896fe29 | bellard | } |
443 | c896fe29 | bellard | |
444 | c896fe29 | bellard | got_start = gen_code_ptr; |
445 | c896fe29 | bellard | |
446 | c896fe29 | bellard | /* First, create the GOT: */
|
447 | c896fe29 | bellard | for (fixup = ltoff_fixes; fixup; fixup = fixup->next) {
|
448 | c896fe29 | bellard | /* first check if we already have this value in the GOT: */
|
449 | c896fe29 | bellard | for (vp = (uint64_t *) got_start; vp < (uint64_t *) gen_code_ptr; ++vp)
|
450 | c896fe29 | bellard | if (*vp == fixup->value)
|
451 | c896fe29 | bellard | break;
|
452 | c896fe29 | bellard | if (vp == (uint64_t *) gen_code_ptr) {
|
453 | c896fe29 | bellard | /* Nope, we need to put the value in the GOT: */
|
454 | c896fe29 | bellard | *vp = fixup->value; |
455 | c896fe29 | bellard | gen_code_ptr += 8;
|
456 | c896fe29 | bellard | } |
457 | c896fe29 | bellard | ia64_imm22(fixup->addr, (long) vp - gp);
|
458 | c896fe29 | bellard | } |
459 | c896fe29 | bellard | /* Keep code ptr aligned. */
|
460 | c896fe29 | bellard | if ((long) gen_code_ptr & 15) |
461 | c896fe29 | bellard | gen_code_ptr += 8;
|
462 | c896fe29 | bellard | *gen_code_pp = gen_code_ptr; |
463 | c896fe29 | bellard | } |
464 | c896fe29 | bellard | #endif
|
465 | c896fe29 | bellard | #endif
|
466 | c896fe29 | bellard | |
467 | bf6247fb | blueswir1 | #ifdef CONFIG_DYNGEN_OP
|
468 | f54b3f92 | aurel32 | |
469 | f54b3f92 | aurel32 | #if defined __hppa__
|
470 | f54b3f92 | aurel32 | struct hppa_branch_stub {
|
471 | f54b3f92 | aurel32 | uint32_t *location; |
472 | f54b3f92 | aurel32 | long target;
|
473 | f54b3f92 | aurel32 | struct hppa_branch_stub *next;
|
474 | f54b3f92 | aurel32 | }; |
475 | f54b3f92 | aurel32 | |
476 | f54b3f92 | aurel32 | #define HPPA_RECORD_BRANCH(LIST, LOC, TARGET) \
|
477 | f54b3f92 | aurel32 | do { \
|
478 | f54b3f92 | aurel32 | struct hppa_branch_stub *stub = alloca(sizeof(struct hppa_branch_stub)); \ |
479 | f54b3f92 | aurel32 | stub->location = LOC; \ |
480 | f54b3f92 | aurel32 | stub->target = TARGET; \ |
481 | f54b3f92 | aurel32 | stub->next = LIST; \ |
482 | f54b3f92 | aurel32 | LIST = stub; \ |
483 | f54b3f92 | aurel32 | } while (0) |
484 | f54b3f92 | aurel32 | |
485 | f54b3f92 | aurel32 | static inline void hppa_process_stubs(struct hppa_branch_stub *stub, |
486 | f54b3f92 | aurel32 | uint8_t **gen_code_pp) |
487 | f54b3f92 | aurel32 | { |
488 | f54b3f92 | aurel32 | uint32_t *s = (uint32_t *)*gen_code_pp; |
489 | f54b3f92 | aurel32 | uint32_t *p = s + 1;
|
490 | f54b3f92 | aurel32 | |
491 | f54b3f92 | aurel32 | if (!stub) return; |
492 | f54b3f92 | aurel32 | |
493 | f54b3f92 | aurel32 | for (; stub != NULL; stub = stub->next) { |
494 | f54b3f92 | aurel32 | unsigned long l = (unsigned long)p; |
495 | f54b3f92 | aurel32 | /* stub:
|
496 | f54b3f92 | aurel32 | * ldil L'target, %r1
|
497 | f54b3f92 | aurel32 | * be,n R'target(%sr4,%r1)
|
498 | f54b3f92 | aurel32 | */
|
499 | f54b3f92 | aurel32 | *p++ = 0x20200000 | reassemble_21(lrsel(stub->target, 0)); |
500 | f54b3f92 | aurel32 | *p++ = 0xe0202002 | (reassemble_17(rrsel(stub->target, 0) >> 2)); |
501 | f54b3f92 | aurel32 | hppa_patch17f(stub->location, l, 0);
|
502 | f54b3f92 | aurel32 | } |
503 | f54b3f92 | aurel32 | /* b,l,n stub,%r0 */
|
504 | f54b3f92 | aurel32 | *s = 0xe8000002 | reassemble_17((p - s) - 2); |
505 | f54b3f92 | aurel32 | *gen_code_pp = (uint8_t *)p; |
506 | f54b3f92 | aurel32 | } |
507 | f54b3f92 | aurel32 | #endif /* __hppa__ */ |
508 | f54b3f92 | aurel32 | |
509 | c896fe29 | bellard | const TCGArg *dyngen_op(TCGContext *s, int opc, const TCGArg *opparam_ptr) |
510 | c896fe29 | bellard | { |
511 | c896fe29 | bellard | uint8_t *gen_code_ptr; |
512 | c896fe29 | bellard | |
513 | f54b3f92 | aurel32 | #ifdef __hppa__
|
514 | f54b3f92 | aurel32 | struct hppa_branch_stub *hppa_stubs = NULL; |
515 | f54b3f92 | aurel32 | #endif
|
516 | f54b3f92 | aurel32 | |
517 | c896fe29 | bellard | gen_code_ptr = s->code_ptr; |
518 | c896fe29 | bellard | switch(opc) {
|
519 | c896fe29 | bellard | |
520 | c896fe29 | bellard | /* op.h is dynamically generated by dyngen.c from op.c */
|
521 | c896fe29 | bellard | #include "op.h" |
522 | c896fe29 | bellard | |
523 | c896fe29 | bellard | default:
|
524 | c896fe29 | bellard | tcg_abort(); |
525 | c896fe29 | bellard | } |
526 | f54b3f92 | aurel32 | |
527 | f54b3f92 | aurel32 | #ifdef __hppa__
|
528 | f54b3f92 | aurel32 | hppa_process_stubs(hppa_stubs, &gen_code_ptr); |
529 | f54b3f92 | aurel32 | #endif
|
530 | f54b3f92 | aurel32 | |
531 | c896fe29 | bellard | s->code_ptr = gen_code_ptr; |
532 | c896fe29 | bellard | return opparam_ptr;
|
533 | c896fe29 | bellard | } |
534 | cf2be984 | blueswir1 | #endif |