rs6000: Don't let swaps pass break multiply low-part (PR101129)

2021-07-15  Bill Schmidt  <wschmidt@linux.ibm.com>

gcc/
	PR target/101129
	* config/rs6000/rs6000-p8swap.c (has_part_mult): New.
	(rs6000_analyze_swaps): Insns containing a subreg of a mult are
	not swappable.

gcc/testsuite/
	PR target/101129
	* gcc.target/powerpc/pr101129.c: New.
This commit is contained in:
Bill Schmidt 2021-07-15 10:16:17 -05:00
parent 92acae5047
commit ad5f8ac1d2
2 changed files with 54 additions and 0 deletions

View file

@ -1523,6 +1523,22 @@ replace_swap_with_copy (swap_web_entry *insn_entry, unsigned i)
insn->set_deleted ();
}
/* INSN is known to contain a SUBREG, which we can normally handle,
but if the SUBREG itself contains a MULT then we need to leave it alone
to avoid turning a mult_hipart into a mult_lopart, for example. */
static bool
has_part_mult (rtx_insn *insn)
{
rtx body = PATTERN (insn);
if (GET_CODE (body) != SET)
return false;
rtx src = SET_SRC (body);
if (GET_CODE (src) != SUBREG)
return false;
rtx inner = XEXP (src, 0);
return (GET_CODE (inner) == MULT);
}
/* Make NEW_MEM_EXP's attributes and flags resemble those of
ORIGINAL_MEM_EXP. */
static void
@ -2501,6 +2517,9 @@ rs6000_analyze_swaps (function *fun)
insn_entry[uid].is_swappable = 0;
else if (special != SH_NONE)
insn_entry[uid].special_handling = special;
else if (insn_entry[uid].contains_subreg
&& has_part_mult (insn))
insn_entry[uid].is_swappable = 0;
else if (insn_entry[uid].contains_subreg)
insn_entry[uid].special_handling = SH_SUBREG;
}

View file

@ -0,0 +1,35 @@
/* { dg-do run } */
/* { dg-require-effective-target p8vector_hw } */
/* { dg-options "-mdejagnu-cpu=power8 -O " } */
/* PR101129: The swaps pass was turning a mult-lopart into a mult-hipart.
Make sure we aren't doing that anymore. */
typedef unsigned char u8;
typedef unsigned char __attribute__((__vector_size__ (8))) U;
typedef unsigned char __attribute__((__vector_size__ (16))) V;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef __int128 u128;
u8 g;
U u;
void
foo0 (u32 u32_0, U *ret)
{
u128 u128_2 = u32_0 * (u128)((V){ 5 } > (u32_0 & 4));
u64 u64_r = u128_2 >> 64;
u8 u8_r = u64_r + g;
*ret = u + u8_r;
}
int
main (void)
{
U x;
foo0 (7, &x);
for (unsigned i = 0; i < sizeof (x); i++)
if (x[i] != 0) __builtin_abort();
return 0;
}