aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-family
diff options
context:
space:
mode:
authorRichard Earnshaw <rearnsha@arm.com>2018-07-31 17:35:32 +0000
committerRichard Earnshaw <rearnsha@gcc.gnu.org>2018-07-31 17:35:32 +0000
commit425fc685dd59c07316a0c9112595331aa77ba112 (patch)
tree2d22b78c91baba7c56447d6b82253d85e3503bfd /gcc/c-family
parent1d8693a0ce9e805acadc11072579e94b913eb1d8 (diff)
downloadgcc-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/ChangeLog9
-rw-r--r--gcc/c-family/c-common.c164
-rw-r--r--gcc/c-family/c-cppbuiltin.c7
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");