diff options
author | Richard Earnshaw <rearnsha@arm.com> | 2018-07-31 17:35:32 +0000 |
---|---|---|
committer | Richard Earnshaw <rearnsha@gcc.gnu.org> | 2018-07-31 17:35:32 +0000 |
commit | 425fc685dd59c07316a0c9112595331aa77ba112 (patch) | |
tree | 2d22b78c91baba7c56447d6b82253d85e3503bfd /gcc/c-family | |
parent | 1d8693a0ce9e805acadc11072579e94b913eb1d8 (diff) | |
download | gcc-425fc685dd59c07316a0c9112595331aa77ba112.zip gcc-425fc685dd59c07316a0c9112595331aa77ba112.tar.gz gcc-425fc685dd59c07316a0c9112595331aa77ba112.tar.bz2 |
Add __builtin_speculation_safe_value
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.
* builtin-attrs.def (ATTR_NOVOPS_NOTHROW_LEAF_LIST): New attribute
list.
* 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 and
TARGET_HAVE_SPECULATION_SAFE_VALUE.
* doc/tm.texi: Regenerated.
* target.def (have_speculation_safe_value, speculation_safe_value): New
hooks.
* targhooks.c (default_have_speculation_safe_value): New function.
(default_speculation_safe_value): New function.
* targhooks.h (default_have_speculation_safe_value): Add prototype.
(default_speculation_safe_value): Add prototype.
c-family:
* c-common.c (speculation_safe_resolve_call): 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:
* c-c++-common/spec-barrier-1.c: New test.
* c-c++-common/spec-barrier-2.c: New test.
* gcc.dg/spec-barrier-3.c: New test.
From-SVN: r263168
Diffstat (limited to 'gcc/c-family')
-rw-r--r-- | gcc/c-family/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/c-family/c-common.c | 164 | ||||
-rw-r--r-- | gcc/c-family/c-cppbuiltin.c | 7 |
3 files changed, 179 insertions, 1 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 0ae008b..bf1232e 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,12 @@ +2018-07-31 Richard Earnshaw <rearnsha@arm.com> + + * c-common.c (speculation_safe_resolve_call): 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. + 2018-07-20 David Malcolm <dmalcolm@redhat.com> * c-common.c (c_cpp_error): Remove redundant "line_table" diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 422d668..d919605 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -6457,6 +6457,122 @@ 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 enum built_in_function +speculation_safe_value_resolve_call (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 BUILT_IN_NONE; + } + + 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 BUILT_IN_SPECULATION_SAFE_VALUE_PTR; + + 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 ((enum built_in_function) + ((int) BUILT_IN_SPECULATION_SAFE_VALUE_1 + exact_log2 (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 BUILT_IN_NONE; +} + +/* 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 +7227,54 @@ resolve_overloaded_builtin (location_t loc, tree function, /* Handle BUILT_IN_NORMAL here. */ switch (orig_code) { + case BUILT_IN_SPECULATION_SAFE_VALUE_N: + { + tree new_function, first_param, result; + enum built_in_function fncode + = speculation_safe_value_resolve_call (function, params);; + + first_param = (*params)[0]; + if (fncode == BUILT_IN_NONE + || !speculation_safe_value_resolve_params (loc, function, params)) + return error_mark_node; + + if (targetm.have_speculation_safe_value (true)) + { + new_function = builtin_decl_explicit (fncode); + 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); + } + else + { + /* This target doesn't have, or doesn't need, active mitigation + against incorrect speculative execution. Simply return the + first parameter to the builtin. */ + if (!targetm.have_speculation_safe_value (false)) + /* The user has invoked __builtin_speculation_safe_value + even though __HAVE_SPECULATION_SAFE_VALUE is not + defined: emit a warning. */ + warning_at (input_location, 0, + "this target does not define a speculation barrier; " + "your program will still execute correctly, " + "but incorrect speculation may not be be " + "restricted"); + + /* If the optional second argument is present, handle any side + effects now. */ + if (params->length () == 2 + && TREE_SIDE_EFFECTS ((*params)[1])) + return build2 (COMPOUND_EXPR, TREE_TYPE (first_param), + (*params)[1], first_param); + + return first_param; + } + } + 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..4fcf3a6 100644 --- a/gcc/c-family/c-cppbuiltin.c +++ b/gcc/c-family/c-cppbuiltin.c @@ -1361,7 +1361,12 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__WCHAR_UNSIGNED__"); cpp_atomic_builtins (pfile); - + + /* Show support for __builtin_speculation_safe_value () if the target + has been updated to fully support it. */ + if (targetm.have_speculation_safe_value (false)) + cpp_define (pfile, "__HAVE_SPECULATION_SAFE_VALUE"); + #ifdef DWARF2_UNWIND_INFO if (dwarf2out_do_cfi_asm ()) cpp_define (pfile, "__GCC_HAVE_DWARF2_CFI_ASM"); |