diff options
author | Ian Bolton <ian.bolton@arm.com> | 2014-08-07 13:42:22 +0000 |
---|---|---|
committer | Kyrylo Tkachov <ktkachov@gcc.gnu.org> | 2014-08-07 13:42:22 +0000 |
commit | c747993a621cc69309e3a9e9fddeba09f470fb86 (patch) | |
tree | 33cb0a390bf1a450247bc8a61461e48e49b446b4 /gcc/config/aarch64 | |
parent | 4da2eb985b6a7c3cf4893d9ab6ab93e158ceb0cf (diff) | |
download | gcc-c747993a621cc69309e3a9e9fddeba09f470fb86.zip gcc-c747993a621cc69309e3a9e9fddeba09f470fb86.tar.gz gcc-c747993a621cc69309e3a9e9fddeba09f470fb86.tar.bz2 |
[AArch64] Use MOVN to generate 64-bit negative immediates where sensible
* config/aarch64/aarch64.c (aarch64_expand_mov_immediate):
Use MOVN when one of the half-words is 0xffff.
Co-Authored-By: Kyrylo Tkachov <kyrylo.tkachov@arm.com>
From-SVN: r213711
Diffstat (limited to 'gcc/config/aarch64')
-rw-r--r-- | gcc/config/aarch64/aarch64.c | 45 |
1 files changed, 32 insertions, 13 deletions
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 1165428..832bcf3 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -1006,7 +1006,7 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) unsigned HOST_WIDE_INT val; bool subtargets; rtx subtarget; - int one_match, zero_match; + int one_match, zero_match, first_not_ffff_match; gcc_assert (mode == SImode || mode == DImode); @@ -1107,29 +1107,48 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) one_match = 0; zero_match = 0; mask = 0xffff; + first_not_ffff_match = -1; for (i = 0; i < 64; i += 16, mask <<= 16) { - if ((val & mask) == 0) - zero_match++; - else if ((val & mask) == mask) + if ((val & mask) == mask) one_match++; + else + { + if (first_not_ffff_match < 0) + first_not_ffff_match = i; + if ((val & mask) == 0) + zero_match++; + } } if (one_match == 2) { - mask = 0xffff; - for (i = 0; i < 64; i += 16, mask <<= 16) + /* Set one of the quarters and then insert back into result. */ + mask = 0xffffll << first_not_ffff_match; + emit_insn (gen_rtx_SET (VOIDmode, dest, GEN_INT (val | mask))); + emit_insn (gen_insv_immdi (dest, GEN_INT (first_not_ffff_match), + GEN_INT ((val >> first_not_ffff_match) + & 0xffff))); + return; + } + + if (one_match > zero_match) + { + /* Set either first three quarters or all but the third. */ + mask = 0xffffll << (16 - first_not_ffff_match); + emit_insn (gen_rtx_SET (VOIDmode, dest, + GEN_INT (val | mask | 0xffffffff00000000ull))); + + /* Now insert other two quarters. */ + for (i = first_not_ffff_match + 16, mask <<= (first_not_ffff_match << 1); + i < 64; i += 16, mask <<= 16) { if ((val & mask) != mask) - { - emit_insn (gen_rtx_SET (VOIDmode, dest, GEN_INT (val | mask))); - emit_insn (gen_insv_immdi (dest, GEN_INT (i), - GEN_INT ((val >> i) & 0xffff))); - return; - } + emit_insn (gen_insv_immdi (dest, GEN_INT (i), + GEN_INT ((val >> i) & 0xffff))); } - gcc_unreachable (); + return; } if (zero_match == 2) |