@@ -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:
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 <rth@twiddle.net> --- tcg/s390/tcg-target.c | 152 +++++++++++++++++++++++-------------------------- 1 files changed, 71 insertions(+), 81 deletions(-)