@@ -294,6 +294,16 @@ static inline int tcg_target_const_match(tcg_target_long val,
#define ASI_PRIMARY_LITTLE 0x88
#endif
+#define LDUH_LE (LDUHA | INSN_ASI(ASI_PRIMARY_LITTLE))
+#define LDSH_LE (LDSHA | INSN_ASI(ASI_PRIMARY_LITTLE))
+#define LDUW_LE (LDUWA | INSN_ASI(ASI_PRIMARY_LITTLE))
+#define LDSW_LE (LDSWA | INSN_ASI(ASI_PRIMARY_LITTLE))
+#define LDX_LE (LDXA | INSN_ASI(ASI_PRIMARY_LITTLE))
+
+#define STH_LE (STHA | INSN_ASI(ASI_PRIMARY_LITTLE))
+#define STW_LE (STWA | INSN_ASI(ASI_PRIMARY_LITTLE))
+#define STX_LE (STXA | INSN_ASI(ASI_PRIMARY_LITTLE))
+
static inline void tcg_out_arith(TCGContext *s, int rd, int rs1, int rs2,
int op)
{
@@ -366,66 +376,46 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type,
}
}
-static inline void tcg_out_ld_raw(TCGContext *s, int ret,
- tcg_target_long arg)
+static inline void tcg_out_ldst_rr(TCGContext *s, int data, int a1,
+ int a2, int op)
{
- tcg_out_sethi(s, ret, arg);
- tcg_out32(s, LDUW | INSN_RD(ret) | INSN_RS1(ret) |
- INSN_IMM13(arg & 0x3ff));
+ tcg_out32(s, op | INSN_RD(data) | INSN_RS1(a1) | INSN_RS2(a2));
}
-static inline void tcg_out_ld_ptr(TCGContext *s, int ret,
- tcg_target_long arg)
+static inline void tcg_out_ldst(TCGContext *s, int ret, int addr,
+ int offset, int op)
{
- if (!check_fit_tl(arg, 10))
- tcg_out_movi(s, TCG_TYPE_PTR, ret, arg & ~0x3ffULL);
- if (TCG_TARGET_REG_BITS == 64) {
- tcg_out32(s, LDX | INSN_RD(ret) | INSN_RS1(ret) |
- INSN_IMM13(arg & 0x3ff));
- } else {
- tcg_out32(s, LDUW | INSN_RD(ret) | INSN_RS1(ret) |
- INSN_IMM13(arg & 0x3ff));
- }
-}
-
-static inline void tcg_out_ldst(TCGContext *s, int ret, int addr, int offset, int op)
-{
- if (check_fit_tl(offset, 13))
+ if (check_fit_tl(offset, 13)) {
tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(addr) |
INSN_IMM13(offset));
- else {
+ } else {
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, offset);
- tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(TCG_REG_I5) |
- INSN_RS2(addr));
+ tcg_out_ldst_rr(s, ret, addr, TCG_REG_I5, op);
}
}
-static inline void tcg_out_ldst_asi(TCGContext *s, int ret, int addr,
- int offset, int op, int asi)
-{
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, offset);
- tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(TCG_REG_I5) |
- INSN_ASI(asi) | INSN_RS2(addr));
-}
-
static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret,
TCGReg arg1, tcg_target_long arg2)
{
- if (type == TCG_TYPE_I32)
- tcg_out_ldst(s, ret, arg1, arg2, LDUW);
- else
- tcg_out_ldst(s, ret, arg1, arg2, LDX);
+ tcg_out_ldst(s, ret, arg1, arg2, (type == TCG_TYPE_I32 ? LDUW : LDX));
}
static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
TCGReg arg1, tcg_target_long arg2)
{
- if (type == TCG_TYPE_I32)
- tcg_out_ldst(s, arg, arg1, arg2, STW);
- else
- tcg_out_ldst(s, arg, arg1, arg2, STX);
+ tcg_out_ldst(s, arg, arg1, arg2, (type == TCG_TYPE_I32 ? STW : STX));
}
+static inline void tcg_out_ld_ptr(TCGContext *s, int ret,
+ tcg_target_long arg)
+{
+ if (!check_fit_tl(arg, 10)) {
+ tcg_out_movi(s, TCG_TYPE_PTR, ret, arg & ~0x3ff);
+ }
+ tcg_out_ld(s, TCG_TYPE_PTR, ret, ret, arg & 0x3ff);
+}
+
+
static inline void tcg_out_sety(TCGContext *s, int rs)
{
tcg_out32(s, WRY | INSN_RS1(TCG_REG_G0) | INSN_RS2(rs));
@@ -833,76 +823,26 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, int addr, int datalo,
int datahi, int sizeop)
{
#ifdef TARGET_WORDS_BIGENDIAN
- const int bigendian = 1;
+ static const int ld_opc[8] = {
+ LDUB, LDUH, LDUW, LDX, LDSB, LDSH, LDSW, LDX
+ };
#else
- const int bigendian = 0;
+ static const int ld_opc[8] = {
+ LDUB, LDUH_LE, LDUW_LE, LDX_LE, LDSB, LDSH_LE, LDSW_LE, LDX_LE
+ };
#endif
- switch (sizeop) {
- case 0:
- /* ldub [addr], datalo */
- tcg_out_ldst(s, datalo, addr, 0, LDUB);
- break;
- case 0 | 4:
- /* ldsb [addr], datalo */
- tcg_out_ldst(s, datalo, addr, 0, LDSB);
- break;
- case 1:
- if (bigendian) {
- /* lduh [addr], datalo */
- tcg_out_ldst(s, datalo, addr, 0, LDUH);
- } else {
- /* lduha [addr] ASI_PRIMARY_LITTLE, datalo */
- tcg_out_ldst_asi(s, datalo, addr, 0, LDUHA, ASI_PRIMARY_LITTLE);
- }
- break;
- case 1 | 4:
- if (bigendian) {
- /* ldsh [addr], datalo */
- tcg_out_ldst(s, datalo, addr, 0, LDSH);
- } else {
- /* ldsha [addr] ASI_PRIMARY_LITTLE, datalo */
- tcg_out_ldst_asi(s, datalo, addr, 0, LDSHA, ASI_PRIMARY_LITTLE);
- }
- break;
- case 2:
- if (bigendian) {
- /* lduw [addr], datalo */
- tcg_out_ldst(s, datalo, addr, 0, LDUW);
- } else {
- /* lduwa [addr] ASI_PRIMARY_LITTLE, datalo */
- tcg_out_ldst_asi(s, datalo, addr, 0, LDUWA, ASI_PRIMARY_LITTLE);
- }
- break;
- case 2 | 4:
- if (bigendian) {
- /* ldsw [addr], datalo */
- tcg_out_ldst(s, datalo, addr, 0, LDSW);
- } else {
- /* ldswa [addr] ASI_PRIMARY_LITTLE, datalo */
- tcg_out_ldst_asi(s, datalo, addr, 0, LDSWA, ASI_PRIMARY_LITTLE);
- }
- break;
- case 3:
- if (TCG_TARGET_REG_BITS == 64) {
- if (bigendian) {
- /* ldx [addr], datalo */
- tcg_out_ldst(s, datalo, addr, 0, LDX);
- } else {
- /* ldxa [addr] ASI_PRIMARY_LITTLE, datalo */
- tcg_out_ldst_asi(s, datalo, addr, 0, LDXA, ASI_PRIMARY_LITTLE);
- }
- } else {
- if (bigendian) {
- tcg_out_ldst(s, datahi, addr, 0, LDUW);
- tcg_out_ldst(s, datalo, addr, 4, LDUW);
- } else {
- tcg_out_ldst_asi(s, datalo, addr, 0, LDUWA, ASI_PRIMARY_LITTLE);
- tcg_out_ldst_asi(s, datahi, addr, 4, LDUWA, ASI_PRIMARY_LITTLE);
- }
+
+ if (TCG_TARGET_REG_BITS == 32 && sizeop == 3) {
+ /* Load all 64-bits into an O/G register. */
+ int reg64 = (datalo < 16 ? datalo : TCG_REG_O0);
+ tcg_out_ldst_rr(s, reg64, addr, TCG_REG_G0, ld_opc[sizeop]);
+ /* Move the two 32-bit pieces into the destination registers. */
+ tcg_out_arithi(s, datahi, reg64, 32, SHIFT_SRLX);
+ if (reg64 != datalo) {
+ tcg_out_mov(s, TCG_TYPE_I32, datalo, reg64);
}
- break;
- default:
- tcg_abort();
+ } else {
+ tcg_out_ldst_rr(s, datalo, addr, TCG_REG_G0, ld_opc[sizeop]);
}
}
@@ -1016,55 +956,18 @@ static void tcg_out_qemu_st_direct(TCGContext *s, int addr, int datalo,
int datahi, int sizeop)
{
#ifdef TARGET_WORDS_BIGENDIAN
- const int bigendian = 1;
+ static const int st_opc[4] = { STB, STH, STW, STX };
#else
- const int bigendian = 0;
+ static const int st_opc[4] = { STB, STH_LE, STW_LE, STX_LE };
#endif
- switch (sizeop) {
- case 0:
- /* stb datalo, [addr] */
- tcg_out_ldst(s, datalo, addr, 0, STB);
- break;
- case 1:
- if (bigendian) {
- /* sth datalo, [addr] */
- tcg_out_ldst(s, datalo, addr, 0, STH);
- } else {
- /* stha datalo, [addr] ASI_PRIMARY_LITTLE */
- tcg_out_ldst_asi(s, datalo, addr, 0, STHA, ASI_PRIMARY_LITTLE);
- }
- break;
- case 2:
- if (bigendian) {
- /* stw datalo, [addr] */
- tcg_out_ldst(s, datalo, addr, 0, STW);
- } else {
- /* stwa datalo, [addr] ASI_PRIMARY_LITTLE */
- tcg_out_ldst_asi(s, datalo, addr, 0, STWA, ASI_PRIMARY_LITTLE);
- }
- break;
- case 3:
- if (TCG_TARGET_REG_BITS == 64) {
- if (bigendian) {
- /* stx datalo, [addr] */
- tcg_out_ldst(s, datalo, addr, 0, STX);
- } else {
- /* stxa datalo, [addr] ASI_PRIMARY_LITTLE */
- tcg_out_ldst_asi(s, datalo, addr, 0, STXA, ASI_PRIMARY_LITTLE);
- }
- } else {
- if (bigendian) {
- tcg_out_ldst(s, datahi, addr, 0, STW);
- tcg_out_ldst(s, datalo, addr, 4, STW);
- } else {
- tcg_out_ldst_asi(s, datalo, addr, 0, STWA, ASI_PRIMARY_LITTLE);
- tcg_out_ldst_asi(s, datahi, addr, 4, STWA, ASI_PRIMARY_LITTLE);
- }
- }
- break;
- default:
- tcg_abort();
+
+ if (TCG_TARGET_REG_BITS == 32 && sizeop == 3) {
+ tcg_out_arithi(s, TCG_REG_O0, datalo, 0, SHIFT_SRL);
+ tcg_out_arithi(s, TCG_REG_O2, datahi, 32, SHIFT_SLLX);
+ tcg_out_arith(s, TCG_REG_O0, TCG_REG_O0, TCG_REG_O2, ARITH_OR);
+ datalo = TCG_REG_O0;
}
+ tcg_out_ldst_rr(s, datalo, addr, TCG_REG_G0, st_opc[sizeop]);
}
static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
Given that we have an opcode for all sizes, all endianness, turn the functions into a simple table lookup. Signed-off-by: Richard Henderson <rth@twiddle.net> --- tcg/sparc/tcg-target.c | 209 +++++++++++++----------------------------------- 1 files changed, 56 insertions(+), 153 deletions(-)