From: Max Chou <[email protected]>
tcg_out_movi, tcg_out_call_int, and tcg_out_ldst only check whether a
PC-relative displacement is signed 32-bit before emitting an AUIPC pair.
This does not account for rounding the signed 12-bit immediate, which
can require an unencodable positive 0x80000000 AUIPC contribution.
Validate the split and emit the pair only when it fits.
Fixes: dfa8e74f9463 ("tcg/riscv: Add the relocation functions")
Signed-off-by: Max Chou <[email protected]>
[rth: Drop 'ret' local variables; update tcg_out_ldst too.]
Signed-off-by: Richard Henderson <[email protected]>
---
tcg/riscv64/tcg-target.c.inc | 54 +++++++++++++++++-------------------
1 file changed, 25 insertions(+), 29 deletions(-)
diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
index 7754bcf39f2..682d9e8320b 100644
--- a/tcg/riscv64/tcg-target.c.inc
+++ b/tcg/riscv64/tcg-target.c.inc
@@ -808,7 +808,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type,
TCGReg rd,
{
tcg_target_long tmp;
int32_t lo, hi;
- int shift, ret;
+ int shift;
if (type == TCG_TYPE_I32) {
val = (int32_t)val;
@@ -829,12 +829,9 @@ static void tcg_out_movi(TCGContext *s, TCGType type,
TCGReg rd,
return;
}
- tmp = tcg_pcrel_diff(s, (void *)val);
- if (tmp == (int32_t)tmp) {
- tcg_out_opc_upper(s, OPC_AUIPC, rd, 0);
- tcg_out_opc_imm(s, OPC_ADDI, rd, rd, 0);
- ret = reloc_call(s->code_ptr - 2, (const tcg_insn_unit *)val);
- tcg_debug_assert(ret == true);
+ if (split_auipc_offset(s->code_ptr, val, &hi, &lo)) {
+ tcg_out_opc_upper(s, OPC_AUIPC, rd, hi);
+ tcg_out_opc_imm(s, OPC_ADDI, rd, rd, lo);
return;
}
@@ -952,16 +949,16 @@ static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg
ret, TCGReg arg)
static void tcg_out_ldst(TCGContext *s, RISCVInsn opc, TCGReg data,
TCGReg addr, intptr_t offset)
{
- intptr_t imm12 = sextreg(offset, 0, 12);
+ int32_t lo = sextract32(offset, 0, 12);
- if (offset != imm12) {
- intptr_t diff = tcg_pcrel_diff(s, (void *)offset);
+ if (offset != lo) {
+ int32_t hi;
- if (addr == TCG_REG_ZERO && diff == (int32_t)diff) {
- imm12 = sextreg(diff, 0, 12);
- tcg_out_opc_upper(s, OPC_AUIPC, TCG_REG_TMP2, diff - imm12);
+ if (addr == TCG_REG_ZERO &&
+ split_auipc_offset(s->code_ptr, offset, &hi, &lo)) {
+ tcg_out_opc_upper(s, OPC_AUIPC, TCG_REG_TMP2, hi);
} else {
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP2, offset - imm12);
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP2, offset - lo);
if (addr != TCG_REG_ZERO) {
tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP2, TCG_REG_TMP2, addr);
}
@@ -974,7 +971,7 @@ static void tcg_out_ldst(TCGContext *s, RISCVInsn opc,
TCGReg data,
case OPC_SH:
case OPC_SW:
case OPC_SD:
- tcg_out_opc_store(s, opc, addr, data, imm12);
+ tcg_out_opc_store(s, opc, addr, data, lo);
break;
case OPC_LB:
case OPC_LBU:
@@ -983,7 +980,7 @@ static void tcg_out_ldst(TCGContext *s, RISCVInsn opc,
TCGReg data,
case OPC_LW:
case OPC_LWU:
case OPC_LD:
- tcg_out_opc_imm(s, opc, data, addr, imm12);
+ tcg_out_opc_imm(s, opc, data, addr, lo);
break;
default:
g_assert_not_reached();
@@ -1589,7 +1586,7 @@ static void tcg_out_call_int(TCGContext *s, const
tcg_insn_unit *arg, bool tail)
TCGReg link = tail ? TCG_REG_ZERO : TCG_REG_RA;
ptrdiff_t offset = tcg_pcrel_diff(s, arg);
tcg_insn_unit insn = encode_j(OPC_JAL, link, 0);
- int ret;
+ int32_t lo, hi;
init_setting_vtype(s);
@@ -1597,19 +1594,18 @@ static void tcg_out_call_int(TCGContext *s, const
tcg_insn_unit *arg, bool tail)
if (encode_jimm20(&insn, offset)) {
/* short jump */
tcg_out32(s, insn);
- } else if (offset == (int32_t)offset) {
- /* long jump: -2147483646 to 2147483648 */
- tcg_out_opc_upper(s, OPC_AUIPC, TCG_REG_TMP0, 0);
- tcg_out_opc_imm(s, OPC_JALR, link, TCG_REG_TMP0, 0);
- ret = reloc_call(s->code_ptr - 2, arg);
- tcg_debug_assert(ret == true);
- } else {
- /* far jump: 64-bit */
- tcg_target_long imm = sextreg((tcg_target_long)arg, 0, 12);
- tcg_target_long base = (tcg_target_long)arg - imm;
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, base);
- tcg_out_opc_imm(s, OPC_JALR, link, TCG_REG_TMP0, imm);
+ return;
}
+
+ if (split_auipc_offset(s->code_ptr, (intptr_t)arg, &hi, &lo)) {
+ /* long jump */
+ tcg_out_opc_upper(s, OPC_AUIPC, TCG_REG_TMP0, hi);
+ } else {
+ /* far jump */
+ lo = sextract32((intptr_t)arg, 0, 12);
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, (intptr_t)arg - lo);
+ }
+ tcg_out_opc_imm(s, OPC_JALR, link, TCG_REG_TMP0, lo);
}
static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg,
--
2.53.0