summaryrefslogtreecommitdiff
path: root/gcc/config/arm
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/arm')
-rw-r--r--gcc/config/arm/arm-builtins.c2
-rw-r--r--gcc/config/arm/arm-c.c19
-rw-r--r--gcc/config/arm/arm-protos.h1
-rw-r--r--gcc/config/arm/arm.c65
-rw-r--r--gcc/config/arm/arm_neon.h72
-rw-r--r--gcc/config/arm/iterators.md6
-rw-r--r--gcc/config/arm/neon.md64
-rw-r--r--gcc/config/arm/thumb2.md24
8 files changed, 169 insertions, 84 deletions
diff --git a/gcc/config/arm/arm-builtins.c b/gcc/config/arm/arm-builtins.c
index db6b29d310d..90fb40fed24 100644
--- a/gcc/config/arm/arm-builtins.c
+++ b/gcc/config/arm/arm-builtins.c
@@ -2246,7 +2246,7 @@ arm_expand_neon_builtin (int fcode, tree exp, rtx target)
neon_builtin_datum *d =
&neon_builtin_data[fcode - ARM_BUILTIN_NEON_PATTERN_START];
enum insn_code icode = d->code;
- builtin_arg args[SIMD_MAX_BUILTIN_ARGS];
+ builtin_arg args[SIMD_MAX_BUILTIN_ARGS + 1];
int num_args = insn_data[d->code].n_operands;
int is_void = 0;
int k;
diff --git a/gcc/config/arm/arm-c.c b/gcc/config/arm/arm-c.c
index 5810608873e..195905fa25b 100644
--- a/gcc/config/arm/arm-c.c
+++ b/gcc/config/arm/arm-c.c
@@ -221,9 +221,6 @@ arm_pragma_target_parse (tree args, tree pop_target)
}
}
- target_option_current_node = cur_tree;
- arm_reset_previous_fndecl ();
-
/* Figure out the previous mode. */
prev_opt = TREE_TARGET_OPTION (prev_tree);
cur_opt = TREE_TARGET_OPTION (cur_tree);
@@ -238,11 +235,8 @@ arm_pragma_target_parse (tree args, tree pop_target)
compiler predefined macros. */
cpp_options *cpp_opts = cpp_get_options (parse_in);
unsigned char saved_warn_unused_macros = cpp_opts->warn_unused_macros;
- unsigned char saved_warn_builtin_macro_redefined
- = cpp_opts->warn_builtin_macro_redefined;
cpp_opts->warn_unused_macros = 0;
- cpp_opts->warn_builtin_macro_redefined = 0;
/* Update macros. */
gcc_assert (cur_opt->x_target_flags == target_flags);
@@ -261,8 +255,19 @@ arm_pragma_target_parse (tree args, tree pop_target)
arm_cpu_builtins (parse_in);
- cpp_opts->warn_builtin_macro_redefined = saved_warn_builtin_macro_redefined;
cpp_opts->warn_unused_macros = saved_warn_unused_macros;
+
+ /* Make sure that target_reinit is called for next function, since
+ TREE_TARGET_OPTION might change with the #pragma even if there is
+ no target attribute attached to the function. */
+ arm_reset_previous_fndecl ();
+
+ /* If going to the default mode, we restore the initial states.
+ if cur_tree is a new target, states will be saved/restored on a per
+ function basis in arm_set_current_function. */
+ if (cur_tree == target_option_default_node)
+ save_restore_target_globals (cur_tree);
+
}
return true;
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 28f226324a0..8261ed80290 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -332,6 +332,7 @@ extern bool arm_autoinc_modes_ok_p (machine_mode, enum arm_auto_incmodes);
extern void arm_emit_eabi_attribute (const char *, int, int);
extern void arm_reset_previous_fndecl (void);
+extern void save_restore_target_globals (tree);
/* Defined in gcc/common/config/arm-common.c. */
extern const char *arm_rewrite_selected_cpu (const char *name);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index f152afa4019..d8a2745f86b 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -3446,8 +3446,7 @@ arm_option_override (void)
/* Save the initial options in case the user does function specific
options. */
- target_option_default_node = target_option_current_node
- = build_target_option_node (&global_options);
+ target_option_default_node = build_target_option_node (&global_options);
/* Init initial mode for testing. */
thumb_flipper = TARGET_THUMB;
@@ -12381,6 +12380,10 @@ neon_valid_immediate (rtx op, machine_mode mode, int inverse,
if (!vfp3_const_double_rtx (el0) && el0 != CONST0_RTX (GET_MODE (el0)))
return -1;
+ /* FP16 vectors cannot be represented. */
+ if (GET_MODE_INNER (mode) == HFmode)
+ return -1;
+
r0 = CONST_DOUBLE_REAL_VALUE (el0);
for (i = 1; i < n_elts; i++)
@@ -29746,6 +29749,25 @@ arm_is_constant_pool_ref (rtx x)
/* Remember the last target of arm_set_current_function. */
static GTY(()) tree arm_previous_fndecl;
+/* Restore or save the TREE_TARGET_GLOBALS from or to NEW_TREE. */
+
+void
+save_restore_target_globals (tree new_tree)
+{
+ /* If we have a previous state, use it. */
+ if (TREE_TARGET_GLOBALS (new_tree))
+ restore_target_globals (TREE_TARGET_GLOBALS (new_tree));
+ else if (new_tree == target_option_default_node)
+ restore_target_globals (&default_target_globals);
+ else
+ {
+ /* Call target_reinit and save the state for TARGET_GLOBALS. */
+ TREE_TARGET_GLOBALS (new_tree) = save_target_globals_default_opts ();
+ }
+
+ arm_option_params_internal ();
+}
+
/* Invalidate arm_previous_fndecl. */
void
arm_reset_previous_fndecl (void)
@@ -29768,38 +29790,23 @@ arm_set_current_function (tree fndecl)
tree new_tree = DECL_FUNCTION_SPECIFIC_TARGET (fndecl);
- arm_previous_fndecl = fndecl;
+ /* If current function has no attributes but previous one did,
+ use the default node." */
+ if (! new_tree && old_tree)
+ new_tree = target_option_default_node;
+
+ /* If nothing to do return. #pragma GCC reset or #pragma GCC pop to
+ the default have been handled by save_restore_target_globals from
+ arm_pragma_target_parse. */
if (old_tree == new_tree)
return;
- if (new_tree && new_tree != target_option_default_node)
- {
- cl_target_option_restore (&global_options,
- TREE_TARGET_OPTION (new_tree));
-
- if (TREE_TARGET_GLOBALS (new_tree))
- restore_target_globals (TREE_TARGET_GLOBALS (new_tree));
- else
- TREE_TARGET_GLOBALS (new_tree)
- = save_target_globals_default_opts ();
- }
-
- else if (old_tree && old_tree != target_option_default_node)
- {
- new_tree = target_option_current_node;
+ arm_previous_fndecl = fndecl;
- cl_target_option_restore (&global_options,
- TREE_TARGET_OPTION (new_tree));
- if (TREE_TARGET_GLOBALS (new_tree))
- restore_target_globals (TREE_TARGET_GLOBALS (new_tree));
- else if (new_tree == target_option_default_node)
- restore_target_globals (&default_target_globals);
- else
- TREE_TARGET_GLOBALS (new_tree)
- = save_target_globals_default_opts ();
- }
+ /* First set the target options. */
+ cl_target_option_restore (&global_options, TREE_TARGET_OPTION (new_tree));
- arm_option_params_internal ();
+ save_restore_target_globals (new_tree);
}
/* Implement TARGET_OPTION_PRINT. */
diff --git a/gcc/config/arm/arm_neon.h b/gcc/config/arm/arm_neon.h
index b311b3a06fb..47816d52187 100644
--- a/gcc/config/arm/arm_neon.h
+++ b/gcc/config/arm/arm_neon.h
@@ -5302,14 +5302,26 @@ vget_lane_s32 (int32x2_t __a, const int __b)
were marked always-inline so there were no call sites, the declaration
would nonetheless raise an error. Hence, we must use a macro instead. */
-#define vget_lane_f16(__v, __idx) \
- __extension__ \
- ({ \
- float16x4_t __vec = (__v); \
- __builtin_arm_lane_check (4, __idx); \
- float16_t __res = __vec[__idx]; \
- __res; \
- })
+ /* For big-endian, GCC's vector indices are reversed within each 64
+ bits compared to the architectural lane indices used by Neon
+ intrinsics. */
+#ifdef __ARM_BIG_ENDIAN
+#define __ARM_NUM_LANES(__v) (sizeof (__v) / sizeof (__v[0]))
+#define __arm_lane(__vec, __idx) (__idx ^ (__ARM_NUM_LANES(__vec) - 1))
+#define __arm_laneq(__vec, __idx) (__idx ^ (__ARM_NUM_LANES(__vec)/2 - 1))
+#else
+#define __arm_lane(__vec, __idx) __idx
+#define __arm_laneq(__vec, __idx) __idx
+#endif
+
+#define vget_lane_f16(__v, __idx) \
+ __extension__ \
+ ({ \
+ float16x4_t __vec = (__v); \
+ __builtin_arm_lane_check (4, __idx); \
+ float16_t __res = __vec[__arm_lane(__vec, __idx)]; \
+ __res; \
+ })
#endif
__extension__ static __inline float32_t __attribute__ ((__always_inline__))
@@ -5379,14 +5391,14 @@ vgetq_lane_s32 (int32x4_t __a, const int __b)
}
#if defined (__ARM_FP16_FORMAT_IEEE) || defined (__ARM_FP16_FORMAT_ALTERNATIVE)
-#define vgetq_lane_f16(__v, __idx) \
- __extension__ \
- ({ \
- float16x8_t __vec = (__v); \
- __builtin_arm_lane_check (8, __idx); \
- float16_t __res = __vec[__idx]; \
- __res; \
- })
+#define vgetq_lane_f16(__v, __idx) \
+ __extension__ \
+ ({ \
+ float16x8_t __vec = (__v); \
+ __builtin_arm_lane_check (8, __idx); \
+ float16_t __res = __vec[__arm_laneq(__vec, __idx)]; \
+ __res; \
+ })
#endif
__extension__ static __inline float32_t __attribute__ ((__always_inline__))
@@ -5458,13 +5470,13 @@ vset_lane_s32 (int32_t __a, int32x2_t __b, const int __c)
#if defined (__ARM_FP16_FORMAT_IEEE) || defined (__ARM_FP16_FORMAT_ALTERNATIVE)
#define vset_lane_f16(__e, __v, __idx) \
__extension__ \
- ({ \
- float16_t __elem = (__e); \
- float16x4_t __vec = (__v); \
- __builtin_arm_lane_check (4, __idx); \
- __vec[__idx] = __elem; \
- __vec; \
- })
+ ({ \
+ float16_t __elem = (__e); \
+ float16x4_t __vec = (__v); \
+ __builtin_arm_lane_check (4, __idx); \
+ __vec[__arm_lane (__vec, __idx)] = __elem; \
+ __vec; \
+ })
#endif
__extension__ static __inline float32x2_t __attribute__ ((__always_inline__))
@@ -5536,13 +5548,13 @@ vsetq_lane_s32 (int32_t __a, int32x4_t __b, const int __c)
#if defined (__ARM_FP16_FORMAT_IEEE) || defined (__ARM_FP16_FORMAT_ALTERNATIVE)
#define vsetq_lane_f16(__e, __v, __idx) \
__extension__ \
- ({ \
- float16_t __elem = (__e); \
- float16x8_t __vec = (__v); \
- __builtin_arm_lane_check (8, __idx); \
- __vec[__idx] = __elem; \
- __vec; \
- })
+ ({ \
+ float16_t __elem = (__e); \
+ float16x8_t __vec = (__v); \
+ __builtin_arm_lane_check (8, __idx); \
+ __vec[__arm_laneq (__vec, __idx)] = __elem; \
+ __vec; \
+ })
#endif
__extension__ static __inline float32x4_t __attribute__ ((__always_inline__))
diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md
index 974cf51cb60..aba1023cdd0 100644
--- a/gcc/config/arm/iterators.md
+++ b/gcc/config/arm/iterators.md
@@ -99,7 +99,7 @@
(define_mode_iterator VQI [V16QI V8HI V4SI])
;; Quad-width vector modes, with TImode added, for moves.
-(define_mode_iterator VQXMOV [V16QI V8HI V4SI V4SF V2DI TI])
+(define_mode_iterator VQXMOV [V16QI V8HI V8HF V4SI V4SF V2DI TI])
;; Opaque structure types wider than TImode.
(define_mode_iterator VSTRUCT [EI OI CI XI])
@@ -114,7 +114,7 @@
(define_mode_iterator VN [V8HI V4SI V2DI])
;; All supported vector modes (except singleton DImode).
-(define_mode_iterator VDQ [V8QI V16QI V4HI V8HI V2SI V4SI V2SF V4SF V2DI])
+(define_mode_iterator VDQ [V8QI V16QI V4HI V8HI V2SI V4SI V4HF V8HF V2SF V4SF V2DI])
;; All supported vector modes (except those with 64-bit integer elements).
(define_mode_iterator VDQW [V8QI V16QI V4HI V8HI V2SI V4SI V2SF V4SF])
@@ -428,6 +428,7 @@
;; Register width from element mode
(define_mode_attr V_reg [(V8QI "P") (V16QI "q")
(V4HI "P") (V8HI "q")
+ (V4HF "P") (V8HF "q")
(V2SI "P") (V4SI "q")
(V2SF "P") (V4SF "q")
(DI "P") (V2DI "q")
@@ -576,6 +577,7 @@
(define_mode_attr Is_float_mode [(V8QI "false") (V16QI "false")
(V4HI "false") (V8HI "false")
(V2SI "false") (V4SI "false")
+ (V4HF "true") (V8HF "true")
(V2SF "true") (V4SF "true")
(DI "false") (V2DI "false")])
diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md
index aff5023f4fd..55b61eb362c 100644
--- a/gcc/config/arm/neon.md
+++ b/gcc/config/arm/neon.md
@@ -137,6 +137,36 @@
}
})
+(define_expand "movv4hf"
+ [(set (match_operand:V4HF 0 "s_register_operand")
+ (match_operand:V4HF 1 "s_register_operand"))]
+ "TARGET_NEON && TARGET_FP16"
+{
+ /* We need to use force_reg to avoid CANNOT_CHANGE_MODE_CLASS
+ causing an ICE on big-endian because it cannot extract subregs in
+ this case. */
+ if (can_create_pseudo_p ())
+ {
+ if (!REG_P (operands[0]))
+ operands[1] = force_reg (V4HFmode, operands[1]);
+ }
+})
+
+(define_expand "movv8hf"
+ [(set (match_operand:V8HF 0 "")
+ (match_operand:V8HF 1 ""))]
+ "TARGET_NEON && TARGET_FP16"
+{
+ /* We need to use force_reg to avoid CANNOT_CHANGE_MODE_CLASS
+ causing an ICE on big-endian because it cannot extract subregs in
+ this case. */
+ if (can_create_pseudo_p ())
+ {
+ if (!REG_P (operands[0]))
+ operands[1] = force_reg (V8HFmode, operands[1]);
+ }
+})
+
(define_insn "*neon_mov<mode>"
[(set (match_operand:VSTRUCT 0 "nonimmediate_operand" "=w,Ut,w")
(match_operand:VSTRUCT 1 "general_operand" " w,w, Ut"))]
@@ -299,11 +329,11 @@
[(set_attr "type" "neon_load1_1reg<q>")])
(define_insn "vec_set<mode>_internal"
- [(set (match_operand:VD 0 "s_register_operand" "=w,w")
- (vec_merge:VD
- (vec_duplicate:VD
+ [(set (match_operand:VD_LANE 0 "s_register_operand" "=w,w")
+ (vec_merge:VD_LANE
+ (vec_duplicate:VD_LANE
(match_operand:<V_elem> 1 "nonimmediate_operand" "Um,r"))
- (match_operand:VD 3 "s_register_operand" "0,0")
+ (match_operand:VD_LANE 3 "s_register_operand" "0,0")
(match_operand:SI 2 "immediate_operand" "i,i")))]
"TARGET_NEON"
{
@@ -385,7 +415,7 @@
(define_insn "vec_extract<mode>"
[(set (match_operand:<V_elem> 0 "nonimmediate_operand" "=Um,r")
(vec_select:<V_elem>
- (match_operand:VD 1 "s_register_operand" "w,w")
+ (match_operand:VD_LANE 1 "s_register_operand" "w,w")
(parallel [(match_operand:SI 2 "immediate_operand" "i,i")])))]
"TARGET_NEON"
{
@@ -2829,6 +2859,22 @@ if (BYTES_BIG_ENDIAN)
[(set_attr "type" "neon_from_gp<q>")]
)
+(define_insn "neon_vdup_nv4hf"
+ [(set (match_operand:V4HF 0 "s_register_operand" "=w")
+ (vec_duplicate:V4HF (match_operand:HF 1 "s_register_operand" "r")))]
+ "TARGET_NEON"
+ "vdup.16\t%P0, %1"
+ [(set_attr "type" "neon_from_gp")]
+)
+
+(define_insn "neon_vdup_nv8hf"
+ [(set (match_operand:V8HF 0 "s_register_operand" "=w")
+ (vec_duplicate:V8HF (match_operand:HF 1 "s_register_operand" "r")))]
+ "TARGET_NEON"
+ "vdup.16\t%q0, %1"
+ [(set_attr "type" "neon_from_gp_q")]
+)
+
(define_insn "neon_vdup_n<mode>"
[(set (match_operand:V32 0 "s_register_operand" "=w,w")
(vec_duplicate:V32 (match_operand:<V_elem> 1 "s_register_operand" "r,t")))]
@@ -4361,8 +4407,8 @@ if (BYTES_BIG_ENDIAN)
)
(define_insn "neon_vld1_dup<mode>"
- [(set (match_operand:VD 0 "s_register_operand" "=w")
- (vec_duplicate:VD (match_operand:<V_elem> 1 "neon_struct_operand" "Um")))]
+ [(set (match_operand:VD_LANE 0 "s_register_operand" "=w")
+ (vec_duplicate:VD_LANE (match_operand:<V_elem> 1 "neon_struct_operand" "Um")))]
"TARGET_NEON"
"vld1.<V_sz_elem>\t{%P0[]}, %A1"
[(set_attr "type" "neon_load1_all_lanes<q>")]
@@ -4378,8 +4424,8 @@ if (BYTES_BIG_ENDIAN)
)
(define_insn "neon_vld1_dup<mode>"
- [(set (match_operand:VQ 0 "s_register_operand" "=w")
- (vec_duplicate:VQ (match_operand:<V_elem> 1 "neon_struct_operand" "Um")))]
+ [(set (match_operand:VQ2 0 "s_register_operand" "=w")
+ (vec_duplicate:VQ2 (match_operand:<V_elem> 1 "neon_struct_operand" "Um")))]
"TARGET_NEON"
{
return "vld1.<V_sz_elem>\t{%e0[], %f0[]}, %A1";
diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md
index 3e762018e4d..39a3d806918 100644
--- a/gcc/config/arm/thumb2.md
+++ b/gcc/config/arm/thumb2.md
@@ -663,15 +663,27 @@
(set_attr "type" "multiple")]
)
-(define_insn "*thumb2_ior_scc_strict_it"
- [(set (match_operand:SI 0 "s_register_operand" "=l,l")
+(define_insn_and_split "*thumb2_ior_scc_strict_it"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r")
(ior:SI (match_operator:SI 2 "arm_comparison_operator"
[(match_operand 3 "cc_register" "") (const_int 0)])
- (match_operand:SI 1 "s_register_operand" "0,?l")))]
+ (match_operand:SI 1 "s_register_operand" "r")))]
"TARGET_THUMB2 && arm_restrict_it"
- "@
- it\\t%d2\;mov%d2\\t%0, #1\;it\\t%d2\;orr%d2\\t%0, %1
- mov\\t%0, #1\;orr\\t%0, %1\;it\\t%D2\;mov%D2\\t%0, %1"
+ "#" ; orr\\t%0, %1, #1\;it\\t%D2\;mov%D2\\t%0, %1
+ "&& reload_completed"
+ [(set (match_dup 0) (ior:SI (match_dup 1) (const_int 1)))
+ (cond_exec (match_dup 4)
+ (set (match_dup 0) (match_dup 1)))]
+ {
+ machine_mode mode = GET_MODE (operands[3]);
+ rtx_code rc = GET_CODE (operands[2]);
+
+ if (mode == CCFPmode || mode == CCFPEmode)
+ rc = reverse_condition_maybe_unordered (rc);
+ else
+ rc = reverse_condition (rc);
+ operands[4] = gen_rtx_fmt_ee (rc, VOIDmode, operands[3], const0_rtx);
+ }
[(set_attr "conds" "use")
(set_attr "length" "8")
(set_attr "type" "multiple")]