@@ -56,6 +56,8 @@ extern void arm_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update
extern rtx arm_simd_vect_par_cnst_half (machine_mode mode, bool high);
extern bool arm_simd_check_vect_par_cnst_half_p (rtx op, machine_mode mode,
bool high);
+extern void arm_emit_speculation_barrier_function (void);
+
#ifdef RTX_CODE
extern void arm_gen_unlikely_cbranch (enum rtx_code, machine_mode cc_mode,
rtx label_ref);
@@ -2466,8 +2466,9 @@ arm_set_fixed_conv_libfunc (convert_optab optable, machine_mode to,
set_conv_libfunc (optable, to, from, buffer);
}
-/* Set up library functions unique to ARM. */
+static GTY(()) rtx speculation_barrier_libfunc;
+/* Set up library functions unique to ARM. */
static void
arm_init_libfuncs (void)
{
@@ -2753,6 +2754,8 @@ arm_init_libfuncs (void)
if (TARGET_AAPCS_BASED)
synchronize_libfunc = init_one_libfunc ("__sync_synchronize");
+
+ speculation_barrier_libfunc = init_one_libfunc ("__speculation_barrier");
}
/* On AAPCS systems, this is the "struct __va_list". */
@@ -31528,6 +31531,16 @@ arm_constant_alignment (const_tree exp, HOST_WIDE_INT align)
return align;
}
+/* Emit a speculation barrier on target architectures that do not have
+ DSB/ISB directly. Such systems probably don't need a barrier
+ themselves, but if the code is ever run on a later architecture, it
+ might become a problem. */
+void
+arm_emit_speculation_barrier_function ()
+{
+ emit_library_call (speculation_barrier_libfunc, LCT_NORMAL, VOIDmode);
+}
+
#if CHECKING_P
namespace selftest {
@@ -12016,10 +12016,16 @@ (define_expand "speculation_barrier"
[(unspec_volatile [(const_int 0)] VUNSPEC_SPECULATION_BARRIER)]
"TARGET_EITHER"
"
- /* Don't emit anything for Thumb1 and suppress the warning from the
- generic expansion. */
- if (!TARGET_32BIT)
- DONE;
+ /* For thumb1 (except Armv8 derivatives), and for pre-Armv7 we don't
+ have a usable barrier (and probably don't need one in practice).
+ But to be safe if such code is run on later architectures, call a
+ helper function in libgcc that will do the thing for the active
+ system. */
+ if (!(arm_arch7 || arm_arch8))
+ {
+ arm_emit_speculation_barrier_function ();
+ DONE;
+ }
"
)
@@ -12027,7 +12033,7 @@ (define_expand "speculation_barrier"
;; tracking.
(define_insn "*speculation_barrier_insn"
[(unspec_volatile [(const_int 0)] VUNSPEC_SPECULATION_BARRIER)]
- "TARGET_32BIT"
+ "arm_arch7 || arm_arch8"
"isb\;dsb\\tsy"
[(set_attr "type" "block")
(set_attr "length" "8")]
@@ -1533,6 +1533,50 @@ LSYM(Lover12):
#error "This is only for ARM EABI GNU/Linux"
#endif
#endif /* L_clear_cache */
+
+#ifdef L_speculation_barrier
+ FUNC_START speculation_barrier
+#if __ARM_ARCH >= 7
+ isb
+ dsb sy
+#elif defined __ARM_EABI__ && defined __linux__
+ /* We don't have a speculation barrier directly for this
+ platform/architecture variant. But we can use a kernel
+ clear_cache service routine which will emit such instructions
+ if run on a later version of the architecture. We don't
+ really want to flush the cache, but we must give it a valid
+ address, so just clear pc..pc+1. */
+#if defined __thumb__ && !defined __thumb2__
+ push {r7}
+ mov r7, #0xf
+ lsl r7, #16
+ add r7, #2
+ adr r0, . + 4
+ add r1, r0, #1
+ mov r2, #0
+ svc 0
+ pop {r7}
+#else
+ do_push {r7}
+#ifdef __ARM_ARCH_6T2__
+ movw r7, #2
+ movt r7, #0xf
+#else
+ mov r7, #0xf0000
+ add r7, r7, #2
+#endif
+ add r0, pc, #0 /* ADR. */
+ add r1, r0, #1
+ mov r2, #0
+ svc 0
+ do_pop {r7}
+#endif /* Thumb1 only */
+#else
+#warning "No speculation barrier defined for this platform"
+#endif
+ RET
+ FUNC_END speculation_barrier
+#endif
/* ------------------------------------------------------------------------ */
/* Dword shift operations. */
/* All the following Dword shift variants rely on the fact that
@@ -1,6 +1,6 @@
LIB1ASMSRC = arm/lib1funcs.S
LIB1ASMFUNCS = _thumb1_case_sqi _thumb1_case_uqi _thumb1_case_shi \
- _thumb1_case_uhi _thumb1_case_si
+ _thumb1_case_uhi _thumb1_case_si _speculation_barrier
HAVE_CMSE:=$(findstring __ARM_FEATURE_CMSE,$(shell $(gcc_compile_bare) -dM -E - </dev/null))
ifneq ($(shell $(gcc_compile_bare) -E -mcmse - </dev/null 2>/dev/null),)