target/hexagon: don't let an idef-parser dest clobber its own source
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. Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
Brian Cain committed
Aug 5, 2026 at 07:02 UTC
8f5bf4fa0aa2f5648f016b8265d86d4b05b42307
5 files changed
+86
target/hexagon/gen_tcg_funcs.py
+15
@@ -75,6 +75,21 @@ def gen_tcg_func(f, tag, regs, imms):
75
f.write(f" int {hex_common.imm_name(immlett)} = insn->immed[{i}];\n")
76
77
if hex_common.is_idef_parser_enabled(tag):
78
+ gpr_operands = [
79
+ hex_common.get_register(tag, regtype, regid)
80
+ for regtype, regid in regs
81
+ if hex_common.get_register(tag, regtype, regid).may_alias_gpr()
82
+ ]
83
+ dests = [reg for reg in gpr_operands if reg.is_written()]
84
+ for reg in gpr_operands:
85
+ if reg.is_written() or not reg.is_read():
86
+ continue
87
+ src = reg.reg_tcg()
88
+ for dest in dests:
89
+ f.write(hex_common.code_fmt(f"""\
90
+ {src} = gen_unalias_gpr_src({src}, {dest.reg_tcg()});
91
+ """))
92
+
93
declared = []
94
## Handle registers
95
for regtype, regid in regs:
target/hexagon/genptr.c
+11
@@ -91,6 +91,17 @@ TCGv get_result_gpr(DisasContext *ctx, int rnum)
91
}
92
}
93
94
+TCGv gen_unalias_gpr_src(TCGv src, TCGv dst)
95
+{
96
+ if (src != dst) {
97
+ return src;
98
+ }
99
+
100
+ TCGv tmp = tcg_temp_new();
101
+ tcg_gen_mov_tl(tmp, src);
102
+ return tmp;
103
+}
104
+
105
static TCGv_i64 get_result_gpr_pair(DisasContext *ctx, int rnum)
106
{
107
TCGv_i64 result = tcg_temp_new_i64();
target/hexagon/genptr.h
+1
@@ -36,6 +36,7 @@ void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, uint32_t slot);
36
TCGv gen_read_reg(TCGv result, int num);
37
TCGv gen_read_preg(TCGv pred, uint8_t num);
38
TCGv get_result_gpr(DisasContext *ctx, int rnum);
39
+TCGv gen_unalias_gpr_src(TCGv src, TCGv dst);
40
TCGv get_result_pred(DisasContext *ctx, int pnum);
41
void gen_pred_write(DisasContext *ctx, int pnum, TCGv val);
42
void gen_set_usr_field(DisasContext *ctx, int field, TCGv val);
target/hexagon/hex_common.py
+12
@@ -388,6 +388,8 @@ class Register:
388
"""))
389
def idef_arg(self, declared):
390
declared.append(self.reg_tcg())
391
+ def may_alias_gpr(self):
392
+ return False
393
def helper_arg(self):
394
return HelperArg(
395
self.helper_proto_type(),
@@ -495,6 +497,8 @@ class ReadWrite:
497
return False
498
499
class GprDest(Register, Single, Dest):
500
+ def may_alias_gpr(self):
501
+ return True
502
def decl_tcg(self, f, tag, regno):
503
self.decl_reg_num(f, regno)
504
f.write(code_fmt(f"""\
@@ -510,6 +514,8 @@ class GprDest(Register, Single, Dest):
514
"""))
515
516
class GprSource(Register, Single, OldSource):
517
+ def may_alias_gpr(self):
518
+ return True
519
def decl_tcg(self, f, tag, regno):
520
self.decl_reg_num(f, regno)
521
f.write(code_fmt(f"""\
@@ -531,6 +537,8 @@ class GprNewSource(Register, Single, NewSource):
537
"""))
538
539
class GprReadWrite(Register, Single, ReadWrite):
540
+ def may_alias_gpr(self):
541
+ return True
542
def decl_tcg(self, f, tag, regno):
543
self.decl_reg_num(f, regno)
544
f.write(code_fmt(f"""\
@@ -557,6 +565,8 @@ class GprReadWrite(Register, Single, ReadWrite):
565
"""))
566
567
class ControlDest(Register, Single, Dest):
568
+ def may_alias_gpr(self):
569
+ return True
570
def decl_reg_num(self, f, regno):
571
f.write(code_fmt(f"""\
572
const int {self.reg_num} = insn->regno[{regno}] + HEX_REG_SA0;
@@ -593,6 +603,8 @@ class ControlSource(Register, Single, OldSource):
603
"""))
604
605
class ModifierSource(Register, Single, OldSource):
606
+ def may_alias_gpr(self):
607
+ return True
608
def decl_reg_num(self, f, regno):
609
f.write(code_fmt(f"""\
610
const int {self.reg_num} = insn->regno[{regno}] + HEX_REG_M0;
tests/tcg/hexagon/read_write_overlap.c
+47
@@ -115,12 +115,59 @@ static void test_swiz(void)
115
check32(swiz(0x11223344), 0x44332211);
116
}
117
118
+#define CMPY(NAME, ASM) \
119
+static inline uint32_t NAME##_rd_eq_rs(uint32_t x, uint32_t y) \
120
+{ \
121
+ uint32_t res; \
122
+ asm("r7 = %1\n\t" \
123
+ ASM("r7", "%2") "\n\t" \
124
+ "%0 = r7\n\t" \
125
+ : "=r"(res) : "r"(x), "r"(y) : "r7"); \
126
+ return res; \
127
+} \
128
+static inline uint32_t NAME##_rd_eq_rt(uint32_t x, uint32_t y) \
129
+{ \
130
+ uint32_t res; \
131
+ asm("r7 = %2\n\t" \
132
+ ASM("%1", "r7") "\n\t" \
133
+ "%0 = r7\n\t" \
134
+ : "=r"(res) : "r"(x), "r"(y) : "r7"); \
135
+ return res; \
136
+}
137
+
138
+#define CMPY_RND_SAT(RS, RT) "r7 = cmpy(" RS "," RT "):rnd:sat"
139
+#define CMPY_S1_RND_SAT(RS, RT) "r7 = cmpy(" RS "," RT "):<<1:rnd:sat"
140
+#define CMPYC_RND_SAT(RS, RT) "r7 = cmpy(" RS "," RT "*):rnd:sat"
141
+#define CMPYC_S1_RND_SAT(RS, RT) "r7 = cmpy(" RS "," RT "*):<<1:rnd:sat"
142
+
143
+CMPY(cmpyrs_s0, CMPY_RND_SAT)
144
+CMPY(cmpyrs_s1, CMPY_S1_RND_SAT)
145
+CMPY(cmpyrsc_s0, CMPYC_RND_SAT)
146
+CMPY(cmpyrsc_s1, CMPYC_S1_RND_SAT)
147
+
148
+static void test_cmpy(void)
149
+{
150
+ check32(cmpyrs_s0_rd_eq_rs(0x32195ce2, 0xef862430), 0x011b105b);
151
+ check32(cmpyrs_s0_rd_eq_rt(0x32195ce2, 0xef862430), 0x011b105b);
152
+ check32(cmpyrs_s1_rd_eq_rs(0x32195ce2, 0xef862430), 0x023520b5);
153
+ check32(cmpyrs_s1_rd_eq_rt(0x32195ce2, 0xef862430), 0x023520b5);
154
+ check32(cmpyrsc_s0_rd_eq_rs(0x32195ce2, 0xef862430), 0x0d0f09e8);
155
+ check32(cmpyrsc_s0_rd_eq_rt(0x32195ce2, 0xef862430), 0x0d0f09e8);
156
+ check32(cmpyrsc_s1_rd_eq_rs(0x32195ce2, 0xef862430), 0x1a1f13d0);
157
+ check32(cmpyrsc_s1_rd_eq_rt(0x32195ce2, 0xef862430), 0x1a1f13d0);
158
+
159
+ /* Both halves saturate */
160
+ check32(cmpyrs_s1_rd_eq_rs(0x80008000, 0x80008000), 0x7fff0000);
161
+ check32(cmpyrsc_s1_rd_eq_rs(0x7fff8001, 0x80017fff), 0x00008000);
162
+}
163
+
164
int main()
165
{
166
test_insert();
167
test_insert_rp();
168
test_asr_r_svw_trun();
169
test_swiz();
170
+ test_cmpy();
171
172
puts(err ? "FAIL" : "PASS");
173
return err ? EXIT_FAILURE : EXIT_SUCCESS;