Define tcg_out_ldst which can properly choose between RX and RXY format instructions based on the offset used, and also handles large offsets. Use it to implement all the INDEX_op_ld/st operations.
Signed-off-by: Richard Henderson <r...@twiddle.net> --- tcg/s390/tcg-target.c | 152 +++++++++++++++++++++++-------------------------- 1 files changed, 71 insertions(+), 81 deletions(-) diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c index b150d1a..21ad1a3 100644 --- a/tcg/s390/tcg-target.c +++ b/tcg/s390/tcg-target.c @@ -90,17 +90,22 @@ typedef enum S390Opcode { RS_SRL = 0x88, RXY_CG = 0xe320, + RXY_LB = 0xe376, RXY_LG = 0xe304, RXY_LGB = 0xe377, RXY_LGF = 0xe314, RXY_LGH = 0xe315, + RXY_LHY = 0xe378, + RXY_LLC = 0xe394, RXY_LLGC = 0xe390, RXY_LLGF = 0xe316, RXY_LLGH = 0xe391, + RXY_LLH = 0xe395, RXY_LMG = 0xeb04, RXY_LRV = 0xe31e, RXY_LRVG = 0xe30f, RXY_LRVH = 0xe31f, + RXY_LY = 0xe358, RXY_STCY = 0xe372, RXY_STG = 0xe324, RXY_STHY = 0xe370, @@ -108,7 +113,10 @@ typedef enum S390Opcode { RXY_STRV = 0xe33e, RXY_STRVG = 0xe32f, RXY_STRVH = 0xe33f, + RXY_STY = 0xe350, + RX_L = 0x58, + RX_LH = 0x48, RX_ST = 0x50, RX_STC = 0x42, RX_STH = 0x40, @@ -362,22 +370,52 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type, } } -/* load data without address translation or endianness conversion */ -static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg data, - TCGReg base, tcg_target_long ofs) + +/* Emit a load/store type instruction. Inputs are: + DATA: The register to be loaded or stored. + BASE+OFS: The effective address. + OPC_RX: If the operation has an RX format opcode (e.g. STC), otherwise 0. + OPC_RXY: The RXY format opcode for the operation (e.g. STCY). */ + +static void tcg_out_ldst(TCGContext *s, S390Opcode opc_rx, S390Opcode opc_rxy, + TCGReg data, TCGReg base, tcg_target_long ofs) { - S390Opcode op; + TCGReg index = 0; + + if (ofs < -0x80000 || ofs >= 0x80000) { + /* Combine the low 16 bits of the offset with the actual load insn; + the high 48 bits must come from an immediate load. */ + index = TCG_REG_R13; + tcg_out_movi(s, TCG_TYPE_PTR, index, ofs & ~0xffff); + ofs &= 0xffff; + } - op = (type == TCG_TYPE_I32) ? RXY_LLGF : RXY_LG; + if (opc_rx && ofs >= 0 && ofs < 0x1000) { + tcg_out_insn_RX(s, opc_rx, data, base, index, ofs); + } else { + tcg_out_insn_RXY(s, opc_rxy, data, base, index, ofs); + } +} - if (ofs < -0x80000 || ofs > 0x7ffff) { - /* load the displacement */ - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, ofs); - /* load the data */ - tcg_out_insn_RXY(s, op, data, base, TCG_REG_R13, 0); + +/* load data without address translation or endianness conversion */ +static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, tcg_target_long ofs) +{ + if (type == TCG_TYPE_I32) { + tcg_out_ldst(s, RX_L, RXY_LY, data, base, ofs); } else { - /* load the data */ - tcg_out_insn_RXY(s, op, data, base, 0, ofs); + tcg_out_ldst(s, 0, RXY_LG, data, base, ofs); + } +} + +static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, tcg_target_long ofs) +{ + if (type == TCG_TYPE_I32) { + tcg_out_ldst(s, RX_ST, RXY_STY, data, base, ofs); + } else { + tcg_out_ldst(s, 0, RXY_STG, data, base, ofs); } } @@ -693,28 +731,6 @@ static void tcg_out_qemu_st(TCGContext* s, const TCGArg* args, int opc) tcg_finish_qemu_ldst(s, label2_ptr); } -static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, - int arg1, tcg_target_long arg2) -{ - dprintf("tcg_out_st arg 0x%x arg1 0x%x arg2 0x%lx\n", arg, arg1, arg2); - - if (type == TCG_TYPE_I32) { - if (((long)arg2) < -0x800 || ((long)arg2) > 0x7ff) { - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, arg2); - tcg_out_insn(s, RRE, AGR, 13, arg1); - tcg_out_insn(s, RX, ST, arg, TCG_REG_R13, 0, 0); - } else { - tcg_out_insn(s, RX, ST, arg, arg1, 0, arg2); - } - } - else { - if (((long)arg2) < -0x80000 || ((long)arg2) > 0x7ffff) { - tcg_abort(); - } - tcg_out_insn(s, RXY, STG, arg, arg1, 0, arg2); - } -} - static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, const int *const_args) { @@ -780,51 +796,41 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; case INDEX_op_ld8u_i32: + tcg_out_ldst(s, 0, RXY_LLC, args[0], args[1], args[2]); + break; case INDEX_op_ld8u_i64: - if ((long)args[2] > -0x80000 && (long)args[2] < 0x7ffff) { - tcg_out_insn(s, RXY, LLGC, args[0], args[1], 0, args[2]); - } else { - /* XXX displacement too large, have to calculate address manually */ - tcg_abort(); - } + tcg_out_ldst(s, 0, RXY_LLGC, args[0], args[1], args[2]); break; case INDEX_op_ld8s_i32: - /* XXX */ - tcg_abort(); + tcg_out_ldst(s, 0, RXY_LB, args[0], args[1], args[2]); + break; + case INDEX_op_ld8s_i64: + tcg_out_ldst(s, 0, RXY_LGB, args[0], args[1], args[2]); break; case INDEX_op_ld16u_i32: - if ((long)args[2] > -0x80000 && (long)args[2] < 0x7ffff) { - tcg_out_insn(s, RXY, LLGH, args[0], args[1], 0, args[2]); - } else { - /* XXX displacement too large, have to calculate address manually */ - tcg_abort(); - } + tcg_out_ldst(s, 0, RXY_LLH, args[0], args[1], args[2]); + break; + case INDEX_op_ld16u_i64: + tcg_out_ldst(s, 0, RXY_LLGH, args[0], args[1], args[2]); break; case INDEX_op_ld16s_i32: - /* XXX */ - tcg_abort(); + tcg_out_ldst(s, RX_LH, RXY_LHY, args[0], args[1], args[2]); + break; + case INDEX_op_ld16s_i64: + tcg_out_ldst(s, 0, RXY_LGH, args[0], args[1], args[2]); break; case INDEX_op_ld_i32: - case INDEX_op_ld32u_i64: tcg_out_ld(s, TCG_TYPE_I32, args[0], args[1], args[2]); break; - + case INDEX_op_ld32u_i64: + tcg_out_ldst(s, 0, RXY_LLGF, args[0], args[1], args[2]); + break; case INDEX_op_ld32s_i64: - if (args[2] < -0x80000 || args[2] > 0x7ffff) { - /* load the displacement */ - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R13, args[2]); - /* add the address */ - tcg_out_insn(s, RRE, AGR, TCG_REG_R13, args[1]); - /* load the data (sign-extended) */ - tcg_out_insn(s, RXY, LGF, args[0], TCG_REG_R13, 0, 0); - } else { - /* load the data (sign-extended) */ - tcg_out_insn(s, RXY, LGF, args[0], args[1], 0, args[2]); - } + tcg_out_ldst(s, 0, RXY_LGF, args[0], args[1], args[2]); break; case INDEX_op_ld_i64: @@ -833,28 +839,12 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_st8_i32: case INDEX_op_st8_i64: - if (((long)args[2]) >= -0x800 && ((long)args[2]) < 0x800) { - tcg_out_insn(s, RX, STC, args[0], args[1], 0, args[2]); - } else if (((long)args[2]) >= -0x80000 && ((long)args[2]) < 0x80000) { - /* FIXME: requires long displacement facility */ - tcg_out_insn(s, RXY, STCY, args[0], args[1], 0, args[2]); - tcg_abort(); - } else { - tcg_abort(); - } + tcg_out_ldst(s, RX_STC, RXY_STCY, args[0], args[1], args[2]); break; case INDEX_op_st16_i32: case INDEX_op_st16_i64: - if (((long)args[2]) >= -0x800 && ((long)args[2]) < 0x800) { - tcg_out_insn(s, RX, STH, args[0], args[1], 0, args[2]); - } else if (((long)args[2]) >= -0x80000 && ((long)args[2]) < 0x80000) { - /* FIXME: requires long displacement facility */ - tcg_out_insn(s, RXY, STHY, args[0], args[1], 0, args[2]); - tcg_abort(); - } else { - tcg_abort(); - } + tcg_out_ldst(s, RX_STH, RXY_STHY, args[0], args[1], args[2]); break; case INDEX_op_st_i32: -- 1.7.0.1