Ping. This patch needs reviewing an appropriate maintainer.
I'm aware that the documentation needs extending a bit to provide some example use cases as discussed in the follow-up to the generic discussion, but the rest of the patch still stands. R. On 09/07/18 17:38, Richard Earnshaw wrote: > > This patch defines a new intrinsic function > __builtin_speculation_safe_value. A generic default implementation is > defined which will attempt to use the backend pattern > "speculation_safe_barrier". If this pattern is not defined, or if it > is not available, then the compiler will emit a warning, but > compilation will continue. > > Note that the test spec-barrier-1.c will currently fail on all > targets. This is deliberate, the failure will go away when > appropriate action is taken for each target backend. > > gcc: > * builtin-types.def (BT_FN_PTR_PTR_VAR): New function type. > (BT_FN_I1_I1_VAR, BT_FN_I2_I2_VAR, BT_FN_I4_I4_VAR): Likewise. > (BT_FN_I8_I8_VAR, BT_FN_I16_I16_VAR): Likewise. > * builtins.def (BUILT_IN_SPECULATION_SAFE_VALUE_N): New builtin. > (BUILT_IN_SPECULATION_SAFE_VALUE_PTR): New internal builtin. > (BUILT_IN_SPECULATION_SAFE_VALUE_1): Likewise. > (BUILT_IN_SPECULATION_SAFE_VALUE_2): Likewise. > (BUILT_IN_SPECULATION_SAFE_VALUE_4): Likewise. > (BUILT_IN_SPECULATION_SAFE_VALUE_8): Likewise. > (BUILT_IN_SPECULATION_SAFE_VALUE_16): Likewise. > * builtins.c (expand_speculation_safe_value): New function. > (expand_builtin): Call it. > * doc/cpp.texi: Document predefine __HAVE_SPECULATION_SAFE_VALUE. > * doc/extend.texi: Document __builtin_speculation_safe_value. > * doc/md.texi: Document "speculation_barrier" pattern. > * doc/tm.texi.in: Pull in TARGET_SPECULATION_SAFE_VALUE. > * doc/tm.texi: Regenerated. > * target.def (speculation_safe_value): New hook. > * targhooks.c (default_speculation_safe_value): New function. > * targhooks.h (default_speculation_safe_value): Add prototype. > > c-family: > * c-common.c (speculation_safe_resolve_size): New function. > (speculation_safe_resolve_params): New function. > (speculation_safe_resolve_return): New function. > (resolve_overloaded_builtin): Handle __builtin_speculation_safe_value. > * c-cppbuiltin.c (c_cpp_builtins): Add pre-define for > __HAVE_SPECULATION_SAFE_VALUE. > > testsuite: > * gcc.dg/spec-barrier-1.c: New test. > * gcc.dg/spec-barrier-2.c: New test. > * gcc.dg/spec-barrier-3.c: New test. > --- > gcc/builtin-types.def | 6 ++ > gcc/builtins.c | 57 ++++++++++++++ > gcc/builtins.def | 20 +++++ > gcc/c-family/c-common.c | 143 > ++++++++++++++++++++++++++++++++++ > gcc/c-family/c-cppbuiltin.c | 5 +- > gcc/doc/cpp.texi | 4 + > gcc/doc/extend.texi | 29 +++++++ > gcc/doc/md.texi | 15 ++++ > gcc/doc/tm.texi | 20 +++++ > gcc/doc/tm.texi.in | 2 + > gcc/target.def | 23 ++++++ > gcc/targhooks.c | 27 +++++++ > gcc/targhooks.h | 2 + > gcc/testsuite/gcc.dg/spec-barrier-1.c | 40 ++++++++++ > gcc/testsuite/gcc.dg/spec-barrier-2.c | 19 +++++ > gcc/testsuite/gcc.dg/spec-barrier-3.c | 13 ++++ > 16 files changed, 424 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/gcc.dg/spec-barrier-1.c > create mode 100644 gcc/testsuite/gcc.dg/spec-barrier-2.c > create mode 100644 gcc/testsuite/gcc.dg/spec-barrier-3.c > > > 0001-Add-__builtin_speculation_safe_value.patch > > > diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def > index b01095c..70fae35 100644 > --- a/gcc/builtin-types.def > +++ b/gcc/builtin-types.def > @@ -763,6 +763,12 @@ DEF_FUNCTION_TYPE_VAR_1 (BT_FN_VOID_LONG_VAR, > BT_VOID, BT_LONG) > DEF_FUNCTION_TYPE_VAR_1 (BT_FN_VOID_ULL_VAR, > BT_VOID, BT_ULONGLONG) > +DEF_FUNCTION_TYPE_VAR_1 (BT_FN_PTR_PTR_VAR, BT_PTR, BT_PTR) > +DEF_FUNCTION_TYPE_VAR_1 (BT_FN_I1_I1_VAR, BT_I1, BT_I1) > +DEF_FUNCTION_TYPE_VAR_1 (BT_FN_I2_I2_VAR, BT_I2, BT_I2) > +DEF_FUNCTION_TYPE_VAR_1 (BT_FN_I4_I4_VAR, BT_I4, BT_I4) > +DEF_FUNCTION_TYPE_VAR_1 (BT_FN_I8_I8_VAR, BT_I8, BT_I8) > +DEF_FUNCTION_TYPE_VAR_1 (BT_FN_I16_I16_VAR, BT_I16, BT_I16) > > DEF_FUNCTION_TYPE_VAR_2 (BT_FN_INT_FILEPTR_CONST_STRING_VAR, > BT_INT, BT_FILEPTR, BT_CONST_STRING) > diff --git a/gcc/builtins.c b/gcc/builtins.c > index 91658e8..9f97ecf 100644 > --- a/gcc/builtins.c > +++ b/gcc/builtins.c > @@ -6716,6 +6716,52 @@ expand_builtin_goacc_parlevel_id_size (tree exp, rtx > target, int ignore) > return target; > } > > +/* Expand a call to __builtin_speculation_safe_value_<N>. MODE > + represents the size of the first argument to that call, or VOIDmode > + if the argument is a pointer. IGNORE will be true if the result > + isn't used. */ > +static rtx > +expand_speculation_safe_value (machine_mode mode, tree exp, rtx target, > + bool ignore) > +{ > + rtx val, failsafe; > + unsigned nargs = call_expr_nargs (exp); > + > + tree arg0 = CALL_EXPR_ARG (exp, 0); > + > + if (mode == VOIDmode) > + { > + mode = TYPE_MODE (TREE_TYPE (arg0)); > + gcc_assert (GET_MODE_CLASS (mode) == MODE_INT); > + } > + > + val = expand_expr (arg0, NULL_RTX, mode, EXPAND_NORMAL); > + > + /* An optional second argument can be used as a failsafe value on > + some machines. If it isn't present, then the failsafe value is > + assumed to be 0. */ > + if (nargs > 1) > + { > + tree arg1 = CALL_EXPR_ARG (exp, 1); > + failsafe = expand_expr (arg1, NULL_RTX, mode, EXPAND_NORMAL); > + } > + else > + failsafe = const0_rtx; > + > + /* If the result isn't used, the behavior is undefined. It would be > + nice to emit a warning here, but path splitting means this might > + happen with legitimate code. So simply drop the builtin > + expansion in that case; we've handled any side-effects above. */ > + if (ignore) > + return const0_rtx; > + > + /* If we don't have a suitable target, create one to hold the result. */ > + if (target == NULL) > + target = gen_reg_rtx (mode); > + > + return targetm.speculation_safe_value (mode, target, val, failsafe); > +} > + > /* Expand an expression EXP that calls a built-in function, > with result going to TARGET if that's convenient > (and in mode MODE if that's convenient). > @@ -7827,6 +7873,17 @@ expand_builtin (tree exp, rtx target, rtx subtarget, > machine_mode mode, > case BUILT_IN_GOACC_PARLEVEL_SIZE: > return expand_builtin_goacc_parlevel_id_size (exp, target, ignore); > > + case BUILT_IN_SPECULATION_SAFE_VALUE_PTR: > + return expand_speculation_safe_value (VOIDmode, exp, target, ignore); > + > + case BUILT_IN_SPECULATION_SAFE_VALUE_1: > + case BUILT_IN_SPECULATION_SAFE_VALUE_2: > + case BUILT_IN_SPECULATION_SAFE_VALUE_4: > + case BUILT_IN_SPECULATION_SAFE_VALUE_8: > + case BUILT_IN_SPECULATION_SAFE_VALUE_16: > + mode = get_builtin_sync_mode (fcode - > BUILT_IN_SPECULATION_SAFE_VALUE_1); > + return expand_speculation_safe_value (mode, exp, target, ignore); > + > default: /* just do library call, if unknown builtin */ > break; > } > diff --git a/gcc/builtins.def b/gcc/builtins.def > index aacbd51..b71d89c 100644 > --- a/gcc/builtins.def > +++ b/gcc/builtins.def > @@ -1003,6 +1003,26 @@ DEF_BUILTIN (BUILT_IN_EMUTLS_REGISTER_COMMON, > true, true, true, ATTR_NOTHROW_LEAF_LIST, false, > !targetm.have_tls) > > +/* Suppressing speculation. Users are expected to use the first (N) > + variant, which will be translated internally into one of the other > + types. */ > + > +DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_N, "speculation_safe_value", > + BT_FN_VOID_VAR, ATTR_NULL) > + > +DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_PTR, > + "speculation_safe_value_ptr", BT_FN_PTR_PTR_VAR, ATTR_NULL) > +DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_1, > "speculation_safe_value_1", > + BT_FN_I1_I1_VAR, ATTR_NULL) > +DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_2, > "speculation_safe_value_2", > + BT_FN_I2_I2_VAR, ATTR_NULL) > +DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_4, > "speculation_safe_value_4", > + BT_FN_I4_I4_VAR, ATTR_NULL) > +DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_8, > "speculation_safe_value_8", > + BT_FN_I8_I8_VAR, ATTR_NULL) > +DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_16, > + "speculation_safe_value_16", BT_FN_I16_I16_VAR, ATTR_NULL) > + > /* Exception support. */ > DEF_BUILTIN_STUB (BUILT_IN_UNWIND_RESUME, "__builtin_unwind_resume") > DEF_BUILTIN_STUB (BUILT_IN_CXA_END_CLEANUP, "__builtin_cxa_end_cleanup") > diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c > index f5e1111..32a2de2 100644 > --- a/gcc/c-family/c-common.c > +++ b/gcc/c-family/c-common.c > @@ -6457,6 +6457,121 @@ builtin_type_for_size (int size, bool unsignedp) > return type ? type : error_mark_node; > } > > +/* Work out the size of the first argument of a call to > + __builtin_speculation_safe_value. Only pointers and integral types > + are permitted. Return -1 if the argument type is not supported or > + the size is too large; 0 if the argument type is a pointer or the > + size if it is integral. */ > +static int > +speculation_safe_value_resolve_size (tree function, vec<tree, va_gc> *params) > +{ > + /* Type of the argument. */ > + tree type; > + int size; > + > + if (vec_safe_is_empty (params)) > + { > + error ("too few arguments to function %qE", function); > + return -1; > + } > + > + type = TREE_TYPE ((*params)[0]); > + if (TREE_CODE (type) == ARRAY_TYPE && c_dialect_cxx ()) > + { > + /* Force array-to-pointer decay for C++. */ > + (*params)[0] = default_conversion ((*params)[0]); > + type = TREE_TYPE ((*params)[0]); > + } > + > + if (POINTER_TYPE_P (type)) > + return 0; > + > + if (!INTEGRAL_TYPE_P (type)) > + goto incompatible; > + > + if (!COMPLETE_TYPE_P (type)) > + goto incompatible; > + > + size = tree_to_uhwi (TYPE_SIZE_UNIT (type)); > + if (size == 1 || size == 2 || size == 4 || size == 8 || size == 16) > + return size; > + > + incompatible: > + /* Issue the diagnostic only if the argument is valid, otherwise > + it would be redundant at best and could be misleading. */ > + if (type != error_mark_node) > + error ("operand type %qT is incompatible with argument %d of %qE", > + type, 1, function); > + > + return -1; > +} > + > +/* Validate and coerce PARAMS, the arguments to ORIG_FUNCTION to fit > + the prototype for FUNCTION. The first argument is mandatory, a second > + argument, if present, must be type compatible with the first. */ > +static bool > +speculation_safe_value_resolve_params (location_t loc, tree orig_function, > + vec<tree, va_gc> *params) > +{ > + tree val; > + > + if (params->length () == 0) > + { > + error_at (loc, "too few arguments to function %qE", orig_function); > + return false; > + } > + > + else if (params->length () > 2) > + { > + error_at (loc, "too many arguments to function %qE", orig_function); > + return false; > + } > + > + val = (*params)[0]; > + if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE) > + val = default_conversion (val); > + if (!(TREE_CODE (TREE_TYPE (val)) == POINTER_TYPE > + || TREE_CODE (TREE_TYPE (val)) == INTEGER_TYPE)) > + { > + error_at (loc, > + "expecting argument of type pointer or of type integer " > + "for argument 1"); > + return false; > + } > + (*params)[0] = val; > + > + if (params->length () == 2) > + { > + tree val2 = (*params)[1]; > + if (TREE_CODE (TREE_TYPE (val2)) == ARRAY_TYPE) > + val2 = default_conversion (val2); > + if (!(TREE_TYPE (val) == TREE_TYPE (val2) > + || useless_type_conversion_p (TREE_TYPE (val), TREE_TYPE (val2)))) > + { > + error_at (loc, "both arguments must be compatible"); > + return false; > + } > + (*params)[1] = val2; > + } > + > + return true; > +} > + > +/* Cast the result of the builtin back to the type of the first argument, > + preserving any qualifiers that it might have. */ > +static tree > +speculation_safe_value_resolve_return (tree first_param, tree result) > +{ > + tree ptype = TREE_TYPE (first_param); > + tree rtype = TREE_TYPE (result); > + ptype = TYPE_MAIN_VARIANT (ptype); > + > + if (tree_int_cst_equal (TYPE_SIZE (ptype), TYPE_SIZE (rtype))) > + return convert (ptype, result); > + > + return result; > +} > + > /* A helper function for resolve_overloaded_builtin in resolving the > overloaded __sync_ builtins. Returns a positive power of 2 if the > first operand of PARAMS is a pointer to a supported data type. > @@ -7111,6 +7226,34 @@ resolve_overloaded_builtin (location_t loc, tree > function, > /* Handle BUILT_IN_NORMAL here. */ > switch (orig_code) > { > + case BUILT_IN_SPECULATION_SAFE_VALUE_N: > + { > + int n = speculation_safe_value_resolve_size (function, params); > + tree new_function, first_param, result; > + enum built_in_function fncode; > + > + if (n == -1) > + return error_mark_node; > + else if (n == 0) > + fncode = (enum built_in_function)((int)orig_code + 1); > + else > + fncode > + = (enum built_in_function)((int)orig_code + exact_log2 (n) + 2); > + > + new_function = builtin_decl_explicit (fncode); > + first_param = (*params)[0]; > + if (!speculation_safe_value_resolve_params (loc, function, params)) > + return error_mark_node; > + > + result = build_function_call_vec (loc, vNULL, new_function, params, > + NULL); > + > + if (result == error_mark_node) > + return result; > + > + return speculation_safe_value_resolve_return (first_param, result); > + } > + > case BUILT_IN_ATOMIC_EXCHANGE: > case BUILT_IN_ATOMIC_COMPARE_EXCHANGE: > case BUILT_IN_ATOMIC_LOAD: > diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c > index bdb5691..0b10e65 100644 > --- a/gcc/c-family/c-cppbuiltin.c > +++ b/gcc/c-family/c-cppbuiltin.c > @@ -1361,7 +1361,10 @@ c_cpp_builtins (cpp_reader *pfile) > cpp_define (pfile, "__WCHAR_UNSIGNED__"); > > cpp_atomic_builtins (pfile); > - > + > + /* Show support for __builtin_speculation_safe_value (). */ > + cpp_define (pfile, "__HAVE_SPECULATION_SAFE_VALUE"); > + > #ifdef DWARF2_UNWIND_INFO > if (dwarf2out_do_cfi_asm ()) > cpp_define (pfile, "__GCC_HAVE_DWARF2_CFI_ASM"); > diff --git a/gcc/doc/cpp.texi b/gcc/doc/cpp.texi > index 3f7a8fc..efad2c8 100644 > --- a/gcc/doc/cpp.texi > +++ b/gcc/doc/cpp.texi > @@ -2381,6 +2381,10 @@ If GCC cannot determine the current date, it will emit > a warning message > These macros are defined when the target processor supports atomic compare > and swap operations on operands 1, 2, 4, 8 or 16 bytes in length, > respectively. > > +@item __HAVE_SPECULATION_SAFE_VALUE > +This macro is defined with the value 1 to show that this version of GCC > +supports @code{__builtin_speculation_safe_value}. > + > @item __GCC_HAVE_DWARF2_CFI_ASM > This macro is defined when the compiler is emitting DWARF CFI directives > to the assembler. When this is defined, it is possible to emit those same > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi > index c7745c4..6eb0c6b 100644 > --- a/gcc/doc/extend.texi > +++ b/gcc/doc/extend.texi > @@ -10935,6 +10935,7 @@ is called and the @var{flag} argument passed to it. > @findex __builtin_powi > @findex __builtin_powif > @findex __builtin_powil > +@findex __builtin_speculation_safe_value > @findex _Exit > @findex _exit > @findex abort > @@ -11579,6 +11580,34 @@ check its compatibility with @var{size}. > > @end deftypefn > > +@deftypefn {Built-in Function} @var{type} __builtin_speculation_safe_value > (@var{type} val, @var{type} failval) > + > +This builtin can be used to help mitigate against unsafe speculative > +execution. @var{type} may be any integral type or any pointer type. > + > +@enumerate > +@item > +If the CPU is not speculatively executing the code, then @var{val} > +is returned. > +@item > +If the CPU is executing speculatively then either: > +@itemize > +@item > +The function may cause execution to pause until it is known that the > +code is no-longer being executed speculatively (in which case > +@var{val} can be returned, as above); or > +@item > +The function may use target-dependent speculation tracking state to cause > +@var{failval} to be returned when it is known that speculative > +execution has incorrectly predicted a conditional branch operation. > +@end itemize > +@end enumerate > + > +The second argument, @var{failval}, is optional and defaults to zero > +if omitted. > + > +@end deftypefn > + > @deftypefn {Built-in Function} int __builtin_types_compatible_p > (@var{type1}, @var{type2}) > > You can use the built-in function @code{__builtin_types_compatible_p} to > diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi > index 6d15d99..5de27f6 100644 > --- a/gcc/doc/md.texi > +++ b/gcc/doc/md.texi > @@ -7026,6 +7026,21 @@ should be defined to an instruction that orders both > loads and stores > before the instruction with respect to loads and stores after the > instruction. > This pattern has no operands. > > +@cindex @code{speculation_barrier} instruction pattern > +@item @samp{speculation_barrier} > +If the target can support speculative execution, then this pattern should > +be defined to an instruction that will block subsequent execution until > +any prior speculation conditions has been resolved. The pattern must also > +ensure that the compiler cannot move memory operations past the barrier, > +so it needs to be an UNSPEC_VOLATILE pattern. The pattern has no > +operands. > + > +If this pattern is not defined then the default expansion of > +@code{__builtin_speculation_safe_value} will emit a warning. You can > +suppress this warning by defining this pattern with a final condition > +of @code{0} (zero), which tells the compiler that a speculation > +barrier is not needed for this target. > + > @cindex @code{sync_compare_and_swap@var{mode}} instruction pattern > @item @samp{sync_compare_and_swap@var{mode}} > This pattern, if defined, emits code for an atomic compare-and-swap > diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi > index 7e2cdc2..681e53b 100644 > --- a/gcc/doc/tm.texi > +++ b/gcc/doc/tm.texi > @@ -11932,6 +11932,26 @@ maintainer is familiar with. > > @end defmac > > +@deftypefn {Target Hook} rtx TARGET_SPECULATION_SAFE_VALUE (machine_mode > @var{mode}, rtx @var{result}, rtx @var{val}, rtx @var{failval}) > +This target hook can be used to generate a target-specific code > + sequence that implements the @code{__builtin_speculation_safe_value} > + built-in function. The function must always return @var{val} in > + @var{result} in mode @var{mode} when the cpu is not executing > + speculatively, but must never return that when speculating until it > + is known that the speculation will not be unwound. The hook supports > + two primary mechanisms for implementing the requirements. The first > + is to emit a speculation barrier which forces the processor to wait > + until all prior speculative operations have been resolved; the second > + is to use a target-specific mechanism that can track the speculation > + state and to return @var{failval} if it can determine that > + speculation must be unwound at a later time. > + > + The default implementation simply copies @var{val} to @var{result} and > + emits a @code{speculation_barrier} instruction if that is defined. If > + @code{speculation_barrier} is not defined for the target a warning will > + be generated. > +@end deftypefn > + > @deftypefn {Target Hook} void TARGET_RUN_TARGET_SELFTESTS (void) > If selftests are enabled, run any selftests for this target. > @end deftypefn > diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in > index b7b0e8a..6e20afb 100644 > --- a/gcc/doc/tm.texi.in > +++ b/gcc/doc/tm.texi.in > @@ -8107,4 +8107,6 @@ maintainer is familiar with. > > @end defmac > > +@hook TARGET_SPECULATION_SAFE_VALUE > + > @hook TARGET_RUN_TARGET_SELFTESTS > diff --git a/gcc/target.def b/gcc/target.def > index 112c772..c8bd7f8 100644 > --- a/gcc/target.def > +++ b/gcc/target.def > @@ -4177,6 +4177,29 @@ DEFHOOK > hook_bool_void_true) > > DEFHOOK > +(speculation_safe_value, > +"This target hook can be used to generate a target-specific code\n\ > + sequence that implements the @code{__builtin_speculation_safe_value}\n\ > + built-in function. The function must always return @var{val} in\n\ > + @var{result} in mode @var{mode} when the cpu is not executing\n\ > + speculatively, but must never return that when speculating until it\n\ > + is known that the speculation will not be unwound. The hook supports\n\ > + two primary mechanisms for implementing the requirements. The first\n\ > + is to emit a speculation barrier which forces the processor to wait\n\ > + until all prior speculative operations have been resolved; the second\n\ > + is to use a target-specific mechanism that can track the speculation\n\ > + state and to return @var{failval} if it can determine that\n\ > + speculation must be unwound at a later time.\n\ > + \n\ > + The default implementation simply copies @var{val} to @var{result} and\n\ > + emits a @code{speculation_barrier} instruction if that is defined. If\n\ > + @code{speculation_barrier} is not defined for the target a warning will\n\ > + be generated.", > +rtx, (machine_mode mode, rtx result, rtx val, rtx failval), > + default_speculation_safe_value) > + > + > +DEFHOOK > (can_use_doloop_p, > "Return true if it is possible to use low-overhead loops > (@code{doloop_end}\n\ > and @code{doloop_begin}) for a particular loop. @var{iterations} gives > the\n\ > diff --git a/gcc/targhooks.c b/gcc/targhooks.c > index 7315f1a..2061f07 100644 > --- a/gcc/targhooks.c > +++ b/gcc/targhooks.c > @@ -2306,4 +2306,31 @@ default_select_early_remat_modes (sbitmap) > { > } > > +/* Default implementation of the speculation-safe-load builtin. This > + implementation simply copies val to result and generates a > + speculation_barrier insn, if such a pattern is defined. If > + speculation_barrier is not defined at all, a warning is generated. */ > + > +rtx > +default_speculation_safe_value (machine_mode mode ATTRIBUTE_UNUSED, > + rtx result, rtx val, > + rtx failval ATTRIBUTE_UNUSED) > +{ > + emit_move_insn (result, val); > +#ifdef HAVE_speculation_barrier > + /* Assume the target knows what it is doing: if it defines a > + speculation barrier, but it is not enabled, then assume that one > + isn't needed. */ > + if (HAVE_speculation_barrier) > + emit_insn (gen_speculation_barrier ()); > + > +#else > + warning_at (input_location, 0, > + "this target does not define a speculation barrier; " > + "your program will still execute correctly, but speculation " > + "will not be inhibited"); > +#endif > + return result; > +} > + > #include "gt-targhooks.h" > diff --git a/gcc/targhooks.h b/gcc/targhooks.h > index 4107e22..80ac283 100644 > --- a/gcc/targhooks.h > +++ b/gcc/targhooks.h > @@ -284,4 +284,6 @@ default_excess_precision (enum excess_precision_type > ATTRIBUTE_UNUSED); > extern bool default_stack_clash_protection_final_dynamic_probe (rtx); > extern void default_select_early_remat_modes (sbitmap); > > +extern rtx default_speculation_safe_value (machine_mode, rtx, rtx, rtx); > + > #endif /* GCC_TARGHOOKS_H */ > diff --git a/gcc/testsuite/gcc.dg/spec-barrier-1.c > b/gcc/testsuite/gcc.dg/spec-barrier-1.c > new file mode 100644 > index 0000000..106f89a > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/spec-barrier-1.c > @@ -0,0 +1,40 @@ > +/* { dg-do run } */ > +/* { dg-options "-O" } */ > + > +/* Test that __builtin_speculation_safe_value returns the correct value. */ > +/* This test will cause an unfiltered warning to be emitted on targets > + that have not implemented support for speculative execution > + barriers. They should fix that rather than disabling this > + test. */ > +char a = 1; > +short b = 2; > +int c = 3; > +long d = 4; > +long long e = 5; > +int *f = (int*) &c; > +#ifdef __SIZEOF_INT128__ > +__int128 g = 9; > +#endif > + > +extern void abort (void); > + > +int main () > +{ > + if (__builtin_speculation_safe_value (a) != 1) > + abort (); > + if (__builtin_speculation_safe_value (b) != 2) > + abort (); > + if (__builtin_speculation_safe_value (c) != 3) > + abort (); > + if (__builtin_speculation_safe_value (d) != 4) > + abort (); > + if (__builtin_speculation_safe_value (e) != 5) > + abort (); > + if (__builtin_speculation_safe_value (f) != &c) > + abort (); > +#ifdef __SIZEOF_INT128__ > + if (__builtin_speculation_safe_value (g) != 9) > + abort (); > +#endif > + return 0; > +} > diff --git a/gcc/testsuite/gcc.dg/spec-barrier-2.c > b/gcc/testsuite/gcc.dg/spec-barrier-2.c > new file mode 100644 > index 0000000..7e9c497 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/spec-barrier-2.c > @@ -0,0 +1,19 @@ > +/* { dg-do run } */ > + > +/* Even on targets that don't need the optional failval parameter, > + side-effects on the operand should still be calculated. */ > + > +int x = 3; > +volatile int y = 9; > + > +extern void abort (void); > + > +int main () > +{ > + int z = __builtin_speculation_safe_value (x, y++); > + if (z != 3 || y != 10) > + abort (); > + return 0; > +} > + > +/* { dg-prune-output "this target does not define a speculation barrier;" } > */ > diff --git a/gcc/testsuite/gcc.dg/spec-barrier-3.c > b/gcc/testsuite/gcc.dg/spec-barrier-3.c > new file mode 100644 > index 0000000..3ed4d39 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/spec-barrier-3.c > @@ -0,0 +1,13 @@ > +/* { dg-do compile } */ > +/* { dg-options "-Wpedantic" } */ > + > +/* __builtin_speculation_safe_value returns a value with the same type > + as its first argument. There should be a warning if that isn't > + type-compatible with the use. */ > +int * > +f (int x) > +{ > + return __builtin_speculation_safe_value (x); /* { dg-warning "returning > 'int' from a function with return type 'int \\*' makes pointer from integer > without a cast" } */ > +} > + > +/* { dg-prune-output "this target does not define a speculation barrier;" } > */ >