Statistics
| Branch: | Revision:

root / tcg / tcg-dyngen.c @ f54b3f92

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 cf2be984 blueswir1
#ifndef CONFIG_NO_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