mirror of
https://github.com/qemu/qemu.git
synced 2024-11-26 12:23:36 +08:00
tcg/s390: Support split-wx code generation
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
dd90043f5d
commit
79dae4ddd8
@ -363,36 +363,37 @@ static void * const qemu_st_helpers[16] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
static tcg_insn_unit *tb_ret_addr;
|
||||
static const tcg_insn_unit *tb_ret_addr;
|
||||
uint64_t s390_facilities;
|
||||
|
||||
static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
|
||||
static bool patch_reloc(tcg_insn_unit *src_rw, int type,
|
||||
intptr_t value, intptr_t addend)
|
||||
{
|
||||
const tcg_insn_unit *src_rx = tcg_splitwx_to_rx(src_rw);
|
||||
intptr_t pcrel2;
|
||||
uint32_t old;
|
||||
|
||||
value += addend;
|
||||
pcrel2 = (tcg_insn_unit *)value - code_ptr;
|
||||
pcrel2 = (tcg_insn_unit *)value - src_rx;
|
||||
|
||||
switch (type) {
|
||||
case R_390_PC16DBL:
|
||||
if (pcrel2 == (int16_t)pcrel2) {
|
||||
tcg_patch16(code_ptr, pcrel2);
|
||||
tcg_patch16(src_rw, pcrel2);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case R_390_PC32DBL:
|
||||
if (pcrel2 == (int32_t)pcrel2) {
|
||||
tcg_patch32(code_ptr, pcrel2);
|
||||
tcg_patch32(src_rw, pcrel2);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case R_390_20:
|
||||
if (value == sextract64(value, 0, 20)) {
|
||||
old = *(uint32_t *)code_ptr & 0xf00000ff;
|
||||
old = *(uint32_t *)src_rw & 0xf00000ff;
|
||||
old |= ((value & 0xfff) << 16) | ((value & 0xff000) >> 4);
|
||||
tcg_patch32(code_ptr, old);
|
||||
tcg_patch32(src_rw, old);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@ -730,7 +731,8 @@ static inline bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
|
||||
}
|
||||
|
||||
/* load data from an absolute host address */
|
||||
static void tcg_out_ld_abs(TCGContext *s, TCGType type, TCGReg dest, void *abs)
|
||||
static void tcg_out_ld_abs(TCGContext *s, TCGType type,
|
||||
TCGReg dest, const void *abs)
|
||||
{
|
||||
intptr_t addr = (intptr_t)abs;
|
||||
|
||||
@ -1304,7 +1306,7 @@ static void tgen_extract(TCGContext *s, TCGReg dest, TCGReg src,
|
||||
|
||||
static void tgen_gotoi(TCGContext *s, int cc, const tcg_insn_unit *dest)
|
||||
{
|
||||
ptrdiff_t off = dest - s->code_ptr;
|
||||
ptrdiff_t off = tcg_pcrel_diff(s, dest) >> 1;
|
||||
if (off == (int16_t)off) {
|
||||
tcg_out_insn(s, RI, BRC, cc, off);
|
||||
} else if (off == (int32_t)off) {
|
||||
@ -1333,34 +1335,18 @@ static void tgen_branch(TCGContext *s, int cc, TCGLabel *l)
|
||||
static void tgen_compare_branch(TCGContext *s, S390Opcode opc, int cc,
|
||||
TCGReg r1, TCGReg r2, TCGLabel *l)
|
||||
{
|
||||
intptr_t off = 0;
|
||||
|
||||
if (l->has_value) {
|
||||
off = l->u.value_ptr - s->code_ptr;
|
||||
tcg_debug_assert(off == (int16_t)off);
|
||||
} else {
|
||||
tcg_out_reloc(s, s->code_ptr + 1, R_390_PC16DBL, l, 2);
|
||||
}
|
||||
|
||||
tcg_out_reloc(s, s->code_ptr + 1, R_390_PC16DBL, l, 2);
|
||||
tcg_out16(s, (opc & 0xff00) | (r1 << 4) | r2);
|
||||
tcg_out16(s, off);
|
||||
tcg_out16(s, 0);
|
||||
tcg_out16(s, cc << 12 | (opc & 0xff));
|
||||
}
|
||||
|
||||
static void tgen_compare_imm_branch(TCGContext *s, S390Opcode opc, int cc,
|
||||
TCGReg r1, int i2, TCGLabel *l)
|
||||
{
|
||||
tcg_target_long off = 0;
|
||||
|
||||
if (l->has_value) {
|
||||
off = l->u.value_ptr - s->code_ptr;
|
||||
tcg_debug_assert(off == (int16_t)off);
|
||||
} else {
|
||||
tcg_out_reloc(s, s->code_ptr + 1, R_390_PC16DBL, l, 2);
|
||||
}
|
||||
|
||||
tcg_out_reloc(s, s->code_ptr + 1, R_390_PC16DBL, l, 2);
|
||||
tcg_out16(s, (opc & 0xff00) | (r1 << 4) | cc);
|
||||
tcg_out16(s, off);
|
||||
tcg_out16(s, 0);
|
||||
tcg_out16(s, (i2 << 8) | (opc & 0xff));
|
||||
}
|
||||
|
||||
@ -1417,7 +1403,7 @@ static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c,
|
||||
|
||||
static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest)
|
||||
{
|
||||
ptrdiff_t off = dest - s->code_ptr;
|
||||
ptrdiff_t off = tcg_pcrel_diff(s, dest) >> 1;
|
||||
if (off == (int32_t)off) {
|
||||
tcg_out_insn(s, RIL, BRASL, TCG_REG_R14, off);
|
||||
} else {
|
||||
@ -1601,7 +1587,8 @@ static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
|
||||
label->oi = oi;
|
||||
label->datalo_reg = data;
|
||||
label->addrlo_reg = addr;
|
||||
label->raddr = raddr;
|
||||
/* TODO: Cast goes away when all hosts converted */
|
||||
label->raddr = (void *)tcg_splitwx_to_rx(raddr);
|
||||
label->label_ptr[0] = label_ptr;
|
||||
}
|
||||
|
||||
@ -1613,7 +1600,7 @@ static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
|
||||
MemOp opc = get_memop(oi);
|
||||
|
||||
if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
|
||||
(intptr_t)s->code_ptr, 2)) {
|
||||
(intptr_t)tcg_splitwx_to_rx(s->code_ptr), 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1638,7 +1625,7 @@ static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
|
||||
MemOp opc = get_memop(oi);
|
||||
|
||||
if (!patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
|
||||
(intptr_t)s->code_ptr, 2)) {
|
||||
(intptr_t)tcg_splitwx_to_rx(s->code_ptr), 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1766,7 +1753,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
||||
case INDEX_op_goto_tb:
|
||||
a0 = args[0];
|
||||
if (s->tb_jmp_insn_offset) {
|
||||
/* branch displacement must be aligned for atomic patching;
|
||||
/*
|
||||
* branch displacement must be aligned for atomic patching;
|
||||
* see if we need to add extra nop before branch
|
||||
*/
|
||||
if (!QEMU_PTR_IS_ALIGNED(s->code_ptr + 1, 4)) {
|
||||
@ -1779,7 +1767,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
||||
} else {
|
||||
/* load address stored at s->tb_jmp_target_addr + a0 */
|
||||
tcg_out_ld_abs(s, TCG_TYPE_PTR, TCG_REG_TB,
|
||||
s->tb_jmp_target_addr + a0);
|
||||
tcg_splitwx_to_rx(s->tb_jmp_target_addr + a0));
|
||||
/* and go there */
|
||||
tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_TB);
|
||||
}
|
||||
@ -1789,8 +1777,10 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
||||
TCG_REG_TB to the beginning of this TB. */
|
||||
if (USE_REG_TB) {
|
||||
int ofs = -tcg_current_code_size(s);
|
||||
assert(ofs == (int16_t)ofs);
|
||||
tcg_out_insn(s, RI, AGHI, TCG_REG_TB, ofs);
|
||||
/* All TB are restricted to 64KiB by unwind info. */
|
||||
tcg_debug_assert(ofs == sextract64(ofs, 0, 20));
|
||||
tcg_out_insn(s, RXY, LAY, TCG_REG_TB,
|
||||
TCG_REG_TB, TCG_REG_NONE, ofs);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -2561,11 +2551,12 @@ static void tcg_target_qemu_prologue(TCGContext *s)
|
||||
* Return path for goto_ptr. Set return value to 0, a-la exit_tb,
|
||||
* and fall through to the rest of the epilogue.
|
||||
*/
|
||||
tcg_code_gen_epilogue = s->code_ptr;
|
||||
/* TODO: Cast goes away when all hosts converted */
|
||||
tcg_code_gen_epilogue = (void *)tcg_splitwx_to_rx(s->code_ptr);
|
||||
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, 0);
|
||||
|
||||
/* TB epilogue */
|
||||
tb_ret_addr = s->code_ptr;
|
||||
tb_ret_addr = tcg_splitwx_to_rx(s->code_ptr);
|
||||
|
||||
/* lmg %r6,%r15,fs+48(%r15) (restore registers) */
|
||||
tcg_out_insn(s, RXY, LMG, TCG_REG_R6, TCG_REG_R15, TCG_REG_R15,
|
||||
|
@ -159,6 +159,6 @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_rx,
|
||||
#define TCG_TARGET_NEED_LDST_LABELS
|
||||
#endif
|
||||
#define TCG_TARGET_NEED_POOL_LABELS
|
||||
#define TCG_TARGET_SUPPORT_MIRROR 0
|
||||
#define TCG_TARGET_SUPPORT_MIRROR 1
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user