The handling of 16-bit integer data-movement in the ARM backend doesn't make full use of the VFP instructions when they are available, even when the values are for use in VFP operations.
This patch adds support for using the VFP instructions and registers when moving 16-bit integer and floating point data between registers and between registers and memory. Tested the series for arm-none-linux-gnueabihf with native bootstrap and make check and for arm-none-eabi and armeb-none-eabi with make check on an ARMv8.2-A emulator. Tested this patch for arm-none-linux-gnueabihf with native bootstrap and make check and for arm-none-eabi with check-gcc on an ARMv8.2-A emulator. Ok for trunk? Matthew 2016-05-17 Jiong Wang <jiong.w...@arm.com> Matthew Wahab <matthew.wa...@arm.com> * config/arm/arm.c (output_move_vfp): Weaken assert to allow HImode. (arm_hard_regno_mode_ok): Allow HImode values in VFP registers. * config/arm/arm.md (*movhi_insn_arch4) Disable when VFP registers are available. (*movhi_bytes): Likewise. * config/arm/vfp.md (*arm_movhi_vfp): New. (*thumb2_movhi_vfp): New. testsuite/ 2016-05-17 Matthew Wahab <matthew.wa...@arm.com> * gcc.target/arm/short-vfp-1.c: New.
>From 0b8bc5f2966924c523d6fd75cf73dd01341914e2 Mon Sep 17 00:00:00 2001 From: Matthew Wahab <matthew.wa...@arm.com> Date: Thu, 7 Apr 2016 13:33:04 +0100 Subject: [PATCH 05/17] [PATCH 5/17][ARM] Enable HI mode moves for floating point values. 2016-05-17 Jiong Wang <jiong.w...@arm.com> Matthew Wahab <matthew.wa...@arm.com> * config/arm/arm.c (output_move_vfp): Weaken assert to allow HImode. (arm_hard_regno_mode_ok): Allow HImode values in VFP registers. * config/arm/arm.md (*movhi_bytes): Disable when VFP registers are available. Also fix some white-space. * config/arm/vfp.md (*arm_movhi_vfp): New. (*thumb2_movhi_vfp): New. testsuite/ 2016-05-17 Matthew Wahab <matthew.wa...@arm.com> * gcc.target/arm/short-vfp-1.c: New. --- gcc/config/arm/arm.c | 5 ++ gcc/config/arm/arm.md | 6 +- gcc/config/arm/vfp.md | 93 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.target/arm/short-vfp-1.c | 45 +++++++++++++++ 4 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.target/arm/short-vfp-1.c diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index f3914ef..26a8a48 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -18628,6 +18628,7 @@ output_move_vfp (rtx *operands) gcc_assert ((mode == HFmode && TARGET_HARD_FLOAT && TARGET_VFP) || mode == SFmode || mode == DFmode + || mode == HImode || mode == SImode || mode == DImode || (TARGET_NEON && VALID_NEON_DREG_MODE (mode))); @@ -23422,6 +23423,10 @@ arm_hard_regno_mode_ok (unsigned int regno, machine_mode mode) if (mode == HFmode) return VFP_REGNO_OK_FOR_SINGLE (regno); + /* VFP registers can hold HImode values. */ + if (mode == HImode) + return VFP_REGNO_OK_FOR_SINGLE (regno); + if (TARGET_NEON) return (VALID_NEON_DREG_MODE (mode) && VFP_REGNO_OK_FOR_DOUBLE (regno)) || (VALID_NEON_QREG_MODE (mode) diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 4049f10..3e23178 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -6365,7 +6365,7 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,m,r") (match_operand:HI 1 "general_operand" "rIk,K,n,r,mi"))] "TARGET_ARM - && arm_arch4 + && arm_arch4 && !(TARGET_HARD_FLOAT && TARGET_VFP) && (register_operand (operands[0], HImode) || register_operand (operands[1], HImode))" "@ @@ -6391,7 +6391,7 @@ (define_insn "*movhi_bytes" [(set (match_operand:HI 0 "s_register_operand" "=r,r,r") (match_operand:HI 1 "arm_rhs_operand" "I,rk,K"))] - "TARGET_ARM" + "TARGET_ARM && !(TARGET_HARD_FLOAT && TARGET_VFP)" "@ mov%?\\t%0, %1\\t%@ movhi mov%?\\t%0, %1\\t%@ movhi @@ -6399,7 +6399,7 @@ [(set_attr "predicable" "yes") (set_attr "type" "mov_imm,mov_reg,mvn_imm")] ) - + ;; We use a DImode scratch because we may occasionally need an additional ;; temporary if the address isn't offsettable -- push_reload doesn't seem ;; to take any notice of the "o" constraints on reload_memory_operand operand. diff --git a/gcc/config/arm/vfp.md b/gcc/config/arm/vfp.md index 9750ba1..d7c874a 100644 --- a/gcc/config/arm/vfp.md +++ b/gcc/config/arm/vfp.md @@ -18,6 +18,99 @@ ;; along with GCC; see the file COPYING3. If not see ;; <http://www.gnu.org/licenses/>. */ +;; Patterns for HI moves which provide more data transfer instructions when VFP +;; support is enabled. +(define_insn "*arm_movhi_vfp" + [(set + (match_operand:HI 0 "nonimmediate_operand" + "=rk, r, r, m, r, *t, r, *t") + (match_operand:HI 1 "general_operand" + "rIk, K, n, r, mi, r, *t, *t"))] + "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP + && (register_operand (operands[0], HImode) + || register_operand (operands[1], HImode))" +{ + switch (which_alternative) + { + case 0: + return "mov%?\t%0, %1\t%@ movhi"; + case 1: + return "mvn%?\t%0, #%B1\t%@ movhi"; + case 2: + return "movw%?\t%0, %L1\t%@ movhi"; + case 3: + return "strh%?\t%1, %0\t%@ movhi"; + case 4: + return "ldrh%?\t%0, %1\t%@ movhi"; + case 5: + case 6: + return "vmov%?\t%0, %1\t%@ int"; + case 7: + return "vmov%?.f32\t%0, %1\t%@ int"; + default: + gcc_unreachable (); + } +} + [(set_attr "predicable" "yes") + (set_attr_alternative "type" + [(if_then_else + (match_operand 1 "const_int_operand" "") + (const_string "mov_imm") + (const_string "mov_reg")) + (const_string "mvn_imm") + (const_string "mov_imm") + (const_string "store1") + (const_string "load1") + (const_string "f_mcr") + (const_string "f_mrc") + (const_string "fmov")]) + (set_attr "pool_range" "*, *, *, *, 256, *, *, *") + (set_attr "neg_pool_range" "*, *, *, *, 244, *, *, *") + (set_attr "length" "4")] +) + +(define_insn "*thumb2_movhi_vfp" + [(set + (match_operand:HI 0 "nonimmediate_operand" + "=rk, r, l, r, m, r, *t, r, *t") + (match_operand:HI 1 "general_operand" + "rk, I, Py, n, r, m, r, *t, *t"))] + "TARGET_THUMB2 && TARGET_HARD_FLOAT && TARGET_VFP + && (register_operand (operands[0], HImode) + || register_operand (operands[1], HImode))" +{ + switch (which_alternative) + { + case 0: + case 1: + case 2: + return "mov%?\t%0, %1\t%@ movhi"; + case 3: + return "movw%?\t%0, %L1\t%@ movhi"; + case 4: + return "strh%?\t%1, %0\t%@ movhi"; + case 5: + return "ldrh%?\t%0, %1\t%@ movhi"; + case 6: + case 7: + return "vmov%?\t%0, %1\t%@ int"; + case 8: + return "vmov%?.f32\t%0, %1\t%@ int"; + default: + gcc_unreachable (); + } +} + [(set_attr "predicable" "yes") + (set_attr "predicable_short_it" + "yes, no, yes, no, no, no, no, no, no") + (set_attr "type" + "mov_reg, mov_imm, mov_imm, mov_imm, store1, load1,\ + f_mcr, f_mrc, fmov") + (set_attr "pool_range" "*, *, *, *, *, 4094, *, *, *") + (set_attr "neg_pool_range" "*, *, *, *, *, 250, *, *, *") + (set_attr "length" "2, 4, 2, 4, 4, 4, 4, 4, 4")] +) + ;; SImode moves ;; ??? For now do not allow loading constants into vfp regs. This causes ;; problems because small constants get converted into adds. diff --git a/gcc/testsuite/gcc.target/arm/short-vfp-1.c b/gcc/testsuite/gcc.target/arm/short-vfp-1.c new file mode 100644 index 0000000..d96c763 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/short-vfp-1.c @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target arm_vfp_ok } +/* { dg-options "-mfpu=vfp" } */ + +int +test_sisf (float x) +{ + return (int)x; +} + +short +test_hisf (float x) +{ + return (short)x; +} + +float +test_sfsi (int x) +{ + return (float)x; +} + +float +test_sfhi (short x) +{ + return (float)x; +} + +short +test_hisi (int x) +{ + return (short)x; +} + +int +test_sihi (short x) +{ + return (int)x; +} + +/* {dg-final { scan-assembler-times {vcvt\.s32\.f32\ts[0-9]+,s[0-9]+} 2 }} */ +/* {dg-final { scan-assembler-times {vcvt\.f32\.s32\ts[0-9]+,s[0-9]+} 2 }} */ +/* {dg-final { scan-assembler-times {vmov\tr[0-9]+,s[0-9]+} 2 }} */ +/* {dg-final { scan-assembler-times {vmov\ts[0-9]+,r[0-9]+} 2 }} */ +/* {dg-final { scan-assembler-times {sxth\tr[0-9]+,r[0-9]+} 2 }} */ -- 2.1.4