powerpc: Handle DImode rotatert implemented with rlwinm (PR69946)
authorSegher Boessenkool <segher@kernel.crashing.org>
Fri, 26 Feb 2016 18:49:18 +0000 (19:49 +0100)
committerSegher Boessenkool <segher@gcc.gnu.org>
Fri, 26 Feb 2016 18:49:18 +0000 (19:49 +0100)
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
gcc/config/rs6000/rs6000.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/powerpc/pr69946.c [new file with mode: 0644]

index 6344092a55df11c753c134fdd61023f638705ca6..89f483c85dcfe5306ad91909714fdec913c7c2f2 100644 (file)
@@ -1,3 +1,9 @@
+2016-02-26  Segher Boessenkool  <segher@kernel.crashing.org>
+
+       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  <rguenther@suse.de>
            Jeff Law  <law@redhat.com>
 
index eed50f43571d93be7da217529831eb2a5923fa90..c7bad3f583a2c14612847239d6dd235d8e70ba6f 100644 (file)
@@ -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 ();
index 316720b5b4bd163f68468afd7c31dd86be61e78f..69289cc264ccd63e39d7c790f5f5171129c75a52 100644 (file)
@@ -1,3 +1,8 @@
+2016-02-26  Segher Boessenkool  <segher@kernel.crashing.org>
+
+       PR target/69946
+       * gcc.target/powerpc/pr69946.c: New file.
+
 2016-02-26  Richard Biener  <rguenther@suse.de>
             Jeff Law  <law@redhat.com>
 
diff --git a/gcc/testsuite/gcc.target/powerpc/pr69946.c b/gcc/testsuite/gcc.target/powerpc/pr69946.c
new file mode 100644 (file)
index 0000000..eb0c365
--- /dev/null
@@ -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 } } */