diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 43a83566..a8e504e 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -1177,6 +1177,18 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) } } + /* Look for case where upper 16 bits are set, so we can use MOVN. */ + if ((val & 0xffff000000000000ll) == 0xffff000000000000ll) + { + emit_insn (gen_rtx_SET (VOIDmode, dest, + GEN_INT (~ (~val & (0xffffll << 32))))); + emit_insn (gen_insv_immdi (dest, GEN_INT (16), + GEN_INT ((val >> 16) & 0xffff))); + emit_insn (gen_insv_immdi (dest, GEN_INT (0), + GEN_INT (val & 0xffff))); + return; + } + simple_sequence: first = true; mask = 0xffff; diff --git a/gcc/testsuite/gcc.target/aarch64/movn_1.c b/gcc/testsuite/gcc.target/aarch64/movn_1.c new file mode 100644 index 0000000..cc11ade --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/movn_1.c @@ -0,0 +1,27 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fno-inline --save-temps" } */ + +extern void abort (void); + +long long +foo () +{ + /* { dg-final { scan-assembler "mov\tx\[0-9\]+, -71536975282177" } } */ + return 0xffffbeefcafebabell; +} + +long long +merge4 (int a, int b, int c, int d) +{ + return ((long long) a << 48 | (long long) b << 32 + | (long long) c << 16 | (long long) d); +} + +int main () +{ + if (foo () != merge4 (0xffff, 0xbeef, 0xcafe, 0xbabe)) + abort (); + return 0; +} + +/* { dg-final { cleanup-saved-temps } } */