diff options
author | Thomas Preud'homme <thomas.preudhomme@arm.com> | 2016-07-13 10:54:01 +0000 |
---|---|---|
committer | Thomas Preud'homme <thopre01@gcc.gnu.org> | 2016-07-13 10:54:01 +0000 |
commit | 2b9509a34d0f7e25202530a4453afc5eb5d06f6b (patch) | |
tree | 86e547979f660cedd32b2e1b5d3363a3017fdb8d /gcc/config | |
parent | 7f15b177ba2b5907242dec45da10da635df3e16e (diff) | |
download | gcc-2b9509a34d0f7e25202530a4453afc5eb5d06f6b.zip gcc-2b9509a34d0f7e25202530a4453afc5eb5d06f6b.tar.gz gcc-2b9509a34d0f7e25202530a4453afc5eb5d06f6b.tar.bz2 |
arm.h (TARGET_HAVE_MOVT): Include ARMv8-M as having MOVT.
2016-07-13 Thomas Preud'homme <thomas.preudhomme@arm.com>
gcc/
* config/arm/arm.h (TARGET_HAVE_MOVT): Include ARMv8-M as having MOVT.
* config/arm/arm.c (arm_arch_name): (const_ok_for_op): Check MOVT/MOVW
availability with TARGET_HAVE_MOVT.
(thumb_legitimate_constant_p): Strip the high part of a label_ref.
(thumb1_rtx_costs): Also return 0 if setting a half word constant and
MOVW is available and replace (unsigned HOST_WIDE_INT) INTVAL by
UINTVAL.
(thumb1_size_rtx_costs): Make set of half word constant also cost 1
extra instruction if MOVW is available. Use a cost variable
incremented by COSTS_N_INSNS (1) when the condition match rather than
returning an arithmetic expression based on COSTS_N_INSNS. Make
constant with bottom half word zero cost 2 instruction if MOVW is
available.
* config/arm/arm.md (define_attr "arch"): Add v8mb.
(define_attr "arch_enabled"): Set to yes if arch value is v8mb and
target is ARMv8-M Baseline.
(arm_movt): New unpredicable alternative for ARMv8-M Baseline.
(arm_movtas_ze): Likewise.
* config/arm/thumb1.md (thumb1_movdi_insn): Add ARMv8-M Baseline only
alternative for constants satisfying j constraint.
(thumb1_movsi_insn): Likewise.
(movsi splitter for K alternative): Tighten condition to not trigger
if movt is available and j constraint is satisfied.
(Pe immediate splitter): Likewise.
(thumb1_movhi_insn): Add ARMv8-M Baseline only alternative for
constant fitting in an halfword to use MOVW.
* doc/sourcebuild.texi (arm_thumb1_movt_ok): Document new ARM
effective target.
gcc/testsuite/
* lib/target-supports.exp (check_effective_target_arm_thumb1_movt_ok):
Define effective target.
* gcc.target/arm/pr42574.c: Require arm_thumb1_ok and
!arm_thumb1_movt_ok to exclude ARMv8-M Baseline.
* gcc.target/arm/movhi_movw.c: New test.
* gcc.target/arm/movsi_movw.c: Likewise.
* gcc.target/arm/movdi_movw.c: Likewise.
From-SVN: r238288
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/arm/arm.c | 31 | ||||
-rw-r--r-- | gcc/config/arm/arm.h | 4 | ||||
-rw-r--r-- | gcc/config/arm/arm.md | 34 | ||||
-rw-r--r-- | gcc/config/arm/thumb1.md | 55 |
4 files changed, 81 insertions, 43 deletions
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 6af0d36..195de48 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -8280,6 +8280,12 @@ arm_legitimate_constant_p_1 (machine_mode, rtx x) static bool thumb_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x) { + /* Splitters for TARGET_USE_MOVT call arm_emit_movpair which creates high + RTX. These RTX must therefore be allowed for Thumb-1 so that when run + for ARMv8-M Baseline or later the result is valid. */ + if (TARGET_HAVE_MOVT && GET_CODE (x) == HIGH) + x = XEXP (x, 0); + return (CONST_INT_P (x) || CONST_DOUBLE_P (x) || CONSTANT_ADDRESS_P (x) @@ -8366,7 +8372,9 @@ thumb1_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer) case CONST_INT: if (outer == SET) { - if ((unsigned HOST_WIDE_INT) INTVAL (x) < 256) + if (UINTVAL (x) < 256 + /* 16-bit constant. */ + || (TARGET_HAVE_MOVT && !(INTVAL (x) & 0xffff0000))) return 0; if (thumb_shiftable_const (INTVAL (x))) return COSTS_N_INSNS (2); @@ -9069,7 +9077,7 @@ static inline int thumb1_size_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer) { machine_mode mode = GET_MODE (x); - int words; + int words, cost; switch (code) { @@ -9115,17 +9123,26 @@ thumb1_size_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer) /* A SET doesn't have a mode, so let's look at the SET_DEST to get the mode. */ words = ARM_NUM_INTS (GET_MODE_SIZE (GET_MODE (SET_DEST (x)))); - return COSTS_N_INSNS (words) - + COSTS_N_INSNS (1) * (satisfies_constraint_J (SET_SRC (x)) - || satisfies_constraint_K (SET_SRC (x)) - /* thumb1_movdi_insn. */ - || ((words > 1) && MEM_P (SET_SRC (x)))); + cost = COSTS_N_INSNS (words); + if (satisfies_constraint_J (SET_SRC (x)) + || satisfies_constraint_K (SET_SRC (x)) + /* Too big an immediate for a 2-byte mov, using MOVT. */ + || (UINTVAL (SET_SRC (x)) >= 256 + && TARGET_HAVE_MOVT + && satisfies_constraint_j (SET_SRC (x))) + /* thumb1_movdi_insn. */ + || ((words > 1) && MEM_P (SET_SRC (x)))) + cost += COSTS_N_INSNS (1); + return cost; case CONST_INT: if (outer == SET) { if (UINTVAL (x) < 256) return COSTS_N_INSNS (1); + /* movw is 4byte long. */ + if (TARGET_HAVE_MOVT && !(INTVAL (x) & 0xffff0000)) + return COSTS_N_INSNS (2); /* See split "TARGET_THUMB1 && satisfies_constraint_J". */ if (INTVAL (x) >= -255 && INTVAL (x) <= -1) return COSTS_N_INSNS (2); diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index c9aaa60..6a0f645 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -263,8 +263,8 @@ extern void (*arm_lang_output_object_attributes_hook)(void); /* Nonzero if this chip supports load-acquire and store-release. */ #define TARGET_HAVE_LDACQ (TARGET_ARM_ARCH >= 8 && arm_arch_notm) -/* Nonzero if this chip provides the MOVW and MOVW instructions. */ -#define TARGET_HAVE_MOVT (arm_arch_thumb2) +/* Nonzero if this chip provides the MOVW and MOVT instructions. */ +#define TARGET_HAVE_MOVT (arm_arch_thumb2 || arm_arch8) /* Nonzero if integer division instructions supported. */ #define TARGET_IDIV ((TARGET_ARM && arm_arch_arm_hwdiv) \ diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 3cd76f9..8727c6d 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -118,10 +118,10 @@ ; This can be "a" for ARM, "t" for either of the Thumbs, "32" for ; TARGET_32BIT, "t1" or "t2" to specify a specific Thumb mode. "v6" ; for ARM or Thumb-2 with arm_arch6, and nov6 for ARM without -; arm_arch6. "v6t2" for Thumb-2 with arm_arch6. This attribute is -; used to compute attribute "enabled", use type "any" to enable an -; alternative in all cases. -(define_attr "arch" "any,a,t,32,t1,t2,v6,nov6,v6t2,neon_for_64bits,avoid_neon_for_64bits,iwmmxt,iwmmxt2,armv6_or_vfpv3,neon" +; arm_arch6. "v6t2" for Thumb-2 with arm_arch6 and "v8mb" for ARMv8-M +; Baseline. This attribute is used to compute attribute "enabled", +; use type "any" to enable an alternative in all cases. +(define_attr "arch" "any,a,t,32,t1,t2,v6,nov6,v6t2,v8mb,neon_for_64bits,avoid_neon_for_64bits,iwmmxt,iwmmxt2,armv6_or_vfpv3,neon" (const_string "any")) (define_attr "arch_enabled" "no,yes" @@ -160,6 +160,10 @@ (match_test "TARGET_32BIT && arm_arch6 && arm_arch_thumb2")) (const_string "yes") + (and (eq_attr "arch" "v8mb") + (match_test "TARGET_THUMB1 && arm_arch8")) + (const_string "yes") + (and (eq_attr "arch" "avoid_neon_for_64bits") (match_test "TARGET_NEON") (not (match_test "TARGET_PREFER_NEON_64BITS"))) @@ -5699,12 +5703,15 @@ ;; LO_SUM adds in the high bits. Fortunately these are opaque operations ;; so this does not matter. (define_insn "*arm_movt" - [(set (match_operand:SI 0 "nonimmediate_operand" "=r") - (lo_sum:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:SI 2 "general_operand" "i")))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r") + (lo_sum:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") + (match_operand:SI 2 "general_operand" "i,i")))] "TARGET_HAVE_MOVT && arm_valid_symbolic_address_p (operands[2])" - "movt%?\t%0, #:upper16:%c2" - [(set_attr "predicable" "yes") + "@ + movt%?\t%0, #:upper16:%c2 + movt\t%0, #:upper16:%c2" + [(set_attr "arch" "32,v8mb") + (set_attr "predicable" "yes") (set_attr "predicable_short_it" "no") (set_attr "length" "4") (set_attr "type" "alu_sreg")] @@ -10971,13 +10978,16 @@ ;; We only care about the lower 16 bits of the constant ;; being inserted into the upper 16 bits of the register. (define_insn "*arm_movtas_ze" - [(set (zero_extract:SI (match_operand:SI 0 "s_register_operand" "+r") + [(set (zero_extract:SI (match_operand:SI 0 "s_register_operand" "+r,r") (const_int 16) (const_int 16)) (match_operand:SI 1 "const_int_operand" ""))] "TARGET_HAVE_MOVT" - "movt%?\t%0, %L1" - [(set_attr "predicable" "yes") + "@ + movt%?\t%0, %L1 + movt\t%0, %L1" + [(set_attr "arch" "32,v8mb") + (set_attr "predicable" "yes") (set_attr "predicable_short_it" "no") (set_attr "length" "4") (set_attr "type" "alu_sreg")] diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md index 035641b..b317f1b 100644 --- a/gcc/config/arm/thumb1.md +++ b/gcc/config/arm/thumb1.md @@ -590,8 +590,8 @@ ;;; ??? The 'i' constraint looks funny, but it should always be replaced by ;;; thumb_reorg with a memory reference. (define_insn "*thumb1_movdi_insn" - [(set (match_operand:DI 0 "nonimmediate_operand" "=l,l,l,l,>,l, m,*r") - (match_operand:DI 1 "general_operand" "l, I,J,>,l,mi,l,*r"))] + [(set (match_operand:DI 0 "nonimmediate_operand" "=l,l,l,r,l,>,l, m,*r") + (match_operand:DI 1 "general_operand" "l, I,J,j,>,l,mi,l,*r"))] "TARGET_THUMB1 && ( register_operand (operands[0], DImode) || register_operand (operands[1], DImode))" @@ -610,36 +610,41 @@ operands[1] = GEN_INT (- INTVAL (operands[1])); return \"movs\\t%Q0, %1\;rsbs\\t%Q0, %Q0, #0\;asrs\\t%R0, %Q0, #31\"; case 3: - return \"ldmia\\t%1, {%0, %H0}\"; + gcc_assert (TARGET_HAVE_MOVT); + return \"movw\\t%Q0, %L1\;movs\\tR0, #0\"; case 4: - return \"stmia\\t%0, {%1, %H1}\"; + return \"ldmia\\t%1, {%0, %H0}\"; case 5: - return thumb_load_double_from_address (operands); + return \"stmia\\t%0, {%1, %H1}\"; case 6: + return thumb_load_double_from_address (operands); + case 7: operands[2] = gen_rtx_MEM (SImode, plus_constant (Pmode, XEXP (operands[0], 0), 4)); output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); return \"\"; - case 7: + case 8: if (REGNO (operands[1]) == REGNO (operands[0]) + 1) return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; } }" - [(set_attr "length" "4,4,6,2,2,6,4,4") - (set_attr "type" "multiple,multiple,multiple,load2,store2,load2,store2,multiple") - (set_attr "pool_range" "*,*,*,*,*,1018,*,*")] + [(set_attr "length" "4,4,6,6,2,2,6,4,4") + (set_attr "type" "multiple,multiple,multiple,multiple,load2,store2,load2,store2,multiple") + (set_attr "arch" "t1,t1,t1,v8mb,t1,t1,t1,t1,t1") + (set_attr "pool_range" "*,*,*,*,*,*,1018,*,*")] ) (define_insn "*thumb1_movsi_insn" - [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l, m,*l*h*k") - (match_operand:SI 1 "general_operand" "l, I,J,K,>,l,mi,l,*l*h*k"))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,r,l,l,l,>,l, m,*l*h*k") + (match_operand:SI 1 "general_operand" "l, I,j,J,K,>,l,mi,l,*l*h*k"))] "TARGET_THUMB1 && ( register_operand (operands[0], SImode) || register_operand (operands[1], SImode))" "@ movs %0, %1 movs %0, %1 + movw %0, %1 # # ldmia\\t%1, {%0} @@ -647,10 +652,11 @@ ldr\\t%0, %1 str\\t%1, %0 mov\\t%0, %1" - [(set_attr "length" "2,2,4,4,2,2,2,2,2") - (set_attr "type" "mov_reg,mov_imm,multiple,multiple,load1,store1,load1,store1,mov_reg") - (set_attr "pool_range" "*,*,*,*,*,*,1018,*,*") - (set_attr "conds" "set,clob,*,*,nocond,nocond,nocond,nocond,nocond")]) + [(set_attr "length" "2,2,4,4,4,2,2,2,2,2") + (set_attr "type" "mov_reg,mov_imm,mov_imm,multiple,multiple,load1,store1,load1,store1,mov_reg") + (set_attr "pool_range" "*,*,*,*,*,*,*,1018,*,*") + (set_attr "arch" "t1,t1,v8mb,t1,t1,t1,t1,t1,t1,t1") + (set_attr "conds" "set,clob,nocond,*,*,nocond,nocond,nocond,nocond,nocond")]) ; Split the load of 64-bit constant into two loads for high and low 32-bit parts respectively ; to see if we can load them in fewer instructions or fewer cycles. @@ -687,7 +693,8 @@ (define_split [(set (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "const_int_operand" ""))] - "TARGET_THUMB1 && satisfies_constraint_K (operands[1])" + "TARGET_THUMB1 && satisfies_constraint_K (operands[1]) + && !(TARGET_HAVE_MOVT && satisfies_constraint_j (operands[1]))" [(set (match_dup 2) (match_dup 1)) (set (match_dup 0) (ashift:SI (match_dup 2) (match_dup 3)))] " @@ -714,7 +721,8 @@ (define_split [(set (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "const_int_operand" ""))] - "TARGET_THUMB1 && satisfies_constraint_Pe (operands[1])" + "TARGET_THUMB1 && satisfies_constraint_Pe (operands[1]) + && !(TARGET_HAVE_MOVT && satisfies_constraint_j (operands[1]))" [(set (match_dup 2) (match_dup 1)) (set (match_dup 0) (plus:SI (match_dup 2) (match_dup 3)))] " @@ -726,8 +734,8 @@ ) (define_insn "*thumb1_movhi_insn" - [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,l*r,*h,l") - (match_operand:HI 1 "general_operand" "l,m,l,k*h,*r,I"))] + [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,l*r,*h,l,r") + (match_operand:HI 1 "general_operand" "l,m,l,k*h,*r,I,n"))] "TARGET_THUMB1 && ( register_operand (operands[0], HImode) || register_operand (operands[1], HImode))" @@ -739,6 +747,8 @@ case 3: return \"mov %0, %1\"; case 4: return \"mov %0, %1\"; case 5: return \"movs %0, %1\"; + case 6: gcc_assert (TARGET_HAVE_MOVT); + return \"movw %0, %L1\"; default: gcc_unreachable (); case 1: /* The stack pointer can end up being taken as an index register. @@ -758,9 +768,10 @@ } return \"ldrh %0, %1\"; }" - [(set_attr "length" "2,4,2,2,2,2") - (set_attr "type" "alus_imm,load1,store1,mov_reg,mov_reg,mov_imm") - (set_attr "conds" "clob,nocond,nocond,nocond,nocond,clob")]) + [(set_attr "length" "2,4,2,2,2,2,4") + (set_attr "type" "alus_imm,load1,store1,mov_reg,mov_reg,mov_imm,mov_imm") + (set_attr "arch" "t1,t1,t1,t1,t1,t1,v8mb") + (set_attr "conds" "clob,nocond,nocond,nocond,nocond,clob,nocond")]) (define_expand "thumb_movhi_clobber" [(set (match_operand:HI 0 "memory_operand" "") |