From bba0c624c8b1d6e54dc58091dd21b0c2ab000434 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 3 Feb 2020 21:43:44 +0000 Subject: [PATCH] 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 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): New pattern. gcc/testsuite/ PR target/87763 * gcc.target/aarch64/movk_2.c: New test. --- gcc/ChangeLog | 7 ++ gcc/config/aarch64/aarch64-protos.h | 1 + gcc/config/aarch64/aarch64.c | 24 +++++++ gcc/config/aarch64/aarch64.md | 17 +++++ gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gcc.target/aarch64/movk_2.c | 78 +++++++++++++++++++++++ 6 files changed, 132 insertions(+) create mode 100644 gcc/testsuite/gcc.target/aarch64/movk_2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index efbbbf08225..cea8ffee99c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2020-02-06 Richard Sandiford + + 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): New pattern. + 2020-02-06 Richard Sandiford PR rtl-optimization/87763 diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index 24cc65a383a..d29975a8921 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 6581e4cb075..6a1b4099af1 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 90eebce85c0..9c1f17d0f85 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" + [(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), + rtx_mode_t (operands[3], mode)) >= 0" + { + int shift = aarch64_movk_shift (rtx_mode_t (operands[2], mode), + rtx_mode_t (operands[3], mode)); + operands[2] = gen_int_mode (UINTVAL (operands[3]) >> shift, SImode); + operands[3] = gen_int_mode (shift, SImode); + return "movk\\t%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 601bc336290..cdb26581b9c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2020-02-06 Richard Sandiford + + PR target/87763 + * gcc.target/aarch64/movk_2.c: New test. + 2020-02-06 Marek Polacek 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 00000000000..a0477ad5d42 --- /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 + +#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); +} -- 2.30.2