[PATCH] target/hexagon: don't let an idef-parser dest clobber its own source
Brian Cain <[email protected]> Wed, 5 Aug 2026 07:02:00 -0700
| Newsgroups | gmane.comp.emulators.qemu |
|---|---|
| Message-ID | <[email protected]> |
The idef-parser emitters write the destination in place, so when a packet is short-circuited and get_result_gpr() returns hex_gpr[] itself, an instruction naming one register as both source and destination reads back a value it already overwrote. `Rd32=cmpy(Rs32,Rt32):<<1:rnd:sat` with Rs == Rd is an example. Give a source reg that aliases a destination its own copy of the register value. Signed-off-by: Brian Cain <[email protected]> --- target/hexagon/genptr.h | 1 + target/hexagon/genptr.c | 11 ++++++ tests/tcg/hexagon/read_write_overlap.c | 47 ++++++++++++++++++++++++++ target/hexagon/gen_tcg_funcs.py | 15 ++++++++ target/hexagon/hex_common.py | 12 +++++++ 5 files changed, 86 insertions(+) diff --git a/target/hexagon/genptr.h b/target/hexagon/genptr.h index 45ee038ca94..5d096774102 100644 --- a/target/hexagon/genptr.h +++ b/target/hexagon/genptr.h @@ -36,6 +36,7 @@ void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, uint32_t slot); TCGv gen_read_reg(TCGv result, int num); TCGv gen_read_preg(TCGv pred, uint8_t num); TCGv get_result_gpr(DisasContext *ctx, int rnum); +TCGv gen_unalias_gpr_src(TCGv src, TCGv dst); TCGv get_result_pred(DisasContext *ctx, int pnum); void gen_pred_write(DisasContext *ctx, int pnum, TCGv val); void gen_set_usr_field(DisasContext *ctx, int field, TCGv val); diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 3f310377097..12813f48bf9 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -91,6 +91,17 @@ TCGv get_result_gpr(DisasContext *ctx, int rnum) } } +TCGv gen_unalias_gpr_src(TCGv src, TCGv dst) +{ + if (src != dst) { + return src; + } + + TCGv tmp = tcg_temp_new(); + tcg_gen_mov_tl(tmp, src); + return tmp; +} + static TCGv_i64 get_result_gpr_pair(DisasContext *ctx, int rnum) { TCGv_i64 result = tcg_temp_new_i64(); diff --git a/tests/tcg/hexagon/read_write_overlap.c b/tests/tcg/hexagon/read_write_overlap.c index 95c54ccd63c..7eaf75f545a 100644 --- a/tests/tcg/hexagon/read_write_overlap.c +++ b/tests/tcg/hexagon/read_write_overlap.c @@ -115,12 +115,59 @@ static void test_swiz(void) check32(swiz(0x11223344), 0x44332211); } +#define CMPY(NAME, ASM) \ +static inline uint32_t NAME##_rd_eq_rs(uint32_t x, uint32_t y) \ +{ \ + uint32_t res; \ + asm("r7 = %1\n\t" \ + ASM("r7", "%2") "\n\t" \ + "%0 = r7\n\t" \ + : "=r"(res) : "r"(x), "r"(y) : "r7"); \ + return res; \ +} \ +static inline uint32_t NAME##_rd_eq_rt(uint32_t x, uint32_t y) \ +{ \ + uint32_t res; \ + asm("r7 = %2\n\t" \ + ASM("%1", "r7") "\n\t" \ + "%0 = r7\n\t" \ + : "=r"(res) : "r"(x), "r"(y) : "r7"); \ + return res; \ +} + +#define CMPY_RND_SAT(RS, RT) "r7 = cmpy(" RS "," RT "):rnd:sat" +#define CMPY_S1_RND_SAT(RS, RT) "r7 = cmpy(" RS "," RT "):<<1:rnd:sat" +#define CMPYC_RND_SAT(RS, RT) "r7 = cmpy(" RS "," RT "*):rnd:sat" +#define CMPYC_S1_RND_SAT(RS, RT) "r7 = cmpy(" RS "," RT "*):<<1:rnd:sat" + +CMPY(cmpyrs_s0, CMPY_RND_SAT) +CMPY(cmpyrs_s1, CMPY_S1_RND_SAT) +CMPY(cmpyrsc_s0, CMPYC_RND_SAT) +CMPY(cmpyrsc_s1, CMPYC_S1_RND_SAT) + +static void test_cmpy(void) +{ + check32(cmpyrs_s0_rd_eq_rs(0x32195ce2, 0xef862430), 0x011b105b); + check32(cmpyrs_s0_rd_eq_rt(0x32195ce2, 0xef862430), 0x011b105b); + check32(cmpyrs_s1_rd_eq_rs(0x32195ce2, 0xef862430), 0x023520b5); + check32(cmpyrs_s1_rd_eq_rt(0x32195ce2, 0xef862430), 0x023520b5); + check32(cmpyrsc_s0_rd_eq_rs(0x32195ce2, 0xef862430), 0x0d0f09e8); + check32(cmpyrsc_s0_rd_eq_rt(0x32195ce2, 0xef862430), 0x0d0f09e8); + check32(cmpyrsc_s1_rd_eq_rs(0x32195ce2, 0xef862430), 0x1a1f13d0); + check32(cmpyrsc_s1_rd_eq_rt(0x32195ce2, 0xef862430), 0x1a1f13d0); + + /* Both halves saturate */ + check32(cmpyrs_s1_rd_eq_rs(0x80008000, 0x80008000), 0x7fff0000); + check32(cmpyrsc_s1_rd_eq_rs(0x7fff8001, 0x80017fff), 0x00008000); +} + int main() { test_insert(); test_insert_rp(); test_asr_r_svw_trun(); test_swiz(); + test_cmpy(); puts(err ? "FAIL" : "PASS"); return err ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs.py index 6d5d99cee3a..43e68077495 100755 --- a/target/hexagon/gen_tcg_funcs.py +++ b/target/hexagon/gen_tcg_funcs.py @@ -75,6 +75,21 @@ def gen_tcg_func(f, tag, regs, imms): f.write(f" int {hex_common.imm_name(immlett)} = insn->immed[{i}];\n") if hex_common.is_idef_parser_enabled(tag): + gpr_operands = [ + hex_common.get_register(tag, regtype, regid) + for regtype, regid in regs + if hex_common.get_register(tag, regtype, regid).may_alias_gpr() + ] + dests = [reg for reg in gpr_operands if reg.is_written()] + for reg in gpr_operands: + if reg.is_written() or not reg.is_read(): + continue + src = reg.reg_tcg() + for dest in dests: + f.write(hex_common.code_fmt(f"""\ + {src} = gen_unalias_gpr_src({src}, {dest.reg_tcg()}); + """)) + declared = [] ## Handle registers for regtype, regid in regs: diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index d91a653c3d4..09a025ba13e 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -388,6 +388,8 @@ def decl_reg_num(self, f, regno): """)) def idef_arg(self, declared): declared.append(self.reg_tcg()) + def may_alias_gpr(self): + return False def helper_arg(self): return HelperArg( self.helper_proto_type(), @@ -495,6 +497,8 @@ def is_new(self): return False class GprDest(Register, Single, Dest): + def may_alias_gpr(self): + return True def decl_tcg(self, f, tag, regno): self.decl_reg_num(f, regno) f.write(code_fmt(f"""\ @@ -510,6 +514,8 @@ def analyze_write(self, f, tag, regno): """)) class GprSource(Register, Single, OldSource): + def may_alias_gpr(self): + return True def decl_tcg(self, f, tag, regno): self.decl_reg_num(f, regno) f.write(code_fmt(f"""\ @@ -531,6 +537,8 @@ def analyze_read(self, f, regno): """)) class GprReadWrite(Register, Single, ReadWrite): + def may_alias_gpr(self): + return True def decl_tcg(self, f, tag, regno): self.decl_reg_num(f, regno) f.write(code_fmt(f"""\ @@ -557,6 +565,8 @@ def analyze_write(self, f, tag, regno): """)) class ControlDest(Register, Single, Dest): + def may_alias_gpr(self): + return True def decl_reg_num(self, f, regno): f.write(code_fmt(f"""\ const int {self.reg_num} = insn->regno[{regno}] + HEX_REG_SA0; @@ -593,6 +603,8 @@ def analyze_read(self, f, regno): """)) class ModifierSource(Register, Single, OldSource): + def may_alias_gpr(self): + return True def decl_reg_num(self, f, regno): f.write(code_fmt(f"""\ const int {self.reg_num} = insn->regno[{regno}] + HEX_REG_M0; -- 2.34.1