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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@233755
138bc75d-0d04-0410-961f-
82ee72b054a4
+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>
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 ();
+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>
--- /dev/null
+/* { 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 } } */