On Sat, Sep 26, 2026 at 1:23 PM Brian Cain <[email protected]> wrote:
> Cc: Taylor Simpson <[email protected]> > Signed-off-by: Brian Cain <[email protected]> > --- > tests/tcg/hexagon/multiple-writes.c | 98 +++++++++++++++++++++++++++++ > 1 file changed, 98 insertions(+) > > diff --git a/tests/tcg/hexagon/multiple-writes.c > b/tests/tcg/hexagon/multiple-writes.c > index bd2b1384dd9..21771252020 100644 > --- a/tests/tcg/hexagon/multiple-writes.c > +++ b/tests/tcg/hexagon/multiple-writes.c > @@ -13,6 +13,7 @@ > > #include <assert.h> > #include <signal.h> > +#include <stdint.h> > #include <stdio.h> > #include <stdlib.h> > #include <string.h> > @@ -223,6 +224,80 @@ static int test_vreg_legal_predicated(void) > return sig; > } > > +/* > + * Complementary predicated writes to the same V-register pair are legal. > + * v16 and v22 are splatted with distinct patterns; since p0 is always > + * true, v14 must end up holding v16's pattern. Extracting a word from > + * v14 confirms the executed branch actually ran, rather than merely that > + * no SIGILL was raised. > + */ > +static int test_vreg_pair_legal_predicated(void) > +{ > + int sig; > + uint32_t result; > + > + asm volatile( > + "r0 = #0\n" > + "r1 = ##1f\n" > + "memw(%[resume_pc]) = r1\n" > + "r4 = #0x11111111\n" > + "r5 = #0x22222222\n" > + "v16 = vsplat(r4)\n" > + "v22 = vsplat(r5)\n" > Go ahead and assign something to v21 and v23 here. Ultimately, the values aren't used but the registers are referenced in the vcombine instructions below. Alternatively, you could just use v16 and v22. Something like " if (p0) v15:14 = vcombine(v22, v16)\n" " if (!p0) v15:14 = vcombine(v16, v22)\n" If you do that, you can remove v21 and v23 from the clobber list. > + "r4 = #0\n" > + "p0 = cmp.eq(r0, r0)\n" > + "{\n" > + " if (p0) v15:14 = vcombine(v21, v16)\n" > + " if (!p0) v15:14 = vcombine(v23, v22)\n" > + "}\n" > + "%[result] = vextract(v14, r4)\n" > + "1:\n" > + "%[sig] = r0\n" > + : [sig] "=r"(sig), [result] "=r"(result) > + : [resume_pc] "r"(&resume_pc) > + : "r0", "r1", "r4", "r5", "p0", > + "v14", "v15", "v16", "v21", "v22", "v23", "memory"); > + > + return sig == SIGILL ? SIGILL : result; > +} > + > +/* > + * A future write may consume a temporary value from the same V-register. > + * buf is zeroed, so v0.tmp loads all-zero and v0.w = vadd(v0.tmp.w, 1) > + * must end up as 1 in every word. Extracting a word from the result > + * confirms the add actually used the loaded .tmp value, rather than > + * merely that no SIGILL was raised. > + */ > +static int test_vreg_legal_tmp(void) > +{ > + long long buf[16] __attribute__((aligned(128))); > + int sig; > + uint32_t result; > + > + memset(buf, 0, sizeof(buf)); > + > + asm volatile( > + "r0 = #0\n" > + "r1 = ##1f\n" > + "memw(%[resume_pc]) = r1\n" > + "r2 = %[buf]\n" > + "r3 = #1\n" > + "r4 = #0\n" > + "v1 = vsplat(r3)\n" > Consider putting something non-zero into v0 here. That will be a stronger check that the read from buf actually took place. > + "{\n" > + " v0.tmp = vmem(r2 + #0)\n" > + " v0.w = vadd(v0.w, v1.w)\n" > + "}\n" > + "%[result] = vextract(v0, r4)\n" > + "1:\n" > + "%[sig] = r0\n" > + : [sig] "=r"(sig), [result] "=r"(result) > + : [resume_pc] "r"(&resume_pc), [buf] "r"(buf) > + : "r0", "r1", "r2", "r3", "r4", "v0", "v1", "memory"); > + > + return sig == SIGILL ? SIGILL : result; > +} > + > static int test_vreg_illegal_mixed(void) > { > int sig; > @@ -242,6 +317,26 @@ static int test_vreg_illegal_mixed(void) > return sig; > } > > +/* A pair write and a single write to either pair member are illegal. */ > +static int test_vreg_illegal_pair_overlap(void) > +{ > + int sig; > + > + asm volatile( > + "r0 = #0\n" > + "r1 = ##1f\n" > + "memw(%[resume_pc]) = r1\n" > Consider putting something into v14 and v15 here and check the values are unchanged at the end. Perhaps a subsequent patch that does this for all the illegal tests. > + ".word 0x1f5055ee /* { v15:14 = vcombine(v21, v16) */\n" > + ".word 0x1e03e5ee /* v14 = v5 } */\n" > + "1:\n" > + "%[sig] = r0\n" > + : [sig] "=r"(sig) > + : [resume_pc] "r"(&resume_pc) > + : "r0", "r1", "memory"); > + > + return sig; > +} > + > static int test_vreg_illegal_uncond(void) > { > int sig; > @@ -308,7 +403,10 @@ int main() > assert(test_post_increment3() == SIGILL); > > assert(test_vreg_legal_predicated() == 23); > + assert(test_vreg_pair_legal_predicated() == 0x11111111); > + assert(test_vreg_legal_tmp() == 1); > assert(test_vreg_illegal_mixed() == SIGILL); > + assert(test_vreg_illegal_pair_overlap() == SIGILL); > assert(test_vreg_illegal_uncond() == SIGILL); > > assert(test_qreg_illegal() == SIGILL); > -- > 2.34.1 > Otherwise Reviewed-by: Taylor Simpson <[email protected]>
