tcg/mips:
- Constant formation improvements - Replace MIPS_BE with HOST_BIG_ENDIAN - General cleanups tcg/riscv: - Improve setcond - Support movcond - Support Zbb, Zba -----BEGIN PGP SIGNATURE----- iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmRvo9kdHHJpY2hhcmQu aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV/ECwf/eQSKdXsppLfgH1zj 1VYOfSHB7kKacm5s9de6n0n0aT5DdBYGT1VkYqczMyanpYrK5jHIyzxYIcxa2KjN /pMRKALUTq1Aku1wvovpybUT9Qt38+6jHw0U9inj11NJIYX4bheVJon3gztOUBRp O67Z22RdfBBu+jL6VD00AE8OhCfeU7CZ+Bj9oNRKYCxXyr1ASla9gfTDy8UG+h2k WqNti04xmgXqOZ+pEQ+ZyOCzhCHNLm8XBCtFjWXBe30ibX1PwWdSXqkuUtddd5nJ MEbzQV42RCk1CNRrFz0RoAJhpcOEiSeDcI3Vx/PN8xS5mIS2jaWqW+5sMyCcI54h JcfcUg== =GI+F -----END PGP SIGNATURE----- Merge tag 'pull-tcg-20230525' of https://gitlab.com/rth7680/qemu into staging tcg/mips: - Constant formation improvements - Replace MIPS_BE with HOST_BIG_ENDIAN - General cleanups tcg/riscv: - Improve setcond - Support movcond - Support Zbb, Zba # -----BEGIN PGP SIGNATURE----- # # iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmRvo9kdHHJpY2hhcmQu # aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV/ECwf/eQSKdXsppLfgH1zj # 1VYOfSHB7kKacm5s9de6n0n0aT5DdBYGT1VkYqczMyanpYrK5jHIyzxYIcxa2KjN # /pMRKALUTq1Aku1wvovpybUT9Qt38+6jHw0U9inj11NJIYX4bheVJon3gztOUBRp # O67Z22RdfBBu+jL6VD00AE8OhCfeU7CZ+Bj9oNRKYCxXyr1ASla9gfTDy8UG+h2k # WqNti04xmgXqOZ+pEQ+ZyOCzhCHNLm8XBCtFjWXBe30ibX1PwWdSXqkuUtddd5nJ # MEbzQV42RCk1CNRrFz0RoAJhpcOEiSeDcI3Vx/PN8xS5mIS2jaWqW+5sMyCcI54h # JcfcUg== # =GI+F # -----END PGP SIGNATURE----- # gpg: Signature made Thu 25 May 2023 11:07:21 AM PDT # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [ultimate] * tag 'pull-tcg-20230525' of https://gitlab.com/rth7680/qemu: (23 commits) tcg/riscv: Support CTZ, CLZ from Zbb tcg/riscv: Implement movcond tcg/riscv: Improve setcond expansion tcg/riscv: Support CPOP from Zbb tcg/riscv: Support REV8 from Zbb tcg/riscv: Support rotates from Zbb tcg/riscv: Use ADD.UW for guest address generation tcg/riscv: Support ADD.UW, SEXT.B, SEXT.H, ZEXT.H from Zba+Zbb tcg/riscv: Support ANDN, ORN, XNOR from Zbb tcg/riscv: Probe for Zba, Zbb, Zicond extensions disas/riscv: Decode czero.{eqz,nez} tcg/mips: Replace MIPS_BE with HOST_BIG_ENDIAN tcg/mips: Use qemu_build_not_reached for LO/HI_OFF tcg/mips: Try three insns with shift and add in tcg_out_movi tcg/mips: Try tb-relative addresses in tcg_out_movi tcg/mips: Aggressively use the constant pool for n64 calls tcg/mips: Use the constant pool for 64-bit constants tcg/mips: Split out tcg_out_movi_two tcg/mips: Split out tcg_out_movi_one tcg/mips: Create and use TCG_REG_TB ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
a3cb6d5004
@ -962,6 +962,8 @@ typedef enum {
|
||||
rv_op_cm_mvsa01 = 786,
|
||||
rv_op_cm_jt = 787,
|
||||
rv_op_cm_jalt = 788,
|
||||
rv_op_czero_eqz = 789,
|
||||
rv_op_czero_nez = 790,
|
||||
} rv_op;
|
||||
|
||||
/* structures */
|
||||
@ -2119,6 +2121,8 @@ const rv_opcode_data opcode_data[] = {
|
||||
{ "cm.mvsa01", rv_codec_zcmp_cm_mv, rv_fmt_rd_rs2, NULL, 0, 0, 0 },
|
||||
{ "cm.jt", rv_codec_zcmt_jt, rv_fmt_zcmt_index, NULL, 0 },
|
||||
{ "cm.jalt", rv_codec_zcmt_jt, rv_fmt_zcmt_index, NULL, 0 },
|
||||
{ "czero.eqz", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||
{ "czero.nez", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||
};
|
||||
|
||||
/* CSR names */
|
||||
@ -2914,6 +2918,8 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
||||
case 45: op = rv_op_minu; break;
|
||||
case 46: op = rv_op_max; break;
|
||||
case 47: op = rv_op_maxu; break;
|
||||
case 075: op = rv_op_czero_eqz; break;
|
||||
case 077: op = rv_op_czero_nez; break;
|
||||
case 130: op = rv_op_sh1add; break;
|
||||
case 132: op = rv_op_sh2add; break;
|
||||
case 134: op = rv_op_sh3add; break;
|
||||
|
@ -25,22 +25,15 @@
|
||||
*/
|
||||
|
||||
#include "../tcg-ldst.c.inc"
|
||||
|
||||
#if HOST_BIG_ENDIAN
|
||||
# define MIPS_BE 1
|
||||
#else
|
||||
# define MIPS_BE 0
|
||||
#endif
|
||||
#include "../tcg-pool.c.inc"
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 32
|
||||
# define LO_OFF (MIPS_BE * 4)
|
||||
# define LO_OFF (HOST_BIG_ENDIAN * 4)
|
||||
# define HI_OFF (4 - LO_OFF)
|
||||
#else
|
||||
/* To assert at compile-time that these values are never used
|
||||
for TCG_TARGET_REG_BITS == 64. */
|
||||
int link_error(void);
|
||||
# define LO_OFF link_error()
|
||||
# define HI_OFF link_error()
|
||||
/* Assert at compile-time that these values are never used for 64-bit. */
|
||||
# define LO_OFF ({ qemu_build_not_reached(); 0; })
|
||||
# define HI_OFF ({ qemu_build_not_reached(); 0; })
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_TCG
|
||||
@ -86,7 +79,12 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
|
||||
#define TCG_TMP3 TCG_REG_T7
|
||||
|
||||
#ifndef CONFIG_SOFTMMU
|
||||
#define TCG_GUEST_BASE_REG TCG_REG_S1
|
||||
#define TCG_GUEST_BASE_REG TCG_REG_S7
|
||||
#endif
|
||||
#if TCG_TARGET_REG_BITS == 64
|
||||
#define TCG_REG_TB TCG_REG_S6
|
||||
#else
|
||||
#define TCG_REG_TB (qemu_build_not_reached(), TCG_REG_ZERO)
|
||||
#endif
|
||||
|
||||
/* check if we really need so many registers :P */
|
||||
@ -163,9 +161,18 @@ static bool reloc_pc16(tcg_insn_unit *src_rw, const tcg_insn_unit *target)
|
||||
static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
|
||||
intptr_t value, intptr_t addend)
|
||||
{
|
||||
tcg_debug_assert(type == R_MIPS_PC16);
|
||||
tcg_debug_assert(addend == 0);
|
||||
return reloc_pc16(code_ptr, (const tcg_insn_unit *)value);
|
||||
value += addend;
|
||||
switch (type) {
|
||||
case R_MIPS_PC16:
|
||||
return reloc_pc16(code_ptr, (const tcg_insn_unit *)value);
|
||||
case R_MIPS_16:
|
||||
if (value != (int16_t)value) {
|
||||
return false;
|
||||
}
|
||||
*code_ptr = deposit32(*code_ptr, 0, 16, value);
|
||||
return true;
|
||||
}
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
#define TCG_CT_CONST_ZERO 0x100
|
||||
@ -481,6 +488,11 @@ static void tcg_out_nop(TCGContext *s)
|
||||
tcg_out32(s, 0);
|
||||
}
|
||||
|
||||
static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
|
||||
{
|
||||
memset(p, 0, count * sizeof(tcg_insn_unit));
|
||||
}
|
||||
|
||||
static void tcg_out_dsll(TCGContext *s, TCGReg rd, TCGReg rt, TCGArg sa)
|
||||
{
|
||||
tcg_out_opc_sa64(s, OPC_DSLL, OPC_DSLL32, rd, rt, sa);
|
||||
@ -505,35 +517,125 @@ static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void tcg_out_movi(TCGContext *s, TCGType type,
|
||||
TCGReg ret, tcg_target_long arg)
|
||||
static bool tcg_out_movi_one(TCGContext *s, TCGReg ret, tcg_target_long arg)
|
||||
{
|
||||
if (TCG_TARGET_REG_BITS == 64 && type == TCG_TYPE_I32) {
|
||||
arg = (int32_t)arg;
|
||||
}
|
||||
if (arg == (int16_t)arg) {
|
||||
tcg_out_opc_imm(s, OPC_ADDIU, ret, TCG_REG_ZERO, arg);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
if (arg == (uint16_t)arg) {
|
||||
tcg_out_opc_imm(s, OPC_ORI, ret, TCG_REG_ZERO, arg);
|
||||
return true;
|
||||
}
|
||||
if (arg == (int32_t)arg && (arg & 0xffff) == 0) {
|
||||
tcg_out_opc_imm(s, OPC_LUI, ret, TCG_REG_ZERO, arg >> 16);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool tcg_out_movi_two(TCGContext *s, TCGReg ret, tcg_target_long arg)
|
||||
{
|
||||
/*
|
||||
* All signed 32-bit constants are loadable with two immediates,
|
||||
* and everything else requires more work.
|
||||
*/
|
||||
if (arg == (int32_t)arg) {
|
||||
if (!tcg_out_movi_one(s, ret, arg)) {
|
||||
tcg_out_opc_imm(s, OPC_LUI, ret, TCG_REG_ZERO, arg >> 16);
|
||||
tcg_out_opc_imm(s, OPC_ORI, ret, ret, arg & 0xffff);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void tcg_out_movi_pool(TCGContext *s, TCGReg ret,
|
||||
tcg_target_long arg, TCGReg tbreg)
|
||||
{
|
||||
new_pool_label(s, arg, R_MIPS_16, s->code_ptr, tcg_tbrel_diff(s, NULL));
|
||||
tcg_out_opc_imm(s, OPC_LD, ret, tbreg, 0);
|
||||
}
|
||||
|
||||
static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret,
|
||||
tcg_target_long arg, TCGReg tbreg)
|
||||
{
|
||||
tcg_target_long tmp;
|
||||
int sh, lo;
|
||||
|
||||
if (TCG_TARGET_REG_BITS == 64 && type == TCG_TYPE_I32) {
|
||||
arg = (int32_t)arg;
|
||||
}
|
||||
|
||||
/* Load all 32-bit constants. */
|
||||
if (tcg_out_movi_two(s, ret, arg)) {
|
||||
return;
|
||||
}
|
||||
if (TCG_TARGET_REG_BITS == 32 || arg == (int32_t)arg) {
|
||||
tcg_out_opc_imm(s, OPC_LUI, ret, TCG_REG_ZERO, arg >> 16);
|
||||
} else {
|
||||
tcg_out_movi(s, TCG_TYPE_I32, ret, arg >> 31 >> 1);
|
||||
if (arg & 0xffff0000ull) {
|
||||
tcg_out_dsll(s, ret, ret, 16);
|
||||
tcg_out_opc_imm(s, OPC_ORI, ret, ret, arg >> 16);
|
||||
tcg_out_dsll(s, ret, ret, 16);
|
||||
} else {
|
||||
tcg_out_dsll(s, ret, ret, 32);
|
||||
assert(TCG_TARGET_REG_BITS == 64);
|
||||
|
||||
/* Load addresses within 2GB of TB with 1 or 3 insns. */
|
||||
tmp = tcg_tbrel_diff(s, (void *)arg);
|
||||
if (tmp == (int16_t)tmp) {
|
||||
tcg_out_opc_imm(s, OPC_DADDIU, ret, tbreg, tmp);
|
||||
return;
|
||||
}
|
||||
if (tcg_out_movi_two(s, ret, tmp)) {
|
||||
tcg_out_opc_reg(s, OPC_DADDU, ret, ret, tbreg);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load bitmasks with a right-shift. This is good for things
|
||||
* like 0x0fff_ffff_ffff_fff0: ADDUI r,0,0xff00 + DSRL r,r,4.
|
||||
* or similarly using LUI. For this to work, bit 31 must be set.
|
||||
*/
|
||||
if (arg > 0 && (int32_t)arg < 0) {
|
||||
sh = clz64(arg);
|
||||
if (tcg_out_movi_one(s, ret, arg << sh)) {
|
||||
tcg_out_dsrl(s, ret, ret, sh);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (arg & 0xffff) {
|
||||
tcg_out_opc_imm(s, OPC_ORI, ret, ret, arg & 0xffff);
|
||||
|
||||
/*
|
||||
* Load slightly larger constants using left-shift.
|
||||
* Limit this sequence to 3 insns to avoid too much expansion.
|
||||
*/
|
||||
sh = ctz64(arg);
|
||||
if (sh && tcg_out_movi_two(s, ret, arg >> sh)) {
|
||||
tcg_out_dsll(s, ret, ret, sh);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load slightly larger constants using left-shift and add/or.
|
||||
* Prefer addi with a negative immediate when that would produce
|
||||
* a larger shift. For this to work, bits 15 and 16 must be set.
|
||||
*/
|
||||
lo = arg & 0xffff;
|
||||
if (lo) {
|
||||
if ((arg & 0x18000) == 0x18000) {
|
||||
lo = (int16_t)arg;
|
||||
}
|
||||
tmp = arg - lo;
|
||||
sh = ctz64(tmp);
|
||||
tmp >>= sh;
|
||||
if (tcg_out_movi_one(s, ret, tmp)) {
|
||||
tcg_out_dsll(s, ret, ret, sh);
|
||||
tcg_out_opc_imm(s, lo < 0 ? OPC_DADDIU : OPC_ORI, ret, ret, lo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, put 64-bit constants into the constant pool. */
|
||||
tcg_out_movi_pool(s, ret, arg, tbreg);
|
||||
}
|
||||
|
||||
static void tcg_out_movi(TCGContext *s, TCGType type,
|
||||
TCGReg ret, tcg_target_long arg)
|
||||
{
|
||||
TCGReg tbreg = TCG_TARGET_REG_BITS == 64 ? TCG_REG_TB : 0;
|
||||
tcg_out_movi_int(s, type, ret, arg, tbreg);
|
||||
}
|
||||
|
||||
static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg rd, TCGReg rs)
|
||||
@ -1048,9 +1150,19 @@ static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret,
|
||||
|
||||
static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail)
|
||||
{
|
||||
/* Note that the ABI requires the called function's address to be
|
||||
loaded into T9, even if a direct branch is in range. */
|
||||
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T9, (uintptr_t)arg);
|
||||
/*
|
||||
* Note that __mips_abicalls requires the called function's address
|
||||
* to be loaded into $25 (t9), even if a direct branch is in range.
|
||||
*
|
||||
* For n64, always drop the pointer into the constant pool.
|
||||
* We can re-use helper addresses often and do not want any
|
||||
* of the longer sequences tcg_out_movi may try.
|
||||
*/
|
||||
if (sizeof(uintptr_t) == 8) {
|
||||
tcg_out_movi_pool(s, TCG_REG_T9, (uintptr_t)arg, TCG_REG_TB);
|
||||
} else {
|
||||
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T9, (uintptr_t)arg);
|
||||
}
|
||||
|
||||
/* But do try a direct branch, allowing the cpu better insn prefetch. */
|
||||
if (tail) {
|
||||
@ -1321,7 +1433,7 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg lo, TCGReg hi,
|
||||
/* Prefer to load from offset 0 first, but allow for overlap. */
|
||||
if (TCG_TARGET_REG_BITS == 64) {
|
||||
tcg_out_opc_imm(s, OPC_LD, lo, base, 0);
|
||||
} else if (MIPS_BE ? hi != base : lo == base) {
|
||||
} else if (HOST_BIG_ENDIAN ? hi != base : lo == base) {
|
||||
tcg_out_opc_imm(s, OPC_LW, hi, base, HI_OFF);
|
||||
tcg_out_opc_imm(s, OPC_LW, lo, base, LO_OFF);
|
||||
} else {
|
||||
@ -1337,10 +1449,10 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg lo, TCGReg hi,
|
||||
static void tcg_out_qemu_ld_unalign(TCGContext *s, TCGReg lo, TCGReg hi,
|
||||
TCGReg base, MemOp opc, TCGType type)
|
||||
{
|
||||
const MIPSInsn lw1 = MIPS_BE ? OPC_LWL : OPC_LWR;
|
||||
const MIPSInsn lw2 = MIPS_BE ? OPC_LWR : OPC_LWL;
|
||||
const MIPSInsn ld1 = MIPS_BE ? OPC_LDL : OPC_LDR;
|
||||
const MIPSInsn ld2 = MIPS_BE ? OPC_LDR : OPC_LDL;
|
||||
const MIPSInsn lw1 = HOST_BIG_ENDIAN ? OPC_LWL : OPC_LWR;
|
||||
const MIPSInsn lw2 = HOST_BIG_ENDIAN ? OPC_LWR : OPC_LWL;
|
||||
const MIPSInsn ld1 = HOST_BIG_ENDIAN ? OPC_LDL : OPC_LDR;
|
||||
const MIPSInsn ld2 = HOST_BIG_ENDIAN ? OPC_LDR : OPC_LDL;
|
||||
bool sgn = opc & MO_SIGN;
|
||||
|
||||
switch (opc & MO_SIZE) {
|
||||
@ -1379,10 +1491,10 @@ static void tcg_out_qemu_ld_unalign(TCGContext *s, TCGReg lo, TCGReg hi,
|
||||
tcg_out_opc_imm(s, ld1, lo, base, 0);
|
||||
tcg_out_opc_imm(s, ld2, lo, base, 7);
|
||||
} else {
|
||||
tcg_out_opc_imm(s, lw1, MIPS_BE ? hi : lo, base, 0 + 0);
|
||||
tcg_out_opc_imm(s, lw2, MIPS_BE ? hi : lo, base, 0 + 3);
|
||||
tcg_out_opc_imm(s, lw1, MIPS_BE ? lo : hi, base, 4 + 0);
|
||||
tcg_out_opc_imm(s, lw2, MIPS_BE ? lo : hi, base, 4 + 3);
|
||||
tcg_out_opc_imm(s, lw1, HOST_BIG_ENDIAN ? hi : lo, base, 0 + 0);
|
||||
tcg_out_opc_imm(s, lw2, HOST_BIG_ENDIAN ? hi : lo, base, 0 + 3);
|
||||
tcg_out_opc_imm(s, lw1, HOST_BIG_ENDIAN ? lo : hi, base, 4 + 0);
|
||||
tcg_out_opc_imm(s, lw2, HOST_BIG_ENDIAN ? lo : hi, base, 4 + 3);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1432,8 +1544,8 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg lo, TCGReg hi,
|
||||
if (TCG_TARGET_REG_BITS == 64) {
|
||||
tcg_out_opc_imm(s, OPC_SD, lo, base, 0);
|
||||
} else {
|
||||
tcg_out_opc_imm(s, OPC_SW, MIPS_BE ? hi : lo, base, 0);
|
||||
tcg_out_opc_imm(s, OPC_SW, MIPS_BE ? lo : hi, base, 4);
|
||||
tcg_out_opc_imm(s, OPC_SW, HOST_BIG_ENDIAN ? hi : lo, base, 0);
|
||||
tcg_out_opc_imm(s, OPC_SW, HOST_BIG_ENDIAN ? lo : hi, base, 4);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -1444,10 +1556,10 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg lo, TCGReg hi,
|
||||
static void tcg_out_qemu_st_unalign(TCGContext *s, TCGReg lo, TCGReg hi,
|
||||
TCGReg base, MemOp opc)
|
||||
{
|
||||
const MIPSInsn sw1 = MIPS_BE ? OPC_SWL : OPC_SWR;
|
||||
const MIPSInsn sw2 = MIPS_BE ? OPC_SWR : OPC_SWL;
|
||||
const MIPSInsn sd1 = MIPS_BE ? OPC_SDL : OPC_SDR;
|
||||
const MIPSInsn sd2 = MIPS_BE ? OPC_SDR : OPC_SDL;
|
||||
const MIPSInsn sw1 = HOST_BIG_ENDIAN ? OPC_SWL : OPC_SWR;
|
||||
const MIPSInsn sw2 = HOST_BIG_ENDIAN ? OPC_SWR : OPC_SWL;
|
||||
const MIPSInsn sd1 = HOST_BIG_ENDIAN ? OPC_SDL : OPC_SDR;
|
||||
const MIPSInsn sd2 = HOST_BIG_ENDIAN ? OPC_SDR : OPC_SDL;
|
||||
|
||||
switch (opc & MO_SIZE) {
|
||||
case MO_16:
|
||||
@ -1466,10 +1578,10 @@ static void tcg_out_qemu_st_unalign(TCGContext *s, TCGReg lo, TCGReg hi,
|
||||
tcg_out_opc_imm(s, sd1, lo, base, 0);
|
||||
tcg_out_opc_imm(s, sd2, lo, base, 7);
|
||||
} else {
|
||||
tcg_out_opc_imm(s, sw1, MIPS_BE ? hi : lo, base, 0 + 0);
|
||||
tcg_out_opc_imm(s, sw2, MIPS_BE ? hi : lo, base, 0 + 3);
|
||||
tcg_out_opc_imm(s, sw1, MIPS_BE ? lo : hi, base, 4 + 0);
|
||||
tcg_out_opc_imm(s, sw2, MIPS_BE ? lo : hi, base, 4 + 3);
|
||||
tcg_out_opc_imm(s, sw1, HOST_BIG_ENDIAN ? hi : lo, base, 0 + 0);
|
||||
tcg_out_opc_imm(s, sw2, HOST_BIG_ENDIAN ? hi : lo, base, 0 + 3);
|
||||
tcg_out_opc_imm(s, sw1, HOST_BIG_ENDIAN ? lo : hi, base, 4 + 0);
|
||||
tcg_out_opc_imm(s, sw2, HOST_BIG_ENDIAN ? lo : hi, base, 4 + 3);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1547,27 +1659,61 @@ static void tcg_out_clz(TCGContext *s, MIPSInsn opcv2, MIPSInsn opcv6,
|
||||
|
||||
static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0)
|
||||
{
|
||||
TCGReg b0 = TCG_REG_ZERO;
|
||||
TCGReg base = TCG_REG_ZERO;
|
||||
int16_t lo = 0;
|
||||
|
||||
if (a0 & ~0xffff) {
|
||||
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_V0, a0 & ~0xffff);
|
||||
b0 = TCG_REG_V0;
|
||||
if (a0) {
|
||||
intptr_t ofs;
|
||||
if (TCG_TARGET_REG_BITS == 64) {
|
||||
ofs = tcg_tbrel_diff(s, (void *)a0);
|
||||
lo = ofs;
|
||||
if (ofs == lo) {
|
||||
base = TCG_REG_TB;
|
||||
} else {
|
||||
base = TCG_REG_V0;
|
||||
tcg_out_movi(s, TCG_TYPE_PTR, base, ofs - lo);
|
||||
tcg_out_opc_reg(s, ALIAS_PADD, base, base, TCG_REG_TB);
|
||||
}
|
||||
} else {
|
||||
ofs = a0;
|
||||
lo = ofs;
|
||||
base = TCG_REG_V0;
|
||||
tcg_out_movi(s, TCG_TYPE_PTR, base, ofs - lo);
|
||||
}
|
||||
}
|
||||
if (!tcg_out_opc_jmp(s, OPC_J, tb_ret_addr)) {
|
||||
tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, (uintptr_t)tb_ret_addr);
|
||||
tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0);
|
||||
}
|
||||
tcg_out_opc_imm(s, OPC_ORI, TCG_REG_V0, b0, a0 & 0xffff);
|
||||
/* delay slot */
|
||||
tcg_out_opc_imm(s, ALIAS_PADDI, TCG_REG_V0, base, lo);
|
||||
}
|
||||
|
||||
static void tcg_out_goto_tb(TCGContext *s, int which)
|
||||
{
|
||||
intptr_t ofs = get_jmp_target_addr(s, which);
|
||||
TCGReg base, dest;
|
||||
|
||||
/* indirect jump method */
|
||||
tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_REG_ZERO,
|
||||
get_jmp_target_addr(s, which));
|
||||
tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0);
|
||||
if (TCG_TARGET_REG_BITS == 64) {
|
||||
dest = TCG_REG_TB;
|
||||
base = TCG_REG_TB;
|
||||
ofs = tcg_tbrel_diff(s, (void *)ofs);
|
||||
} else {
|
||||
dest = TCG_TMP0;
|
||||
base = TCG_REG_ZERO;
|
||||
}
|
||||
tcg_out_ld(s, TCG_TYPE_PTR, dest, base, ofs);
|
||||
tcg_out_opc_reg(s, OPC_JR, 0, dest, 0);
|
||||
/* delay slot */
|
||||
tcg_out_nop(s);
|
||||
|
||||
set_jmp_reset_offset(s, which);
|
||||
if (TCG_TARGET_REG_BITS == 64) {
|
||||
/* For the unlinked case, need to reset TCG_REG_TB. */
|
||||
tcg_out_ldst(s, ALIAS_PADDI, TCG_REG_TB, TCG_REG_TB,
|
||||
-tcg_current_code_size(s));
|
||||
}
|
||||
}
|
||||
|
||||
void tb_target_set_jmp_target(const TranslationBlock *tb, int n,
|
||||
@ -1598,7 +1744,11 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
||||
case INDEX_op_goto_ptr:
|
||||
/* jmp to the given host address (could be epilogue) */
|
||||
tcg_out_opc_reg(s, OPC_JR, 0, a0, 0);
|
||||
tcg_out_nop(s);
|
||||
if (TCG_TARGET_REG_BITS == 64) {
|
||||
tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_TB, a0);
|
||||
} else {
|
||||
tcg_out_nop(s);
|
||||
}
|
||||
break;
|
||||
case INDEX_op_br:
|
||||
tcg_out_brcond(s, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO,
|
||||
@ -2183,15 +2333,15 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
|
||||
}
|
||||
|
||||
static const int tcg_target_callee_save_regs[] = {
|
||||
TCG_REG_S0, /* used for the global env (TCG_AREG0) */
|
||||
TCG_REG_S0,
|
||||
TCG_REG_S1,
|
||||
TCG_REG_S2,
|
||||
TCG_REG_S3,
|
||||
TCG_REG_S4,
|
||||
TCG_REG_S5,
|
||||
TCG_REG_S6,
|
||||
TCG_REG_S7,
|
||||
TCG_REG_S8,
|
||||
TCG_REG_S6, /* used for the tb base (TCG_REG_TB) */
|
||||
TCG_REG_S7, /* used for guest_base */
|
||||
TCG_REG_S8, /* used for the global env (TCG_AREG0) */
|
||||
TCG_REG_RA, /* should be last for ABI compliance */
|
||||
};
|
||||
|
||||
@ -2312,12 +2462,25 @@ static void tcg_target_qemu_prologue(TCGContext *s)
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SOFTMMU
|
||||
if (guest_base) {
|
||||
tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base);
|
||||
if (guest_base != (int16_t)guest_base) {
|
||||
/*
|
||||
* The function call abi for n32 and n64 will have loaded $25 (t9)
|
||||
* with the address of the prologue, so we can use that instead
|
||||
* of TCG_REG_TB.
|
||||
*/
|
||||
#if TCG_TARGET_REG_BITS == 64 && !defined(__mips_abicalls)
|
||||
# error "Unknown mips abi"
|
||||
#endif
|
||||
tcg_out_movi_int(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base,
|
||||
TCG_TARGET_REG_BITS == 64 ? TCG_REG_T9 : 0);
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (TCG_TARGET_REG_BITS == 64) {
|
||||
tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_TB, tcg_target_call_iarg_regs[1]);
|
||||
}
|
||||
|
||||
/* Call generated code */
|
||||
tcg_out_opc_reg(s, OPC_JR, 0, tcg_target_call_iarg_regs[1], 0);
|
||||
/* delay slot */
|
||||
@ -2498,6 +2661,9 @@ static void tcg_target_init(TCGContext *s)
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA); /* return address */
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); /* stack pointer */
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_GP); /* global pointer */
|
||||
if (TCG_TARGET_REG_BITS == 64) {
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_TB); /* tc->tc_ptr */
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
|
@ -76,7 +76,7 @@ typedef enum {
|
||||
TCG_REG_RA,
|
||||
|
||||
TCG_REG_CALL_STACK = TCG_REG_SP,
|
||||
TCG_AREG0 = TCG_REG_S0,
|
||||
TCG_AREG0 = TCG_REG_S8,
|
||||
} TCGReg;
|
||||
|
||||
/* used for function call generation */
|
||||
@ -208,5 +208,6 @@ extern bool use_mips32r2_instructions;
|
||||
|
||||
#define TCG_TARGET_DEFAULT_MO 0
|
||||
#define TCG_TARGET_NEED_LDST_LABELS
|
||||
#define TCG_TARGET_NEED_POOL_LABELS
|
||||
|
||||
#endif
|
||||
|
@ -15,6 +15,9 @@ C_O0_I2(rZ, rZ)
|
||||
C_O1_I1(r, r)
|
||||
C_O1_I2(r, r, ri)
|
||||
C_O1_I2(r, r, rI)
|
||||
C_O1_I2(r, r, rJ)
|
||||
C_O1_I2(r, rZ, rN)
|
||||
C_O1_I2(r, rZ, rZ)
|
||||
C_N1_I2(r, r, rM)
|
||||
C_O1_I4(r, r, rI, rM, rM)
|
||||
C_O2_I4(r, r, rZ, rZ, rM, rM)
|
||||
|
@ -15,6 +15,7 @@ REGS('r', ALL_GENERAL_REGS)
|
||||
* CONST(letter, TCG_CT_CONST_* bit set)
|
||||
*/
|
||||
CONST('I', TCG_CT_CONST_S12)
|
||||
CONST('J', TCG_CT_CONST_J12)
|
||||
CONST('N', TCG_CT_CONST_N12)
|
||||
CONST('M', TCG_CT_CONST_M12)
|
||||
CONST('Z', TCG_CT_CONST_ZERO)
|
||||
|
@ -113,6 +113,20 @@ static const int tcg_target_call_iarg_regs[] = {
|
||||
TCG_REG_A7,
|
||||
};
|
||||
|
||||
#ifndef have_zbb
|
||||
bool have_zbb;
|
||||
#endif
|
||||
#if defined(__riscv_arch_test) && defined(__riscv_zba)
|
||||
# define have_zba true
|
||||
#else
|
||||
static bool have_zba;
|
||||
#endif
|
||||
#if defined(__riscv_arch_test) && defined(__riscv_zicond)
|
||||
# define have_zicond true
|
||||
#else
|
||||
static bool have_zicond;
|
||||
#endif
|
||||
|
||||
static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot)
|
||||
{
|
||||
tcg_debug_assert(kind == TCG_CALL_RET_NORMAL);
|
||||
@ -124,6 +138,7 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot)
|
||||
#define TCG_CT_CONST_S12 0x200
|
||||
#define TCG_CT_CONST_N12 0x400
|
||||
#define TCG_CT_CONST_M12 0x800
|
||||
#define TCG_CT_CONST_J12 0x1000
|
||||
|
||||
#define ALL_GENERAL_REGS MAKE_64BIT_MASK(0, 32)
|
||||
|
||||
@ -154,12 +169,19 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct)
|
||||
}
|
||||
/*
|
||||
* Sign extended from 12 bits, +/- matching: [-0x7ff, 0x7ff].
|
||||
* Used by addsub2, which may need the negative operation,
|
||||
* Used by addsub2 and movcond, which may need the negative value,
|
||||
* and requires the modified constant to be representable.
|
||||
*/
|
||||
if ((ct & TCG_CT_CONST_M12) && val >= -0x7ff && val <= 0x7ff) {
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* Inverse of sign extended from 12 bits: ~[-0x800, 0x7ff].
|
||||
* Used to map ANDN back to ANDI, etc.
|
||||
*/
|
||||
if ((ct & TCG_CT_CONST_J12) && ~val >= -0x800 && ~val <= 0x7ff) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -234,6 +256,34 @@ typedef enum {
|
||||
|
||||
OPC_FENCE = 0x0000000f,
|
||||
OPC_NOP = OPC_ADDI, /* nop = addi r0,r0,0 */
|
||||
|
||||
/* Zba: Bit manipulation extension, address generation */
|
||||
OPC_ADD_UW = 0x0800003b,
|
||||
|
||||
/* Zbb: Bit manipulation extension, basic bit manipulaton */
|
||||
OPC_ANDN = 0x40007033,
|
||||
OPC_CLZ = 0x60001013,
|
||||
OPC_CLZW = 0x6000101b,
|
||||
OPC_CPOP = 0x60201013,
|
||||
OPC_CPOPW = 0x6020101b,
|
||||
OPC_CTZ = 0x60101013,
|
||||
OPC_CTZW = 0x6010101b,
|
||||
OPC_ORN = 0x40006033,
|
||||
OPC_REV8 = 0x6b805013,
|
||||
OPC_ROL = 0x60001033,
|
||||
OPC_ROLW = 0x6000103b,
|
||||
OPC_ROR = 0x60005033,
|
||||
OPC_RORW = 0x6000503b,
|
||||
OPC_RORI = 0x60005013,
|
||||
OPC_RORIW = 0x6000501b,
|
||||
OPC_SEXT_B = 0x60401013,
|
||||
OPC_SEXT_H = 0x60501013,
|
||||
OPC_XNOR = 0x40004033,
|
||||
OPC_ZEXT_H = 0x0800403b,
|
||||
|
||||
/* Zicond: integer conditional operations */
|
||||
OPC_CZERO_EQZ = 0x0e005033,
|
||||
OPC_CZERO_NEZ = 0x0e007033,
|
||||
} RISCVInsn;
|
||||
|
||||
/*
|
||||
@ -543,26 +593,42 @@ static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg)
|
||||
|
||||
static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg)
|
||||
{
|
||||
tcg_out_opc_imm(s, OPC_SLLIW, ret, arg, 16);
|
||||
tcg_out_opc_imm(s, OPC_SRLIW, ret, ret, 16);
|
||||
if (have_zbb) {
|
||||
tcg_out_opc_reg(s, OPC_ZEXT_H, ret, arg, TCG_REG_ZERO);
|
||||
} else {
|
||||
tcg_out_opc_imm(s, OPC_SLLIW, ret, arg, 16);
|
||||
tcg_out_opc_imm(s, OPC_SRLIW, ret, ret, 16);
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg)
|
||||
{
|
||||
tcg_out_opc_imm(s, OPC_SLLI, ret, arg, 32);
|
||||
tcg_out_opc_imm(s, OPC_SRLI, ret, ret, 32);
|
||||
if (have_zba) {
|
||||
tcg_out_opc_reg(s, OPC_ADD_UW, ret, arg, TCG_REG_ZERO);
|
||||
} else {
|
||||
tcg_out_opc_imm(s, OPC_SLLI, ret, arg, 32);
|
||||
tcg_out_opc_imm(s, OPC_SRLI, ret, ret, 32);
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg)
|
||||
{
|
||||
tcg_out_opc_imm(s, OPC_SLLIW, ret, arg, 24);
|
||||
tcg_out_opc_imm(s, OPC_SRAIW, ret, ret, 24);
|
||||
if (have_zbb) {
|
||||
tcg_out_opc_imm(s, OPC_SEXT_B, ret, arg, 0);
|
||||
} else {
|
||||
tcg_out_opc_imm(s, OPC_SLLIW, ret, arg, 24);
|
||||
tcg_out_opc_imm(s, OPC_SRAIW, ret, ret, 24);
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_out_ext16s(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg)
|
||||
{
|
||||
tcg_out_opc_imm(s, OPC_SLLIW, ret, arg, 16);
|
||||
tcg_out_opc_imm(s, OPC_SRAIW, ret, ret, 16);
|
||||
if (have_zbb) {
|
||||
tcg_out_opc_imm(s, OPC_SEXT_H, ret, arg, 0);
|
||||
} else {
|
||||
tcg_out_opc_imm(s, OPC_SLLIW, ret, arg, 16);
|
||||
tcg_out_opc_imm(s, OPC_SRAIW, ret, ret, 16);
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_out_ext32s(TCGContext *s, TCGReg ret, TCGReg arg)
|
||||
@ -746,50 +812,271 @@ static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1,
|
||||
tcg_out_opc_branch(s, op, arg1, arg2, 0);
|
||||
}
|
||||
|
||||
static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret,
|
||||
TCGReg arg1, TCGReg arg2)
|
||||
#define SETCOND_INV TCG_TARGET_NB_REGS
|
||||
#define SETCOND_NEZ (SETCOND_INV << 1)
|
||||
#define SETCOND_FLAGS (SETCOND_INV | SETCOND_NEZ)
|
||||
|
||||
static int tcg_out_setcond_int(TCGContext *s, TCGCond cond, TCGReg ret,
|
||||
TCGReg arg1, tcg_target_long arg2, bool c2)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
switch (cond) {
|
||||
case TCG_COND_EQ:
|
||||
tcg_out_opc_reg(s, OPC_SUB, ret, arg1, arg2);
|
||||
tcg_out_opc_imm(s, OPC_SLTIU, ret, ret, 1);
|
||||
break;
|
||||
case TCG_COND_NE:
|
||||
tcg_out_opc_reg(s, OPC_SUB, ret, arg1, arg2);
|
||||
tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, ret);
|
||||
break;
|
||||
case TCG_COND_LT:
|
||||
tcg_out_opc_reg(s, OPC_SLT, ret, arg1, arg2);
|
||||
break;
|
||||
case TCG_COND_GE:
|
||||
tcg_out_opc_reg(s, OPC_SLT, ret, arg1, arg2);
|
||||
tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
|
||||
break;
|
||||
case TCG_COND_LE:
|
||||
tcg_out_opc_reg(s, OPC_SLT, ret, arg2, arg1);
|
||||
tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
|
||||
break;
|
||||
case TCG_COND_GT:
|
||||
tcg_out_opc_reg(s, OPC_SLT, ret, arg2, arg1);
|
||||
break;
|
||||
case TCG_COND_LTU:
|
||||
tcg_out_opc_reg(s, OPC_SLTU, ret, arg1, arg2);
|
||||
break;
|
||||
case TCG_COND_GEU:
|
||||
tcg_out_opc_reg(s, OPC_SLTU, ret, arg1, arg2);
|
||||
tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
|
||||
break;
|
||||
case TCG_COND_LEU:
|
||||
tcg_out_opc_reg(s, OPC_SLTU, ret, arg2, arg1);
|
||||
tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
|
||||
break;
|
||||
case TCG_COND_GTU:
|
||||
tcg_out_opc_reg(s, OPC_SLTU, ret, arg2, arg1);
|
||||
case TCG_COND_EQ: /* -> NE */
|
||||
case TCG_COND_GE: /* -> LT */
|
||||
case TCG_COND_GEU: /* -> LTU */
|
||||
case TCG_COND_GT: /* -> LE */
|
||||
case TCG_COND_GTU: /* -> LEU */
|
||||
cond = tcg_invert_cond(cond);
|
||||
flags ^= SETCOND_INV;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cond) {
|
||||
case TCG_COND_LE:
|
||||
case TCG_COND_LEU:
|
||||
/*
|
||||
* If we have a constant input, the most efficient way to implement
|
||||
* LE is by adding 1 and using LT. Watch out for wrap around for LEU.
|
||||
* We don't need to care for this for LE because the constant input
|
||||
* is constrained to signed 12-bit, and 0x800 is representable in the
|
||||
* temporary register.
|
||||
*/
|
||||
if (c2) {
|
||||
if (cond == TCG_COND_LEU) {
|
||||
/* unsigned <= -1 is true */
|
||||
if (arg2 == -1) {
|
||||
tcg_out_movi(s, TCG_TYPE_REG, ret, !(flags & SETCOND_INV));
|
||||
return ret;
|
||||
}
|
||||
cond = TCG_COND_LTU;
|
||||
} else {
|
||||
cond = TCG_COND_LT;
|
||||
}
|
||||
tcg_debug_assert(arg2 <= 0x7ff);
|
||||
if (++arg2 == 0x800) {
|
||||
tcg_out_movi(s, TCG_TYPE_REG, TCG_REG_TMP0, arg2);
|
||||
arg2 = TCG_REG_TMP0;
|
||||
c2 = false;
|
||||
}
|
||||
} else {
|
||||
TCGReg tmp = arg2;
|
||||
arg2 = arg1;
|
||||
arg1 = tmp;
|
||||
cond = tcg_swap_cond(cond); /* LE -> GE */
|
||||
cond = tcg_invert_cond(cond); /* GE -> LT */
|
||||
flags ^= SETCOND_INV;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cond) {
|
||||
case TCG_COND_NE:
|
||||
flags |= SETCOND_NEZ;
|
||||
if (!c2) {
|
||||
tcg_out_opc_reg(s, OPC_XOR, ret, arg1, arg2);
|
||||
} else if (arg2 == 0) {
|
||||
ret = arg1;
|
||||
} else {
|
||||
tcg_out_opc_imm(s, OPC_XORI, ret, arg1, arg2);
|
||||
}
|
||||
break;
|
||||
|
||||
case TCG_COND_LT:
|
||||
if (c2) {
|
||||
tcg_out_opc_imm(s, OPC_SLTI, ret, arg1, arg2);
|
||||
} else {
|
||||
tcg_out_opc_reg(s, OPC_SLT, ret, arg1, arg2);
|
||||
}
|
||||
break;
|
||||
|
||||
case TCG_COND_LTU:
|
||||
if (c2) {
|
||||
tcg_out_opc_imm(s, OPC_SLTIU, ret, arg1, arg2);
|
||||
} else {
|
||||
tcg_out_opc_reg(s, OPC_SLTU, ret, arg1, arg2);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
return ret | flags;
|
||||
}
|
||||
|
||||
static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret,
|
||||
TCGReg arg1, tcg_target_long arg2, bool c2)
|
||||
{
|
||||
int tmpflags = tcg_out_setcond_int(s, cond, ret, arg1, arg2, c2);
|
||||
|
||||
if (tmpflags != ret) {
|
||||
TCGReg tmp = tmpflags & ~SETCOND_FLAGS;
|
||||
|
||||
switch (tmpflags & SETCOND_FLAGS) {
|
||||
case SETCOND_INV:
|
||||
/* Intermediate result is boolean: simply invert. */
|
||||
tcg_out_opc_imm(s, OPC_XORI, ret, tmp, 1);
|
||||
break;
|
||||
case SETCOND_NEZ:
|
||||
/* Intermediate result is zero/non-zero: test != 0. */
|
||||
tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, tmp);
|
||||
break;
|
||||
case SETCOND_NEZ | SETCOND_INV:
|
||||
/* Intermediate result is zero/non-zero: test == 0. */
|
||||
tcg_out_opc_imm(s, OPC_SLTIU, ret, tmp, 1);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_out_movcond_zicond(TCGContext *s, TCGReg ret, TCGReg test_ne,
|
||||
int val1, bool c_val1,
|
||||
int val2, bool c_val2)
|
||||
{
|
||||
if (val1 == 0) {
|
||||
if (c_val2) {
|
||||
tcg_out_movi(s, TCG_TYPE_REG, TCG_REG_TMP1, val2);
|
||||
val2 = TCG_REG_TMP1;
|
||||
}
|
||||
tcg_out_opc_reg(s, OPC_CZERO_NEZ, ret, val2, test_ne);
|
||||
return;
|
||||
}
|
||||
|
||||
if (val2 == 0) {
|
||||
if (c_val1) {
|
||||
tcg_out_movi(s, TCG_TYPE_REG, TCG_REG_TMP1, val1);
|
||||
val1 = TCG_REG_TMP1;
|
||||
}
|
||||
tcg_out_opc_reg(s, OPC_CZERO_EQZ, ret, val1, test_ne);
|
||||
return;
|
||||
}
|
||||
|
||||
if (c_val2) {
|
||||
if (c_val1) {
|
||||
tcg_out_movi(s, TCG_TYPE_REG, TCG_REG_TMP1, val1 - val2);
|
||||
} else {
|
||||
tcg_out_opc_imm(s, OPC_ADDI, TCG_REG_TMP1, val1, -val2);
|
||||
}
|
||||
tcg_out_opc_reg(s, OPC_CZERO_EQZ, ret, TCG_REG_TMP1, test_ne);
|
||||
tcg_out_opc_imm(s, OPC_ADDI, ret, ret, val2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (c_val1) {
|
||||
tcg_out_opc_imm(s, OPC_ADDI, TCG_REG_TMP1, val2, -val1);
|
||||
tcg_out_opc_reg(s, OPC_CZERO_NEZ, ret, TCG_REG_TMP1, test_ne);
|
||||
tcg_out_opc_imm(s, OPC_ADDI, ret, ret, val1);
|
||||
return;
|
||||
}
|
||||
|
||||
tcg_out_opc_reg(s, OPC_CZERO_NEZ, TCG_REG_TMP1, val2, test_ne);
|
||||
tcg_out_opc_reg(s, OPC_CZERO_EQZ, TCG_REG_TMP0, val1, test_ne);
|
||||
tcg_out_opc_reg(s, OPC_OR, ret, TCG_REG_TMP0, TCG_REG_TMP1);
|
||||
}
|
||||
|
||||
static void tcg_out_movcond_br1(TCGContext *s, TCGCond cond, TCGReg ret,
|
||||
TCGReg cmp1, TCGReg cmp2,
|
||||
int val, bool c_val)
|
||||
{
|
||||
RISCVInsn op;
|
||||
int disp = 8;
|
||||
|
||||
tcg_debug_assert((unsigned)cond < ARRAY_SIZE(tcg_brcond_to_riscv));
|
||||
op = tcg_brcond_to_riscv[cond].op;
|
||||
tcg_debug_assert(op != 0);
|
||||
|
||||
if (tcg_brcond_to_riscv[cond].swap) {
|
||||
tcg_out_opc_branch(s, op, cmp2, cmp1, disp);
|
||||
} else {
|
||||
tcg_out_opc_branch(s, op, cmp1, cmp2, disp);
|
||||
}
|
||||
if (c_val) {
|
||||
tcg_out_opc_imm(s, OPC_ADDI, ret, TCG_REG_ZERO, val);
|
||||
} else {
|
||||
tcg_out_opc_imm(s, OPC_ADDI, ret, val, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_out_movcond_br2(TCGContext *s, TCGCond cond, TCGReg ret,
|
||||
TCGReg cmp1, TCGReg cmp2,
|
||||
int val1, bool c_val1,
|
||||
int val2, bool c_val2)
|
||||
{
|
||||
TCGReg tmp;
|
||||
|
||||
/* TCG optimizer reorders to prefer ret matching val2. */
|
||||
if (!c_val2 && ret == val2) {
|
||||
cond = tcg_invert_cond(cond);
|
||||
tcg_out_movcond_br1(s, cond, ret, cmp1, cmp2, val1, c_val1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!c_val1 && ret == val1) {
|
||||
tcg_out_movcond_br1(s, cond, ret, cmp1, cmp2, val2, c_val2);
|
||||
return;
|
||||
}
|
||||
|
||||
tmp = (ret == cmp1 || ret == cmp2 ? TCG_REG_TMP1 : ret);
|
||||
if (c_val1) {
|
||||
tcg_out_movi(s, TCG_TYPE_REG, tmp, val1);
|
||||
} else {
|
||||
tcg_out_mov(s, TCG_TYPE_REG, tmp, val1);
|
||||
}
|
||||
tcg_out_movcond_br1(s, cond, tmp, cmp1, cmp2, val2, c_val2);
|
||||
tcg_out_mov(s, TCG_TYPE_REG, ret, tmp);
|
||||
}
|
||||
|
||||
static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret,
|
||||
TCGReg cmp1, int cmp2, bool c_cmp2,
|
||||
TCGReg val1, bool c_val1,
|
||||
TCGReg val2, bool c_val2)
|
||||
{
|
||||
int tmpflags;
|
||||
TCGReg t;
|
||||
|
||||
if (!have_zicond && (!c_cmp2 || cmp2 == 0)) {
|
||||
tcg_out_movcond_br2(s, cond, ret, cmp1, cmp2,
|
||||
val1, c_val1, val2, c_val2);
|
||||
return;
|
||||
}
|
||||
|
||||
tmpflags = tcg_out_setcond_int(s, cond, TCG_REG_TMP0, cmp1, cmp2, c_cmp2);
|
||||
t = tmpflags & ~SETCOND_FLAGS;
|
||||
|
||||
if (have_zicond) {
|
||||
if (tmpflags & SETCOND_INV) {
|
||||
tcg_out_movcond_zicond(s, ret, t, val2, c_val2, val1, c_val1);
|
||||
} else {
|
||||
tcg_out_movcond_zicond(s, ret, t, val1, c_val1, val2, c_val2);
|
||||
}
|
||||
} else {
|
||||
cond = tmpflags & SETCOND_INV ? TCG_COND_EQ : TCG_COND_NE;
|
||||
tcg_out_movcond_br2(s, cond, ret, t, TCG_REG_ZERO,
|
||||
val1, c_val1, val2, c_val2);
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_out_cltz(TCGContext *s, TCGType type, RISCVInsn insn,
|
||||
TCGReg ret, TCGReg src1, int src2, bool c_src2)
|
||||
{
|
||||
tcg_out_opc_imm(s, insn, ret, src1, 0);
|
||||
|
||||
if (!c_src2 || src2 != (type == TCG_TYPE_I32 ? 32 : 64)) {
|
||||
/*
|
||||
* The requested zero result does not match the insn, so adjust.
|
||||
* Note that constraints put 'ret' in a new register, so the
|
||||
* computation above did not clobber either 'src1' or 'src2'.
|
||||
*/
|
||||
tcg_out_movcond(s, TCG_COND_EQ, ret, src1, 0, true,
|
||||
src2, c_src2, ret, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail)
|
||||
@ -972,14 +1259,18 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, TCGReg *pbase,
|
||||
tcg_out_opc_branch(s, OPC_BNE, TCG_REG_TMP0, TCG_REG_TMP1, 0);
|
||||
|
||||
/* TLB Hit - translate address using addend. */
|
||||
addr_adj = addr_reg;
|
||||
if (TARGET_LONG_BITS == 32) {
|
||||
addr_adj = TCG_REG_TMP0;
|
||||
tcg_out_ext32u(s, addr_adj, addr_reg);
|
||||
if (TARGET_LONG_BITS == 64) {
|
||||
tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP0, addr_reg, TCG_REG_TMP2);
|
||||
} else if (have_zba) {
|
||||
tcg_out_opc_reg(s, OPC_ADD_UW, TCG_REG_TMP0, addr_reg, TCG_REG_TMP2);
|
||||
} else {
|
||||
tcg_out_ext32u(s, TCG_REG_TMP0, addr_reg);
|
||||
tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP0, TCG_REG_TMP0, TCG_REG_TMP2);
|
||||
}
|
||||
tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP0, TCG_REG_TMP2, addr_adj);
|
||||
*pbase = TCG_REG_TMP0;
|
||||
#else
|
||||
TCGReg base;
|
||||
|
||||
if (a_mask) {
|
||||
ldst = new_ldst_label(s);
|
||||
ldst->is_ld = is_ld;
|
||||
@ -994,14 +1285,21 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, TCGReg *pbase,
|
||||
tcg_out_opc_branch(s, OPC_BNE, TCG_REG_TMP1, TCG_REG_ZERO, 0);
|
||||
}
|
||||
|
||||
TCGReg base = addr_reg;
|
||||
if (TARGET_LONG_BITS == 32) {
|
||||
tcg_out_ext32u(s, TCG_REG_TMP0, base);
|
||||
base = TCG_REG_TMP0;
|
||||
}
|
||||
if (guest_base != 0) {
|
||||
tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP0, TCG_GUEST_BASE_REG, base);
|
||||
base = TCG_REG_TMP0;
|
||||
if (TARGET_LONG_BITS == 64) {
|
||||
tcg_out_opc_reg(s, OPC_ADD, base, addr_reg, TCG_GUEST_BASE_REG);
|
||||
} else if (have_zba) {
|
||||
tcg_out_opc_reg(s, OPC_ADD_UW, base, addr_reg, TCG_GUEST_BASE_REG);
|
||||
} else {
|
||||
tcg_out_ext32u(s, base, addr_reg);
|
||||
tcg_out_opc_reg(s, OPC_ADD, base, base, TCG_GUEST_BASE_REG);
|
||||
}
|
||||
} else if (TARGET_LONG_BITS == 64) {
|
||||
base = addr_reg;
|
||||
} else {
|
||||
base = TCG_REG_TMP0;
|
||||
tcg_out_ext32u(s, base, addr_reg);
|
||||
}
|
||||
*pbase = base;
|
||||
#endif
|
||||
@ -1263,6 +1561,31 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
||||
}
|
||||
break;
|
||||
|
||||
case INDEX_op_andc_i32:
|
||||
case INDEX_op_andc_i64:
|
||||
if (c2) {
|
||||
tcg_out_opc_imm(s, OPC_ANDI, a0, a1, ~a2);
|
||||
} else {
|
||||
tcg_out_opc_reg(s, OPC_ANDN, a0, a1, a2);
|
||||
}
|
||||
break;
|
||||
case INDEX_op_orc_i32:
|
||||
case INDEX_op_orc_i64:
|
||||
if (c2) {
|
||||
tcg_out_opc_imm(s, OPC_ORI, a0, a1, ~a2);
|
||||
} else {
|
||||
tcg_out_opc_reg(s, OPC_ORN, a0, a1, a2);
|
||||
}
|
||||
break;
|
||||
case INDEX_op_eqv_i32:
|
||||
case INDEX_op_eqv_i64:
|
||||
if (c2) {
|
||||
tcg_out_opc_imm(s, OPC_XORI, a0, a1, ~a2);
|
||||
} else {
|
||||
tcg_out_opc_reg(s, OPC_XNOR, a0, a1, a2);
|
||||
}
|
||||
break;
|
||||
|
||||
case INDEX_op_not_i32:
|
||||
case INDEX_op_not_i64:
|
||||
tcg_out_opc_imm(s, OPC_XORI, a0, a1, -1);
|
||||
@ -1355,6 +1678,80 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
||||
}
|
||||
break;
|
||||
|
||||
case INDEX_op_rotl_i32:
|
||||
if (c2) {
|
||||
tcg_out_opc_imm(s, OPC_RORIW, a0, a1, -a2 & 0x1f);
|
||||
} else {
|
||||
tcg_out_opc_reg(s, OPC_ROLW, a0, a1, a2);
|
||||
}
|
||||
break;
|
||||
case INDEX_op_rotl_i64:
|
||||
if (c2) {
|
||||
tcg_out_opc_imm(s, OPC_RORI, a0, a1, -a2 & 0x3f);
|
||||
} else {
|
||||
tcg_out_opc_reg(s, OPC_ROL, a0, a1, a2);
|
||||
}
|
||||
break;
|
||||
|
||||
case INDEX_op_rotr_i32:
|
||||
if (c2) {
|
||||
tcg_out_opc_imm(s, OPC_RORIW, a0, a1, a2 & 0x1f);
|
||||
} else {
|
||||
tcg_out_opc_reg(s, OPC_RORW, a0, a1, a2);
|
||||
}
|
||||
break;
|
||||
case INDEX_op_rotr_i64:
|
||||
if (c2) {
|
||||
tcg_out_opc_imm(s, OPC_RORI, a0, a1, a2 & 0x3f);
|
||||
} else {
|
||||
tcg_out_opc_reg(s, OPC_ROR, a0, a1, a2);
|
||||
}
|
||||
break;
|
||||
|
||||
case INDEX_op_bswap64_i64:
|
||||
tcg_out_opc_imm(s, OPC_REV8, a0, a1, 0);
|
||||
break;
|
||||
case INDEX_op_bswap32_i32:
|
||||
a2 = 0;
|
||||
/* fall through */
|
||||
case INDEX_op_bswap32_i64:
|
||||
tcg_out_opc_imm(s, OPC_REV8, a0, a1, 0);
|
||||
if (a2 & TCG_BSWAP_OZ) {
|
||||
tcg_out_opc_imm(s, OPC_SRLI, a0, a0, 32);
|
||||
} else {
|
||||
tcg_out_opc_imm(s, OPC_SRAI, a0, a0, 32);
|
||||
}
|
||||
break;
|
||||
case INDEX_op_bswap16_i64:
|
||||
case INDEX_op_bswap16_i32:
|
||||
tcg_out_opc_imm(s, OPC_REV8, a0, a1, 0);
|
||||
if (a2 & TCG_BSWAP_OZ) {
|
||||
tcg_out_opc_imm(s, OPC_SRLI, a0, a0, 48);
|
||||
} else {
|
||||
tcg_out_opc_imm(s, OPC_SRAI, a0, a0, 48);
|
||||
}
|
||||
break;
|
||||
|
||||
case INDEX_op_ctpop_i32:
|
||||
tcg_out_opc_imm(s, OPC_CPOPW, a0, a1, 0);
|
||||
break;
|
||||
case INDEX_op_ctpop_i64:
|
||||
tcg_out_opc_imm(s, OPC_CPOP, a0, a1, 0);
|
||||
break;
|
||||
|
||||
case INDEX_op_clz_i32:
|
||||
tcg_out_cltz(s, TCG_TYPE_I32, OPC_CLZW, a0, a1, a2, c2);
|
||||
break;
|
||||
case INDEX_op_clz_i64:
|
||||
tcg_out_cltz(s, TCG_TYPE_I64, OPC_CLZ, a0, a1, a2, c2);
|
||||
break;
|
||||
case INDEX_op_ctz_i32:
|
||||
tcg_out_cltz(s, TCG_TYPE_I32, OPC_CTZW, a0, a1, a2, c2);
|
||||
break;
|
||||
case INDEX_op_ctz_i64:
|
||||
tcg_out_cltz(s, TCG_TYPE_I64, OPC_CTZ, a0, a1, a2, c2);
|
||||
break;
|
||||
|
||||
case INDEX_op_add2_i32:
|
||||
tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5],
|
||||
const_args[4], const_args[5], false, true);
|
||||
@ -1379,7 +1776,13 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
||||
|
||||
case INDEX_op_setcond_i32:
|
||||
case INDEX_op_setcond_i64:
|
||||
tcg_out_setcond(s, args[3], a0, a1, a2);
|
||||
tcg_out_setcond(s, args[3], a0, a1, a2, c2);
|
||||
break;
|
||||
|
||||
case INDEX_op_movcond_i32:
|
||||
case INDEX_op_movcond_i64:
|
||||
tcg_out_movcond(s, args[5], a0, a1, a2, c2,
|
||||
args[3], const_args[3], args[4], const_args[4]);
|
||||
break;
|
||||
|
||||
case INDEX_op_qemu_ld_a32_i32:
|
||||
@ -1476,6 +1879,13 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
|
||||
case INDEX_op_extrl_i64_i32:
|
||||
case INDEX_op_extrh_i64_i32:
|
||||
case INDEX_op_ext_i32_i64:
|
||||
case INDEX_op_bswap16_i32:
|
||||
case INDEX_op_bswap32_i32:
|
||||
case INDEX_op_bswap16_i64:
|
||||
case INDEX_op_bswap32_i64:
|
||||
case INDEX_op_bswap64_i64:
|
||||
case INDEX_op_ctpop_i32:
|
||||
case INDEX_op_ctpop_i64:
|
||||
return C_O1_I1(r, r);
|
||||
|
||||
case INDEX_op_st8_i32:
|
||||
@ -1495,8 +1905,18 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
|
||||
case INDEX_op_and_i64:
|
||||
case INDEX_op_or_i64:
|
||||
case INDEX_op_xor_i64:
|
||||
case INDEX_op_setcond_i32:
|
||||
case INDEX_op_setcond_i64:
|
||||
return C_O1_I2(r, r, rI);
|
||||
|
||||
case INDEX_op_andc_i32:
|
||||
case INDEX_op_andc_i64:
|
||||
case INDEX_op_orc_i32:
|
||||
case INDEX_op_orc_i64:
|
||||
case INDEX_op_eqv_i32:
|
||||
case INDEX_op_eqv_i64:
|
||||
return C_O1_I2(r, r, rJ);
|
||||
|
||||
case INDEX_op_sub_i32:
|
||||
case INDEX_op_sub_i64:
|
||||
return C_O1_I2(r, rZ, rN);
|
||||
@ -1508,7 +1928,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
|
||||
case INDEX_op_divu_i32:
|
||||
case INDEX_op_rem_i32:
|
||||
case INDEX_op_remu_i32:
|
||||
case INDEX_op_setcond_i32:
|
||||
case INDEX_op_mul_i64:
|
||||
case INDEX_op_mulsh_i64:
|
||||
case INDEX_op_muluh_i64:
|
||||
@ -1516,21 +1935,34 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
|
||||
case INDEX_op_divu_i64:
|
||||
case INDEX_op_rem_i64:
|
||||
case INDEX_op_remu_i64:
|
||||
case INDEX_op_setcond_i64:
|
||||
return C_O1_I2(r, rZ, rZ);
|
||||
|
||||
case INDEX_op_shl_i32:
|
||||
case INDEX_op_shr_i32:
|
||||
case INDEX_op_sar_i32:
|
||||
case INDEX_op_rotl_i32:
|
||||
case INDEX_op_rotr_i32:
|
||||
case INDEX_op_shl_i64:
|
||||
case INDEX_op_shr_i64:
|
||||
case INDEX_op_sar_i64:
|
||||
case INDEX_op_rotl_i64:
|
||||
case INDEX_op_rotr_i64:
|
||||
return C_O1_I2(r, r, ri);
|
||||
|
||||
case INDEX_op_clz_i32:
|
||||
case INDEX_op_clz_i64:
|
||||
case INDEX_op_ctz_i32:
|
||||
case INDEX_op_ctz_i64:
|
||||
return C_N1_I2(r, r, rM);
|
||||
|
||||
case INDEX_op_brcond_i32:
|
||||
case INDEX_op_brcond_i64:
|
||||
return C_O0_I2(rZ, rZ);
|
||||
|
||||
case INDEX_op_movcond_i32:
|
||||
case INDEX_op_movcond_i64:
|
||||
return C_O1_I4(r, r, rI, rM, rM);
|
||||
|
||||
case INDEX_op_add2_i32:
|
||||
case INDEX_op_add2_i64:
|
||||
case INDEX_op_sub2_i32:
|
||||
@ -1619,8 +2051,62 @@ static void tcg_target_qemu_prologue(TCGContext *s)
|
||||
tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, TCG_REG_RA, 0);
|
||||
}
|
||||
|
||||
static volatile sig_atomic_t got_sigill;
|
||||
|
||||
static void sigill_handler(int signo, siginfo_t *si, void *data)
|
||||
{
|
||||
/* Skip the faulty instruction */
|
||||
ucontext_t *uc = (ucontext_t *)data;
|
||||
uc->uc_mcontext.__gregs[REG_PC] += 4;
|
||||
|
||||
got_sigill = 1;
|
||||
}
|
||||
|
||||
static void tcg_target_detect_isa(void)
|
||||
{
|
||||
#if !defined(have_zba) || !defined(have_zbb) || !defined(have_zicond)
|
||||
/*
|
||||
* TODO: It is expected that this will be determinable via
|
||||
* linux riscv_hwprobe syscall, not yet merged.
|
||||
* In the meantime, test via sigill.
|
||||
*/
|
||||
|
||||
struct sigaction sa_old, sa_new;
|
||||
|
||||
memset(&sa_new, 0, sizeof(sa_new));
|
||||
sa_new.sa_flags = SA_SIGINFO;
|
||||
sa_new.sa_sigaction = sigill_handler;
|
||||
sigaction(SIGILL, &sa_new, &sa_old);
|
||||
|
||||
#ifndef have_zba
|
||||
/* Probe for Zba: add.uw zero,zero,zero. */
|
||||
got_sigill = 0;
|
||||
asm volatile(".insn r 0x3b, 0, 0x04, zero, zero, zero" : : : "memory");
|
||||
have_zba = !got_sigill;
|
||||
#endif
|
||||
|
||||
#ifndef have_zbb
|
||||
/* Probe for Zba: andn zero,zero,zero. */
|
||||
got_sigill = 0;
|
||||
asm volatile(".insn r 0x33, 7, 0x20, zero, zero, zero" : : : "memory");
|
||||
have_zbb = !got_sigill;
|
||||
#endif
|
||||
|
||||
#ifndef have_zicond
|
||||
/* Probe for Zicond: czero.eqz zero,zero,zero. */
|
||||
got_sigill = 0;
|
||||
asm volatile(".insn r 0x33, 5, 0x07, zero, zero, zero" : : : "memory");
|
||||
have_zicond = !got_sigill;
|
||||
#endif
|
||||
|
||||
sigaction(SIGILL, &sa_old, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void tcg_target_init(TCGContext *s)
|
||||
{
|
||||
tcg_target_detect_isa();
|
||||
|
||||
tcg_target_available_regs[TCG_TYPE_I32] = 0xffffffff;
|
||||
tcg_target_available_regs[TCG_TYPE_I64] = 0xffffffff;
|
||||
|
||||
|
@ -90,12 +90,18 @@ typedef enum {
|
||||
#define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_NORMAL
|
||||
#define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_NORMAL
|
||||
|
||||
#if defined(__riscv_arch_test) && defined(__riscv_zbb)
|
||||
# define have_zbb true
|
||||
#else
|
||||
extern bool have_zbb;
|
||||
#endif
|
||||
|
||||
/* optional instructions */
|
||||
#define TCG_TARGET_HAS_movcond_i32 0
|
||||
#define TCG_TARGET_HAS_movcond_i32 1
|
||||
#define TCG_TARGET_HAS_div_i32 1
|
||||
#define TCG_TARGET_HAS_rem_i32 1
|
||||
#define TCG_TARGET_HAS_div2_i32 0
|
||||
#define TCG_TARGET_HAS_rot_i32 0
|
||||
#define TCG_TARGET_HAS_rot_i32 have_zbb
|
||||
#define TCG_TARGET_HAS_deposit_i32 0
|
||||
#define TCG_TARGET_HAS_extract_i32 0
|
||||
#define TCG_TARGET_HAS_sextract_i32 0
|
||||
@ -110,27 +116,27 @@ typedef enum {
|
||||
#define TCG_TARGET_HAS_ext16s_i32 1
|
||||
#define TCG_TARGET_HAS_ext8u_i32 1
|
||||
#define TCG_TARGET_HAS_ext16u_i32 1
|
||||
#define TCG_TARGET_HAS_bswap16_i32 0
|
||||
#define TCG_TARGET_HAS_bswap32_i32 0
|
||||
#define TCG_TARGET_HAS_bswap16_i32 have_zbb
|
||||
#define TCG_TARGET_HAS_bswap32_i32 have_zbb
|
||||
#define TCG_TARGET_HAS_not_i32 1
|
||||
#define TCG_TARGET_HAS_neg_i32 1
|
||||
#define TCG_TARGET_HAS_andc_i32 0
|
||||
#define TCG_TARGET_HAS_orc_i32 0
|
||||
#define TCG_TARGET_HAS_eqv_i32 0
|
||||
#define TCG_TARGET_HAS_andc_i32 have_zbb
|
||||
#define TCG_TARGET_HAS_orc_i32 have_zbb
|
||||
#define TCG_TARGET_HAS_eqv_i32 have_zbb
|
||||
#define TCG_TARGET_HAS_nand_i32 0
|
||||
#define TCG_TARGET_HAS_nor_i32 0
|
||||
#define TCG_TARGET_HAS_clz_i32 0
|
||||
#define TCG_TARGET_HAS_ctz_i32 0
|
||||
#define TCG_TARGET_HAS_ctpop_i32 0
|
||||
#define TCG_TARGET_HAS_clz_i32 have_zbb
|
||||
#define TCG_TARGET_HAS_ctz_i32 have_zbb
|
||||
#define TCG_TARGET_HAS_ctpop_i32 have_zbb
|
||||
#define TCG_TARGET_HAS_brcond2 1
|
||||
#define TCG_TARGET_HAS_setcond2 1
|
||||
#define TCG_TARGET_HAS_qemu_st8_i32 0
|
||||
|
||||
#define TCG_TARGET_HAS_movcond_i64 0
|
||||
#define TCG_TARGET_HAS_movcond_i64 1
|
||||
#define TCG_TARGET_HAS_div_i64 1
|
||||
#define TCG_TARGET_HAS_rem_i64 1
|
||||
#define TCG_TARGET_HAS_div2_i64 0
|
||||
#define TCG_TARGET_HAS_rot_i64 0
|
||||
#define TCG_TARGET_HAS_rot_i64 have_zbb
|
||||
#define TCG_TARGET_HAS_deposit_i64 0
|
||||
#define TCG_TARGET_HAS_extract_i64 0
|
||||
#define TCG_TARGET_HAS_sextract_i64 0
|
||||
@ -143,19 +149,19 @@ typedef enum {
|
||||
#define TCG_TARGET_HAS_ext8u_i64 1
|
||||
#define TCG_TARGET_HAS_ext16u_i64 1
|
||||
#define TCG_TARGET_HAS_ext32u_i64 1
|
||||
#define TCG_TARGET_HAS_bswap16_i64 0
|
||||
#define TCG_TARGET_HAS_bswap32_i64 0
|
||||
#define TCG_TARGET_HAS_bswap64_i64 0
|
||||
#define TCG_TARGET_HAS_bswap16_i64 have_zbb
|
||||
#define TCG_TARGET_HAS_bswap32_i64 have_zbb
|
||||
#define TCG_TARGET_HAS_bswap64_i64 have_zbb
|
||||
#define TCG_TARGET_HAS_not_i64 1
|
||||
#define TCG_TARGET_HAS_neg_i64 1
|
||||
#define TCG_TARGET_HAS_andc_i64 0
|
||||
#define TCG_TARGET_HAS_orc_i64 0
|
||||
#define TCG_TARGET_HAS_eqv_i64 0
|
||||
#define TCG_TARGET_HAS_andc_i64 have_zbb
|
||||
#define TCG_TARGET_HAS_orc_i64 have_zbb
|
||||
#define TCG_TARGET_HAS_eqv_i64 have_zbb
|
||||
#define TCG_TARGET_HAS_nand_i64 0
|
||||
#define TCG_TARGET_HAS_nor_i64 0
|
||||
#define TCG_TARGET_HAS_clz_i64 0
|
||||
#define TCG_TARGET_HAS_ctz_i64 0
|
||||
#define TCG_TARGET_HAS_ctpop_i64 0
|
||||
#define TCG_TARGET_HAS_clz_i64 have_zbb
|
||||
#define TCG_TARGET_HAS_ctz_i64 have_zbb
|
||||
#define TCG_TARGET_HAS_ctpop_i64 have_zbb
|
||||
#define TCG_TARGET_HAS_add2_i64 1
|
||||
#define TCG_TARGET_HAS_sub2_i64 1
|
||||
#define TCG_TARGET_HAS_mulu2_i64 0
|
||||
|
Loading…
Reference in New Issue
Block a user