aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2020-02-03 21:43:44 +0000
committerRichard Sandiford <richard.sandiford@arm.com>2020-02-06 17:27:00 +0000
commitbba0c624c8b1d6e54dc58091dd21b0c2ab000434 (patch)
tree8ed844c674d1357b8f72de97999951e19879f18e /gcc
parentb65a1eb3fae53f2e1ea1ef8c1164f490d55855a1 (diff)
downloadgcc-bba0c624c8b1d6e54dc58091dd21b0c2ab000434.zip
gcc-bba0c624c8b1d6e54dc58091dd21b0c2ab000434.tar.gz
gcc-bba0c624c8b1d6e54dc58091dd21b0c2ab000434.tar.bz2
aarch64: Add an and/ior-based movk pattern [PR87763]
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/config/aarch64/aarch64-protos.h1
-rw-r--r--gcc/config/aarch64/aarch64.c24
-rw-r--r--gcc/config/aarch64/aarch64.md17
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.target/aarch64/movk_2.c78
6 files changed, 132 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index efbbbf0..cea8ffe 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index 24cc65a..d29975a 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -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 *);
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 6581e4c..6a1b409 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -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. */
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 90eebce..9c1f17d 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -1282,6 +1282,23 @@
[(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"))]
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 601bc33..cdb2658 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..a0477ad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/movk_2.c
@@ -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);
+}