Bootstrapped and regtested on powerpc64le-linux-gnu {P10,P9} powerpc64-linux-gnu {P8, P7} and X86. OK for master?
gcc/ChangeLog: PR 90323 * simplify-rtx.c (simplify_context::simplify_binary_operation_1): Relax C from constant to constant or reg. gcc/testsuite/ChangeLog: * gcc.target/powerpc/pr90323.c: New test. --- gcc/simplify-rtx.c | 11 ++++---- gcc/testsuite/gcc.target/powerpc/pr90323.c | 33 ++++++++++++++++++++++ 2 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gcc.target/powerpc/pr90323.c diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index a060f1bbce0..be240b2979e 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -3581,12 +3581,13 @@ simplify_context::simplify_binary_operation_1 (rtx_code code, } } - /* If we have (xor (and (xor A B) C) A) with C a constant we can instead - do (ior (and A ~C) (and B C)) which is a machine instruction on some - machines, and also has shorter instruction path length. */ + /* If we have (xor (and (xor A B) C) A) with C a constant or register + we can instead do (ior (and A ~C) (and B C)) which is a machine + instruction on some machines, and also has shorter instruction path + length. */ if (GET_CODE (op0) == AND && GET_CODE (XEXP (op0, 0)) == XOR - && CONST_INT_P (XEXP (op0, 1)) + && (CONST_INT_P (XEXP (op0, 1)) || REG_P (XEXP (op0, 1))) && rtx_equal_p (XEXP (XEXP (op0, 0), 0), trueop1)) { rtx a = trueop1; @@ -3600,7 +3601,7 @@ simplify_context::simplify_binary_operation_1 (rtx_code code, /* Similarly, (xor (and (xor A B) C) B) as (ior (and A C) (and B ~C)) */ else if (GET_CODE (op0) == AND && GET_CODE (XEXP (op0, 0)) == XOR - && CONST_INT_P (XEXP (op0, 1)) + && (CONST_INT_P (XEXP (op0, 1)) || REG_P (XEXP (op0, 1))) && rtx_equal_p (XEXP (XEXP (op0, 0), 1), trueop1)) { rtx a = XEXP (XEXP (op0, 0), 0); diff --git a/gcc/testsuite/gcc.target/powerpc/pr90323.c b/gcc/testsuite/gcc.target/powerpc/pr90323.c new file mode 100644 index 00000000000..e80609c477f --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr90323.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <altivec.h> +#include <stdio.h> +volatile vector unsigned orig = {0xebebebeb, 0x34343434, 0x76767676, 0x12121212}; +volatile vector unsigned mask = {0xffffffff, 0, 0xffffffff, 0}; +volatile vector unsigned fill = {0xfefefefe, 0xaaaaaaaa, 0xbbbbbbbb, 0xcccccccc}; +volatile vector unsigned expected = {0xfefefefe, 0x34343434, 0xbbbbbbbb, 0x12121212}; +__attribute__((noinline)) vector unsigned +without_sel(vector unsigned l, vector unsigned r, vector unsigned mask) { + l = l & ~mask; + l |= mask & r; + return l; +} + +__attribute__((noinline)) vector unsigned +with_sel(vector unsigned l, vector unsigned r, vector unsigned mask) { + return vec_sel(l, r, mask); +} + +int main() { + vector unsigned res1 = without_sel(orig, fill, mask); + vector unsigned res2 = with_sel(orig, fill, mask); + if (!vec_all_eq(res1, expected)) + printf("error1\n"); + if (!vec_all_eq(res2, expected)) + printf("error2\n"); + return 0; +} + + +/* { dg-final { scan-assembler-times {\mxxsel\M} 2 } } */ -- 2.27.0