aarch64: Add an and/ior-based movk pattern [PR87763]
authorRichard Sandiford <richard.sandiford@arm.com>
Mon, 3 Feb 2020 21:43:44 +0000 (21:43 +0000)
committerRichard Sandiford <richard.sandiford@arm.com>
Thu, 6 Feb 2020 17:27:00 +0000 (17:27 +0000)
This patch adds a second movk pattern that models the instruction
as a "normal" and/ior operation rather than an insertion.  It fixes
the third insv_1.c failure in PR87763, which was a regression from
GCC 8.

2020-02-06  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
PR target/87763
* config/aarch64/aarch64-protos.h (aarch64_movk_shift): Declare.
* config/aarch64/aarch64.c (aarch64_movk_shift): New function.
* config/aarch64/aarch64.md (aarch64_movk<mode>): New pattern.

gcc/testsuite/
PR target/87763
* gcc.target/aarch64/movk_2.c: New test.

gcc/ChangeLog
gcc/config/aarch64/aarch64-protos.h
gcc/config/aarch64/aarch64.c
gcc/config/aarch64/aarch64.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/aarch64/movk_2.c [new file with mode: 0644]

index efbbbf0..cea8ffe 100644 (file)
@@ -1,5 +1,12 @@
 2020-02-06  Richard Sandiford  <richard.sandiford@arm.com>
 
+       PR target/87763
+       * config/aarch64/aarch64-protos.h (aarch64_movk_shift): Declare.
+       * config/aarch64/aarch64.c (aarch64_movk_shift): New function.
+       * config/aarch64/aarch64.md (aarch64_movk<mode>): New pattern.
+
+2020-02-06  Richard Sandiford  <richard.sandiford@arm.com>
+
        PR rtl-optimization/87763
        * config/aarch64/aarch64.md (*ashiftsi_extvdi_bfiz): New pattern.
 
index 24cc65a..d29975a 100644 (file)
@@ -560,6 +560,7 @@ bool aarch64_sve_float_mul_immediate_p (rtx);
 bool aarch64_split_dimode_const_store (rtx, rtx);
 bool aarch64_symbolic_address_p (rtx);
 bool aarch64_uimm12_shift (HOST_WIDE_INT);
+int aarch64_movk_shift (const wide_int_ref &, const wide_int_ref &);
 bool aarch64_use_return_insn_p (void);
 const char *aarch64_output_casesi (rtx *);
 
index 6581e4c..6a1b409 100644 (file)
@@ -7895,6 +7895,30 @@ aarch64_movw_imm (HOST_WIDE_INT val, scalar_int_mode mode)
          || (val & (((HOST_WIDE_INT) 0xffff) << 16)) == val);
 }
 
+/* Test whether:
+
+     X = (X & AND_VAL) | IOR_VAL;
+
+   can be implemented using:
+
+     MOVK X, #(IOR_VAL >> shift), LSL #shift
+
+   Return the shift if so, otherwise return -1.  */
+int
+aarch64_movk_shift (const wide_int_ref &and_val,
+                   const wide_int_ref &ior_val)
+{
+  unsigned int precision = and_val.get_precision ();
+  unsigned HOST_WIDE_INT mask = 0xffff;
+  for (unsigned int shift = 0; shift < precision; shift += 16)
+    {
+      if (and_val == ~mask && (ior_val & mask) == ior_val)
+       return shift;
+      mask <<= 16;
+    }
+  return -1;
+}
+
 /* VAL is a value with the inner mode of MODE.  Replicate it to fill a
    64-bit (DImode) integer.  */
 
index 90eebce..9c1f17d 100644 (file)
   [(set_attr "type" "mov_imm")]
 )
 
+;; Match MOVK as a normal AND and IOR operation.
+(define_insn "aarch64_movk<mode>"
+  [(set (match_operand:GPI 0 "register_operand" "=r")
+       (ior:GPI (and:GPI (match_operand:GPI 1 "register_operand" "0")
+                         (match_operand:GPI 2 "const_int_operand"))
+                (match_operand:GPI 3 "const_int_operand")))]
+  "aarch64_movk_shift (rtx_mode_t (operands[2], <MODE>mode),
+                      rtx_mode_t (operands[3], <MODE>mode)) >= 0"
+  {
+    int shift = aarch64_movk_shift (rtx_mode_t (operands[2], <MODE>mode),
+                                   rtx_mode_t (operands[3], <MODE>mode));
+    operands[2] = gen_int_mode (UINTVAL (operands[3]) >> shift, SImode);
+    operands[3] = gen_int_mode (shift, SImode);
+    return "movk\\t%<w>0, #%X2, lsl %3";
+  }
+)
+
 (define_expand "movti"
   [(set (match_operand:TI 0 "nonimmediate_operand")
        (match_operand:TI 1 "general_operand"))]
index 601bc33..cdb2658 100644 (file)
@@ -1,3 +1,8 @@
+2020-02-06  Richard Sandiford  <richard.sandiford@arm.com>
+
+       PR target/87763
+       * gcc.target/aarch64/movk_2.c: New test.
+
 2020-02-06  Marek Polacek  <polacek@redhat.com>
 
        PR c++/93597 - ICE with lambda in operator function.
diff --git a/gcc/testsuite/gcc.target/aarch64/movk_2.c b/gcc/testsuite/gcc.target/aarch64/movk_2.c
new file mode 100644 (file)
index 0000000..a0477ad
--- /dev/null
@@ -0,0 +1,78 @@
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <stdint.h>
+
+#define H3 ((uint64_t) 0xffff << 48)
+#define H2 ((uint64_t) 0xffff << 32)
+#define H1 ((uint64_t) 0xffff << 16)
+#define H0 ((uint64_t) 0xffff)
+
+/*
+** f1:
+**     mov     w0, w1
+**     movk    w0, #0x9876(?:, lsl #?0)?
+**     ret
+*/
+uint32_t
+f1 (uint32_t dummy, uint32_t x)
+{
+  return (x & 0xffff0000) | 0x9876;
+}
+
+/*
+** f2:
+**     movk    w0, #0x1234, lsl #?16
+**     ret
+*/
+uint32_t
+f2 (uint32_t x)
+{
+  return (x & 0xffff) | 0x12340000;
+}
+
+/*
+** g1:
+**     movk    x0, #0x1234, lsl #?0
+**     ret
+*/
+uint64_t
+g1 (uint64_t x)
+{
+  return (x & (H3 | H2 | H1)) | 0x1234;
+}
+
+/*
+** g2:
+**     movk    x0, #0x900e, lsl #?16
+**     ret
+*/
+uint64_t
+g2 (uint64_t x)
+{
+  return (x & (H3 | H2 | H0)) | ((uint64_t) 0x900e << 16);
+}
+
+/*
+** g3:
+**     movk    x0, #0xee33, lsl #?32
+**     ret
+*/
+uint64_t
+g3 (uint64_t x)
+{
+  return (x & (H3 | H1 | H0)) | ((uint64_t) 0xee33 << 32);
+}
+
+/*
+** g4:
+**     mov     x0, x1
+**     movk    x0, #0x7654, lsl #?48
+**     ret
+*/
+uint64_t
+g4 (uint64_t dummy, uint64_t x)
+{
+  return (x & (H2 | H1 | H0)) | ((uint64_t) 0x7654 << 48);
+}