diff mbox series

Hexagon (target/hexagon) Fix predicated assignment to .tmp

Message ID 20220929023131.22935-1-tsimpson@quicinc.com
State New
Headers show
Series Hexagon (target/hexagon) Fix predicated assignment to .tmp | expand

Commit Message

Taylor Simpson Sept. 29, 2022, 2:31 a.m. UTC
Here is an example of an instruction with a predicated assignment
to a .tmp HVX register
    if (p1) v12.tmp = vmem(%1 + #0)
Note that the .tmp indicates that references to v12 in the same packet
take the result of the load.  However, when the predicate is false,
the value at the start of the packet should be used.

To fix this bug, we preload the temporary with the value from the
HVX register.

Test case added to tests/tcg/hexagon/hvx_misc.c

Signed-off-by: Taylor Simpson <tsimpson@quicinc.com>
---
 target/hexagon/translate.h      |  5 +++++
 tests/tcg/hexagon/hvx_misc.c    | 39 +++++++++++++++++++++++++++++++++
 target/hexagon/gen_tcg_funcs.py | 12 ++++++++++
 3 files changed, 56 insertions(+)
diff mbox series

Patch

diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index a245172827..1256899dfa 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -83,6 +83,11 @@  static inline bool is_preloaded(DisasContext *ctx, int num)
     return test_bit(num, ctx->regs_written);
 }
 
+static inline bool is_tmp_vreg_preloaded(DisasContext *ctx, int num)
+{
+    return test_bit(num, ctx->vregs_updated_tmp);
+}
+
 intptr_t ctx_future_vreg_off(DisasContext *ctx, int regnum,
                              int num, bool alloc_ok);
 intptr_t ctx_tmp_vreg_off(DisasContext *ctx, int regnum,
diff --git a/tests/tcg/hexagon/hvx_misc.c b/tests/tcg/hexagon/hvx_misc.c
index 6e2c9ab3cd..3eb4705fb3 100644
--- a/tests/tcg/hexagon/hvx_misc.c
+++ b/tests/tcg/hexagon/hvx_misc.c
@@ -541,6 +541,43 @@  static void test_vshuff(void)
     check_output_b(__LINE__, 1);
 }
 
+static void test_load_tmp_predicated(void)
+{
+    void *p0 = buffer0;
+    void *p1 = buffer1;
+    void *pout = output;
+
+    for (int i = 0; i < BUFSIZE; i++) {
+        /*
+         * Load into v12 as .tmp with a false predicate, then
+         * use it in the next packet
+         * Should get old new value within the same packet and
+         * the old value in the next packet
+         */
+        asm("v3 = vmem(%0 + #0)\n\t"
+            "r1 = #1\n\t"
+            "v12 = vsplat(r1)\n\t"
+            "p1 = cmp.gt(r0, r0)\n\t"
+            "{\n\t"
+            "    if (p1) v12.tmp = vmem(%1 + #0)\n\t"
+            "    v4.w = vadd(v12.w, v3.w)\n\t"
+            "}\n\t"
+            "v4.w = vadd(v4.w, v12.w)\n\t"
+            "vmem(%2 + #0) = v4\n\t"
+            : : "r"(p0), "r"(p1), "r"(pout)
+            : "r1", "p1", "v12", "v3", "v4", "v6", "memory");
+        p0 += sizeof(MMVector);
+        p1 += sizeof(MMVector);
+        pout += sizeof(MMVector);
+
+        for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) {
+            expect[i].w[j] = buffer0[i].w[j] + 2;
+        }
+    }
+
+    check_output_w(__LINE__, BUFSIZE);
+}
+
 int main()
 {
     init_buffers();
@@ -578,6 +615,8 @@  int main()
 
     test_vshuff();
 
+    test_load_tmp_predicated();
+
     puts(err ? "FAIL" : "PASS");
     return err ? 1 : 0;
 }
diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs.py
index d72c689ad7..0e13fcbe1f 100755
--- a/target/hexagon/gen_tcg_funcs.py
+++ b/target/hexagon/gen_tcg_funcs.py
@@ -169,6 +169,18 @@  def genptr_decl(f, tag, regtype, regid, regno):
             elif (hex_common.is_tmp_result(tag)):
                 f.write("        ctx_tmp_vreg_off(ctx, %s%sN, 1, true);\n" % \
                     (regtype, regid))
+                if ('A_CONDEXEC' in hex_common.attribdict[tag]):
+                    f.write("    if (!is_tmp_vreg_preloaded(ctx, %s)) {\n" % \
+                                     regN)
+                    f.write("        intptr_t src_off =")
+                    f.write(" offsetof(CPUHexagonState, VRegs[%s%sN]);\n"% \
+                                         (regtype, regid))
+                    f.write("        tcg_gen_gvec_mov(MO_64, %s%sV_off,\n" % \
+                                         (regtype, regid))
+                    f.write("                         src_off,\n")
+                    f.write("                         sizeof(MMVector),\n")
+                    f.write("                         sizeof(MMVector));\n")
+                    f.write("    }\n")
             else:
                 f.write("        ctx_future_vreg_off(ctx, %s%sN," % \
                     (regtype, regid))