From d1f2bea53f8990253f655cfa22815046efb2ed87 Mon Sep 17 00:00:00 2001 From: Segher Boessenkool Date: Fri, 26 Feb 2016 19:49:18 +0100 Subject: [PATCH] powerpc: Handle DImode rotatert implemented with rlwinm (PR69946) Some DImode rotate-right-and-mask can be implemented best with a rlwinm instruction: those that could be a lshiftrt instead of a rotatert, while the mask is not right-aligned. Why the rotate in the testcase is not optimised to a plain shift is another question, but we need to handle it here anyway. We compute the shift amount for a 64-bit rotate. This is 32 too high in this case; if we print using %h that is masked out (and this doesn't silently let through invalid instructions, everything is checked by rs6000_is_valid_shift_mask which is much more thorough). PR target/69946 * config/rs6000/rs6000.c (rs6000_insn_for_shift_mask): Print rlwinm shift amount using %h. Add comment. gcc/testsuite/ * gcc.target/powerpc/pr69946.c: New file. From-SVN: r233755 --- gcc/ChangeLog | 6 ++++ gcc/config/rs6000/rs6000.c | 7 ++-- gcc/testsuite/ChangeLog | 5 +++ gcc/testsuite/gcc.target/powerpc/pr69946.c | 38 ++++++++++++++++++++++ 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.target/powerpc/pr69946.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6344092a55d..89f483c85dc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2016-02-26 Segher Boessenkool + + PR target/69946 + * config/rs6000/rs6000.c (rs6000_insn_for_shift_mask): Print rlwinm + shift amount using %h. Add comment. + 2016-02-26 Richard Biener Jeff Law diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index eed50f43571..c7bad3f583a 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -17438,9 +17438,12 @@ rs6000_insn_for_shift_mask (machine_mode mode, rtx *operands, bool dot) operands[2] = GEN_INT (32 - INTVAL (operands[2])); operands[3] = GEN_INT (31 - nb); operands[4] = GEN_INT (31 - ne); + /* This insn can also be a 64-bit rotate with mask that really makes + it just a shift right (with mask); the %h below are to adjust for + that situation (shift count is >= 32 in that case). */ if (dot) - return "rlw%I2nm. %0,%1,%2,%3,%4"; - return "rlw%I2nm %0,%1,%2,%3,%4"; + return "rlw%I2nm. %0,%1,%h2,%3,%4"; + return "rlw%I2nm %0,%1,%h2,%3,%4"; } gcc_unreachable (); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 316720b5b4b..69289cc264c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2016-02-26 Segher Boessenkool + + PR target/69946 + * gcc.target/powerpc/pr69946.c: New file. + 2016-02-26 Richard Biener Jeff Law diff --git a/gcc/testsuite/gcc.target/powerpc/pr69946.c b/gcc/testsuite/gcc.target/powerpc/pr69946.c new file mode 100644 index 00000000000..eb0c365d137 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr69946.c @@ -0,0 +1,38 @@ +/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */ +/* { dg-skip-if "" { powerpc_elfv2 } } */ +/* { dg-options "-O2" } */ + +/* This generates a rotate:DI by 44, with mask 0xf00, which is implemented + using a rlwinm instruction. We used to write 44 for the shift count + there; it should be 12. */ + +struct A +{ + int a : 4; + int : 2; + int b : 2; + int : 2; + int c : 2; + int d : 1; + int e; +}; +struct B +{ + int a : 4; +} *a; +void bar (struct A); + +void +foo (void) +{ + struct B b = a[0]; + struct A c; + c.a = b.a; + c.b = 1; + c.c = 1; + c.d = 0; + bar (c); +} + +/* { dg-final { scan-assembler-not {(?n)rlwinm.*,44,20,23} } } */ +/* { dg-final { scan-assembler-times {(?n)rlwinm.*,12,20,23} 1 } } */ -- 2.30.2