RISC-V: Fix bug of VSETVL fusion

This patch fixes bugs in the fusion of this following case:

li a5,-1
vmv.s.x v0,a5 -> demand any non-zero AVL
vsetvli a5, ...

Incorrect fusion after VSETVL PASS:

li a5,-1
vsetvli a5...
vmv.s.x v0, a5 --> a5 is modified as incorrect value.

We disallow this incorrect fusion above.

Full coverage testing of RV64 and RV32 no regression.

	PR target/113087

gcc/ChangeLog:

	* config/riscv/riscv-vsetvl.cc: Disallow fusion when VL modification pollutes non AVL use.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/autovec/pr113087-1.c: New test.
This commit is contained in:
Juzhe-Zhong 2023-12-20 14:50:11 +08:00 committed by Pan Li
parent d7e9ae4fa9
commit d82bb518fa
2 changed files with 99 additions and 2 deletions

View File

@ -1128,6 +1128,27 @@ public:
return gen_vsetvl_discard_result (Pmode, avl, sew, vlmul, ta, ma);
}
/* Return true that the non-AVL operands of THIS will be modified
if we fuse the VL modification from OTHER into THIS. */
bool vl_modify_non_avl_op_p (const vsetvl_info &other) const
{
/* We don't need to worry about any operands from THIS be
modified by OTHER vsetvl since we OTHER vsetvl doesn't
modify any operand. */
if (!other.has_vl ())
return false;
/* THIS VL operand always preempt OTHER VL operand. */
if (this->has_vl ())
return false;
/* If THIS has non IMM AVL and THIS is AVL compatible with
OTHER, the AVL value of THIS is same as VL value of OTHER. */
if (!this->has_imm_avl ())
return false;
return find_access (this->get_insn ()->uses (), REGNO (other.get_vl ()));
}
bool operator== (const vsetvl_info &other) const
{
gcc_assert (!uninit_p () && !other.uninit_p ()
@ -1896,6 +1917,20 @@ public:
gcc_unreachable ();
}
bool vl_not_in_conflict_p (const vsetvl_info &prev, const vsetvl_info &next)
{
/* We don't fuse this following case:
li a5, -1
vmv.s.x v0, a5 -- PREV
vsetvli a5, ... -- NEXT
Don't fuse NEXT into PREV.
*/
return !prev.vl_modify_non_avl_op_p (next)
&& !next.vl_modify_non_avl_op_p (prev);
}
bool avl_compatible_p (const vsetvl_info &prev, const vsetvl_info &next)
{
gcc_assert (prev.valid_p () && next.valid_p ());
@ -1953,7 +1988,8 @@ public:
{
bool compatible_p = sew_lmul_compatible_p (prev, next)
&& policy_compatible_p (prev, next)
&& avl_compatible_p (prev, next);
&& avl_compatible_p (prev, next)
&& vl_not_in_conflict_p (prev, next);
return compatible_p;
}
@ -1961,7 +1997,8 @@ public:
{
bool available_p = sew_lmul_available_p (prev, next)
&& policy_available_p (prev, next)
&& avl_available_p (prev, next);
&& avl_available_p (prev, next)
&& vl_not_in_conflict_p (prev, next);
gcc_assert (!available_p || compatible_p (prev, next));
return available_p;
}

View File

@ -0,0 +1,60 @@
/* { dg-do run } */
/* { dg-options "-O3" } */
/* { dg-require-effective-target riscv_v } */
#include <assert.h>
int (e) (int g, int h) { return h > 0x10 || g > 0xFFFFFFFF >> h ? g : g << h; }
struct i
{
int j;
int l : 1;
};
struct m
{
char k;
int n;
};
char o;
char p;
short s;
int q;
struct m r;
int v;
int t;
short z;
long ac;
int ad;
int ae;
static void
ai (struct i bf)
{
for (; v; v++)
r.k = 0;
do
ac ^= bf.j;
while (bf.j < 0);
s = 0;
if (bf.l)
q |= 0x800;
}
int
main ()
{
struct i aw = {0xE00, 1};
o = 4;
s = p;
ai (aw);
t = 1;
++p;
for (; t <= 7; t++)
{
ad &= 1;
(o &= 1 - e (0x40000012, ++ae)) & (z |= 1);
}
for (; r.n;)
;
assert (o == 4);
return 0;
}