public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
@ 2018-07-09 16:39 Richard Earnshaw
  2018-07-09 16:39 ` [PATCH 5/7] AArch64 - disable CB[N]Z TB[N]Z when tracking speculation Richard Earnshaw
                   ` (9 more replies)
  0 siblings, 10 replies; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-09 16:39 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Earnshaw, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 5611 bytes --]


The patches I posted earlier this year for mitigating against
CVE-2017-5753 (Spectre variant 1) attracted some useful feedback, from
which it became obvious that a rethink was needed.  This mail, and the
following patches attempt to address that feedback and present a new
approach to mitigating against this form of attack surface.

There were two major issues with the original approach:

- The speculation bounds were too tightly constrained - essentially
  they had to represent and upper and lower bound on a pointer, or a
  pointer offset.
- The speculation constraints could only cover the immediately preceding
  branch, which often did not fit well with the structure of the existing
  code.

An additional criticism was that the shape of the intrinsic did not
fit particularly well with systems that used a single speculation
barrier that essentially had to wait until all preceding speculation
had to be resolved.

To address all of the above, these patches adopt a new approach, based
in part on a posting by Chandler Carruth to the LLVM developers list
(https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
but which we have extended to deal with inter-function speculation.
The patches divide the problem into two halves.

The first half is some target-specific code to track the speculation
condition through the generated code to provide an internal variable
which can tell us whether or not the CPU's control flow speculation
matches the data flow calculations.  The idea is that the internal
variable starts with the value TRUE and if the CPU's control flow
speculation ever causes a jump to the wrong block of code the variable
becomes false until such time as the incorrect control flow
speculation gets unwound.

The second half is that a new intrinsic function is introduced that is
much simpler than we had before.  The basic version of the intrinsic
is now simply:

      T var = __builtin_speculation_safe_value (T unsafe_var);

Full details of the syntax can be found in the documentation patch, in
patch 1.  In summary, when not speculating the intrinsic returns
unsafe_var; when speculating then if it can be shown that the
speculative flow has diverged from the intended control flow then zero
is returned.  An optional second argument can be used to return an
alternative value to zero.  The builtin may cause execution to pause
until the speculation state is resolved.

There are seven patches in this set, as follows.

1) Introduces the new intrinsic __builtin_sepculation_safe_value.
2) Adds a basic hard barrier implementation for AArch32 (arm) state.
3) Adds a basic hard barrier implementation for AArch64 state.
4) Adds a new command-line option -mtrack-speculation (currently a no-op).
5) Disables CB[N]Z and TB[N]Z when -mtrack-speculation.
6) Adds the new speculation tracking pass for AArch64
7) Uses the new speculation tracking pass to generate CSDB-based barrier
   sequences

I haven't added a speculation-tracking pass for AArch32 at this time.
It is possible to do this, but would require quite a lot of rework for
the arm backend due to the limited number of registers that are
available.

Although patch 6 is AArch64 specific, I'd appreciate a review from
someone more familiar with the branch edge code than myself.  There
appear to be a number of tricky issues with more complex edges so I'd
like a second opinion on that code in case I've missed an important
case.

R.

  

Richard Earnshaw (7):
  Add __builtin_speculation_safe_value
  Arm - add speculation_barrier pattern
  AArch64 - add speculation barrier
  AArch64 - Add new option -mtrack-speculation
  AArch64 - disable CB[N]Z TB[N]Z when tracking speculation
  AArch64 - new pass to add conditional-branch speculation tracking
  AArch64 - use CSDB based sequences if speculation tracking is enabled

 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/config.gcc                            |   2 +-
 gcc/config/aarch64/aarch64-passes.def     |   1 +
 gcc/config/aarch64/aarch64-protos.h       |   3 +-
 gcc/config/aarch64/aarch64-speculation.cc | 494 ++++++++++++++++++++++++++++++
 gcc/config/aarch64/aarch64.c              |  88 +++++-
 gcc/config/aarch64/aarch64.md             | 140 ++++++++-
 gcc/config/aarch64/aarch64.opt            |   4 +
 gcc/config/aarch64/iterators.md           |   3 +
 gcc/config/aarch64/t-aarch64              |  10 +
 gcc/config/arm/arm.md                     |  21 ++
 gcc/config/arm/unspecs.md                 |   1 +
 gcc/doc/cpp.texi                          |   4 +
 gcc/doc/extend.texi                       |  29 ++
 gcc/doc/invoke.texi                       |  10 +-
 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 +
 28 files changed, 1191 insertions(+), 11 deletions(-)
 create mode 100644 gcc/config/aarch64/aarch64-speculation.cc
 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

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 7/7] AArch64 - use CSDB based sequences if speculation tracking is enabled
  2018-07-09 16:39 [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753) Richard Earnshaw
                   ` (5 preceding siblings ...)
  2018-07-09 16:39 ` [PATCH 3/7] AArch64 - add speculation barrier Richard Earnshaw
@ 2018-07-09 16:39 ` Richard Earnshaw
  2018-07-09 23:13 ` [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753) Jeff Law
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-09 16:39 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Earnshaw, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 841 bytes --]


In this final patch, now that we can track speculation through conditional
branches, we can use this information to use a less expensive CSDB based
speculation barrier.

	* config/aarch64/iterators.md (ALLI_TI): New iterator.
	* config/aarch64/aarch64.md (despeculate_copy<ALLI_TI:mode>): New
	expand.
	(despeculate_copy<ALLI:mode>_insn): New insn.
	(despeculate_copyti_insn): New insn.
	(despeculate_simple<ALLI:mode>): New insn
	(despeculate_simpleti): New insn.
	* config/aarch64/aarch64.c (aarch64_speculation_safe_value): New
	function.
	(TARGET_SPECULATION_SAFE_VALUE): Redefine to
	aarch64_speculation_safe_value.
---
 gcc/config/aarch64/aarch64.c    | 42 ++++++++++++++++++
 gcc/config/aarch64/aarch64.md   | 96 +++++++++++++++++++++++++++++++++++++++++
 gcc/config/aarch64/iterators.md |  3 ++
 3 files changed, 141 insertions(+)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0007-AArch64-use-CSDB-based-sequences-if-speculation-trac.patch --]
[-- Type: text/x-patch; name="0007-AArch64-use-CSDB-based-sequences-if-speculation-trac.patch", Size: 5947 bytes --]

diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index b11d768..b30b857 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -17648,6 +17648,45 @@ aarch64_select_early_remat_modes (sbitmap modes)
     }
 }
 
+/* Override the default target speculation_safe_value.  */
+static rtx
+aarch64_speculation_safe_value (machine_mode mode,
+				rtx result, rtx val, rtx failval)
+{
+  /* Maybe we should warn if falling back to hard barriers.  They are
+     likely to be noticably more expensive than the alternative below.  */
+  if (!aarch64_track_speculation)
+    return default_speculation_safe_value (mode, result, val, failval);
+
+  if (!REG_P (val))
+    val = copy_to_mode_reg (mode, val);
+
+  if (!aarch64_reg_or_zero (failval, mode))
+    failval = copy_to_mode_reg (mode, failval);
+
+  switch (mode)
+    {
+    case E_QImode:
+      emit_insn (gen_despeculate_copyqi (result, val, failval));
+      break;
+    case E_HImode:
+      emit_insn (gen_despeculate_copyhi (result, val, failval));
+      break;
+    case E_SImode:
+      emit_insn (gen_despeculate_copysi (result, val, failval));
+      break;
+    case E_DImode:
+      emit_insn (gen_despeculate_copydi (result, val, failval));
+      break;
+    case E_TImode:
+      emit_insn (gen_despeculate_copyti (result, val, failval));
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  return result;
+}
+
 /* Target-specific selftests.  */
 
 #if CHECKING_P
@@ -18117,6 +18156,9 @@ aarch64_libgcc_floating_mode_supported_p
 #undef TARGET_SELECT_EARLY_REMAT_MODES
 #define TARGET_SELECT_EARLY_REMAT_MODES aarch64_select_early_remat_modes
 
+#undef TARGET_SPECULATION_SAFE_VALUE
+#define TARGET_SPECULATION_SAFE_VALUE aarch64_speculation_safe_value
+
 #if CHECKING_P
 #undef TARGET_RUN_TARGET_SELFTESTS
 #define TARGET_RUN_TARGET_SELFTESTS selftest::aarch64_run_selftests
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 528d03d..cbcada2 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -6129,6 +6129,102 @@ (define_insn "speculation_barrier"
    (set_attr "speculation_barrier" "true")]
 )
 
+;; Support for __builtin_speculation_safe_value when we have speculation
+;; tracking enabled.  Use the speculation tracker to decide whether to
+;; copy operand 1 to the target, or to copy the fail value (operand 2).
+(define_expand "despeculate_copy<ALLI_TI:mode>"
+  [(set (match_operand:ALLI_TI 0 "register_operand" "=r")
+	(unspec_volatile:ALLI_TI
+	 [(match_operand:ALLI_TI 1 "register_operand" "r")
+	  (match_operand:ALLI_TI 2 "aarch64_reg_or_zero" "rZ")
+	  (use (reg:DI SPECULATION_TRACKER_REGNUM))
+	  (clobber (reg:CC CC_REGNUM))] UNSPECV_SPECULATION_BARRIER))]
+  ""
+  "
+  {
+    if (operands[2] == const0_rtx)
+      {
+	rtx tracker;
+	if (<MODE>mode == TImode)
+	  tracker = gen_rtx_REG (DImode, SPECULATION_TRACKER_REGNUM);
+	else
+	  tracker = gen_rtx_REG (<MODE>mode, SPECULATION_TRACKER_REGNUM);
+
+	emit_insn (gen_despeculate_simple<mode> (operands[0], operands[1],
+						 tracker));
+	DONE;
+      }
+  }
+  "
+)
+
+;; Pattern to match despeculate_copy<mode>
+(define_insn "*despeculate_copy<ALLI:mode>_insn"
+  [(set (match_operand:ALLI 0 "register_operand" "=r")
+	(unspec_volatile:ALLI
+	 [(match_operand:ALLI 1 "register_operand" "r")
+	  (match_operand:ALLI 2 "aarch64_reg_or_zero" "rZ")
+	  (use (reg:DI SPECULATION_TRACKER_REGNUM))
+	  (clobber (reg:CC CC_REGNUM))] UNSPECV_SPECULATION_BARRIER))]
+  ""
+  {
+    operands[3] = gen_rtx_REG (DImode, SPECULATION_TRACKER_REGNUM);
+    output_asm_insn ("cmp\\t%3, #0\;csel\\t%<w>0, %<w>1, %<w>2, ne\;csdb",
+		     operands);
+    return "";
+  }
+  [(set_attr "length" "12")
+   (set_attr "type" "block")
+   (set_attr "speculation_barrier" "true")]
+)
+
+;; Pattern to match despeculate_copyti
+(define_insn "*despeculate_copyti_insn"
+  [(set (match_operand:TI 0 "register_operand" "=r")
+	(unspec_volatile:TI
+	 [(match_operand:TI 1 "register_operand" "r")
+	  (match_operand:TI 2 "aarch64_reg_or_zero" "rZ")
+	  (use (reg:DI SPECULATION_TRACKER_REGNUM))
+	  (clobber (reg:CC CC_REGNUM))] UNSPECV_SPECULATION_BARRIER))]
+  ""
+  {
+    operands[3] = gen_rtx_REG (DImode, SPECULATION_TRACKER_REGNUM);
+    output_asm_insn
+      ("cmp\\t%3, #0\;csel\\t%0, %1, %2, ne\;csel\\t%R0, %R1, %R2, ne\;csdb",
+       operands);
+    return "";
+  }
+  [(set_attr "length" "16")
+   (set_attr "type" "block")
+   (set_attr "speculation_barrier" "true")]
+)
+
+(define_insn "despeculate_simple<ALLI:mode>"
+  [(set (match_operand:ALLI 0 "register_operand" "=r")
+	(unspec_volatile:ALLI
+	 [(match_operand:ALLI 1 "register_operand" "r")
+	  (use (match_operand:ALLI 2 "register_operand" ""))]
+	 UNSPECV_SPECULATION_BARRIER))]
+  ""
+  "and\\t%<w>0, %<w>1, %<w>2\;csdb"
+  [(set_attr "type" "block")
+   (set_attr "length" "8")
+   (set_attr "speculation_barrier" "true")]
+)
+
+(define_insn "despeculate_simpleti"
+  [(set (match_operand:TI 0 "register_operand" "=r")
+	(unspec_volatile:TI
+	 [(match_operand:TI 1 "register_operand" "r")
+	  (use (match_operand:DI 2 "register_operand" ""))]
+	 UNSPECV_SPECULATION_BARRIER))]
+  ""
+  "and\\t%0, %1, %2\;and\\t%R0, %R1, %2\;csdb"
+  [(set_attr "type" "block")
+   (set_attr "length" "12")
+   (set_attr "speculation_barrier" "true")]
+)
+
 ;; AdvSIMD Stuff
 (include "aarch64-simd.md")
 
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index 949fd2a..d2b7fff 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -35,6 +35,9 @@ (define_mode_iterator SHORT [QI HI])
 ;; Iterator for all integer modes (up to 64-bit)
 (define_mode_iterator ALLI [QI HI SI DI])
 
+;; Iterator for all integer modes (up to 128-bit)
+(define_mode_iterator ALLI_TI [QI HI SI DI TI])
+
 ;; Iterator for all integer modes that can be extended (up to 64-bit)
 (define_mode_iterator ALLX [QI HI SI])
 

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 3/7] AArch64 - add speculation barrier
  2018-07-09 16:39 [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753) Richard Earnshaw
                   ` (4 preceding siblings ...)
  2018-07-09 16:39 ` [PATCH 6/7] AArch64 - new pass to add conditional-branch speculation tracking Richard Earnshaw
@ 2018-07-09 16:39 ` Richard Earnshaw
  2018-07-09 16:39 ` [PATCH 7/7] AArch64 - use CSDB based sequences if speculation tracking is enabled Richard Earnshaw
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-09 16:39 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Earnshaw, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 262 bytes --]


Similar to Arm, this adds an unconditional speculation barrier for AArch64.

	* config/aarch64.md (unspecv): Add UNSPECV_SPECULAION_BARRIER.
	(speculation_barrier): New insn.
---
 gcc/config/aarch64/aarch64.md | 10 ++++++++++
 1 file changed, 10 insertions(+)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0003-AArch64-add-speculation-barrier.patch --]
[-- Type: text/x-patch; name="0003-AArch64-add-speculation-barrier.patch", Size: 863 bytes --]

diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index a014a01..c135ada 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -205,6 +205,7 @@ (define_c_enum "unspecv" [
     UNSPECV_SET_FPSR		; Represent assign of FPSR content.
     UNSPECV_BLOCKAGE		; Represent a blockage
     UNSPECV_PROBE_STACK_RANGE	; Represent stack range probing.
+    UNSPECV_SPECULATION_BARRIER ; Represent speculation barrier.
   ]
 )
 
@@ -6093,6 +6094,15 @@ (define_expand "set_clobber_cc"
 		   (match_operand 1))
 	      (clobber (reg:CC CC_REGNUM))])])
 
+;; Hard speculation barrier.
+(define_insn "speculation_barrier"
+  [(unspec_volatile [(const_int 0)] UNSPECV_SPECULATION_BARRIER)]
+  ""
+  "isb\;dsb\\tsy"
+  [(set_attr "length" "8")
+   (set_attr "type" "block")]
+)
+
 ;; AdvSIMD Stuff
 (include "aarch64-simd.md")
 

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 4/7] AArch64 - Add new option -mtrack-speculation
  2018-07-09 16:39 [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753) Richard Earnshaw
  2018-07-09 16:39 ` [PATCH 5/7] AArch64 - disable CB[N]Z TB[N]Z when tracking speculation Richard Earnshaw
  2018-07-09 16:39 ` [PATCH 2/7] Arm - add speculation_barrier pattern Richard Earnshaw
@ 2018-07-09 16:39 ` Richard Earnshaw
  2018-07-09 16:39 ` [PATCH 1/7] Add __builtin_speculation_safe_value Richard Earnshaw
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-09 16:39 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Earnshaw, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 299 bytes --]


This patch doesn't do anything useful, it simply adds a new command-line
option -mtrack-speculation to AArch64.  Subsequent patches build on this.

	* config/aarch64/aarch64.opt (mtrack-speculation): New target option.
---
 gcc/config/aarch64/aarch64.opt | 4 ++++
 1 file changed, 4 insertions(+)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0004-AArch64-Add-new-option-mtrack-speculation.patch --]
[-- Type: text/x-patch; name="0004-AArch64-Add-new-option-mtrack-speculation.patch", Size: 546 bytes --]

diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt
index 1426b45..bc9b22a 100644
--- a/gcc/config/aarch64/aarch64.opt
+++ b/gcc/config/aarch64/aarch64.opt
@@ -214,3 +214,7 @@ Target RejectNegative Joined Enum(sve_vector_bits) Var(aarch64_sve_vector_bits)
 mverbose-cost-dump
 Common Undocumented Var(flag_aarch64_verbose_cost)
 Enables verbose cost model dumping in the debug dump files.
+
+mtrack-speculation
+Target Var(aarch64_track_speculation)
+Generate code to track when the CPU might be speculating incorrectly.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 1/7] Add __builtin_speculation_safe_value
  2018-07-09 16:39 [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753) Richard Earnshaw
                   ` (2 preceding siblings ...)
  2018-07-09 16:39 ` [PATCH 4/7] AArch64 - Add new option -mtrack-speculation Richard Earnshaw
@ 2018-07-09 16:39 ` Richard Earnshaw
  2018-07-23 14:28   ` Richard Earnshaw (lists)
  2018-07-24 17:26   ` Richard Biener
  2018-07-09 16:39 ` [PATCH 6/7] AArch64 - new pass to add conditional-branch speculation tracking Richard Earnshaw
                   ` (5 subsequent siblings)
  9 siblings, 2 replies; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-09 16:39 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Earnshaw, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 3125 bytes --]


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


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-__builtin_speculation_safe_value.patch --]
[-- Type: text/x-patch; name="0001-Add-__builtin_speculation_safe_value.patch", Size: 21607 bytes --]

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;" } */

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 6/7] AArch64 - new pass to add conditional-branch speculation tracking
  2018-07-09 16:39 [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753) Richard Earnshaw
                   ` (3 preceding siblings ...)
  2018-07-09 16:39 ` [PATCH 1/7] Add __builtin_speculation_safe_value Richard Earnshaw
@ 2018-07-09 16:39 ` Richard Earnshaw
  2018-07-11 21:01   ` Jeff Law
  2018-07-09 16:39 ` [PATCH 3/7] AArch64 - add speculation barrier Richard Earnshaw
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-09 16:39 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Earnshaw, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 1987 bytes --]


This patch is the main part of the speculation tracking code.  It adds
a new target-specific pass that is run just before the final branch
reorg pass (so that it can clean up any new edge insertions we make).
The pass is only run with -mtrack-speculation is passed on the command
line.

One thing that did come to light as part of this was that the stack pointer
register was not being permitted in comparision instructions.  We rely on
that for moving the tracking state between SP and the scratch register at
function call boundaries.

	* config/aarch64/aarch64-speculation.cc: New file.
	* config/aarch64/aarch64-passes.def (pass_track_speculation): Add before
	pass_reorder_blocks.
	* config/aarch64/aarch64-protos.h (make_pass_track_speculation): Add
	prototype.
	* config/aarch64/aarch64.c (aarch64_conditional_register_usage): Fix
	X14 and X15 when tracking speculation.
	* config/aarch64/aarch64.md (register name constants): Add
	SPECULATION_TRACKER_REGNUM and SPECULATION_SCRATCH_REGNUM.
	(unspec): Add UNSPEC_SPECULATION_TRACKER.
	(speculation_barrier): New insn attribute.
	(cmp<mode>): Allow SP in comparisons.
	(speculation_tracker): New insn.
	(speculation_barrier): Add speculation_barrier attribute.
	* config/aarch64/t-aarch64: Add make rule for aarch64-speculation.o.
	* config.gcc (aarch64*-*-*): Add aarch64-speculation.o to extra_objs.
	* doc/invoke.texi (AArch64 Options): Document -mtrack-speculation.
---
 gcc/config.gcc                            |   2 +-
 gcc/config/aarch64/aarch64-passes.def     |   1 +
 gcc/config/aarch64/aarch64-protos.h       |   3 +-
 gcc/config/aarch64/aarch64-speculation.cc | 494 ++++++++++++++++++++++++++++++
 gcc/config/aarch64/aarch64.c              |  13 +
 gcc/config/aarch64/aarch64.md             |  30 +-
 gcc/config/aarch64/t-aarch64              |  10 +
 gcc/doc/invoke.texi                       |  10 +-
 8 files changed, 558 insertions(+), 5 deletions(-)
 create mode 100644 gcc/config/aarch64/aarch64-speculation.cc


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0006-AArch64-new-pass-to-add-conditional-branch-speculati.patch --]
[-- Type: text/x-patch; name="0006-AArch64-new-pass-to-add-conditional-branch-speculati.patch", Size: 23645 bytes --]

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 78e84c2..b17fdba 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -304,7 +304,7 @@ aarch64*-*-*)
 	extra_headers="arm_fp16.h arm_neon.h arm_acle.h"
 	c_target_objs="aarch64-c.o"
 	cxx_target_objs="aarch64-c.o"
-	extra_objs="aarch64-builtins.o aarch-common.o cortex-a57-fma-steering.o"
+	extra_objs="aarch64-builtins.o aarch-common.o cortex-a57-fma-steering.o aarch64-speculation.o"
 	target_gtfiles="\$(srcdir)/config/aarch64/aarch64-builtins.c"
 	target_has_targetm_common=yes
 	;;
diff --git a/gcc/config/aarch64/aarch64-passes.def b/gcc/config/aarch64/aarch64-passes.def
index 87747b4..3d6a254 100644
--- a/gcc/config/aarch64/aarch64-passes.def
+++ b/gcc/config/aarch64/aarch64-passes.def
@@ -19,3 +19,4 @@
    <http://www.gnu.org/licenses/>.  */
 
 INSERT_PASS_AFTER (pass_regrename, 1, pass_fma_steering);
+INSERT_PASS_BEFORE (pass_reorder_blocks, 1, pass_track_speculation);
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index bc11a78..e80ffcf 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -554,7 +554,8 @@ enum aarch64_parse_opt_result aarch64_parse_extension (const char *,
 std::string aarch64_get_extension_string_for_isa_flags (unsigned long,
 							unsigned long);
 
-rtl_opt_pass *make_pass_fma_steering (gcc::context *ctxt);
+rtl_opt_pass *make_pass_fma_steering (gcc::context *);
+rtl_opt_pass *make_pass_track_speculation (gcc::context *);
 
 poly_uint64 aarch64_regmode_natural_size (machine_mode);
 
diff --git a/gcc/config/aarch64/aarch64-speculation.cc b/gcc/config/aarch64/aarch64-speculation.cc
new file mode 100644
index 0000000..2dd06ae
--- /dev/null
+++ b/gcc/config/aarch64/aarch64-speculation.cc
@@ -0,0 +1,494 @@
+/* Speculation tracking and mitigation (e.g. CVE 2017-5753) for AArch64.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "rtl.h"
+#include "tree-pass.h"
+#include "profile-count.h"
+#include "cfg.h"
+#include "cfgbuild.h"
+#include "print-rtl.h"
+#include "cfgrtl.h"
+#include "function.h"
+#include "basic-block.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
+#include "insn-attr.h"
+#include "df.h"
+#include "tm_p.h"
+#include "insn-config.h"
+#include "recog.h"
+
+/* This pass scans the RTL just before the final branch
+   re-organisation pass.  The aim is to identify all places where
+   there is conditional control flow and to insert code that tracks
+   any speculative execution of a conditional branch.
+
+   To do this we reserve a call-clobbered register (so that it can be
+   initialized very early in the function prologue) that can then be
+   updated each time there is a conditional branch.  At each such
+   branch we then generate a code sequence that uses conditional
+   select operations that are not subject to speculation themselves
+   (we ignore for the moment situations where that might not always be
+   strictly true).  For example, a branch sequence such as:
+
+	B.EQ	<dst>
+	...
+   <dst>:
+
+   is transformed to:
+
+	B.EQ	<dst>
+	CSEL	tracker, tracker, XZr, ne
+	...
+   <dst>:
+	CSEL	tracker, tracker, XZr, eq
+
+   Since we start with the tracker initialized to all bits one, if at any
+   time the predicted control flow diverges from the architectural program
+   behavior, then the tracker will become zero (but not otherwise).
+
+   The tracker value can be used at any time at which a value needs
+   guarding against incorrect speculation.  This can be done in
+   several ways, but they all amount to the same thing.  For an
+   untrusted address, or an untrusted offset to a trusted address, we
+   can simply mask the address with the tracker with the untrusted
+   value.  If the CPU is not speculating, or speculating correctly,
+   then the value will remain unchanged, otherwise it will be clamped
+   to zero.  For more complex scenarios we can compare the tracker
+   against zero and use the flags to form a new selection with an
+   alternate safe value.
+
+   On implementations where the data processing instructions may
+   themselves produce speculative values, the architecture requires
+   that a CSDB instruction will resolve such data speculation, so each
+   time we use the tracker for protecting a vulnerable value we also
+   emit a CSDB: we do not need to do that each time the tracker itself
+   is updated.
+
+   At function boundaries, we need to communicate the speculation
+   tracking state with the caller or the callee.  This is tricky
+   because there is no register available for such a purpose without
+   creating a new ABI.  We deal with this by relying on the principle
+   that in all real programs the stack pointer, SP will never be NULL
+   at a function boundary; we can thus encode the speculation state in
+   SP by clearing SP if the speculation tracker itself is NULL.  After
+   the call we recover the tracking state back from SP into the
+   tracker register.  The results is that a function call sequence is
+   transformed to
+
+	MOV	tmp, SP
+	AND	tmp, tmp, tracker
+	MOV	SP, tmp
+	BL	<callee>
+	CMP	SP, #0
+	CSETM	tracker, ne
+
+   The additional MOV instructions in the pre-call sequence are needed
+   because SP cannot be used directly with the AND instruction.
+
+   The code inside a function body uses the post-call sequence in the
+   prologue to establish the tracker and the pre-call sequence in the
+   epilogue to re-encode the state for the return.
+
+   The code sequences have the nice property that if called from, or
+   calling a function that does not track speculation then the stack pointer
+   will always be non-NULL and hence the tracker will be initialized to all
+   bits one as we need: we lose the ability to fully track speculation in that
+   case, but we are still architecturally safe.
+
+   Tracking speculation in this way is quite expensive, both in code
+   size and execution time.  We employ a number of tricks to try to
+   limit this:
+
+   1) Simple leaf functions with no conditional branches (or use of
+   the tracker) do not need to establish a new tracker: they simply
+   carry the tracking state through SP for the duration of the call.
+   The same is also true for leaf functions that end in a tail-call.
+
+   2) Back-to-back function calls in a single basic block also do not
+   need to re-establish the tracker between the calls.  Again, we can
+   carry the tracking state in SP for this period of time unless the
+   tracker value is needed at that point in time.
+
+   We run the pass just before the final branch reorganization pass so
+   that we can handle most of the conditional branch cases using the
+   standard edge insertion code.  The reorg pass will hopefully clean
+   things up for afterwards so that the results aren't too
+   horrible.  */
+
+/* Generate a code sequence to clobber SP if speculating incorreclty.  */
+static rtx_insn *
+aarch64_speculation_clobber_sp ()
+{
+  rtx sp = gen_rtx_REG (DImode, SP_REGNUM);
+  rtx tracker = gen_rtx_REG (DImode, SPECULATION_TRACKER_REGNUM);
+  rtx scratch = gen_rtx_REG (DImode, SPECULATION_SCRATCH_REGNUM);
+
+  start_sequence ();
+  emit_insn (gen_rtx_SET (scratch, sp));
+  emit_insn (gen_anddi3 (scratch, scratch, tracker));
+  emit_insn (gen_rtx_SET (sp, scratch));
+  rtx_insn *seq = get_insns ();
+  end_sequence ();
+  return seq;
+}
+
+/* Generate a code sequence to establish the tracker variable from the
+   contents of SP.  */
+static rtx_insn *
+aarch64_speculation_establish_tracker ()
+{
+  rtx sp = gen_rtx_REG (DImode, SP_REGNUM);
+  rtx tracker = gen_rtx_REG (DImode, SPECULATION_TRACKER_REGNUM);
+  start_sequence ();
+  rtx cc = aarch64_gen_compare_reg (EQ, sp, const0_rtx);
+  emit_insn (gen_cstoredi_neg (tracker,
+			       gen_rtx_NE (CCmode, cc, const0_rtx), cc));
+  rtx_insn *seq = get_insns ();
+  end_sequence ();
+  return seq;
+}
+
+/* Main speculation tracking pass.  */
+unsigned int
+aarch64_do_track_speculation ()
+{
+  basic_block bb;
+  bool needs_tracking = false;
+  bool need_second_pass = false;
+  rtx_insn *insn;
+  int fixups_pending = 0;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      insn = BB_END (bb);
+
+      if (dump_file)
+	fprintf (dump_file, "Basic block %d:\n", bb->index);
+
+      while (insn != BB_HEAD (bb)
+	     && NOTE_P (insn))
+	insn = PREV_INSN (insn);
+
+      if (control_flow_insn_p (insn))
+	{
+	  if (any_condjump_p (insn))
+	    {
+	      if (dump_file)
+		{
+		  fprintf (dump_file, "  condjump\n");
+		  dump_insn_slim (dump_file, insn);
+		}
+
+	      rtx src = SET_SRC (pc_set (insn));
+
+	      /* Check for an inverted jump, where the fall-through edge
+		 appears first.  */
+	      bool inverted = GET_CODE (XEXP (src, 2)) != PC;
+	      /* The other edge must be the PC (we assume that we don't
+		 have conditional return instructions).  */
+	      gcc_assert (GET_CODE (XEXP (src, 1 + !inverted)) == PC);
+
+	      rtx cond = copy_rtx (XEXP (src, 0));
+	      gcc_assert (COMPARISON_P (cond)
+			  && REG_P (XEXP (cond, 0))
+			  && REGNO (XEXP (cond, 0)) == CC_REGNUM
+			  && XEXP (cond, 1) == const0_rtx);
+	      enum rtx_code inv_cond_code
+		= reversed_comparison_code (cond, insn);
+	      /* We should be able to reverse all conditions.  */
+	      gcc_assert (inv_cond_code != UNKNOWN);
+	      rtx inv_cond = gen_rtx_fmt_ee (inv_cond_code, GET_MODE (cond),
+					     copy_rtx (XEXP (cond, 0)),
+					     copy_rtx (XEXP (cond, 1)));
+	      if (inverted)
+		std::swap (cond, inv_cond);
+
+	      insert_insn_on_edge (gen_speculation_tracker (cond),
+				   BRANCH_EDGE (bb));
+	      insert_insn_on_edge (gen_speculation_tracker (inv_cond),
+				   FALLTHRU_EDGE (bb));
+	      needs_tracking = true;
+	    }
+	  else if (GET_CODE (PATTERN (insn)) == RETURN)
+	    {
+	      /* If we already know we'll need a second pass, don't put
+		 out the return sequence now, or we might end up with
+		 two copies.  Instead, we'll do all return statements
+		 during the second pass.  However, if this is the
+		 first return insn we've found and we already
+		 know that we'll need to emit the code, we can save a
+		 second pass by emitting the code now.  */
+	      if (needs_tracking && ! need_second_pass)
+		{
+		  rtx_insn *seq = aarch64_speculation_clobber_sp ();
+		  emit_insn_before (seq, insn);
+		}
+	      else
+		{
+		  fixups_pending++;
+		  need_second_pass = true;
+		}
+	    }
+	  else if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
+	    {
+	      rtx_insn *seq = aarch64_speculation_clobber_sp ();
+	      emit_insn_before (seq, insn);
+	      needs_tracking = true;
+	    }
+	}
+      else
+	{
+	  if (dump_file)
+	    {
+	      fprintf (dump_file, "  other\n");
+	      dump_insn_slim (dump_file, insn);
+	    }
+	}
+    }
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      rtx_insn *end = BB_END (bb);
+      rtx_insn *call_insn = NULL;
+
+      if (bb->flags & BB_NON_LOCAL_GOTO_TARGET)
+	{
+	  rtx_insn *label = NULL;
+	  /* For non-local goto targets we have to recover the
+	     speculation state from SP.  Find the last code label at
+	     the head of the block and place the fixup sequence after
+	     that.  */
+	  for (insn = BB_HEAD (bb); insn != end; insn = NEXT_INSN (insn))
+	    {
+	      if (LABEL_P (insn))
+		label = insn;
+	      /* Never put anything before the basic block note.  */
+	      if (NOTE_INSN_BASIC_BLOCK_P (insn))
+		label = insn;
+	      if (INSN_P (insn))
+		break;
+	    }
+
+	  gcc_assert (label);
+	  emit_insn_after (aarch64_speculation_establish_tracker (), label);
+	}
+
+      /* Scan the insns looking for calls.  We need to pass the
+	 speculation tracking state encoded in to SP.  After a call we
+	 restore the speculation tracking into the tracker register.
+	 To avoid unnecessary transfers we look for two or more calls
+	 within a single basic block and eliminate, where possible,
+	 any redundant operations.  */
+      for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn))
+	{
+	  if (NONDEBUG_INSN_P (insn)
+	      && recog_memoized (insn) >= 0
+	      && (get_attr_speculation_barrier (insn)
+		  == SPECULATION_BARRIER_TRUE))
+	    {
+	      if (call_insn)
+		{
+		  /* This instruction requires the speculation
+		     tracking to be in the tracker register.  If there
+		     was an earlier call in this block, we need to
+		     copy the speculation tracking back there.  */
+		  emit_insn_after (aarch64_speculation_establish_tracker (),
+				   call_insn);
+		  call_insn = NULL;
+		}
+
+	      needs_tracking = true;
+	    }
+
+	  if (CALL_P (insn))
+	    {
+	      bool tailcall
+		= (SIBLING_CALL_P (insn)
+		   || find_reg_note (insn, REG_NORETURN, NULL_RTX));
+
+	      /* Tailcalls are like returns, we can eliminate the
+		 transfer between the tracker register and SP if we
+		 know that this function does not itself need
+		 tracking.  */
+	      if (tailcall && (need_second_pass || !needs_tracking))
+		{
+		  /* Don't clear call_insn if it is set - needs_tracking
+		     will be true in that case and so we will end
+		     up putting out mitigation sequences.  */
+		  fixups_pending++;
+		  need_second_pass = true;
+		  break;
+		}
+
+	      needs_tracking = true;
+
+	      /* We always need a transfer before the first call in a BB.  */
+	      if (!call_insn)
+		emit_insn_before (aarch64_speculation_clobber_sp (), insn);
+
+	      /* Tail-calls and no-return calls don't need any post-call
+		 reestablishment of the tracker.  */
+	      if (! tailcall)
+		call_insn = insn;
+	      else
+		call_insn = NULL;
+	    }
+
+	  if (insn == end)
+	    break;
+	}
+
+      if (call_insn)
+	{
+	  rtx_insn *seq = aarch64_speculation_establish_tracker ();
+
+	  /* Handle debug insns at the end of the BB.  Put the extra
+	     insns after them.  This ensures that we have consistent
+	     behaviour for the placement of the extra insns between
+	     debug and non-debug builds.  */
+	  for (insn = call_insn;
+	       insn != end && DEBUG_INSN_P (NEXT_INSN (insn));
+	       insn = NEXT_INSN (insn))
+	    ;
+
+	  if (insn == end)
+	    {
+	      edge e = find_fallthru_edge (bb->succs);
+	      /* We need to be very careful about some calls that
+		 appear at the end of a basic block.  If the call
+		 involves exceptions, then the compiler may depend on
+		 this being the last instruction in the block.  The
+		 easiest way to handle this is to commit the new
+		 instructions on the fall-through edge and to let
+		 commit_edge_insertions clean things up for us.
+
+		 Sometimes, eg with OMP, there may not even be an
+		 outgoing edge after the call.  In that case, there's
+		 not much we can do, presumably the compiler has
+		 decided that the call can never return in this
+		 context.  */
+	      if (e)
+		{
+		  /* We need to set the location lists explicitly in
+		     this case.  */
+		  if (! INSN_P (seq))
+		    {
+		      start_sequence ();
+		      emit_insn (seq);
+		      seq = get_insns ();
+		      end_sequence ();
+		    }
+
+		  for (rtx_insn *list = seq; list; list = NEXT_INSN (list))
+		    INSN_LOCATION (list) = INSN_LOCATION (call_insn);
+
+		  insert_insn_on_edge (seq, e);
+		}
+	    }
+	  else
+	    emit_insn_after (seq, call_insn);
+	}
+    }
+
+  if (needs_tracking)
+    {
+      if (need_second_pass)
+	{
+	  /* We found a return instruction before we found out whether
+	     or not we need to emit the tracking code, but we now
+	     know we do.  Run quickly over the basic blocks and
+	     fix up the return insns.  */
+	  FOR_EACH_BB_FN (bb, cfun)
+	    {
+	      insn = BB_END (bb);
+
+	      while (insn != BB_HEAD (bb)
+		     && NOTE_P (insn))
+		insn = PREV_INSN (insn);
+
+	      if ((control_flow_insn_p (insn)
+		   && GET_CODE (PATTERN (insn)) == RETURN)
+		  || (CALL_P (insn)
+		      && (SIBLING_CALL_P (insn)
+			  || find_reg_note (insn, REG_NORETURN, NULL_RTX))))
+		{
+		  rtx_insn *seq = aarch64_speculation_clobber_sp ();
+		  emit_insn_before (seq, insn);
+		  fixups_pending--;
+		}
+	    }
+	  gcc_assert (fixups_pending == 0);
+	}
+
+      /* Set up the initial value of the tracker, using the incoming SP.  */
+      insert_insn_on_edge (aarch64_speculation_establish_tracker (),
+			   single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+      commit_edge_insertions ();
+    }
+
+  return 0;
+}
+
+namespace {
+
+const pass_data pass_data_aarch64_track_speculation =
+{
+  RTL_PASS,		/* type.  */
+  "speculation",	/* name.  */
+  OPTGROUP_NONE,	/* optinfo_flags.  */
+  TV_MACH_DEP,		/* tv_id.  */
+  0,			/* properties_required.  */
+  0,			/* properties_provided.  */
+  0,			/* properties_destroyed.  */
+  0,			/* todo_flags_start.  */
+  0			/* todo_flags_finish.  */
+};
+
+class pass_track_speculation : public rtl_opt_pass
+{
+ public:
+  pass_track_speculation(gcc::context *ctxt)
+    : rtl_opt_pass(pass_data_aarch64_track_speculation, ctxt)
+    {}
+
+  /* opt_pass methods:  */
+  virtual bool gate (function *)
+    {
+      return aarch64_track_speculation;
+    }
+
+  virtual unsigned int execute (function *)
+    {
+      return aarch64_do_track_speculation ();
+    }
+}; // class pass_track_speculation.
+} // anon namespace.
+
+/* Create a new pass instance.  */
+rtl_opt_pass *
+make_pass_track_speculation (gcc::context *ctxt)
+{
+  return new pass_track_speculation (ctxt);
+}
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index da96afd..b11d768 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -12573,6 +12573,19 @@ aarch64_conditional_register_usage (void)
 	fixed_regs[i] = 1;
 	call_used_regs[i] = 1;
       }
+
+  /* When tracking speculation, we need a couple of call-clobbered registers
+     to track the speculation state.  It would be nice to just use
+     IP0 and IP1, but currently there are numerous places that just
+     assume these registers are free for other uses (eg pointer
+     authentication).  */
+  if (aarch64_track_speculation)
+    {
+      fixed_regs[SPECULATION_TRACKER_REGNUM] = 1;
+      call_used_regs[SPECULATION_TRACKER_REGNUM] = 1;
+      fixed_regs[SPECULATION_SCRATCH_REGNUM] = 1;
+      call_used_regs[SPECULATION_SCRATCH_REGNUM] = 1;
+    }
 }
 
 /* Walk down the type tree of TYPE counting consecutive base elements.
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 259a07d..528d03d 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -88,6 +88,10 @@ (define_constants
     (P13_REGNUM		81)
     (P14_REGNUM		82)
     (P15_REGNUM		83)
+    ;; A couple of call-clobbered registers that we need to reserve when
+    ;; tracking speculation this is not ABI, so is subject to change.
+    (SPECULATION_TRACKER_REGNUM 15)
+    (SPECULATION_SCRATCH_REGNUM 14)
   ]
 )
 
@@ -195,6 +199,7 @@ (define_c_enum "unspec" [
     UNSPEC_CLASTB
     UNSPEC_FADDA
     UNSPEC_REV_SUBREG
+    UNSPEC_SPECULATION_TRACKER
 ])
 
 (define_c_enum "unspecv" [
@@ -287,6 +292,11 @@ (define_attr "length" ""
 ;; no predicated insns.
 (define_attr "predicated" "yes,no" (const_string "no"))
 
+;; Set to true on an insn that requires the speculation tracking state to be
+;; in the tracking register before the insn issues.  Otherwise the compiler
+;; may chose to hold the tracking state encoded in SP.
+(define_attr "speculation_barrier" "true,false" (const_string "false"))
+
 ;; -------------------------------------------------------------------
 ;; Pipeline descriptions and scheduling
 ;; -------------------------------------------------------------------
@@ -3079,7 +3089,7 @@ (define_insn "*<su_optab>divsi3_uxtw"
 
 (define_insn "cmp<mode>"
   [(set (reg:CC CC_REGNUM)
-	(compare:CC (match_operand:GPI 0 "register_operand" "r,r,r")
+	(compare:CC (match_operand:GPI 0 "register_operand" "rk,rk,rk")
 		    (match_operand:GPI 1 "aarch64_plus_operand" "r,I,J")))]
   ""
   "@
@@ -6088,6 +6098,21 @@ (define_expand "doloop_end"
   DONE;
 })
 
+;; Track speculation through conditional branches.  We assume that
+;; SPECULATION_TRACKER_REGNUM is reserved for this purpose when necessary.
+(define_insn "speculation_tracker"
+  [(set (reg:DI SPECULATION_TRACKER_REGNUM)
+	(unspec [(reg:DI SPECULATION_TRACKER_REGNUM) (match_operand 0)]
+	 UNSPEC_SPECULATION_TRACKER))]
+  ""
+  {
+    operands[1] = gen_rtx_REG (DImode, SPECULATION_TRACKER_REGNUM);
+    output_asm_insn ("csel\\t%1, %1, xzr, %m0", operands);
+    return "";
+  }
+  [(set_attr "type" "csel")]
+)
+
 ;; Helper for aarch64.c code.
 (define_expand "set_clobber_cc"
   [(parallel [(set (match_operand 0)
@@ -6100,7 +6125,8 @@ (define_insn "speculation_barrier"
   ""
   "isb\;dsb\\tsy"
   [(set_attr "length" "8")
-   (set_attr "type" "block")]
+   (set_attr "type" "block")
+   (set_attr "speculation_barrier" "true")]
 )
 
 ;; AdvSIMD Stuff
diff --git a/gcc/config/aarch64/t-aarch64 b/gcc/config/aarch64/t-aarch64
index 0be1f0d..5d54853 100644
--- a/gcc/config/aarch64/t-aarch64
+++ b/gcc/config/aarch64/t-aarch64
@@ -67,6 +67,16 @@ cortex-a57-fma-steering.o: $(srcdir)/config/aarch64/cortex-a57-fma-steering.c \
 	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 		$(srcdir)/config/aarch64/cortex-a57-fma-steering.c
 
+aarch64-speculation.o: $(srcdir)/config/aarch64/aarch64-speculation.cc \
+    $(CONFIG_H) \
+    $(SYSTEM_H) \
+    $(TM_H) \
+    $(TARGET_H) \
+    $(RTL_BASE_H) \
+    $(TREE_PASS_H)
+	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_SPPFLAGS) $(INCLUDES) \
+	  $(srcdir)/config/aarch64/aarch64-speculation.cc
+
 comma=,
 MULTILIB_OPTIONS    = $(subst $(comma),/, $(patsubst %, mabi=%, $(subst $(comma),$(comma)mabi=,$(TM_MULTILIB_CONFIG))))
 MULTILIB_DIRNAMES   = $(subst $(comma), ,$(TM_MULTILIB_CONFIG))
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index e0e59f6..db39304 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -598,7 +598,7 @@ Objective-C and Objective-C++ Dialects}.
 -mpc-relative-literal-loads @gol
 -msign-return-address=@var{scope} @gol
 -march=@var{name}  -mcpu=@var{name}  -mtune=@var{name}  @gol
--moverride=@var{string}  -mverbose-cost-dump}
+-moverride=@var{string}  -mverbose-cost-dump -mtrack-speculation} 
 
 @emph{Adapteva Epiphany Options}
 @gccoptlist{-mhalf-reg-file  -mprefer-short-insn-regs @gol
@@ -14649,6 +14649,14 @@ This option only has an effect if @option{-ffast-math} or
 precision of division results to about 16 bits for
 single precision and to 32 bits for double precision.
 
+@item -mtrack-speculation
+@itemx -mno-track-speculation
+Enable or disable generation of additional code to track speculative
+execution through conditional branches.  The tracking state can then
+be used by the compiler when expanding calls to
+@code{__builtin_speculation_safe_copy} to permit a more efficient code
+sequence to be generated.
+
 @item -march=@var{name}
 @opindex march
 Specify the name of the target architecture and, optionally, one or

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 2/7] Arm - add speculation_barrier pattern
  2018-07-09 16:39 [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753) Richard Earnshaw
  2018-07-09 16:39 ` [PATCH 5/7] AArch64 - disable CB[N]Z TB[N]Z when tracking speculation Richard Earnshaw
@ 2018-07-09 16:39 ` Richard Earnshaw
  2018-07-09 16:39 ` [PATCH 4/7] AArch64 - Add new option -mtrack-speculation Richard Earnshaw
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-09 16:39 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Earnshaw, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 351 bytes --]


This patch defines a speculation barrier for AArch32.

	* config/arm/unspecs.md (unspecv): Add VUNSPEC_SPECULATION_BARRIER.
	* config/arm/arm.md (speculation_barrier): New expand.
	(speculation_barrier_insn): New pattern.
---
 gcc/config/arm/arm.md     | 21 +++++++++++++++++++++
 gcc/config/arm/unspecs.md |  1 +
 2 files changed, 22 insertions(+)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0002-Arm-add-speculation_barrier-pattern.patch --]
[-- Type: text/x-patch; name="0002-Arm-add-speculation_barrier-pattern.patch", Size: 1487 bytes --]

diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 361a026..ca2a2f5 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -12012,6 +12012,27 @@ (define_insn "<mrrc>"
   [(set_attr "length" "4")
    (set_attr "type" "coproc")])
 
+(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;
+  "
+)
+
+;; Generate a hard speculation barrier when we have not enabled speculation
+;; tracking.
+(define_insn "*speculation_barrier_insn"
+  [(unspec_volatile [(const_int 0)] VUNSPEC_SPECULATION_BARRIER)]
+  "TARGET_32BIT"
+  "isb\;dsb\\tsy"
+  [(set_attr "type" "block")
+   (set_attr "length" "8")]
+)
+
 ;; Vector bits common to IWMMXT and Neon
 (include "vec-common.md")
 ;; Load the Intel Wireless Multimedia Extension patterns
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index b05f85e..1941673 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -168,6 +168,7 @@ (define_c_enum "unspecv" [
   VUNSPEC_MCRR2		; Represent the coprocessor mcrr2 instruction.
   VUNSPEC_MRRC		; Represent the coprocessor mrrc instruction.
   VUNSPEC_MRRC2		; Represent the coprocessor mrrc2 instruction.
+  VUNSPEC_SPECULATION_BARRIER ; Represents an unconditional speculation barrier.
 ])
 
 ;; Enumerators for NEON unspecs.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 5/7] AArch64 - disable CB[N]Z TB[N]Z when tracking speculation
  2018-07-09 16:39 [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753) Richard Earnshaw
@ 2018-07-09 16:39 ` Richard Earnshaw
  2018-07-09 16:39 ` [PATCH 2/7] Arm - add speculation_barrier pattern Richard Earnshaw
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-09 16:39 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Earnshaw, richard.earnshaw

[-- Attachment #1: Type: text/plain, Size: 957 bytes --]


The CB[N]Z and TB[N]Z instructions do not expose the comparison through
the condition code flags.  This makes it impossible to track speculative
execution through such a branch.  We can handle this relatively easily
by simply disabling the patterns in this case.

A side effect of this is that the split patterns for the atomic operations
need to also avoid generating these instructions.  They mostly have simple
fall-backs for this already.

	* config/aarch64/aarch64.md (cb<optab><mode>1): Disable when
	aarch64_track_speculation is true.
	(tb<optab><mode>1): Likewise.
	* config/aarch64/aarch64.c (aarch64_split_compare_regs): Do not
	generate CB[N]Z when tracking speculation.
	(aarch64_split_compare_and_swap): Likewise.
	(aarch64_split_atomic_op): Likewise.
---
 gcc/config/aarch64/aarch64.c  | 33 ++++++++++++++++++++++++++++++---
 gcc/config/aarch64/aarch64.md |  6 +++---
 2 files changed, 33 insertions(+), 6 deletions(-)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0005-AArch64-disable-CB-N-Z-TB-N-Z-when-tracking-speculat.patch --]
[-- Type: text/x-patch; name="0005-AArch64-disable-CB-N-Z-TB-N-Z-when-tracking-speculat.patch", Size: 3255 bytes --]

diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 01f35f8..da96afd 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -14465,7 +14465,16 @@ aarch64_split_compare_and_swap (rtx operands[])
 
   if (strong_zero_p)
     {
-      x = gen_rtx_NE (VOIDmode, rval, const0_rtx);
+      if (aarch64_track_speculation)
+	{
+	  /* Emit an explicit compare instruction, so that we can correctly
+	     track the condition codes.  */
+	  rtx cc_reg = aarch64_gen_compare_reg (NE, rval, const0_rtx);
+	  x = gen_rtx_NE (GET_MODE (cc_reg), cc_reg, const0_rtx);
+	}
+      else
+	x = gen_rtx_NE (VOIDmode, rval, const0_rtx);
+
       x = gen_rtx_IF_THEN_ELSE (VOIDmode, x,
 				gen_rtx_LABEL_REF (Pmode, label2), pc_rtx);
       aarch64_emit_unlikely_jump (gen_rtx_SET (pc_rtx, x));
@@ -14483,7 +14492,16 @@ aarch64_split_compare_and_swap (rtx operands[])
 
   if (!is_weak)
     {
-      x = gen_rtx_NE (VOIDmode, scratch, const0_rtx);
+      if (aarch64_track_speculation)
+	{
+	  /* Emit an explicit compare instruction, so that we can correctly
+	     track the condition codes.  */
+	  rtx cc_reg = aarch64_gen_compare_reg (NE, scratch, const0_rtx);
+	  x = gen_rtx_NE (GET_MODE (cc_reg), cc_reg, const0_rtx);
+	}
+      else
+	x = gen_rtx_NE (VOIDmode, scratch, const0_rtx);
+
       x = gen_rtx_IF_THEN_ELSE (VOIDmode, x,
 				gen_rtx_LABEL_REF (Pmode, label1), pc_rtx);
       aarch64_emit_unlikely_jump (gen_rtx_SET (pc_rtx, x));
@@ -14819,7 +14837,16 @@ aarch64_split_atomic_op (enum rtx_code code, rtx old_out, rtx new_out, rtx mem,
   aarch64_emit_store_exclusive (mode, cond, mem,
 				gen_lowpart (mode, new_out), model_rtx);
 
-  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
+  if (aarch64_track_speculation)
+    {
+      /* Emit an explicit compare instruction, so that we can correctly
+	 track the condition codes.  */
+      rtx cc_reg = aarch64_gen_compare_reg (NE, cond, const0_rtx);
+      x = gen_rtx_NE (GET_MODE (cc_reg), cc_reg, const0_rtx);
+    }
+  else
+    x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
+
   x = gen_rtx_IF_THEN_ELSE (VOIDmode, x,
 			    gen_rtx_LABEL_REF (Pmode, label), pc_rtx);
   aarch64_emit_unlikely_jump (gen_rtx_SET (pc_rtx, x));
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index c135ada..259a07d 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -690,7 +690,7 @@ (define_insn "*cb<optab><mode>1"
 				(const_int 0))
 			   (label_ref (match_operand 1 "" ""))
 			   (pc)))]
-  ""
+  "!aarch64_track_speculation"
   {
     if (get_attr_length (insn) == 8)
       return aarch64_gen_far_branch (operands, 1, "Lcb", "<inv_cb>\\t%<w>0, ");
@@ -720,7 +720,7 @@ (define_insn "*tb<optab><mode>1"
 	     (label_ref (match_operand 2 "" ""))
 	     (pc)))
    (clobber (reg:CC CC_REGNUM))]
-  ""
+  "!aarch64_track_speculation"
   {
     if (get_attr_length (insn) == 8)
       {
@@ -756,7 +756,7 @@ (define_insn "*cb<optab><mode>1"
 			   (label_ref (match_operand 1 "" ""))
 			   (pc)))
    (clobber (reg:CC CC_REGNUM))]
-  ""
+  "!aarch64_track_speculation"
   {
     if (get_attr_length (insn) == 8)
       {

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-09 16:39 [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753) Richard Earnshaw
                   ` (6 preceding siblings ...)
  2018-07-09 16:39 ` [PATCH 7/7] AArch64 - use CSDB based sequences if speculation tracking is enabled Richard Earnshaw
@ 2018-07-09 23:13 ` Jeff Law
  2018-07-10  8:49   ` Richard Earnshaw (lists)
  2018-07-10  7:19 ` Richard Biener
  2018-07-27  9:38 ` [PATCH 00/11] (v2) " Richard Earnshaw
  9 siblings, 1 reply; 82+ messages in thread
From: Jeff Law @ 2018-07-09 23:13 UTC (permalink / raw)
  To: Richard Earnshaw, gcc-patches

On 07/09/2018 10:38 AM, Richard Earnshaw wrote:
> 
> The patches I posted earlier this year for mitigating against
> CVE-2017-5753 (Spectre variant 1) attracted some useful feedback, from
> which it became obvious that a rethink was needed.  This mail, and the
> following patches attempt to address that feedback and present a new
> approach to mitigating against this form of attack surface.
> 
> There were two major issues with the original approach:
> 
> - The speculation bounds were too tightly constrained - essentially
>   they had to represent and upper and lower bound on a pointer, or a
>   pointer offset.
> - The speculation constraints could only cover the immediately preceding
>   branch, which often did not fit well with the structure of the existing
>   code.
> 
> An additional criticism was that the shape of the intrinsic did not
> fit particularly well with systems that used a single speculation
> barrier that essentially had to wait until all preceding speculation
> had to be resolved.
Right.  I suggest the Intel and IBM reps chime in on the updated semantics.

> 
> To address all of the above, these patches adopt a new approach, based
> in part on a posting by Chandler Carruth to the LLVM developers list
> (https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
> but which we have extended to deal with inter-function speculation.
> The patches divide the problem into two halves.
We're essentially turning the control dependency into a value that we
can then use to munge the pointer or the resultant data.

> 
> The first half is some target-specific code to track the speculation
> condition through the generated code to provide an internal variable
> which can tell us whether or not the CPU's control flow speculation
> matches the data flow calculations.  The idea is that the internal
> variable starts with the value TRUE and if the CPU's control flow
> speculation ever causes a jump to the wrong block of code the variable
> becomes false until such time as the incorrect control flow
> speculation gets unwound.
Right.

So one of the things that comes immediately to mind is you have to run
this early enough that you can still get to all the control flow and
build your predicates.  Otherwise you have do undo stuff like
conditional move generation.

On the flip side, the earlier you do this mitigation, the more you have
to worry about what the optimizers are going to do to the code later in
the pipeline.  It's almost guaranteed a naive implementation is going to
muck this up since we can propagate the state of the condition into the
arms which will make the predicate state a compile time constant.

In fact this seems to be running into the area of pointer providence and
some discussions we had around atomic a few years back.

I also wonder if this could be combined with taint analysis to produce a
much lower overhead solution in cases were developers have done analysis
and know what objects are potentially under attacker control.  So
instead of analyzing everything, we can have a much narrower focus.

The pointer munging could well run afoul of alias analysis engines that
don't expect to be seeing those kind of operations.

Anyway, just some initial high level thoughts.  I'm sure there'll be
more as I read the implementation.


Jeff

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-09 16:39 [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753) Richard Earnshaw
                   ` (7 preceding siblings ...)
  2018-07-09 23:13 ` [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753) Jeff Law
@ 2018-07-10  7:19 ` Richard Biener
  2018-07-10  8:39   ` Richard Earnshaw (lists)
  2018-07-27  9:38 ` [PATCH 00/11] (v2) " Richard Earnshaw
  9 siblings, 1 reply; 82+ messages in thread
From: Richard Biener @ 2018-07-10  7:19 UTC (permalink / raw)
  To: Richard Earnshaw; +Cc: GCC Patches

On Mon, Jul 9, 2018 at 6:39 PM Richard Earnshaw
<Richard.Earnshaw@arm.com> wrote:
>
>
> The patches I posted earlier this year for mitigating against
> CVE-2017-5753 (Spectre variant 1) attracted some useful feedback, from
> which it became obvious that a rethink was needed.  This mail, and the
> following patches attempt to address that feedback and present a new
> approach to mitigating against this form of attack surface.
>
> There were two major issues with the original approach:
>
> - The speculation bounds were too tightly constrained - essentially
>   they had to represent and upper and lower bound on a pointer, or a
>   pointer offset.
> - The speculation constraints could only cover the immediately preceding
>   branch, which often did not fit well with the structure of the existing
>   code.
>
> An additional criticism was that the shape of the intrinsic did not
> fit particularly well with systems that used a single speculation
> barrier that essentially had to wait until all preceding speculation
> had to be resolved.
>
> To address all of the above, these patches adopt a new approach, based
> in part on a posting by Chandler Carruth to the LLVM developers list
> (https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
> but which we have extended to deal with inter-function speculation.
> The patches divide the problem into two halves.
>
> The first half is some target-specific code to track the speculation
> condition through the generated code to provide an internal variable
> which can tell us whether or not the CPU's control flow speculation
> matches the data flow calculations.  The idea is that the internal
> variable starts with the value TRUE and if the CPU's control flow
> speculation ever causes a jump to the wrong block of code the variable
> becomes false until such time as the incorrect control flow
> speculation gets unwound.
>
> The second half is that a new intrinsic function is introduced that is
> much simpler than we had before.  The basic version of the intrinsic
> is now simply:
>
>       T var = __builtin_speculation_safe_value (T unsafe_var);
>
> Full details of the syntax can be found in the documentation patch, in
> patch 1.  In summary, when not speculating the intrinsic returns
> unsafe_var; when speculating then if it can be shown that the
> speculative flow has diverged from the intended control flow then zero
> is returned.  An optional second argument can be used to return an
> alternative value to zero.  The builtin may cause execution to pause
> until the speculation state is resolved.

So a trivial target implementation would be to emit a barrier and then
it would always return unsafe_var and never zero.  What I don't understand
fully is what users should do here, thus what the value of ever returning
"unsafe" is.  Also I wonder why the API is forcing you to single-out a
special value instead of doing

 bool safe = __builtin_speculation_safe_value_p (T unsafe_value);
 if (!safe)
   /* what now? */

I'm only guessing that the correct way to handle "unsafe" is basically

 while (__builtin_speculation_safe_value (val) == 0)
    ;

use val, it's now safe

that is, the return value is only interesting in sofar as to whether it is equal
to val or the special value?

That said, I wonder why we don't hide that details from the user and
provide a predicate instead.

Richard.

> There are seven patches in this set, as follows.
>
> 1) Introduces the new intrinsic __builtin_sepculation_safe_value.
> 2) Adds a basic hard barrier implementation for AArch32 (arm) state.
> 3) Adds a basic hard barrier implementation for AArch64 state.
> 4) Adds a new command-line option -mtrack-speculation (currently a no-op).
> 5) Disables CB[N]Z and TB[N]Z when -mtrack-speculation.
> 6) Adds the new speculation tracking pass for AArch64
> 7) Uses the new speculation tracking pass to generate CSDB-based barrier
>    sequences
>
> I haven't added a speculation-tracking pass for AArch32 at this time.
> It is possible to do this, but would require quite a lot of rework for
> the arm backend due to the limited number of registers that are
> available.
>
> Although patch 6 is AArch64 specific, I'd appreciate a review from
> someone more familiar with the branch edge code than myself.  There
> appear to be a number of tricky issues with more complex edges so I'd
> like a second opinion on that code in case I've missed an important
> case.
>
> R.
>
>
>
> Richard Earnshaw (7):
>   Add __builtin_speculation_safe_value
>   Arm - add speculation_barrier pattern
>   AArch64 - add speculation barrier
>   AArch64 - Add new option -mtrack-speculation
>   AArch64 - disable CB[N]Z TB[N]Z when tracking speculation
>   AArch64 - new pass to add conditional-branch speculation tracking
>   AArch64 - use CSDB based sequences if speculation tracking is enabled
>
>  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/config.gcc                            |   2 +-
>  gcc/config/aarch64/aarch64-passes.def     |   1 +
>  gcc/config/aarch64/aarch64-protos.h       |   3 +-
>  gcc/config/aarch64/aarch64-speculation.cc | 494 ++++++++++++++++++++++++++++++
>  gcc/config/aarch64/aarch64.c              |  88 +++++-
>  gcc/config/aarch64/aarch64.md             | 140 ++++++++-
>  gcc/config/aarch64/aarch64.opt            |   4 +
>  gcc/config/aarch64/iterators.md           |   3 +
>  gcc/config/aarch64/t-aarch64              |  10 +
>  gcc/config/arm/arm.md                     |  21 ++
>  gcc/config/arm/unspecs.md                 |   1 +
>  gcc/doc/cpp.texi                          |   4 +
>  gcc/doc/extend.texi                       |  29 ++
>  gcc/doc/invoke.texi                       |  10 +-
>  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 +
>  28 files changed, 1191 insertions(+), 11 deletions(-)
>  create mode 100644 gcc/config/aarch64/aarch64-speculation.cc
>  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

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-10  7:19 ` Richard Biener
@ 2018-07-10  8:39   ` Richard Earnshaw (lists)
  2018-07-10 10:10     ` Richard Biener
  0 siblings, 1 reply; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-07-10  8:39 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

On 10/07/18 08:19, Richard Biener wrote:
> On Mon, Jul 9, 2018 at 6:39 PM Richard Earnshaw
> <Richard.Earnshaw@arm.com> wrote:
>>
>>
>> The patches I posted earlier this year for mitigating against
>> CVE-2017-5753 (Spectre variant 1) attracted some useful feedback, from
>> which it became obvious that a rethink was needed.  This mail, and the
>> following patches attempt to address that feedback and present a new
>> approach to mitigating against this form of attack surface.
>>
>> There were two major issues with the original approach:
>>
>> - The speculation bounds were too tightly constrained - essentially
>>   they had to represent and upper and lower bound on a pointer, or a
>>   pointer offset.
>> - The speculation constraints could only cover the immediately preceding
>>   branch, which often did not fit well with the structure of the existing
>>   code.
>>
>> An additional criticism was that the shape of the intrinsic did not
>> fit particularly well with systems that used a single speculation
>> barrier that essentially had to wait until all preceding speculation
>> had to be resolved.
>>
>> To address all of the above, these patches adopt a new approach, based
>> in part on a posting by Chandler Carruth to the LLVM developers list
>> (https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
>> but which we have extended to deal with inter-function speculation.
>> The patches divide the problem into two halves.
>>
>> The first half is some target-specific code to track the speculation
>> condition through the generated code to provide an internal variable
>> which can tell us whether or not the CPU's control flow speculation
>> matches the data flow calculations.  The idea is that the internal
>> variable starts with the value TRUE and if the CPU's control flow
>> speculation ever causes a jump to the wrong block of code the variable
>> becomes false until such time as the incorrect control flow
>> speculation gets unwound.
>>
>> The second half is that a new intrinsic function is introduced that is
>> much simpler than we had before.  The basic version of the intrinsic
>> is now simply:
>>
>>       T var = __builtin_speculation_safe_value (T unsafe_var);
>>
>> Full details of the syntax can be found in the documentation patch, in
>> patch 1.  In summary, when not speculating the intrinsic returns
>> unsafe_var; when speculating then if it can be shown that the
>> speculative flow has diverged from the intended control flow then zero
>> is returned.  An optional second argument can be used to return an
>> alternative value to zero.  The builtin may cause execution to pause
>> until the speculation state is resolved.
> 
> So a trivial target implementation would be to emit a barrier and then
> it would always return unsafe_var and never zero.  What I don't understand
> fully is what users should do here, thus what the value of ever returning
> "unsafe" is.  Also I wonder why the API is forcing you to single-out a
> special value instead of doing
> 
>  bool safe = __builtin_speculation_safe_value_p (T unsafe_value);
>  if (!safe)
>    /* what now? */
> 
> I'm only guessing that the correct way to handle "unsafe" is basically
> 
>  while (__builtin_speculation_safe_value (val) == 0)
>     ;
> 
> use val, it's now safe

No, a safe version of val is returned, not a bool telling you it is now
safe to use the original.  You must use the sanitized version in future,
not the unprotected version.


So the usage is going to be more like:

val = __builtin_speculation_safe_value (val);  // Overwrite val with a
sanitized version.

You have to use the cleaned up version, the unclean version is still
vulnerable to incorrect speculation.

R.

> 
> that is, the return value is only interesting in sofar as to whether it is equal
> to val or the special value?
> 
> That said, I wonder why we don't hide that details from the user and
> provide a predicate instead.
> 
> Richard.
> 
>> There are seven patches in this set, as follows.
>>
>> 1) Introduces the new intrinsic __builtin_sepculation_safe_value.
>> 2) Adds a basic hard barrier implementation for AArch32 (arm) state.
>> 3) Adds a basic hard barrier implementation for AArch64 state.
>> 4) Adds a new command-line option -mtrack-speculation (currently a no-op).
>> 5) Disables CB[N]Z and TB[N]Z when -mtrack-speculation.
>> 6) Adds the new speculation tracking pass for AArch64
>> 7) Uses the new speculation tracking pass to generate CSDB-based barrier
>>    sequences
>>
>> I haven't added a speculation-tracking pass for AArch32 at this time.
>> It is possible to do this, but would require quite a lot of rework for
>> the arm backend due to the limited number of registers that are
>> available.
>>
>> Although patch 6 is AArch64 specific, I'd appreciate a review from
>> someone more familiar with the branch edge code than myself.  There
>> appear to be a number of tricky issues with more complex edges so I'd
>> like a second opinion on that code in case I've missed an important
>> case.
>>
>> R.
>>
>>
>>
>> Richard Earnshaw (7):
>>   Add __builtin_speculation_safe_value
>>   Arm - add speculation_barrier pattern
>>   AArch64 - add speculation barrier
>>   AArch64 - Add new option -mtrack-speculation
>>   AArch64 - disable CB[N]Z TB[N]Z when tracking speculation
>>   AArch64 - new pass to add conditional-branch speculation tracking
>>   AArch64 - use CSDB based sequences if speculation tracking is enabled
>>
>>  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/config.gcc                            |   2 +-
>>  gcc/config/aarch64/aarch64-passes.def     |   1 +
>>  gcc/config/aarch64/aarch64-protos.h       |   3 +-
>>  gcc/config/aarch64/aarch64-speculation.cc | 494 ++++++++++++++++++++++++++++++
>>  gcc/config/aarch64/aarch64.c              |  88 +++++-
>>  gcc/config/aarch64/aarch64.md             | 140 ++++++++-
>>  gcc/config/aarch64/aarch64.opt            |   4 +
>>  gcc/config/aarch64/iterators.md           |   3 +
>>  gcc/config/aarch64/t-aarch64              |  10 +
>>  gcc/config/arm/arm.md                     |  21 ++
>>  gcc/config/arm/unspecs.md                 |   1 +
>>  gcc/doc/cpp.texi                          |   4 +
>>  gcc/doc/extend.texi                       |  29 ++
>>  gcc/doc/invoke.texi                       |  10 +-
>>  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 +
>>  28 files changed, 1191 insertions(+), 11 deletions(-)
>>  create mode 100644 gcc/config/aarch64/aarch64-speculation.cc
>>  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

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-09 23:13 ` [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753) Jeff Law
@ 2018-07-10  8:49   ` Richard Earnshaw (lists)
  2018-07-10 13:48     ` Bill Schmidt
  2018-07-10 15:42     ` Jeff Law
  0 siblings, 2 replies; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-07-10  8:49 UTC (permalink / raw)
  To: Jeff Law, gcc-patches

On 10/07/18 00:13, Jeff Law wrote:
> On 07/09/2018 10:38 AM, Richard Earnshaw wrote:
>>
>> The patches I posted earlier this year for mitigating against
>> CVE-2017-5753 (Spectre variant 1) attracted some useful feedback, from
>> which it became obvious that a rethink was needed.  This mail, and the
>> following patches attempt to address that feedback and present a new
>> approach to mitigating against this form of attack surface.
>>
>> There were two major issues with the original approach:
>>
>> - The speculation bounds were too tightly constrained - essentially
>>   they had to represent and upper and lower bound on a pointer, or a
>>   pointer offset.
>> - The speculation constraints could only cover the immediately preceding
>>   branch, which often did not fit well with the structure of the existing
>>   code.
>>
>> An additional criticism was that the shape of the intrinsic did not
>> fit particularly well with systems that used a single speculation
>> barrier that essentially had to wait until all preceding speculation
>> had to be resolved.
> Right.  I suggest the Intel and IBM reps chime in on the updated semantics.
> 

Yes, logically, this is a boolean tracker value.  In practice we use ~0
for true and 0 for false, so that we can simply use it as a mask
operation later.

I hope this intrinsic will be even more acceptable than the one that
Bill Schmidt acked previously, it's even simpler than the version we had
last time.

>>
>> To address all of the above, these patches adopt a new approach, based
>> in part on a posting by Chandler Carruth to the LLVM developers list
>> (https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
>> but which we have extended to deal with inter-function speculation.
>> The patches divide the problem into two halves.
> We're essentially turning the control dependency into a value that we
> can then use to munge the pointer or the resultant data.
> 
>>
>> The first half is some target-specific code to track the speculation
>> condition through the generated code to provide an internal variable
>> which can tell us whether or not the CPU's control flow speculation
>> matches the data flow calculations.  The idea is that the internal
>> variable starts with the value TRUE and if the CPU's control flow
>> speculation ever causes a jump to the wrong block of code the variable
>> becomes false until such time as the incorrect control flow
>> speculation gets unwound.
> Right.
> 
> So one of the things that comes immediately to mind is you have to run
> this early enough that you can still get to all the control flow and
> build your predicates.  Otherwise you have do undo stuff like
> conditional move generation.

No, the opposite, in fact.  We want to run this very late, at least on
Arm systems (AArch64 or AArch32).  Conditional move instructions are
fine - they're data-flow operations, not control flow (in fact, that's
exactly what the control flow tracker instructions are).  By running it
late we avoid disrupting any of the earlier optimization passes as well.

> 
> On the flip side, the earlier you do this mitigation, the more you have
> to worry about what the optimizers are going to do to the code later in
> the pipeline.  It's almost guaranteed a naive implementation is going to
> muck this up since we can propagate the state of the condition into the
> arms which will make the predicate state a compile time constant.
> 
> In fact this seems to be running into the area of pointer providence and
> some discussions we had around atomic a few years back.
> 
> I also wonder if this could be combined with taint analysis to produce a
> much lower overhead solution in cases were developers have done analysis
> and know what objects are potentially under attacker control.  So
> instead of analyzing everything, we can have a much narrower focus.

Automatic application of the tracker to vulnerable variables would be
nice, but I haven't attempted to go there yet: at present I still rely
on the user to annotate code with the new intrinsic.

That doesn't mean that we couldn't extend the overall approach later to
include automatic tracking.

> 
> The pointer munging could well run afoul of alias analysis engines that
> don't expect to be seeing those kind of operations.

I think the pass runs late enough that it isn't a problem.

> 
> Anyway, just some initial high level thoughts.  I'm sure there'll be
> more as I read the implementation.
> 

Thanks for starting to look at this so quickly.

R.

> 
> Jeff
> 

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-10  8:39   ` Richard Earnshaw (lists)
@ 2018-07-10 10:10     ` Richard Biener
  2018-07-10 10:53       ` Richard Earnshaw (lists)
  0 siblings, 1 reply; 82+ messages in thread
From: Richard Biener @ 2018-07-10 10:10 UTC (permalink / raw)
  To: Richard Earnshaw; +Cc: GCC Patches

On Tue, Jul 10, 2018 at 10:39 AM Richard Earnshaw (lists)
<Richard.Earnshaw@arm.com> wrote:
>
> On 10/07/18 08:19, Richard Biener wrote:
> > On Mon, Jul 9, 2018 at 6:39 PM Richard Earnshaw
> > <Richard.Earnshaw@arm.com> wrote:
> >>
> >>
> >> The patches I posted earlier this year for mitigating against
> >> CVE-2017-5753 (Spectre variant 1) attracted some useful feedback, from
> >> which it became obvious that a rethink was needed.  This mail, and the
> >> following patches attempt to address that feedback and present a new
> >> approach to mitigating against this form of attack surface.
> >>
> >> There were two major issues with the original approach:
> >>
> >> - The speculation bounds were too tightly constrained - essentially
> >>   they had to represent and upper and lower bound on a pointer, or a
> >>   pointer offset.
> >> - The speculation constraints could only cover the immediately preceding
> >>   branch, which often did not fit well with the structure of the existing
> >>   code.
> >>
> >> An additional criticism was that the shape of the intrinsic did not
> >> fit particularly well with systems that used a single speculation
> >> barrier that essentially had to wait until all preceding speculation
> >> had to be resolved.
> >>
> >> To address all of the above, these patches adopt a new approach, based
> >> in part on a posting by Chandler Carruth to the LLVM developers list
> >> (https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
> >> but which we have extended to deal with inter-function speculation.
> >> The patches divide the problem into two halves.
> >>
> >> The first half is some target-specific code to track the speculation
> >> condition through the generated code to provide an internal variable
> >> which can tell us whether or not the CPU's control flow speculation
> >> matches the data flow calculations.  The idea is that the internal
> >> variable starts with the value TRUE and if the CPU's control flow
> >> speculation ever causes a jump to the wrong block of code the variable
> >> becomes false until such time as the incorrect control flow
> >> speculation gets unwound.
> >>
> >> The second half is that a new intrinsic function is introduced that is
> >> much simpler than we had before.  The basic version of the intrinsic
> >> is now simply:
> >>
> >>       T var = __builtin_speculation_safe_value (T unsafe_var);
> >>
> >> Full details of the syntax can be found in the documentation patch, in
> >> patch 1.  In summary, when not speculating the intrinsic returns
> >> unsafe_var; when speculating then if it can be shown that the
> >> speculative flow has diverged from the intended control flow then zero
> >> is returned.  An optional second argument can be used to return an
> >> alternative value to zero.  The builtin may cause execution to pause
> >> until the speculation state is resolved.
> >
> > So a trivial target implementation would be to emit a barrier and then
> > it would always return unsafe_var and never zero.  What I don't understand
> > fully is what users should do here, thus what the value of ever returning
> > "unsafe" is.  Also I wonder why the API is forcing you to single-out a
> > special value instead of doing
> >
> >  bool safe = __builtin_speculation_safe_value_p (T unsafe_value);
> >  if (!safe)
> >    /* what now? */
> >
> > I'm only guessing that the correct way to handle "unsafe" is basically
> >
> >  while (__builtin_speculation_safe_value (val) == 0)
> >     ;
> >
> > use val, it's now safe
>
> No, a safe version of val is returned, not a bool telling you it is now
> safe to use the original.

OK, so making the old value dead is required to preserve the desired
dataflow.

But how should I use the special value that signaled "failure"?

Obviously the user isn't supposed to simply replace 'val' with

 val = __builtin_speculation_safe_value (val);

to make it speculation-proof.  So - how should the user _use_ this
builtin?  The docs do not say anything about this but says the
very confusing

+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.

because speculation is about executing instructions as if they were
supposed to be executed.  Once it is known the prediciton was wrong
no more "wrong" instructions will be executed but a previously
speculated instruction cannot know it was "falsely" speculated.

Does the above try to say that the function may return failval if the
instruction is currently executed speculatively instead?  That would
make sense to me.  And return failval independent of if the speculation
later turns out to be correct or not.

>  You must use the sanitized version in future,
> not the unprotected version.
>
>
> So the usage is going to be more like:
>
> val = __builtin_speculation_safe_value (val);  // Overwrite val with a
> sanitized version.
>
> You have to use the cleaned up version, the unclean version is still
> vulnerable to incorrect speculation.

But then where does failval come into play?  The above cannot be correct
if failval matters.

Does the builtin try to say that iff the current instruction is speculated
then it will return failval, otherwise it will return val and thus following
code needs to handle 'failval' in a way that is safe?

Again, the wording "when it is known that speculative execution has
incorrectly predicted a conditional branch operation" is very confusing...

Richard.

> R.
>
> >
> > that is, the return value is only interesting in sofar as to whether it is equal
> > to val or the special value?
> >
> > That said, I wonder why we don't hide that details from the user and
> > provide a predicate instead.
> >
> > Richard.
> >
> >> There are seven patches in this set, as follows.
> >>
> >> 1) Introduces the new intrinsic __builtin_sepculation_safe_value.
> >> 2) Adds a basic hard barrier implementation for AArch32 (arm) state.
> >> 3) Adds a basic hard barrier implementation for AArch64 state.
> >> 4) Adds a new command-line option -mtrack-speculation (currently a no-op).
> >> 5) Disables CB[N]Z and TB[N]Z when -mtrack-speculation.
> >> 6) Adds the new speculation tracking pass for AArch64
> >> 7) Uses the new speculation tracking pass to generate CSDB-based barrier
> >>    sequences
> >>
> >> I haven't added a speculation-tracking pass for AArch32 at this time.
> >> It is possible to do this, but would require quite a lot of rework for
> >> the arm backend due to the limited number of registers that are
> >> available.
> >>
> >> Although patch 6 is AArch64 specific, I'd appreciate a review from
> >> someone more familiar with the branch edge code than myself.  There
> >> appear to be a number of tricky issues with more complex edges so I'd
> >> like a second opinion on that code in case I've missed an important
> >> case.
> >>
> >> R.
> >>
> >>
> >>
> >> Richard Earnshaw (7):
> >>   Add __builtin_speculation_safe_value
> >>   Arm - add speculation_barrier pattern
> >>   AArch64 - add speculation barrier
> >>   AArch64 - Add new option -mtrack-speculation
> >>   AArch64 - disable CB[N]Z TB[N]Z when tracking speculation
> >>   AArch64 - new pass to add conditional-branch speculation tracking
> >>   AArch64 - use CSDB based sequences if speculation tracking is enabled
> >>
> >>  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/config.gcc                            |   2 +-
> >>  gcc/config/aarch64/aarch64-passes.def     |   1 +
> >>  gcc/config/aarch64/aarch64-protos.h       |   3 +-
> >>  gcc/config/aarch64/aarch64-speculation.cc | 494 ++++++++++++++++++++++++++++++
> >>  gcc/config/aarch64/aarch64.c              |  88 +++++-
> >>  gcc/config/aarch64/aarch64.md             | 140 ++++++++-
> >>  gcc/config/aarch64/aarch64.opt            |   4 +
> >>  gcc/config/aarch64/iterators.md           |   3 +
> >>  gcc/config/aarch64/t-aarch64              |  10 +
> >>  gcc/config/arm/arm.md                     |  21 ++
> >>  gcc/config/arm/unspecs.md                 |   1 +
> >>  gcc/doc/cpp.texi                          |   4 +
> >>  gcc/doc/extend.texi                       |  29 ++
> >>  gcc/doc/invoke.texi                       |  10 +-
> >>  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 +
> >>  28 files changed, 1191 insertions(+), 11 deletions(-)
> >>  create mode 100644 gcc/config/aarch64/aarch64-speculation.cc
> >>  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
>

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-10 10:10     ` Richard Biener
@ 2018-07-10 10:53       ` Richard Earnshaw (lists)
  2018-07-10 11:22         ` Richard Biener
  2018-07-10 15:56         ` Jeff Law
  0 siblings, 2 replies; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-07-10 10:53 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

On 10/07/18 11:10, Richard Biener wrote:
> On Tue, Jul 10, 2018 at 10:39 AM Richard Earnshaw (lists)
> <Richard.Earnshaw@arm.com> wrote:
>>
>> On 10/07/18 08:19, Richard Biener wrote:
>>> On Mon, Jul 9, 2018 at 6:39 PM Richard Earnshaw
>>> <Richard.Earnshaw@arm.com> wrote:
>>>>
>>>>
>>>> The patches I posted earlier this year for mitigating against
>>>> CVE-2017-5753 (Spectre variant 1) attracted some useful feedback, from
>>>> which it became obvious that a rethink was needed.  This mail, and the
>>>> following patches attempt to address that feedback and present a new
>>>> approach to mitigating against this form of attack surface.
>>>>
>>>> There were two major issues with the original approach:
>>>>
>>>> - The speculation bounds were too tightly constrained - essentially
>>>>   they had to represent and upper and lower bound on a pointer, or a
>>>>   pointer offset.
>>>> - The speculation constraints could only cover the immediately preceding
>>>>   branch, which often did not fit well with the structure of the existing
>>>>   code.
>>>>
>>>> An additional criticism was that the shape of the intrinsic did not
>>>> fit particularly well with systems that used a single speculation
>>>> barrier that essentially had to wait until all preceding speculation
>>>> had to be resolved.
>>>>
>>>> To address all of the above, these patches adopt a new approach, based
>>>> in part on a posting by Chandler Carruth to the LLVM developers list
>>>> (https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
>>>> but which we have extended to deal with inter-function speculation.
>>>> The patches divide the problem into two halves.
>>>>
>>>> The first half is some target-specific code to track the speculation
>>>> condition through the generated code to provide an internal variable
>>>> which can tell us whether or not the CPU's control flow speculation
>>>> matches the data flow calculations.  The idea is that the internal
>>>> variable starts with the value TRUE and if the CPU's control flow
>>>> speculation ever causes a jump to the wrong block of code the variable
>>>> becomes false until such time as the incorrect control flow
>>>> speculation gets unwound.
>>>>
>>>> The second half is that a new intrinsic function is introduced that is
>>>> much simpler than we had before.  The basic version of the intrinsic
>>>> is now simply:
>>>>
>>>>       T var = __builtin_speculation_safe_value (T unsafe_var);
>>>>
>>>> Full details of the syntax can be found in the documentation patch, in
>>>> patch 1.  In summary, when not speculating the intrinsic returns
>>>> unsafe_var; when speculating then if it can be shown that the
>>>> speculative flow has diverged from the intended control flow then zero
>>>> is returned.  An optional second argument can be used to return an
>>>> alternative value to zero.  The builtin may cause execution to pause
>>>> until the speculation state is resolved.
>>>
>>> So a trivial target implementation would be to emit a barrier and then
>>> it would always return unsafe_var and never zero.  What I don't understand
>>> fully is what users should do here, thus what the value of ever returning
>>> "unsafe" is.  Also I wonder why the API is forcing you to single-out a
>>> special value instead of doing
>>>
>>>  bool safe = __builtin_speculation_safe_value_p (T unsafe_value);
>>>  if (!safe)
>>>    /* what now? */
>>>
>>> I'm only guessing that the correct way to handle "unsafe" is basically
>>>
>>>  while (__builtin_speculation_safe_value (val) == 0)
>>>     ;
>>>
>>> use val, it's now safe
>>
>> No, a safe version of val is returned, not a bool telling you it is now
>> safe to use the original.
> 
> OK, so making the old value dead is required to preserve the desired
> dataflow.
> 
> But how should I use the special value that signaled "failure"?
> 
> Obviously the user isn't supposed to simply replace 'val' with
> 
>  val = __builtin_speculation_safe_value (val);
> 
> to make it speculation-proof.  So - how should the user _use_ this
> builtin?  The docs do not say anything about this but says the
> very confusing
> 
> +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.
> 
> because speculation is about executing instructions as if they were
> supposed to be executed.  Once it is known the prediciton was wrong
> no more "wrong" instructions will be executed but a previously
> speculated instruction cannot know it was "falsely" speculated.
> 
> Does the above try to say that the function may return failval if the
> instruction is currently executed speculatively instead?  That would
> make sense to me.  And return failval independent of if the speculation
> later turns out to be correct or not.
> 
>>  You must use the sanitized version in future,
>> not the unprotected version.
>>
>>
>> So the usage is going to be more like:
>>
>> val = __builtin_speculation_safe_value (val);  // Overwrite val with a
>> sanitized version.
>>
>> You have to use the cleaned up version, the unclean version is still
>> vulnerable to incorrect speculation.
> 
> But then where does failval come into play?  The above cannot be correct
> if failval matters.

failval only comes into play if the CPU is speculating incorrectly.
It's just a safe value that some CPUs might use until such time as the
speculation gets unwound.  In most cases it can be zero.  Perhaps a more
concrete example would be something like.


void **mem;

void* f(unsigned untrusted)
{
  if (untrusted < 100)
    return mem[untrusted];
  return NULL;
}

This can be rewritten as either:

void *mem;

void* f(unsigned untrusted)
{
  if (untrusted < 100)
    return mem[__builtin_speculation_safe_value (untrusted)];
  return NULL;
}

if leaking mem[0] is not a problem; or if you're really paranoid:

void* f(unsigned untrusted)
{
  if (untrusted < 100)
    return *__builtin_speculation_safe_value (mem + untrusted);
  return NULL;
}

which becomes a NULL pointer dereference if the speculation is
incorrect.  The programmer doesn't need to test this code (any test
would likely be useless anyway as the CPU would predict the outcome and
speculate based on such a prediction).  They do need to think a bit
about what might leak if the CPU does miss-speculate, hence the two
examples above.

A more complex case, where you might want a different failure value can
come up if you have a mask operation.  A slightly convoluted example
(derived from a real example we found in the Linux kernel) might be

if (mode32)
  mask_from = 0x100000000;
else
  mask_from = 0;

... // some code

return mem[untrusted_val & (mask_from - 1)];

It would probably be better to place the speculation cleanup nearer the
initialization of mask_from, especially if mask_from could be used more
than once; but in that case 0 is less safe than any other (since 0-1 is
all bits 1).  In this case you might write:

if (mode32)
  mask_from = 0x100000000;
else
  mask_from = 0;

mask_from = __builtin_speculation_safe_value (mask_from, 1);

... // some code

return mem[untrusted_val & (mask_from - 1)];

And in this case if the speculation is incorrect the (mask_from - 1)
expression becomes 0 and the whole range is protected.

Note that speculation is fine if it is correct, we don't want to hold
things up in that case since it will happen anyway.  It's only a problem
if the speculation is incorrect :-)


> 
> Does the builtin try to say that iff the current instruction is speculated
> then it will return failval, otherwise it will return val and thus following
> code needs to handle 'failval' in a way that is safe?

No.  From an abstract machine sense the builtin only ever returns its
first argument.  The fail value only appears if the CPU guesses the
direction of a branch and guesses *incorrectly* (incorrect speculation)

> 
> Again, the wording "when it is known that speculative execution has
> incorrectly predicted a conditional branch operation" is very confusing...
> 
> Richard.
> 
>> R.
>>
>>>
>>> that is, the return value is only interesting in sofar as to whether it is equal
>>> to val or the special value?
>>>
>>> That said, I wonder why we don't hide that details from the user and
>>> provide a predicate instead.
>>>
>>> Richard.
>>>
>>>> There are seven patches in this set, as follows.
>>>>
>>>> 1) Introduces the new intrinsic __builtin_sepculation_safe_value.
>>>> 2) Adds a basic hard barrier implementation for AArch32 (arm) state.
>>>> 3) Adds a basic hard barrier implementation for AArch64 state.
>>>> 4) Adds a new command-line option -mtrack-speculation (currently a no-op).
>>>> 5) Disables CB[N]Z and TB[N]Z when -mtrack-speculation.
>>>> 6) Adds the new speculation tracking pass for AArch64
>>>> 7) Uses the new speculation tracking pass to generate CSDB-based barrier
>>>>    sequences
>>>>
>>>> I haven't added a speculation-tracking pass for AArch32 at this time.
>>>> It is possible to do this, but would require quite a lot of rework for
>>>> the arm backend due to the limited number of registers that are
>>>> available.
>>>>
>>>> Although patch 6 is AArch64 specific, I'd appreciate a review from
>>>> someone more familiar with the branch edge code than myself.  There
>>>> appear to be a number of tricky issues with more complex edges so I'd
>>>> like a second opinion on that code in case I've missed an important
>>>> case.
>>>>
>>>> R.
>>>>
>>>>
>>>>
>>>> Richard Earnshaw (7):
>>>>   Add __builtin_speculation_safe_value
>>>>   Arm - add speculation_barrier pattern
>>>>   AArch64 - add speculation barrier
>>>>   AArch64 - Add new option -mtrack-speculation
>>>>   AArch64 - disable CB[N]Z TB[N]Z when tracking speculation
>>>>   AArch64 - new pass to add conditional-branch speculation tracking
>>>>   AArch64 - use CSDB based sequences if speculation tracking is enabled
>>>>
>>>>  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/config.gcc                            |   2 +-
>>>>  gcc/config/aarch64/aarch64-passes.def     |   1 +
>>>>  gcc/config/aarch64/aarch64-protos.h       |   3 +-
>>>>  gcc/config/aarch64/aarch64-speculation.cc | 494 ++++++++++++++++++++++++++++++
>>>>  gcc/config/aarch64/aarch64.c              |  88 +++++-
>>>>  gcc/config/aarch64/aarch64.md             | 140 ++++++++-
>>>>  gcc/config/aarch64/aarch64.opt            |   4 +
>>>>  gcc/config/aarch64/iterators.md           |   3 +
>>>>  gcc/config/aarch64/t-aarch64              |  10 +
>>>>  gcc/config/arm/arm.md                     |  21 ++
>>>>  gcc/config/arm/unspecs.md                 |   1 +
>>>>  gcc/doc/cpp.texi                          |   4 +
>>>>  gcc/doc/extend.texi                       |  29 ++
>>>>  gcc/doc/invoke.texi                       |  10 +-
>>>>  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 +
>>>>  28 files changed, 1191 insertions(+), 11 deletions(-)
>>>>  create mode 100644 gcc/config/aarch64/aarch64-speculation.cc
>>>>  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
>>

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-10 10:53       ` Richard Earnshaw (lists)
@ 2018-07-10 11:22         ` Richard Biener
  2018-07-10 13:43           ` Richard Earnshaw (lists)
  2018-07-10 15:56         ` Jeff Law
  1 sibling, 1 reply; 82+ messages in thread
From: Richard Biener @ 2018-07-10 11:22 UTC (permalink / raw)
  To: Richard Earnshaw; +Cc: GCC Patches

On Tue, Jul 10, 2018 at 12:53 PM Richard Earnshaw (lists)
<Richard.Earnshaw@arm.com> wrote:
>
> On 10/07/18 11:10, Richard Biener wrote:
> > On Tue, Jul 10, 2018 at 10:39 AM Richard Earnshaw (lists)
> > <Richard.Earnshaw@arm.com> wrote:
> >>
> >> On 10/07/18 08:19, Richard Biener wrote:
> >>> On Mon, Jul 9, 2018 at 6:39 PM Richard Earnshaw
> >>> <Richard.Earnshaw@arm.com> wrote:
> >>>>
> >>>>
> >>>> The patches I posted earlier this year for mitigating against
> >>>> CVE-2017-5753 (Spectre variant 1) attracted some useful feedback, from
> >>>> which it became obvious that a rethink was needed.  This mail, and the
> >>>> following patches attempt to address that feedback and present a new
> >>>> approach to mitigating against this form of attack surface.
> >>>>
> >>>> There were two major issues with the original approach:
> >>>>
> >>>> - The speculation bounds were too tightly constrained - essentially
> >>>>   they had to represent and upper and lower bound on a pointer, or a
> >>>>   pointer offset.
> >>>> - The speculation constraints could only cover the immediately preceding
> >>>>   branch, which often did not fit well with the structure of the existing
> >>>>   code.
> >>>>
> >>>> An additional criticism was that the shape of the intrinsic did not
> >>>> fit particularly well with systems that used a single speculation
> >>>> barrier that essentially had to wait until all preceding speculation
> >>>> had to be resolved.
> >>>>
> >>>> To address all of the above, these patches adopt a new approach, based
> >>>> in part on a posting by Chandler Carruth to the LLVM developers list
> >>>> (https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
> >>>> but which we have extended to deal with inter-function speculation.
> >>>> The patches divide the problem into two halves.
> >>>>
> >>>> The first half is some target-specific code to track the speculation
> >>>> condition through the generated code to provide an internal variable
> >>>> which can tell us whether or not the CPU's control flow speculation
> >>>> matches the data flow calculations.  The idea is that the internal
> >>>> variable starts with the value TRUE and if the CPU's control flow
> >>>> speculation ever causes a jump to the wrong block of code the variable
> >>>> becomes false until such time as the incorrect control flow
> >>>> speculation gets unwound.
> >>>>
> >>>> The second half is that a new intrinsic function is introduced that is
> >>>> much simpler than we had before.  The basic version of the intrinsic
> >>>> is now simply:
> >>>>
> >>>>       T var = __builtin_speculation_safe_value (T unsafe_var);
> >>>>
> >>>> Full details of the syntax can be found in the documentation patch, in
> >>>> patch 1.  In summary, when not speculating the intrinsic returns
> >>>> unsafe_var; when speculating then if it can be shown that the
> >>>> speculative flow has diverged from the intended control flow then zero
> >>>> is returned.  An optional second argument can be used to return an
> >>>> alternative value to zero.  The builtin may cause execution to pause
> >>>> until the speculation state is resolved.
> >>>
> >>> So a trivial target implementation would be to emit a barrier and then
> >>> it would always return unsafe_var and never zero.  What I don't understand
> >>> fully is what users should do here, thus what the value of ever returning
> >>> "unsafe" is.  Also I wonder why the API is forcing you to single-out a
> >>> special value instead of doing
> >>>
> >>>  bool safe = __builtin_speculation_safe_value_p (T unsafe_value);
> >>>  if (!safe)
> >>>    /* what now? */
> >>>
> >>> I'm only guessing that the correct way to handle "unsafe" is basically
> >>>
> >>>  while (__builtin_speculation_safe_value (val) == 0)
> >>>     ;
> >>>
> >>> use val, it's now safe
> >>
> >> No, a safe version of val is returned, not a bool telling you it is now
> >> safe to use the original.
> >
> > OK, so making the old value dead is required to preserve the desired
> > dataflow.
> >
> > But how should I use the special value that signaled "failure"?
> >
> > Obviously the user isn't supposed to simply replace 'val' with
> >
> >  val = __builtin_speculation_safe_value (val);
> >
> > to make it speculation-proof.  So - how should the user _use_ this
> > builtin?  The docs do not say anything about this but says the
> > very confusing
> >
> > +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.
> >
> > because speculation is about executing instructions as if they were
> > supposed to be executed.  Once it is known the prediciton was wrong
> > no more "wrong" instructions will be executed but a previously
> > speculated instruction cannot know it was "falsely" speculated.
> >
> > Does the above try to say that the function may return failval if the
> > instruction is currently executed speculatively instead?  That would
> > make sense to me.  And return failval independent of if the speculation
> > later turns out to be correct or not.
> >
> >>  You must use the sanitized version in future,
> >> not the unprotected version.
> >>
> >>
> >> So the usage is going to be more like:
> >>
> >> val = __builtin_speculation_safe_value (val);  // Overwrite val with a
> >> sanitized version.
> >>
> >> You have to use the cleaned up version, the unclean version is still
> >> vulnerable to incorrect speculation.
> >
> > But then where does failval come into play?  The above cannot be correct
> > if failval matters.
>
> failval only comes into play if the CPU is speculating incorrectly.
> It's just a safe value that some CPUs might use until such time as the
> speculation gets unwound.  In most cases it can be zero.  Perhaps a more
> concrete example would be something like.
>
>
> void **mem;
>
> void* f(unsigned untrusted)
> {
>   if (untrusted < 100)
>     return mem[untrusted];
>   return NULL;
> }
>
> This can be rewritten as either:
>
> void *mem;
>
> void* f(unsigned untrusted)
> {
>   if (untrusted < 100)
>     return mem[__builtin_speculation_safe_value (untrusted)];
>   return NULL;
> }
>
> if leaking mem[0] is not a problem; or if you're really paranoid:
>
> void* f(unsigned untrusted)
> {
>   if (untrusted < 100)
>     return *__builtin_speculation_safe_value (mem + untrusted);
>   return NULL;
> }
>
> which becomes a NULL pointer dereference if the speculation is
> incorrect.  The programmer doesn't need to test this code (any test
> would likely be useless anyway as the CPU would predict the outcome and
> speculate based on such a prediction).  They do need to think a bit
> about what might leak if the CPU does miss-speculate, hence the two
> examples above.
>
> A more complex case, where you might want a different failure value can
> come up if you have a mask operation.  A slightly convoluted example
> (derived from a real example we found in the Linux kernel) might be
>
> if (mode32)
>   mask_from = 0x100000000;
> else
>   mask_from = 0;
>
> ... // some code
>
> return mem[untrusted_val & (mask_from - 1)];
>
> It would probably be better to place the speculation cleanup nearer the
> initialization of mask_from, especially if mask_from could be used more
> than once; but in that case 0 is less safe than any other (since 0-1 is
> all bits 1).  In this case you might write:
>
> if (mode32)
>   mask_from = 0x100000000;
> else
>   mask_from = 0;
>
> mask_from = __builtin_speculation_safe_value (mask_from, 1);
>
> ... // some code
>
> return mem[untrusted_val & (mask_from - 1)];
>
> And in this case if the speculation is incorrect the (mask_from - 1)
> expression becomes 0 and the whole range is protected.
>
> Note that speculation is fine if it is correct, we don't want to hold
> things up in that case since it will happen anyway.  It's only a problem
> if the speculation is incorrect :-)

Ok, please amend at least the user-level documentation with one or two
examples like above.

>
> >
> > Does the builtin try to say that iff the current instruction is speculated
> > then it will return failval, otherwise it will return val and thus following
> > code needs to handle 'failval' in a way that is safe?
>
> No.  From an abstract machine sense the builtin only ever returns its
> first argument.  The fail value only appears if the CPU guesses the
> direction of a branch and guesses *incorrectly* (incorrect speculation)

I understand how it works when the implementation issues a fence.
How does the actual implementation (assembly) look like that makes
the CPU know whether it speculated wrongly or not at the time the
value is needed for further speculation given the *__bsfs (mem + offset)
instruction _is_ speculated as well.

Richard.

> >
> > Again, the wording "when it is known that speculative execution has
> > incorrectly predicted a conditional branch operation" is very confusing...
> >
> > Richard.
> >
> >> R.
> >>
> >>>
> >>> that is, the return value is only interesting in sofar as to whether it is equal
> >>> to val or the special value?
> >>>
> >>> That said, I wonder why we don't hide that details from the user and
> >>> provide a predicate instead.
> >>>
> >>> Richard.
> >>>
> >>>> There are seven patches in this set, as follows.
> >>>>
> >>>> 1) Introduces the new intrinsic __builtin_sepculation_safe_value.
> >>>> 2) Adds a basic hard barrier implementation for AArch32 (arm) state.
> >>>> 3) Adds a basic hard barrier implementation for AArch64 state.
> >>>> 4) Adds a new command-line option -mtrack-speculation (currently a no-op).
> >>>> 5) Disables CB[N]Z and TB[N]Z when -mtrack-speculation.
> >>>> 6) Adds the new speculation tracking pass for AArch64
> >>>> 7) Uses the new speculation tracking pass to generate CSDB-based barrier
> >>>>    sequences
> >>>>
> >>>> I haven't added a speculation-tracking pass for AArch32 at this time.
> >>>> It is possible to do this, but would require quite a lot of rework for
> >>>> the arm backend due to the limited number of registers that are
> >>>> available.
> >>>>
> >>>> Although patch 6 is AArch64 specific, I'd appreciate a review from
> >>>> someone more familiar with the branch edge code than myself.  There
> >>>> appear to be a number of tricky issues with more complex edges so I'd
> >>>> like a second opinion on that code in case I've missed an important
> >>>> case.
> >>>>
> >>>> R.
> >>>>
> >>>>
> >>>>
> >>>> Richard Earnshaw (7):
> >>>>   Add __builtin_speculation_safe_value
> >>>>   Arm - add speculation_barrier pattern
> >>>>   AArch64 - add speculation barrier
> >>>>   AArch64 - Add new option -mtrack-speculation
> >>>>   AArch64 - disable CB[N]Z TB[N]Z when tracking speculation
> >>>>   AArch64 - new pass to add conditional-branch speculation tracking
> >>>>   AArch64 - use CSDB based sequences if speculation tracking is enabled
> >>>>
> >>>>  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/config.gcc                            |   2 +-
> >>>>  gcc/config/aarch64/aarch64-passes.def     |   1 +
> >>>>  gcc/config/aarch64/aarch64-protos.h       |   3 +-
> >>>>  gcc/config/aarch64/aarch64-speculation.cc | 494 ++++++++++++++++++++++++++++++
> >>>>  gcc/config/aarch64/aarch64.c              |  88 +++++-
> >>>>  gcc/config/aarch64/aarch64.md             | 140 ++++++++-
> >>>>  gcc/config/aarch64/aarch64.opt            |   4 +
> >>>>  gcc/config/aarch64/iterators.md           |   3 +
> >>>>  gcc/config/aarch64/t-aarch64              |  10 +
> >>>>  gcc/config/arm/arm.md                     |  21 ++
> >>>>  gcc/config/arm/unspecs.md                 |   1 +
> >>>>  gcc/doc/cpp.texi                          |   4 +
> >>>>  gcc/doc/extend.texi                       |  29 ++
> >>>>  gcc/doc/invoke.texi                       |  10 +-
> >>>>  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 +
> >>>>  28 files changed, 1191 insertions(+), 11 deletions(-)
> >>>>  create mode 100644 gcc/config/aarch64/aarch64-speculation.cc
> >>>>  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
> >>
>

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-10 11:22         ` Richard Biener
@ 2018-07-10 13:43           ` Richard Earnshaw (lists)
  0 siblings, 0 replies; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-07-10 13:43 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

On 10/07/18 12:21, Richard Biener wrote:
> On Tue, Jul 10, 2018 at 12:53 PM Richard Earnshaw (lists)
> <Richard.Earnshaw@arm.com> wrote:
>>
>> On 10/07/18 11:10, Richard Biener wrote:
>>> On Tue, Jul 10, 2018 at 10:39 AM Richard Earnshaw (lists)
>>> <Richard.Earnshaw@arm.com> wrote:
>>>>
>>>> On 10/07/18 08:19, Richard Biener wrote:
>>>>> On Mon, Jul 9, 2018 at 6:39 PM Richard Earnshaw
>>>>> <Richard.Earnshaw@arm.com> wrote:
>>>>>>
>>>>>>
>>>>>> The patches I posted earlier this year for mitigating against
>>>>>> CVE-2017-5753 (Spectre variant 1) attracted some useful feedback, from
>>>>>> which it became obvious that a rethink was needed.  This mail, and the
>>>>>> following patches attempt to address that feedback and present a new
>>>>>> approach to mitigating against this form of attack surface.
>>>>>>
>>>>>> There were two major issues with the original approach:
>>>>>>
>>>>>> - The speculation bounds were too tightly constrained - essentially
>>>>>>   they had to represent and upper and lower bound on a pointer, or a
>>>>>>   pointer offset.
>>>>>> - The speculation constraints could only cover the immediately preceding
>>>>>>   branch, which often did not fit well with the structure of the existing
>>>>>>   code.
>>>>>>
>>>>>> An additional criticism was that the shape of the intrinsic did not
>>>>>> fit particularly well with systems that used a single speculation
>>>>>> barrier that essentially had to wait until all preceding speculation
>>>>>> had to be resolved.
>>>>>>
>>>>>> To address all of the above, these patches adopt a new approach, based
>>>>>> in part on a posting by Chandler Carruth to the LLVM developers list
>>>>>> (https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
>>>>>> but which we have extended to deal with inter-function speculation.
>>>>>> The patches divide the problem into two halves.
>>>>>>
>>>>>> The first half is some target-specific code to track the speculation
>>>>>> condition through the generated code to provide an internal variable
>>>>>> which can tell us whether or not the CPU's control flow speculation
>>>>>> matches the data flow calculations.  The idea is that the internal
>>>>>> variable starts with the value TRUE and if the CPU's control flow
>>>>>> speculation ever causes a jump to the wrong block of code the variable
>>>>>> becomes false until such time as the incorrect control flow
>>>>>> speculation gets unwound.
>>>>>>
>>>>>> The second half is that a new intrinsic function is introduced that is
>>>>>> much simpler than we had before.  The basic version of the intrinsic
>>>>>> is now simply:
>>>>>>
>>>>>>       T var = __builtin_speculation_safe_value (T unsafe_var);
>>>>>>
>>>>>> Full details of the syntax can be found in the documentation patch, in
>>>>>> patch 1.  In summary, when not speculating the intrinsic returns
>>>>>> unsafe_var; when speculating then if it can be shown that the
>>>>>> speculative flow has diverged from the intended control flow then zero
>>>>>> is returned.  An optional second argument can be used to return an
>>>>>> alternative value to zero.  The builtin may cause execution to pause
>>>>>> until the speculation state is resolved.
>>>>>
>>>>> So a trivial target implementation would be to emit a barrier and then
>>>>> it would always return unsafe_var and never zero.  What I don't understand
>>>>> fully is what users should do here, thus what the value of ever returning
>>>>> "unsafe" is.  Also I wonder why the API is forcing you to single-out a
>>>>> special value instead of doing
>>>>>
>>>>>  bool safe = __builtin_speculation_safe_value_p (T unsafe_value);
>>>>>  if (!safe)
>>>>>    /* what now? */
>>>>>
>>>>> I'm only guessing that the correct way to handle "unsafe" is basically
>>>>>
>>>>>  while (__builtin_speculation_safe_value (val) == 0)
>>>>>     ;
>>>>>
>>>>> use val, it's now safe
>>>>
>>>> No, a safe version of val is returned, not a bool telling you it is now
>>>> safe to use the original.
>>>
>>> OK, so making the old value dead is required to preserve the desired
>>> dataflow.
>>>
>>> But how should I use the special value that signaled "failure"?
>>>
>>> Obviously the user isn't supposed to simply replace 'val' with
>>>
>>>  val = __builtin_speculation_safe_value (val);
>>>
>>> to make it speculation-proof.  So - how should the user _use_ this
>>> builtin?  The docs do not say anything about this but says the
>>> very confusing
>>>
>>> +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.
>>>
>>> because speculation is about executing instructions as if they were
>>> supposed to be executed.  Once it is known the prediciton was wrong
>>> no more "wrong" instructions will be executed but a previously
>>> speculated instruction cannot know it was "falsely" speculated.
>>>
>>> Does the above try to say that the function may return failval if the
>>> instruction is currently executed speculatively instead?  That would
>>> make sense to me.  And return failval independent of if the speculation
>>> later turns out to be correct or not.
>>>
>>>>  You must use the sanitized version in future,
>>>> not the unprotected version.
>>>>
>>>>
>>>> So the usage is going to be more like:
>>>>
>>>> val = __builtin_speculation_safe_value (val);  // Overwrite val with a
>>>> sanitized version.
>>>>
>>>> You have to use the cleaned up version, the unclean version is still
>>>> vulnerable to incorrect speculation.
>>>
>>> But then where does failval come into play?  The above cannot be correct
>>> if failval matters.
>>
>> failval only comes into play if the CPU is speculating incorrectly.
>> It's just a safe value that some CPUs might use until such time as the
>> speculation gets unwound.  In most cases it can be zero.  Perhaps a more
>> concrete example would be something like.
>>
>>
>> void **mem;
>>
>> void* f(unsigned untrusted)
>> {
>>   if (untrusted < 100)
>>     return mem[untrusted];
>>   return NULL;
>> }
>>
>> This can be rewritten as either:
>>
>> void *mem;
>>
>> void* f(unsigned untrusted)
>> {
>>   if (untrusted < 100)
>>     return mem[__builtin_speculation_safe_value (untrusted)];
>>   return NULL;
>> }
>>
>> if leaking mem[0] is not a problem; or if you're really paranoid:
>>
>> void* f(unsigned untrusted)
>> {
>>   if (untrusted < 100)
>>     return *__builtin_speculation_safe_value (mem + untrusted);
>>   return NULL;
>> }
>>
>> which becomes a NULL pointer dereference if the speculation is
>> incorrect.  The programmer doesn't need to test this code (any test
>> would likely be useless anyway as the CPU would predict the outcome and
>> speculate based on such a prediction).  They do need to think a bit
>> about what might leak if the CPU does miss-speculate, hence the two
>> examples above.
>>
>> A more complex case, where you might want a different failure value can
>> come up if you have a mask operation.  A slightly convoluted example
>> (derived from a real example we found in the Linux kernel) might be
>>
>> if (mode32)
>>   mask_from = 0x100000000;
>> else
>>   mask_from = 0;
>>
>> ... // some code
>>
>> return mem[untrusted_val & (mask_from - 1)];
>>
>> It would probably be better to place the speculation cleanup nearer the
>> initialization of mask_from, especially if mask_from could be used more
>> than once; but in that case 0 is less safe than any other (since 0-1 is
>> all bits 1).  In this case you might write:
>>
>> if (mode32)
>>   mask_from = 0x100000000;
>> else
>>   mask_from = 0;
>>
>> mask_from = __builtin_speculation_safe_value (mask_from, 1);
>>
>> ... // some code
>>
>> return mem[untrusted_val & (mask_from - 1)];
>>
>> And in this case if the speculation is incorrect the (mask_from - 1)
>> expression becomes 0 and the whole range is protected.
>>
>> Note that speculation is fine if it is correct, we don't want to hold
>> things up in that case since it will happen anyway.  It's only a problem
>> if the speculation is incorrect :-)
> 
> Ok, please amend at least the user-level documentation with one or two
> examples like above.
> 
>>
>>>
>>> Does the builtin try to say that iff the current instruction is speculated
>>> then it will return failval, otherwise it will return val and thus following
>>> code needs to handle 'failval' in a way that is safe?
>>
>> No.  From an abstract machine sense the builtin only ever returns its
>> first argument.  The fail value only appears if the CPU guesses the
>> direction of a branch and guesses *incorrectly* (incorrect speculation)
> 
> I understand how it works when the implementation issues a fence.
> How does the actual implementation (assembly) look like that makes
> the CPU know whether it speculated wrongly or not at the time the
> value is needed for further speculation given the *__bsfs (mem + offset)
> instruction _is_ speculated as well.
> 

If you've not already read it, then I suggest you read
https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability/download-the-whitepaper
and the link I posted in the original mail to Chandler's posting on this
subject.

In essence, we start with a register (tracker) initialized to ~0.  At
every conditional branch we change

	b.cond tgt
	...
tgt:
	...

into

	b.cond tgt
	// tracker == ~cond ? tracker, 0
	csel	tracker, tracker, 0, ~cond
	...
tgt:
	// tracker == cond ? tracker, 0
	csel	tracker, tracker, 0, cond


Now when we need to inhibit speculation we emit

	and	safe_val, unsafe_val, tracker
	CSDB

Assuming we want the default result of 0 if speculating unsafely.  CSDB
is a light-weight barrier that ensures that all preceding
/data-processing/ instructions are using real results from earlier
instructions: it will resolve any data-flow speculation, but not
necessarily any control-flow speculation.

Obviously the inserted instructions only appear on the edges between the
blocks, but we take care of that during the insertion process.

R.

> Richard.
> 
>>>
>>> Again, the wording "when it is known that speculative execution has
>>> incorrectly predicted a conditional branch operation" is very confusing...
>>>
>>> Richard.
>>>
>>>> R.
>>>>
>>>>>
>>>>> that is, the return value is only interesting in sofar as to whether it is equal
>>>>> to val or the special value?
>>>>>
>>>>> That said, I wonder why we don't hide that details from the user and
>>>>> provide a predicate instead.
>>>>>
>>>>> Richard.
>>>>>
>>>>>> There are seven patches in this set, as follows.
>>>>>>
>>>>>> 1) Introduces the new intrinsic __builtin_sepculation_safe_value.
>>>>>> 2) Adds a basic hard barrier implementation for AArch32 (arm) state.
>>>>>> 3) Adds a basic hard barrier implementation for AArch64 state.
>>>>>> 4) Adds a new command-line option -mtrack-speculation (currently a no-op).
>>>>>> 5) Disables CB[N]Z and TB[N]Z when -mtrack-speculation.
>>>>>> 6) Adds the new speculation tracking pass for AArch64
>>>>>> 7) Uses the new speculation tracking pass to generate CSDB-based barrier
>>>>>>    sequences
>>>>>>
>>>>>> I haven't added a speculation-tracking pass for AArch32 at this time.
>>>>>> It is possible to do this, but would require quite a lot of rework for
>>>>>> the arm backend due to the limited number of registers that are
>>>>>> available.
>>>>>>
>>>>>> Although patch 6 is AArch64 specific, I'd appreciate a review from
>>>>>> someone more familiar with the branch edge code than myself.  There
>>>>>> appear to be a number of tricky issues with more complex edges so I'd
>>>>>> like a second opinion on that code in case I've missed an important
>>>>>> case.
>>>>>>
>>>>>> R.
>>>>>>
>>>>>>
>>>>>>
>>>>>> Richard Earnshaw (7):
>>>>>>   Add __builtin_speculation_safe_value
>>>>>>   Arm - add speculation_barrier pattern
>>>>>>   AArch64 - add speculation barrier
>>>>>>   AArch64 - Add new option -mtrack-speculation
>>>>>>   AArch64 - disable CB[N]Z TB[N]Z when tracking speculation
>>>>>>   AArch64 - new pass to add conditional-branch speculation tracking
>>>>>>   AArch64 - use CSDB based sequences if speculation tracking is enabled
>>>>>>
>>>>>>  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/config.gcc                            |   2 +-
>>>>>>  gcc/config/aarch64/aarch64-passes.def     |   1 +
>>>>>>  gcc/config/aarch64/aarch64-protos.h       |   3 +-
>>>>>>  gcc/config/aarch64/aarch64-speculation.cc | 494 ++++++++++++++++++++++++++++++
>>>>>>  gcc/config/aarch64/aarch64.c              |  88 +++++-
>>>>>>  gcc/config/aarch64/aarch64.md             | 140 ++++++++-
>>>>>>  gcc/config/aarch64/aarch64.opt            |   4 +
>>>>>>  gcc/config/aarch64/iterators.md           |   3 +
>>>>>>  gcc/config/aarch64/t-aarch64              |  10 +
>>>>>>  gcc/config/arm/arm.md                     |  21 ++
>>>>>>  gcc/config/arm/unspecs.md                 |   1 +
>>>>>>  gcc/doc/cpp.texi                          |   4 +
>>>>>>  gcc/doc/extend.texi                       |  29 ++
>>>>>>  gcc/doc/invoke.texi                       |  10 +-
>>>>>>  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 +
>>>>>>  28 files changed, 1191 insertions(+), 11 deletions(-)
>>>>>>  create mode 100644 gcc/config/aarch64/aarch64-speculation.cc
>>>>>>  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
>>>>
>>

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-10  8:49   ` Richard Earnshaw (lists)
@ 2018-07-10 13:48     ` Bill Schmidt
  2018-07-10 14:14       ` Richard Earnshaw (lists)
  2018-07-10 15:42     ` Jeff Law
  1 sibling, 1 reply; 82+ messages in thread
From: Bill Schmidt @ 2018-07-10 13:48 UTC (permalink / raw)
  To: Richard Earnshaw (lists); +Cc: Jeff Law, gcc-patches


> On Jul 10, 2018, at 3:49 AM, Richard Earnshaw (lists) <Richard.Earnshaw@arm.com> wrote:
> 
> On 10/07/18 00:13, Jeff Law wrote:
>> On 07/09/2018 10:38 AM, Richard Earnshaw wrote:
>>> 
>>> The patches I posted earlier this year for mitigating against
>>> CVE-2017-5753 (Spectre variant 1) attracted some useful feedback, from
>>> which it became obvious that a rethink was needed.  This mail, and the
>>> following patches attempt to address that feedback and present a new
>>> approach to mitigating against this form of attack surface.
>>> 
>>> There were two major issues with the original approach:
>>> 
>>> - The speculation bounds were too tightly constrained - essentially
>>>  they had to represent and upper and lower bound on a pointer, or a
>>>  pointer offset.
>>> - The speculation constraints could only cover the immediately preceding
>>>  branch, which often did not fit well with the structure of the existing
>>>  code.
>>> 
>>> An additional criticism was that the shape of the intrinsic did not
>>> fit particularly well with systems that used a single speculation
>>> barrier that essentially had to wait until all preceding speculation
>>> had to be resolved.
>> Right.  I suggest the Intel and IBM reps chime in on the updated semantics.
>> 
> 
> Yes, logically, this is a boolean tracker value.  In practice we use ~0
> for true and 0 for false, so that we can simply use it as a mask
> operation later.
> 
> I hope this intrinsic will be even more acceptable than the one that
> Bill Schmidt acked previously, it's even simpler than the version we had
> last time.

Yes, I think this looks quite good.  Thanks!

Thanks also for digging into the speculation tracking algorithm.  This
has good potential as a conservative opt-in approach.  The obvious
concern is whether performance will be acceptable even for apps
that really want the protection.

We took a look at Chandler's WIP LLVM patch and ran some SPEC2006 
numbers on a Skylake box.  We saw geomean degradations of about
42% (int) and 33% (fp).  (This was just one test, so caveat emptor.)
This isn't terrible given the number of potential false positives and the
early state of the algorithm, but it's still a lot from a customer perspective.
I'll be interested in whether your interprocedural improvements are
able to reduce the conservatism a bit.

Thanks,
Bill
> 
>>> 
>>> To address all of the above, these patches adopt a new approach, based
>>> in part on a posting by Chandler Carruth to the LLVM developers list
>>> (https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
>>> but which we have extended to deal with inter-function speculation.
>>> The patches divide the problem into two halves.
>> We're essentially turning the control dependency into a value that we
>> can then use to munge the pointer or the resultant data.
>> 
>>> 
>>> The first half is some target-specific code to track the speculation
>>> condition through the generated code to provide an internal variable
>>> which can tell us whether or not the CPU's control flow speculation
>>> matches the data flow calculations.  The idea is that the internal
>>> variable starts with the value TRUE and if the CPU's control flow
>>> speculation ever causes a jump to the wrong block of code the variable
>>> becomes false until such time as the incorrect control flow
>>> speculation gets unwound.
>> Right.
>> 
>> So one of the things that comes immediately to mind is you have to run
>> this early enough that you can still get to all the control flow and
>> build your predicates.  Otherwise you have do undo stuff like
>> conditional move generation.
> 
> No, the opposite, in fact.  We want to run this very late, at least on
> Arm systems (AArch64 or AArch32).  Conditional move instructions are
> fine - they're data-flow operations, not control flow (in fact, that's
> exactly what the control flow tracker instructions are).  By running it
> late we avoid disrupting any of the earlier optimization passes as well.
> 
>> 
>> On the flip side, the earlier you do this mitigation, the more you have
>> to worry about what the optimizers are going to do to the code later in
>> the pipeline.  It's almost guaranteed a naive implementation is going to
>> muck this up since we can propagate the state of the condition into the
>> arms which will make the predicate state a compile time constant.
>> 
>> In fact this seems to be running into the area of pointer providence and
>> some discussions we had around atomic a few years back.
>> 
>> I also wonder if this could be combined with taint analysis to produce a
>> much lower overhead solution in cases were developers have done analysis
>> and know what objects are potentially under attacker control.  So
>> instead of analyzing everything, we can have a much narrower focus.
> 
> Automatic application of the tracker to vulnerable variables would be
> nice, but I haven't attempted to go there yet: at present I still rely
> on the user to annotate code with the new intrinsic.
> 
> That doesn't mean that we couldn't extend the overall approach later to
> include automatic tracking.
> 
>> 
>> The pointer munging could well run afoul of alias analysis engines that
>> don't expect to be seeing those kind of operations.
> 
> I think the pass runs late enough that it isn't a problem.
> 
>> 
>> Anyway, just some initial high level thoughts.  I'm sure there'll be
>> more as I read the implementation.
>> 
> 
> Thanks for starting to look at this so quickly.
> 
> R.
> 
>> 
>> Jeff

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-10 13:48     ` Bill Schmidt
@ 2018-07-10 14:14       ` Richard Earnshaw (lists)
  2018-07-10 15:44         ` Jeff Law
  0 siblings, 1 reply; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-07-10 14:14 UTC (permalink / raw)
  To: Bill Schmidt; +Cc: Jeff Law, gcc-patches

On 10/07/18 14:48, Bill Schmidt wrote:
> 
>> On Jul 10, 2018, at 3:49 AM, Richard Earnshaw (lists) <Richard.Earnshaw@arm.com> wrote:
>>
>> On 10/07/18 00:13, Jeff Law wrote:
>>> On 07/09/2018 10:38 AM, Richard Earnshaw wrote:
>>>>
>>>> The patches I posted earlier this year for mitigating against
>>>> CVE-2017-5753 (Spectre variant 1) attracted some useful feedback, from
>>>> which it became obvious that a rethink was needed.  This mail, and the
>>>> following patches attempt to address that feedback and present a new
>>>> approach to mitigating against this form of attack surface.
>>>>
>>>> There were two major issues with the original approach:
>>>>
>>>> - The speculation bounds were too tightly constrained - essentially
>>>>  they had to represent and upper and lower bound on a pointer, or a
>>>>  pointer offset.
>>>> - The speculation constraints could only cover the immediately preceding
>>>>  branch, which often did not fit well with the structure of the existing
>>>>  code.
>>>>
>>>> An additional criticism was that the shape of the intrinsic did not
>>>> fit particularly well with systems that used a single speculation
>>>> barrier that essentially had to wait until all preceding speculation
>>>> had to be resolved.
>>> Right.  I suggest the Intel and IBM reps chime in on the updated semantics.
>>>
>>
>> Yes, logically, this is a boolean tracker value.  In practice we use ~0
>> for true and 0 for false, so that we can simply use it as a mask
>> operation later.
>>
>> I hope this intrinsic will be even more acceptable than the one that
>> Bill Schmidt acked previously, it's even simpler than the version we had
>> last time.
> 
> Yes, I think this looks quite good.  Thanks!
> 
> Thanks also for digging into the speculation tracking algorithm.  This
> has good potential as a conservative opt-in approach.  The obvious
> concern is whether performance will be acceptable even for apps
> that really want the protection.
> 
> We took a look at Chandler's WIP LLVM patch and ran some SPEC2006 
> numbers on a Skylake box.  We saw geomean degradations of about
> 42% (int) and 33% (fp).  (This was just one test, so caveat emptor.)
> This isn't terrible given the number of potential false positives and the
> early state of the algorithm, but it's still a lot from a customer perspective.
> I'll be interested in whether your interprocedural improvements are
> able to reduce the conservatism a bit.
> 

So I don't have any numbers for SPEC2006.  I have some initial numbers
for SPEC2000 when just adding the tracking code (so not applying the
second part of the mitigation).  In that case INT2000 is down by ~13%
and FP2000 was by comparison almost in the noise (~2.4%).

Applying the tracker value to all memory loads would push those numbers
up significantly, I suspect.  That's part of the reason for preferring
the intrinsic rather than automatic mitigation: the intrinsic is much
more targeted.

R.


> Thanks,
> Bill
>>
>>>>
>>>> To address all of the above, these patches adopt a new approach, based
>>>> in part on a posting by Chandler Carruth to the LLVM developers list
>>>> (https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
>>>> but which we have extended to deal with inter-function speculation.
>>>> The patches divide the problem into two halves.
>>> We're essentially turning the control dependency into a value that we
>>> can then use to munge the pointer or the resultant data.
>>>
>>>>
>>>> The first half is some target-specific code to track the speculation
>>>> condition through the generated code to provide an internal variable
>>>> which can tell us whether or not the CPU's control flow speculation
>>>> matches the data flow calculations.  The idea is that the internal
>>>> variable starts with the value TRUE and if the CPU's control flow
>>>> speculation ever causes a jump to the wrong block of code the variable
>>>> becomes false until such time as the incorrect control flow
>>>> speculation gets unwound.
>>> Right.
>>>
>>> So one of the things that comes immediately to mind is you have to run
>>> this early enough that you can still get to all the control flow and
>>> build your predicates.  Otherwise you have do undo stuff like
>>> conditional move generation.
>>
>> No, the opposite, in fact.  We want to run this very late, at least on
>> Arm systems (AArch64 or AArch32).  Conditional move instructions are
>> fine - they're data-flow operations, not control flow (in fact, that's
>> exactly what the control flow tracker instructions are).  By running it
>> late we avoid disrupting any of the earlier optimization passes as well.
>>
>>>
>>> On the flip side, the earlier you do this mitigation, the more you have
>>> to worry about what the optimizers are going to do to the code later in
>>> the pipeline.  It's almost guaranteed a naive implementation is going to
>>> muck this up since we can propagate the state of the condition into the
>>> arms which will make the predicate state a compile time constant.
>>>
>>> In fact this seems to be running into the area of pointer providence and
>>> some discussions we had around atomic a few years back.
>>>
>>> I also wonder if this could be combined with taint analysis to produce a
>>> much lower overhead solution in cases were developers have done analysis
>>> and know what objects are potentially under attacker control.  So
>>> instead of analyzing everything, we can have a much narrower focus.
>>
>> Automatic application of the tracker to vulnerable variables would be
>> nice, but I haven't attempted to go there yet: at present I still rely
>> on the user to annotate code with the new intrinsic.
>>
>> That doesn't mean that we couldn't extend the overall approach later to
>> include automatic tracking.
>>
>>>
>>> The pointer munging could well run afoul of alias analysis engines that
>>> don't expect to be seeing those kind of operations.
>>
>> I think the pass runs late enough that it isn't a problem.
>>
>>>
>>> Anyway, just some initial high level thoughts.  I'm sure there'll be
>>> more as I read the implementation.
>>>
>>
>> Thanks for starting to look at this so quickly.
>>
>> R.
>>
>>>
>>> Jeff
> 

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-10  8:49   ` Richard Earnshaw (lists)
  2018-07-10 13:48     ` Bill Schmidt
@ 2018-07-10 15:42     ` Jeff Law
  2018-07-10 16:43       ` Richard Earnshaw (lists)
  1 sibling, 1 reply; 82+ messages in thread
From: Jeff Law @ 2018-07-10 15:42 UTC (permalink / raw)
  To: Richard Earnshaw (lists), gcc-patches

On 07/10/2018 02:49 AM, Richard Earnshaw (lists) wrote:
> On 10/07/18 00:13, Jeff Law wrote:
>> On 07/09/2018 10:38 AM, Richard Earnshaw wrote:
>>>
>>> To address all of the above, these patches adopt a new approach, based
>>> in part on a posting by Chandler Carruth to the LLVM developers list
>>> (https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
>>> but which we have extended to deal with inter-function speculation.
>>> The patches divide the problem into two halves.
>> We're essentially turning the control dependency into a value that we
>> can then use to munge the pointer or the resultant data.
>>
>>>
>>> The first half is some target-specific code to track the speculation
>>> condition through the generated code to provide an internal variable
>>> which can tell us whether or not the CPU's control flow speculation
>>> matches the data flow calculations.  The idea is that the internal
>>> variable starts with the value TRUE and if the CPU's control flow
>>> speculation ever causes a jump to the wrong block of code the variable
>>> becomes false until such time as the incorrect control flow
>>> speculation gets unwound.
>> Right.
>>
>> So one of the things that comes immediately to mind is you have to run
>> this early enough that you can still get to all the control flow and
>> build your predicates.  Otherwise you have do undo stuff like
>> conditional move generation.
> 
> No, the opposite, in fact.  We want to run this very late, at least on
> Arm systems (AArch64 or AArch32).  Conditional move instructions are
> fine - they're data-flow operations, not control flow (in fact, that's
> exactly what the control flow tracker instructions are).  By running it
> late we avoid disrupting any of the earlier optimization passes as well.
Ack.  I looked at the aarch64 implementation after sending my message
and it clearly runs very late.

I haven't convinced myself that all the work generic parts of the
compiler to rewrite and eliminate conditionals is safe.  But even if it
isn't, you're probably getting enough coverage to drastically reduce the
attack surface.  I'm going to have to think about the early
transformations we make and how they interact here harder.  But I think
the general approach can dramatically reduce the attack surface.

With running very late, as you noted, the big concern is edge
insertions.  I'm going to have to re-familiarize myself with all the
rules there :-)    I did note you stumbled on some of the issues in that
space (what to do with calls that throw exceptions).

Placement before the final bbro pass probably avoids a lot of pain.  So
the basic placement seems reasonable.  And again, if we're missing
something due to the effects of earlier passes, I still think you're
reducing the attack surface in a meaningful way.



> 
>>
>> On the flip side, the earlier you do this mitigation, the more you have
>> to worry about what the optimizers are going to do to the code later in
>> the pipeline.  It's almost guaranteed a naive implementation is going to
>> muck this up since we can propagate the state of the condition into the
>> arms which will make the predicate state a compile time constant.
>>
>> In fact this seems to be running into the area of pointer providence and
>> some discussions we had around atomic a few years back.
>>
>> I also wonder if this could be combined with taint analysis to produce a
>> much lower overhead solution in cases were developers have done analysis
>> and know what objects are potentially under attacker control.  So
>> instead of analyzing everything, we can have a much narrower focus.
> 
> Automatic application of the tracker to vulnerable variables would be
> nice, but I haven't attempted to go there yet: at present I still rely
> on the user to annotate code with the new intrinsic.
ACK.  My sense is we are going to want taint analysis.  I think it'd be
useful here and in other contexts.  However, I don't think it
necessarily needs to be a requirement to go forward.

I'm going to review the atomic discussion we had a while back with the
kernel folks as well as some pointer providence discussions I've had
with Martin S.  I can't put my finger on it yet, but I still have the
sense there's some interactions here we want to at least be aware of.

> 
> That doesn't mean that we couldn't extend the overall approach later to
> include automatic tracking.
Absolutely.

> 
>>
>> The pointer munging could well run afoul of alias analysis engines that
>> don't expect to be seeing those kind of operations.
> 
> I think the pass runs late enough that it isn't a problem.
Yea, I think you're right.


> 
>>
>> Anyway, just some initial high level thoughts.  I'm sure there'll be
>> more as I read the implementation.
>>
> 
> Thanks for starting to look at this so quickly.
NP.  Your timing to come back to this is good.

Jeff

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-10 14:14       ` Richard Earnshaw (lists)
@ 2018-07-10 15:44         ` Jeff Law
  0 siblings, 0 replies; 82+ messages in thread
From: Jeff Law @ 2018-07-10 15:44 UTC (permalink / raw)
  To: Richard Earnshaw (lists), Bill Schmidt; +Cc: gcc-patches

On 07/10/2018 08:14 AM, Richard Earnshaw (lists) wrote:
> On 10/07/18 14:48, Bill Schmidt wrote:
>>
>>> On Jul 10, 2018, at 3:49 AM, Richard Earnshaw (lists) <Richard.Earnshaw@arm.com> wrote:
>>>
>>> On 10/07/18 00:13, Jeff Law wrote:
>>>> On 07/09/2018 10:38 AM, Richard Earnshaw wrote:
>>>>>
>>>>> The patches I posted earlier this year for mitigating against
>>>>> CVE-2017-5753 (Spectre variant 1) attracted some useful feedback, from
>>>>> which it became obvious that a rethink was needed.  This mail, and the
>>>>> following patches attempt to address that feedback and present a new
>>>>> approach to mitigating against this form of attack surface.
>>>>>
>>>>> There were two major issues with the original approach:
>>>>>
>>>>> - The speculation bounds were too tightly constrained - essentially
>>>>>  they had to represent and upper and lower bound on a pointer, or a
>>>>>  pointer offset.
>>>>> - The speculation constraints could only cover the immediately preceding
>>>>>  branch, which often did not fit well with the structure of the existing
>>>>>  code.
>>>>>
>>>>> An additional criticism was that the shape of the intrinsic did not
>>>>> fit particularly well with systems that used a single speculation
>>>>> barrier that essentially had to wait until all preceding speculation
>>>>> had to be resolved.
>>>> Right.  I suggest the Intel and IBM reps chime in on the updated semantics.
>>>>
>>>
>>> Yes, logically, this is a boolean tracker value.  In practice we use ~0
>>> for true and 0 for false, so that we can simply use it as a mask
>>> operation later.
>>>
>>> I hope this intrinsic will be even more acceptable than the one that
>>> Bill Schmidt acked previously, it's even simpler than the version we had
>>> last time.
>>
>> Yes, I think this looks quite good.  Thanks!
>>
>> Thanks also for digging into the speculation tracking algorithm.  This
>> has good potential as a conservative opt-in approach.  The obvious
>> concern is whether performance will be acceptable even for apps
>> that really want the protection.
>>
>> We took a look at Chandler's WIP LLVM patch and ran some SPEC2006 
>> numbers on a Skylake box.  We saw geomean degradations of about
>> 42% (int) and 33% (fp).  (This was just one test, so caveat emptor.)
>> This isn't terrible given the number of potential false positives and the
>> early state of the algorithm, but it's still a lot from a customer perspective.
>> I'll be interested in whether your interprocedural improvements are
>> able to reduce the conservatism a bit.
>>
> 
> So I don't have any numbers for SPEC2006.  I have some initial numbers
> for SPEC2000 when just adding the tracking code (so not applying the
> second part of the mitigation).  In that case INT2000 is down by ~13%
> and FP2000 was by comparison almost in the noise (~2.4%).
> 
> Applying the tracker value to all memory loads would push those numbers
> up significantly, I suspect.  That's part of the reason for preferring
> the intrinsic rather than automatic mitigation: the intrinsic is much
> more targeted.
Right.  Fully automatic without any "hints" is going to be very
expensive, possibly prohibitively expensive.

Using the intrinsic or exploiting some kind of taint analysis has the
potential to drastically reduce the overhead.  At least it seems like
they should :-)

jeff

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-10 10:53       ` Richard Earnshaw (lists)
  2018-07-10 11:22         ` Richard Biener
@ 2018-07-10 15:56         ` Jeff Law
  1 sibling, 0 replies; 82+ messages in thread
From: Jeff Law @ 2018-07-10 15:56 UTC (permalink / raw)
  To: Richard Earnshaw (lists), Richard Biener; +Cc: GCC Patches

On 07/10/2018 04:53 AM, Richard Earnshaw (lists) wrote:
> On 10/07/18 11:10, Richard Biener wrote:
>> On Tue, Jul 10, 2018 at 10:39 AM Richard Earnshaw (lists)
>> <Richard.Earnshaw@arm.com> wrote:
>>>
>>> On 10/07/18 08:19, Richard Biener wrote:
>>>> On Mon, Jul 9, 2018 at 6:39 PM Richard Earnshaw
>>>> <Richard.Earnshaw@arm.com> wrote:
>>>>>
>>>>>
>>>>> The patches I posted earlier this year for mitigating against
>>>>> CVE-2017-5753 (Spectre variant 1) attracted some useful feedback, from
>>>>> which it became obvious that a rethink was needed.  This mail, and the
>>>>> following patches attempt to address that feedback and present a new
>>>>> approach to mitigating against this form of attack surface.
>>>>>
>>>>> There were two major issues with the original approach:
>>>>>
>>>>> - The speculation bounds were too tightly constrained - essentially
>>>>>   they had to represent and upper and lower bound on a pointer, or a
>>>>>   pointer offset.
>>>>> - The speculation constraints could only cover the immediately preceding
>>>>>   branch, which often did not fit well with the structure of the existing
>>>>>   code.
>>>>>
>>>>> An additional criticism was that the shape of the intrinsic did not
>>>>> fit particularly well with systems that used a single speculation
>>>>> barrier that essentially had to wait until all preceding speculation
>>>>> had to be resolved.
>>>>>
>>>>> To address all of the above, these patches adopt a new approach, based
>>>>> in part on a posting by Chandler Carruth to the LLVM developers list
>>>>> (https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
>>>>> but which we have extended to deal with inter-function speculation.
>>>>> The patches divide the problem into two halves.
>>>>>
>>>>> The first half is some target-specific code to track the speculation
>>>>> condition through the generated code to provide an internal variable
>>>>> which can tell us whether or not the CPU's control flow speculation
>>>>> matches the data flow calculations.  The idea is that the internal
>>>>> variable starts with the value TRUE and if the CPU's control flow
>>>>> speculation ever causes a jump to the wrong block of code the variable
>>>>> becomes false until such time as the incorrect control flow
>>>>> speculation gets unwound.
>>>>>
>>>>> The second half is that a new intrinsic function is introduced that is
>>>>> much simpler than we had before.  The basic version of the intrinsic
>>>>> is now simply:
>>>>>
>>>>>       T var = __builtin_speculation_safe_value (T unsafe_var);
>>>>>
>>>>> Full details of the syntax can be found in the documentation patch, in
>>>>> patch 1.  In summary, when not speculating the intrinsic returns
>>>>> unsafe_var; when speculating then if it can be shown that the
>>>>> speculative flow has diverged from the intended control flow then zero
>>>>> is returned.  An optional second argument can be used to return an
>>>>> alternative value to zero.  The builtin may cause execution to pause
>>>>> until the speculation state is resolved.
>>>>
>>>> So a trivial target implementation would be to emit a barrier and then
>>>> it would always return unsafe_var and never zero.  What I don't understand
>>>> fully is what users should do here, thus what the value of ever returning
>>>> "unsafe" is.  Also I wonder why the API is forcing you to single-out a
>>>> special value instead of doing
>>>>
>>>>  bool safe = __builtin_speculation_safe_value_p (T unsafe_value);
>>>>  if (!safe)
>>>>    /* what now? */
>>>>
>>>> I'm only guessing that the correct way to handle "unsafe" is basically
>>>>
>>>>  while (__builtin_speculation_safe_value (val) == 0)
>>>>     ;
>>>>
>>>> use val, it's now safe
>>>
>>> No, a safe version of val is returned, not a bool telling you it is now
>>> safe to use the original.
>>
>> OK, so making the old value dead is required to preserve the desired
>> dataflow.
>>
>> But how should I use the special value that signaled "failure"?
>>
>> Obviously the user isn't supposed to simply replace 'val' with
>>
>>  val = __builtin_speculation_safe_value (val);
>>
>> to make it speculation-proof.  So - how should the user _use_ this
>> builtin?  The docs do not say anything about this but says the
>> very confusing
>>
>> +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.
>>
>> because speculation is about executing instructions as if they were
>> supposed to be executed.  Once it is known the prediciton was wrong
>> no more "wrong" instructions will be executed but a previously
>> speculated instruction cannot know it was "falsely" speculated.
>>
>> Does the above try to say that the function may return failval if the
>> instruction is currently executed speculatively instead?  That would
>> make sense to me.  And return failval independent of if the speculation
>> later turns out to be correct or not.
>>
>>>  You must use the sanitized version in future,
>>> not the unprotected version.
>>>
>>>
>>> So the usage is going to be more like:
>>>
>>> val = __builtin_speculation_safe_value (val);  // Overwrite val with a
>>> sanitized version.
>>>
>>> You have to use the cleaned up version, the unclean version is still
>>> vulnerable to incorrect speculation.
>>
>> But then where does failval come into play?  The above cannot be correct
>> if failval matters.
> 
> failval only comes into play if the CPU is speculating incorrectly.
> It's just a safe value that some CPUs might use until such time as the
> speculation gets unwound.  In most cases it can be zero.  Perhaps a more
> concrete example would be something like.
The value really only matters in the sense that if the processor is
speculating and using that value that the uses don't lead information leaks.

That's why 0 is so useful here as safeval.  Reading/writing *0
speculatively isn't going to populate the cache in a way that is useful
to the attacker.

Jeff

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-10 15:42     ` Jeff Law
@ 2018-07-10 16:43       ` Richard Earnshaw (lists)
  2018-07-11 20:47         ` Jeff Law
  0 siblings, 1 reply; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-07-10 16:43 UTC (permalink / raw)
  To: Jeff Law, gcc-patches

On 10/07/18 16:42, Jeff Law wrote:
> On 07/10/2018 02:49 AM, Richard Earnshaw (lists) wrote:
>> On 10/07/18 00:13, Jeff Law wrote:
>>> On 07/09/2018 10:38 AM, Richard Earnshaw wrote:
>>>>
>>>> To address all of the above, these patches adopt a new approach, based
>>>> in part on a posting by Chandler Carruth to the LLVM developers list
>>>> (https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
>>>> but which we have extended to deal with inter-function speculation.
>>>> The patches divide the problem into two halves.
>>> We're essentially turning the control dependency into a value that we
>>> can then use to munge the pointer or the resultant data.
>>>
>>>>
>>>> The first half is some target-specific code to track the speculation
>>>> condition through the generated code to provide an internal variable
>>>> which can tell us whether or not the CPU's control flow speculation
>>>> matches the data flow calculations.  The idea is that the internal
>>>> variable starts with the value TRUE and if the CPU's control flow
>>>> speculation ever causes a jump to the wrong block of code the variable
>>>> becomes false until such time as the incorrect control flow
>>>> speculation gets unwound.
>>> Right.
>>>
>>> So one of the things that comes immediately to mind is you have to run
>>> this early enough that you can still get to all the control flow and
>>> build your predicates.  Otherwise you have do undo stuff like
>>> conditional move generation.
>>
>> No, the opposite, in fact.  We want to run this very late, at least on
>> Arm systems (AArch64 or AArch32).  Conditional move instructions are
>> fine - they're data-flow operations, not control flow (in fact, that's
>> exactly what the control flow tracker instructions are).  By running it
>> late we avoid disrupting any of the earlier optimization passes as well.
> Ack.  I looked at the aarch64 implementation after sending my message
> and it clearly runs very late.
> 
> I haven't convinced myself that all the work generic parts of the
> compiler to rewrite and eliminate conditionals is safe.  But even if it
> isn't, you're probably getting enough coverage to drastically reduce the
> attack surface.  I'm going to have to think about the early
> transformations we make and how they interact here harder.  But I think
> the general approach can dramatically reduce the attack surface.

My argument here would be that we are concerned about speculation that
the CPU does with the generated program.  We're not particularly
bothered about the abstract machine description it's based upon.  As
long as the earlier transforms lead to a valid translation (it hasn't
removed a necessary bounds check) then running late is fine.

I can't currently conceive a situation where the compiler would be able
to remove a /necessary/ bounds check that could lead to unsafe
speculation later on.  A redundant bounds check removal shouldn't be a
problem as the non-redundant check should remain and that will still get
tracking code added.

> 
> With running very late, as you noted, the big concern is edge
> insertions.  I'm going to have to re-familiarize myself with all the
> rules there :-)    I did note you stumbled on some of the issues in that
> space (what to do with calls that throw exceptions).
> 
> Placement before the final bbro pass probably avoids a lot of pain.  So
> the basic placement seems reasonable.  And again, if we're missing
> something due to the effects of earlier passes, I still think you're
> reducing the attack surface in a meaningful way.
> 
> 
> 
>>
>>>
>>> On the flip side, the earlier you do this mitigation, the more you have
>>> to worry about what the optimizers are going to do to the code later in
>>> the pipeline.  It's almost guaranteed a naive implementation is going to
>>> muck this up since we can propagate the state of the condition into the
>>> arms which will make the predicate state a compile time constant.
>>>
>>> In fact this seems to be running into the area of pointer providence and
>>> some discussions we had around atomic a few years back.
>>>
>>> I also wonder if this could be combined with taint analysis to produce a
>>> much lower overhead solution in cases were developers have done analysis
>>> and know what objects are potentially under attacker control.  So
>>> instead of analyzing everything, we can have a much narrower focus.
>>
>> Automatic application of the tracker to vulnerable variables would be
>> nice, but I haven't attempted to go there yet: at present I still rely
>> on the user to annotate code with the new intrinsic.
> ACK.  My sense is we are going to want taint analysis.  I think it'd be
> useful here and in other contexts.  However, I don't think it
> necessarily needs to be a requirement to go forward.
> 
> I'm going to review the atomic discussion we had a while back with the
> kernel folks as well as some pointer providence discussions I've had
> with Martin S.  I can't put my finger on it yet, but I still have the
> sense there's some interactions here we want to at least be aware of.
> 
>>
>> That doesn't mean that we couldn't extend the overall approach later to
>> include automatic tracking.
> Absolutely.
> 
>>
>>>
>>> The pointer munging could well run afoul of alias analysis engines that
>>> don't expect to be seeing those kind of operations.
>>
>> I think the pass runs late enough that it isn't a problem.
> Yea, I think you're right.
> 
> 
>>
>>>
>>> Anyway, just some initial high level thoughts.  I'm sure there'll be
>>> more as I read the implementation.
>>>
>>
>> Thanks for starting to look at this so quickly.
> NP.  Your timing to come back to this is good.
> 
> Jeff
> 

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-10 16:43       ` Richard Earnshaw (lists)
@ 2018-07-11 20:47         ` Jeff Law
  2018-07-11 22:31           ` Richard Earnshaw (lists)
  0 siblings, 1 reply; 82+ messages in thread
From: Jeff Law @ 2018-07-11 20:47 UTC (permalink / raw)
  To: Richard Earnshaw (lists), gcc-patches

On 07/10/2018 10:43 AM, Richard Earnshaw (lists) wrote:
> On 10/07/18 16:42, Jeff Law wrote:
>> On 07/10/2018 02:49 AM, Richard Earnshaw (lists) wrote:
>>> On 10/07/18 00:13, Jeff Law wrote:
>>>> On 07/09/2018 10:38 AM, Richard Earnshaw wrote:
>>>>>
>>>>> To address all of the above, these patches adopt a new approach, based
>>>>> in part on a posting by Chandler Carruth to the LLVM developers list
>>>>> (https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
>>>>> but which we have extended to deal with inter-function speculation.
>>>>> The patches divide the problem into two halves.
>>>> We're essentially turning the control dependency into a value that we
>>>> can then use to munge the pointer or the resultant data.
>>>>
>>>>>
>>>>> The first half is some target-specific code to track the speculation
>>>>> condition through the generated code to provide an internal variable
>>>>> which can tell us whether or not the CPU's control flow speculation
>>>>> matches the data flow calculations.  The idea is that the internal
>>>>> variable starts with the value TRUE and if the CPU's control flow
>>>>> speculation ever causes a jump to the wrong block of code the variable
>>>>> becomes false until such time as the incorrect control flow
>>>>> speculation gets unwound.
>>>> Right.
>>>>
>>>> So one of the things that comes immediately to mind is you have to run
>>>> this early enough that you can still get to all the control flow and
>>>> build your predicates.  Otherwise you have do undo stuff like
>>>> conditional move generation.
>>>
>>> No, the opposite, in fact.  We want to run this very late, at least on
>>> Arm systems (AArch64 or AArch32).  Conditional move instructions are
>>> fine - they're data-flow operations, not control flow (in fact, that's
>>> exactly what the control flow tracker instructions are).  By running it
>>> late we avoid disrupting any of the earlier optimization passes as well.
>> Ack.  I looked at the aarch64 implementation after sending my message
>> and it clearly runs very late.
>>
>> I haven't convinced myself that all the work generic parts of the
>> compiler to rewrite and eliminate conditionals is safe.  But even if it
>> isn't, you're probably getting enough coverage to drastically reduce the
>> attack surface.  I'm going to have to think about the early
>> transformations we make and how they interact here harder.  But I think
>> the general approach can dramatically reduce the attack surface.
> 
> My argument here would be that we are concerned about speculation that
> the CPU does with the generated program.  We're not particularly
> bothered about the abstract machine description it's based upon.  As
> long as the earlier transforms lead to a valid translation (it hasn't
> removed a necessary bounds check) then running late is fine.
I'm thinking about obfuscation of the bounds check or the pointer or
turning branchy into straightline code, possibly doing some speculation
in the process, if-conversion and the like.

For example hoist_adjacent_loads which results in speculative loads and
likely a conditional move to select between the two loaded values.

Or what if we've done something like

if (x < maxval)
   res = *p;

And we've turned that into


t = *p;
res = (x < maxval) ? t : res;


That may be implemented as a conditional move at the RTL level, so
protecting that may be nontrivial.

In those examples the compiler itself has introduced the speculation.

I can't find the conditional obfuscation I was looking for, so it's hard
to rule it in our out as potentially problematical.

WRT pointer obfuscation, we no longer propagate conditional equivalences
very agressively, so it may be a non-issue in the end.

But again, even with these concerns I think what you're doing cuts down
the attack surface in meaningful ways.



> 
> I can't currently conceive a situation where the compiler would be able
> to remove a /necessary/ bounds check that could lead to unsafe
> speculation later on.  A redundant bounds check removal shouldn't be a
> problem as the non-redundant check should remain and that will still get
> tracking code added.
It's less about removal and more about either compiler-generated
speculation or obfuscation of the patterns you're looking for.


jeff




^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 6/7] AArch64 - new pass to add conditional-branch speculation tracking
  2018-07-09 16:39 ` [PATCH 6/7] AArch64 - new pass to add conditional-branch speculation tracking Richard Earnshaw
@ 2018-07-11 21:01   ` Jeff Law
  2018-07-23 14:33     ` Richard Earnshaw (lists)
  0 siblings, 1 reply; 82+ messages in thread
From: Jeff Law @ 2018-07-11 21:01 UTC (permalink / raw)
  To: Richard Earnshaw, gcc-patches

On 07/09/2018 10:38 AM, Richard Earnshaw wrote:
> This patch is the main part of the speculation tracking code.  It adds
> a new target-specific pass that is run just before the final branch
> reorg pass (so that it can clean up any new edge insertions we make).
> The pass is only run with -mtrack-speculation is passed on the command
> line.
> 
> One thing that did come to light as part of this was that the stack pointer
> register was not being permitted in comparision instructions.  We rely on
> that for moving the tracking state between SP and the scratch register at
> function call boundaries.
Note that the sp in comparison instructions issue came up with the
improvements to stack-clash that Tamar, Richard S. and you worked on.


> 
> 	* config/aarch64/aarch64-speculation.cc: New file.
> 	* config/aarch64/aarch64-passes.def (pass_track_speculation): Add before
> 	pass_reorder_blocks.
> 	* config/aarch64/aarch64-protos.h (make_pass_track_speculation): Add
> 	prototype.
> 	* config/aarch64/aarch64.c (aarch64_conditional_register_usage): Fix
> 	X14 and X15 when tracking speculation.
> 	* config/aarch64/aarch64.md (register name constants): Add
> 	SPECULATION_TRACKER_REGNUM and SPECULATION_SCRATCH_REGNUM.
> 	(unspec): Add UNSPEC_SPECULATION_TRACKER.
> 	(speculation_barrier): New insn attribute.
> 	(cmp<mode>): Allow SP in comparisons.
> 	(speculation_tracker): New insn.
> 	(speculation_barrier): Add speculation_barrier attribute.
> 	* config/aarch64/t-aarch64: Add make rule for aarch64-speculation.o.
> 	* config.gcc (aarch64*-*-*): Add aarch64-speculation.o to extra_objs.
> 	* doc/invoke.texi (AArch64 Options): Document -mtrack-speculation.
> ---
>  gcc/config.gcc                            |   2 +-
>  gcc/config/aarch64/aarch64-passes.def     |   1 +
>  gcc/config/aarch64/aarch64-protos.h       |   3 +-
>  gcc/config/aarch64/aarch64-speculation.cc | 494 ++++++++++++++++++++++++++++++
>  gcc/config/aarch64/aarch64.c              |  13 +
>  gcc/config/aarch64/aarch64.md             |  30 +-
>  gcc/config/aarch64/t-aarch64              |  10 +
>  gcc/doc/invoke.texi                       |  10 +-
>  8 files changed, 558 insertions(+), 5 deletions(-)
>  create mode 100644 gcc/config/aarch64/aarch64-speculation.cc
Given the consensus forming about using these kind of masking
instructions being the preferred way to mitigate (as opposed to lfence
barriers and the like) I have to ask your opinions about making the bulk
of this a general pass rather than one specific to the aarch backend.
I'd hate to end up duplicating all this stuff across multiple architectures.

I think it all looks pretty reasonable though.

jeff

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-11 20:47         ` Jeff Law
@ 2018-07-11 22:31           ` Richard Earnshaw (lists)
  0 siblings, 0 replies; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-07-11 22:31 UTC (permalink / raw)
  To: Jeff Law, gcc-patches

On 11/07/18 21:46, Jeff Law wrote:
> On 07/10/2018 10:43 AM, Richard Earnshaw (lists) wrote:
>> On 10/07/18 16:42, Jeff Law wrote:
>>> On 07/10/2018 02:49 AM, Richard Earnshaw (lists) wrote:
>>>> On 10/07/18 00:13, Jeff Law wrote:
>>>>> On 07/09/2018 10:38 AM, Richard Earnshaw wrote:
>>>>>>
>>>>>> To address all of the above, these patches adopt a new approach, based
>>>>>> in part on a posting by Chandler Carruth to the LLVM developers list
>>>>>> (https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
>>>>>> but which we have extended to deal with inter-function speculation.
>>>>>> The patches divide the problem into two halves.
>>>>> We're essentially turning the control dependency into a value that we
>>>>> can then use to munge the pointer or the resultant data.
>>>>>
>>>>>>
>>>>>> The first half is some target-specific code to track the speculation
>>>>>> condition through the generated code to provide an internal variable
>>>>>> which can tell us whether or not the CPU's control flow speculation
>>>>>> matches the data flow calculations.  The idea is that the internal
>>>>>> variable starts with the value TRUE and if the CPU's control flow
>>>>>> speculation ever causes a jump to the wrong block of code the variable
>>>>>> becomes false until such time as the incorrect control flow
>>>>>> speculation gets unwound.
>>>>> Right.
>>>>>
>>>>> So one of the things that comes immediately to mind is you have to run
>>>>> this early enough that you can still get to all the control flow and
>>>>> build your predicates.  Otherwise you have do undo stuff like
>>>>> conditional move generation.
>>>>
>>>> No, the opposite, in fact.  We want to run this very late, at least on
>>>> Arm systems (AArch64 or AArch32).  Conditional move instructions are
>>>> fine - they're data-flow operations, not control flow (in fact, that's
>>>> exactly what the control flow tracker instructions are).  By running it
>>>> late we avoid disrupting any of the earlier optimization passes as well.
>>> Ack.  I looked at the aarch64 implementation after sending my message
>>> and it clearly runs very late.
>>>
>>> I haven't convinced myself that all the work generic parts of the
>>> compiler to rewrite and eliminate conditionals is safe.  But even if it
>>> isn't, you're probably getting enough coverage to drastically reduce the
>>> attack surface.  I'm going to have to think about the early
>>> transformations we make and how they interact here harder.  But I think
>>> the general approach can dramatically reduce the attack surface.
>>
>> My argument here would be that we are concerned about speculation that
>> the CPU does with the generated program.  We're not particularly
>> bothered about the abstract machine description it's based upon.  As
>> long as the earlier transforms lead to a valid translation (it hasn't
>> removed a necessary bounds check) then running late is fine.
> I'm thinking about obfuscation of the bounds check or the pointer or
> turning branchy into straightline code, possibly doing some speculation
> in the process, if-conversion and the like.
> 
> For example hoist_adjacent_loads which results in speculative loads and
> likely a conditional move to select between the two loaded values.
> 
> Or what if we've done something like
> 
> if (x < maxval)
>    res = *p;
> 
> And we've turned that into
> 
> 
> t = *p;
> res = (x < maxval) ? t : res;

Hmm, interesting.  But for that to be safe, the compiler would have to
be able to prove that dereferencing p was safe even if x >= maxval,
otherwise the run-time code could fault (so if there's any chance that
it could point to something vulnerable, then there must also be a chance
that it points to unmapped memory).  Given that requirement, I don't
think this case can be a specific concern, since the requirement implies
that p must already be within some known bounds for the type of object
it points to.

R.

> 
> 
> That may be implemented as a conditional move at the RTL level, so
> protecting that may be nontrivial.
> 
> In those examples the compiler itself has introduced the speculation.
> 
> I can't find the conditional obfuscation I was looking for, so it's hard
> to rule it in our out as potentially problematical.
> 
> WRT pointer obfuscation, we no longer propagate conditional equivalences
> very agressively, so it may be a non-issue in the end.
> 
> But again, even with these concerns I think what you're doing cuts down
> the attack surface in meaningful ways.
> 
> 
> 
>>
>> I can't currently conceive a situation where the compiler would be able
>> to remove a /necessary/ bounds check that could lead to unsafe
>> speculation later on.  A redundant bounds check removal shouldn't be a
>> problem as the non-redundant check should remain and that will still get
>> tracking code added.
> It's less about removal and more about either compiler-generated
> speculation or obfuscation of the patterns you're looking for.
> 
> 
> jeff
> 
> 
> 
> 

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 1/7] Add __builtin_speculation_safe_value
  2018-07-09 16:39 ` [PATCH 1/7] Add __builtin_speculation_safe_value Richard Earnshaw
@ 2018-07-23 14:28   ` Richard Earnshaw (lists)
  2018-07-24 17:26   ` Richard Biener
  1 sibling, 0 replies; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-07-23 14:28 UTC (permalink / raw)
  To: gcc-patches

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;" } */
> 

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 6/7] AArch64 - new pass to add conditional-branch speculation tracking
  2018-07-11 21:01   ` Jeff Law
@ 2018-07-23 14:33     ` Richard Earnshaw (lists)
  2018-07-24 21:31       ` Jeff Law
  0 siblings, 1 reply; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-07-23 14:33 UTC (permalink / raw)
  To: Jeff Law, gcc-patches

[sorry, missed this mail somehow]

On 11/07/18 22:01, Jeff Law wrote:
> On 07/09/2018 10:38 AM, Richard Earnshaw wrote:
>> This patch is the main part of the speculation tracking code.  It adds
>> a new target-specific pass that is run just before the final branch
>> reorg pass (so that it can clean up any new edge insertions we make).
>> The pass is only run with -mtrack-speculation is passed on the command
>> line.
>>
>> One thing that did come to light as part of this was that the stack pointer
>> register was not being permitted in comparision instructions.  We rely on
>> that for moving the tracking state between SP and the scratch register at
>> function call boundaries.
> Note that the sp in comparison instructions issue came up with the
> improvements to stack-clash that Tamar, Richard S. and you worked on.
> 

I can certainly lift that part into a separate patch.

> 
>>
>> 	* config/aarch64/aarch64-speculation.cc: New file.
>> 	* config/aarch64/aarch64-passes.def (pass_track_speculation): Add before
>> 	pass_reorder_blocks.
>> 	* config/aarch64/aarch64-protos.h (make_pass_track_speculation): Add
>> 	prototype.
>> 	* config/aarch64/aarch64.c (aarch64_conditional_register_usage): Fix
>> 	X14 and X15 when tracking speculation.
>> 	* config/aarch64/aarch64.md (register name constants): Add
>> 	SPECULATION_TRACKER_REGNUM and SPECULATION_SCRATCH_REGNUM.
>> 	(unspec): Add UNSPEC_SPECULATION_TRACKER.
>> 	(speculation_barrier): New insn attribute.
>> 	(cmp<mode>): Allow SP in comparisons.
>> 	(speculation_tracker): New insn.
>> 	(speculation_barrier): Add speculation_barrier attribute.
>> 	* config/aarch64/t-aarch64: Add make rule for aarch64-speculation.o.
>> 	* config.gcc (aarch64*-*-*): Add aarch64-speculation.o to extra_objs.
>> 	* doc/invoke.texi (AArch64 Options): Document -mtrack-speculation.
>> ---
>>  gcc/config.gcc                            |   2 +-
>>  gcc/config/aarch64/aarch64-passes.def     |   1 +
>>  gcc/config/aarch64/aarch64-protos.h       |   3 +-
>>  gcc/config/aarch64/aarch64-speculation.cc | 494 ++++++++++++++++++++++++++++++
>>  gcc/config/aarch64/aarch64.c              |  13 +
>>  gcc/config/aarch64/aarch64.md             |  30 +-
>>  gcc/config/aarch64/t-aarch64              |  10 +
>>  gcc/doc/invoke.texi                       |  10 +-
>>  8 files changed, 558 insertions(+), 5 deletions(-)
>>  create mode 100644 gcc/config/aarch64/aarch64-speculation.cc
> Given the consensus forming about using these kind of masking
> instructions being the preferred way to mitigate (as opposed to lfence
> barriers and the like) I have to ask your opinions about making the bulk
> of this a general pass rather than one specific to the aarch backend.
> I'd hate to end up duplicating all this stuff across multiple architectures.
> 
> I think it all looks pretty reasonable though.
> 
> jeff
> 


It would be nice to make this more generic, but I'm not sure how easy
that would be.  Some of the analysis is surely the same, but deployment
of the mitigation itself is perhaps more complex.  At this point in
time, I think I'd prefer to go with the target-specific implementation
and then look to generalize it as a follow-up.  There may be some more
optimizations to add later as well.

R.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 1/7] Add __builtin_speculation_safe_value
  2018-07-09 16:39 ` [PATCH 1/7] Add __builtin_speculation_safe_value Richard Earnshaw
  2018-07-23 14:28   ` Richard Earnshaw (lists)
@ 2018-07-24 17:26   ` Richard Biener
  2018-07-25  9:49     ` Richard Earnshaw (lists)
  2018-07-25 18:03     ` Richard Earnshaw (lists)
  1 sibling, 2 replies; 82+ messages in thread
From: Richard Biener @ 2018-07-24 17:26 UTC (permalink / raw)
  To: Richard Earnshaw; +Cc: GCC Patches

On Mon, Jul 9, 2018 at 6:40 PM Richard Earnshaw
<Richard.Earnshaw@arm.com> 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.

So given this series is supposed to be backported I question

+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;

which makes all but aarch64 archs warn on __bultin_speculation_safe_value
uses, even those that do not suffer from Spectre like all those embedded targets
where implementations usually do not speculate at all.

In fact for those targets the builtin stays in the way of optimization on GIMPLE
as well so we should fold it away early if neither the target hook is
implemented
nor there is a speculation_barrier insn.

So, please make resolve_overloaded_builtin return a no-op on such targets
which means you can remove the above warning.  Maybe such targets
shouldn't advertise / initialize the builtins at all?

The builtins also have no attributes which mean they are assumed to be
1) calling back into the CU via exported functions, 2) possibly throwing
exceptions, 3) affecting memory state.  I think you at least want
to use ATTR_NOTHROW_LEAF_LIST.

The builtins are not designed to be optimization or memory barriers as
far as I can see and should thus be CONST as well.

BUILT_IN_SPECULATION_SAFE_VALUE_PTR is declared but
nowhere generated?  Maybe

+    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);

resolve_size does that?  Why can that not return the built_in_function
itself or BUILT_IN_NONE on error to make that clearer?

Otherwise it looks reasonable but C FE maintainers should comment.
I miss C++ testcases (or rather testcases should be in c-c++-common).

Richard.

> 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
>

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 6/7] AArch64 - new pass to add conditional-branch speculation tracking
  2018-07-23 14:33     ` Richard Earnshaw (lists)
@ 2018-07-24 21:31       ` Jeff Law
  0 siblings, 0 replies; 82+ messages in thread
From: Jeff Law @ 2018-07-24 21:31 UTC (permalink / raw)
  To: Richard Earnshaw (lists), gcc-patches

On 07/23/2018 08:33 AM, Richard Earnshaw (lists) wrote:
> [sorry, missed this mail somehow]
> 
> On 11/07/18 22:01, Jeff Law wrote:
>> On 07/09/2018 10:38 AM, Richard Earnshaw wrote:
>>> This patch is the main part of the speculation tracking code.  It adds
>>> a new target-specific pass that is run just before the final branch
>>> reorg pass (so that it can clean up any new edge insertions we make).
>>> The pass is only run with -mtrack-speculation is passed on the command
>>> line.
>>>
>>> One thing that did come to light as part of this was that the stack pointer
>>> register was not being permitted in comparision instructions.  We rely on
>>> that for moving the tracking state between SP and the scratch register at
>>> function call boundaries.
>> Note that the sp in comparison instructions issue came up with the
>> improvements to stack-clash that Tamar, Richard S. and you worked on.
>>
> 
> I can certainly lift that part into a separate patch.
Your call.  It was mostly an observation that the change was clearly
needed elsewhere.  I'm certainly comfortable letting that hunk go in
with whichever kit is approved first :-)

> 
>>
>>>
>>> 	* config/aarch64/aarch64-speculation.cc: New file.
>>> 	* config/aarch64/aarch64-passes.def (pass_track_speculation): Add before
>>> 	pass_reorder_blocks.
>>> 	* config/aarch64/aarch64-protos.h (make_pass_track_speculation): Add
>>> 	prototype.
>>> 	* config/aarch64/aarch64.c (aarch64_conditional_register_usage): Fix
>>> 	X14 and X15 when tracking speculation.
>>> 	* config/aarch64/aarch64.md (register name constants): Add
>>> 	SPECULATION_TRACKER_REGNUM and SPECULATION_SCRATCH_REGNUM.
>>> 	(unspec): Add UNSPEC_SPECULATION_TRACKER.
>>> 	(speculation_barrier): New insn attribute.
>>> 	(cmp<mode>): Allow SP in comparisons.
>>> 	(speculation_tracker): New insn.
>>> 	(speculation_barrier): Add speculation_barrier attribute.
>>> 	* config/aarch64/t-aarch64: Add make rule for aarch64-speculation.o.
>>> 	* config.gcc (aarch64*-*-*): Add aarch64-speculation.o to extra_objs.
>>> 	* doc/invoke.texi (AArch64 Options): Document -mtrack-speculation.
>>> ---
>>>  gcc/config.gcc                            |   2 +-
>>>  gcc/config/aarch64/aarch64-passes.def     |   1 +
>>>  gcc/config/aarch64/aarch64-protos.h       |   3 +-
>>>  gcc/config/aarch64/aarch64-speculation.cc | 494 ++++++++++++++++++++++++++++++
>>>  gcc/config/aarch64/aarch64.c              |  13 +
>>>  gcc/config/aarch64/aarch64.md             |  30 +-
>>>  gcc/config/aarch64/t-aarch64              |  10 +
>>>  gcc/doc/invoke.texi                       |  10 +-
>>>  8 files changed, 558 insertions(+), 5 deletions(-)
>>>  create mode 100644 gcc/config/aarch64/aarch64-speculation.cc
>> Given the consensus forming about using these kind of masking
>> instructions being the preferred way to mitigate (as opposed to lfence
>> barriers and the like) I have to ask your opinions about making the bulk
>> of this a general pass rather than one specific to the aarch backend.
>> I'd hate to end up duplicating all this stuff across multiple architectures.
>>
>> I think it all looks pretty reasonable though.
>>
>> jeff
>>
> 
> 
> It would be nice to make this more generic, but I'm not sure how easy
> that would be.  Some of the analysis is surely the same, but deployment
> of the mitigation itself is perhaps more complex.  At this point in
> time, I think I'd prefer to go with the target-specific implementation
> and then look to generalize it as a follow-up.  There may be some more
> optimizations to add later as well.
ACK.  I suspect it's mostly the analysis side that we'll want to share.
I don't mind giving you the advantage of going first and letting it live
in the aarch64 backend.  Second implementation can extract the analysis
bits :-)

So IMHO, this can go forward whenever you want to push it.

Jeff

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 1/7] Add __builtin_speculation_safe_value
  2018-07-24 17:26   ` Richard Biener
@ 2018-07-25  9:49     ` Richard Earnshaw (lists)
  2018-07-25 10:36       ` Richard Biener
  2018-07-25 18:03     ` Richard Earnshaw (lists)
  1 sibling, 1 reply; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-07-25  9:49 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

On 24/07/18 18:26, Richard Biener wrote:
> On Mon, Jul 9, 2018 at 6:40 PM Richard Earnshaw
> <Richard.Earnshaw@arm.com> 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.
> 
> So given this series is supposed to be backported I question
> 
> +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;
> 
> which makes all but aarch64 archs warn on __bultin_speculation_safe_value
> uses, even those that do not suffer from Spectre like all those embedded targets
> where implementations usually do not speculate at all.
> 
> In fact for those targets the builtin stays in the way of optimization on GIMPLE
> as well so we should fold it away early if neither the target hook is
> implemented
> nor there is a speculation_barrier insn.
> 
> So, please make resolve_overloaded_builtin return a no-op on such targets
> which means you can remove the above warning.  Maybe such targets
> shouldn't advertise / initialize the builtins at all?

I disagree with your approach here.  Why would users not want to know
when the compiler is failing to implement a security feature when it
should?  As for targets that don't need something, they can easily
define the hook as described to suppress the warning.

Or are you just suggesting moving the warning to resolve overloaded builtin.

Other ports will need to take action, but in general, it can be as
simple as, eg patch 2 or 3 do for the Arm and AArch64 backends - or
simpler still if nothing is needed for that architecture.

There is a test which is intended to fail to targets that have not yet
been patched - I thought that was better than hard-failing the build,
especially given that we want to back-port.

Port maintainers DO need to decide what to do about speculation, even if
it is explicitly that no mitigation is needed.

> 
> The builtins also have no attributes which mean they are assumed to be
> 1) calling back into the CU via exported functions, 2) possibly throwing
> exceptions, 3) affecting memory state.  I think you at least want
> to use ATTR_NOTHROW_LEAF_LIST.
> 
> The builtins are not designed to be optimization or memory barriers as
> far as I can see and should thus be CONST as well.
> 

I think they should be barriers.  They do need to ensure that they can't
be moved past other operations that might depend on the speculation
state.  Consider, for example,

 ...
 t = untrusted_value;
 ...
 if (t + 5 < limit)
 {
   v = mem[__builtin_speculation_safe_value (untrusted_value)];
   ...

The compiler must never lift the builtin outside the bounds check as
that is part of the speculation state.


> BUILT_IN_SPECULATION_SAFE_VALUE_PTR is declared but
> nowhere generated?  Maybe
> 
> +    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);
> 
> resolve_size does that?  Why can that not return the built_in_function
> itself or BUILT_IN_NONE on error to make that clearer?
> 
> Otherwise it looks reasonable but C FE maintainers should comment.
> I miss C++ testcases (or rather testcases should be in c-c++-common).
> 
> Richard.
> 
>> 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
>>

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 1/7] Add __builtin_speculation_safe_value
  2018-07-25  9:49     ` Richard Earnshaw (lists)
@ 2018-07-25 10:36       ` Richard Biener
  2018-07-25 12:41         ` Richard Earnshaw (lists)
  0 siblings, 1 reply; 82+ messages in thread
From: Richard Biener @ 2018-07-25 10:36 UTC (permalink / raw)
  To: Richard Earnshaw; +Cc: GCC Patches

On Wed, Jul 25, 2018 at 11:49 AM Richard Earnshaw (lists)
<Richard.Earnshaw@arm.com> wrote:
>
> On 24/07/18 18:26, Richard Biener wrote:
> > On Mon, Jul 9, 2018 at 6:40 PM Richard Earnshaw
> > <Richard.Earnshaw@arm.com> 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.
> >
> > So given this series is supposed to be backported I question
> >
> > +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;
> >
> > which makes all but aarch64 archs warn on __bultin_speculation_safe_value
> > uses, even those that do not suffer from Spectre like all those embedded targets
> > where implementations usually do not speculate at all.
> >
> > In fact for those targets the builtin stays in the way of optimization on GIMPLE
> > as well so we should fold it away early if neither the target hook is
> > implemented
> > nor there is a speculation_barrier insn.
> >
> > So, please make resolve_overloaded_builtin return a no-op on such targets
> > which means you can remove the above warning.  Maybe such targets
> > shouldn't advertise / initialize the builtins at all?
>
> I disagree with your approach here.  Why would users not want to know
> when the compiler is failing to implement a security feature when it
> should?  As for targets that don't need something, they can easily
> define the hook as described to suppress the warning.
>
> Or are you just suggesting moving the warning to resolve overloaded builtin.

Well.  You could argue I say we shouldn't even support
__builtin_sepeculation_safe_value
for archs that do not need it or have it not implemented.  That way users can
decide:

#if __HAVE_SPECULATION_SAFE_VALUE
 ....
#else
#warning oops // or nothing
#endif

> Other ports will need to take action, but in general, it can be as
> simple as, eg patch 2 or 3 do for the Arm and AArch64 backends - or
> simpler still if nothing is needed for that architecture.

Then that should be the default.  You might argue we'll only see
__builtin_speculation_safe_value uses for things like Firefox which
is unlikely built for AVR (just to make an example).  But people
are going to test build just on x86 and if they build with -Werror
this will break builds on all targets that didn't even get the chance
to implement this feature.

> There is a test which is intended to fail to targets that have not yet
> been patched - I thought that was better than hard-failing the build,
> especially given that we want to back-port.
>
> Port maintainers DO need to decide what to do about speculation, even if
> it is explicitly that no mitigation is needed.

Agreed.  But I didn't yet see a request for maintainers to decide that?

> >
> > The builtins also have no attributes which mean they are assumed to be
> > 1) calling back into the CU via exported functions, 2) possibly throwing
> > exceptions, 3) affecting memory state.  I think you at least want
> > to use ATTR_NOTHROW_LEAF_LIST.
> >
> > The builtins are not designed to be optimization or memory barriers as
> > far as I can see and should thus be CONST as well.
> >
>
> I think they should be barriers.  They do need to ensure that they can't
> be moved past other operations that might depend on the speculation
> state.  Consider, for example,

That makes eliding them for targets that do not need mitigation even
more important.

>  ...
>  t = untrusted_value;
>  ...
>  if (t + 5 < limit)
>  {
>    v = mem[__builtin_speculation_safe_value (untrusted_value)];
>    ...
>
> The compiler must never lift the builtin outside the bounds check as
> that is part of the speculation state.

OK, so you are relying on the fact that with the current setup GCC has
to assume the builtin has side-effects (GCC may not move it to a place that
the original location is not post-dominated on).  It doesn't explain
why you cannot set ECF_LEAF or why the builtin needs to be
considered affecting the memory state.  That is, ECF_NOVOPS
or ECF_LOOPING_CONST_OR_PURE (I don't think you can
set that manually) would work here, both keep the builtin as
having side-effects.

Btw, if you have an inline function with a pattern like above and
you use it multiple times in a row GCC should be able to
optimize this?  That is, optimizations like jump-threading also
affect the speculation state by modifying the controling
conditions.

You didn't answer my question about "what about C++"?

Richard.

>
>
> > BUILT_IN_SPECULATION_SAFE_VALUE_PTR is declared but
> > nowhere generated?  Maybe
> >
> > +    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);
> >
> > resolve_size does that?  Why can that not return the built_in_function
> > itself or BUILT_IN_NONE on error to make that clearer?
> >
> > Otherwise it looks reasonable but C FE maintainers should comment.
> > I miss C++ testcases (or rather testcases should be in c-c++-common).
> >
> > Richard.
> >
> >> 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
> >>
>

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 1/7] Add __builtin_speculation_safe_value
  2018-07-25 10:36       ` Richard Biener
@ 2018-07-25 12:41         ` Richard Earnshaw (lists)
  2018-07-25 13:47           ` Richard Biener
  2018-07-26 23:34           ` Joseph Myers
  0 siblings, 2 replies; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-07-25 12:41 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

On 25/07/18 11:36, Richard Biener wrote:
> On Wed, Jul 25, 2018 at 11:49 AM Richard Earnshaw (lists)
> <Richard.Earnshaw@arm.com> wrote:
>>
>> On 24/07/18 18:26, Richard Biener wrote:
>>> On Mon, Jul 9, 2018 at 6:40 PM Richard Earnshaw
>>> <Richard.Earnshaw@arm.com> 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.
>>>
>>> So given this series is supposed to be backported I question
>>>
>>> +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;
>>>
>>> which makes all but aarch64 archs warn on __bultin_speculation_safe_value
>>> uses, even those that do not suffer from Spectre like all those embedded targets
>>> where implementations usually do not speculate at all.
>>>
>>> In fact for those targets the builtin stays in the way of optimization on GIMPLE
>>> as well so we should fold it away early if neither the target hook is
>>> implemented
>>> nor there is a speculation_barrier insn.
>>>
>>> So, please make resolve_overloaded_builtin return a no-op on such targets
>>> which means you can remove the above warning.  Maybe such targets
>>> shouldn't advertise / initialize the builtins at all?
>>
>> I disagree with your approach here.  Why would users not want to know
>> when the compiler is failing to implement a security feature when it
>> should?  As for targets that don't need something, they can easily
>> define the hook as described to suppress the warning.
>>
>> Or are you just suggesting moving the warning to resolve overloaded builtin.
> 
> Well.  You could argue I say we shouldn't even support
> __builtin_sepeculation_safe_value
> for archs that do not need it or have it not implemented.  That way users can
> decide:
> 
> #if __HAVE_SPECULATION_SAFE_VALUE
>  ....
> #else
> #warning oops // or nothing
> #endif
> 

So how about removing the predefine of __HAVE_S_S_V when the builtin is
a nop, but then leaving the warning in if people try to use it anyway?

>> Other ports will need to take action, but in general, it can be as
>> simple as, eg patch 2 or 3 do for the Arm and AArch64 backends - or
>> simpler still if nothing is needed for that architecture.
> 
> Then that should be the default.  You might argue we'll only see
> __builtin_speculation_safe_value uses for things like Firefox which
> is unlikely built for AVR (just to make an example).  But people
> are going to test build just on x86 and if they build with -Werror
> this will break builds on all targets that didn't even get the chance
> to implement this feature.
> 
>> There is a test which is intended to fail to targets that have not yet
>> been patched - I thought that was better than hard-failing the build,
>> especially given that we want to back-port.
>>
>> Port maintainers DO need to decide what to do about speculation, even if
>> it is explicitly that no mitigation is needed.
> 
> Agreed.  But I didn't yet see a request for maintainers to decide that?
> 

consider it made, then :-)

>>>
>>> The builtins also have no attributes which mean they are assumed to be
>>> 1) calling back into the CU via exported functions, 2) possibly throwing
>>> exceptions, 3) affecting memory state.  I think you at least want
>>> to use ATTR_NOTHROW_LEAF_LIST.
>>>
>>> The builtins are not designed to be optimization or memory barriers as
>>> far as I can see and should thus be CONST as well.
>>>
>>
>> I think they should be barriers.  They do need to ensure that they can't
>> be moved past other operations that might depend on the speculation
>> state.  Consider, for example,
> 
> That makes eliding them for targets that do not need mitigation even
> more important.
> 
>>  ...
>>  t = untrusted_value;
>>  ...
>>  if (t + 5 < limit)
>>  {
>>    v = mem[__builtin_speculation_safe_value (untrusted_value)];
>>    ...
>>
>> The compiler must never lift the builtin outside the bounds check as
>> that is part of the speculation state.
> 
> OK, so you are relying on the fact that with the current setup GCC has
> to assume the builtin has side-effects (GCC may not move it to a place that
> the original location is not post-dominated on).  It doesn't explain
> why you cannot set ECF_LEAF or why the builtin needs to be
> considered affecting the memory state.  That is, ECF_NOVOPS
> or ECF_LOOPING_CONST_OR_PURE (I don't think you can
> set that manually) would work here, both keep the builtin as
> having side-effects.
> 

I wish some of this builtin gloop were better documented; at present you
have to reverse engineer significant amounts of code just to decide
whether or not you even have to think about whether or not it's relevant...


> Btw, if you have an inline function with a pattern like above and
> you use it multiple times in a row GCC should be able to
> optimize this?  That is, optimizations like jump-threading also
> affect the speculation state by modifying the controling
> conditions.

Ideally, if there's no control flow change, yes.  As soon as you insert
another branch (in or out) then you might have another speculation path
to consider.  Not sure how that can easily merging could be done, though.

> 
> You didn't answer my question about "what about C++"?
> 

It didn't need a response at this point.  It's a reasonable one, as are
some of your others...  I was focusing on the the comments that were
potentially contentious.

BTW, this bit:

+    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);

> resolve_size does that?  Why can that not return the built_in_function
> itself or BUILT_IN_NONE on error to make that clearer?

is essentially a clone of some existing code that already does it this
way.  See BUILT_IN_SYNC_LOCK_RELEASE_N etc.  Admittedly, that hunk
handles multiple origins so would be harder to rewrite as you suggest;
it just seemed more appropriate to handle the cases similarly.

R.

> Richard.
> 
>>
>>
>>> BUILT_IN_SPECULATION_SAFE_VALUE_PTR is declared but
>>> nowhere generated?  Maybe
>>>
>>> +    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);
>>>
>>> resolve_size does that?  Why can that not return the built_in_function
>>> itself or BUILT_IN_NONE on error to make that clearer?
>>>
>>> Otherwise it looks reasonable but C FE maintainers should comment.
>>> I miss C++ testcases (or rather testcases should be in c-c++-common).
>>>
>>> Richard.
>>>
>>>> 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
>>>>
>>

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 1/7] Add __builtin_speculation_safe_value
  2018-07-25 12:41         ` Richard Earnshaw (lists)
@ 2018-07-25 13:47           ` Richard Biener
  2018-07-26 10:03             ` Richard Earnshaw (lists)
  2018-07-26 23:34           ` Joseph Myers
  1 sibling, 1 reply; 82+ messages in thread
From: Richard Biener @ 2018-07-25 13:47 UTC (permalink / raw)
  To: Richard Earnshaw; +Cc: GCC Patches

On Wed, Jul 25, 2018 at 2:41 PM Richard Earnshaw (lists)
<Richard.Earnshaw@arm.com> wrote:
>
> On 25/07/18 11:36, Richard Biener wrote:
> > On Wed, Jul 25, 2018 at 11:49 AM Richard Earnshaw (lists)
> > <Richard.Earnshaw@arm.com> wrote:
> >>
> >> On 24/07/18 18:26, Richard Biener wrote:
> >>> On Mon, Jul 9, 2018 at 6:40 PM Richard Earnshaw
> >>> <Richard.Earnshaw@arm.com> 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.
> >>>
> >>> So given this series is supposed to be backported I question
> >>>
> >>> +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;
> >>>
> >>> which makes all but aarch64 archs warn on __bultin_speculation_safe_value
> >>> uses, even those that do not suffer from Spectre like all those embedded targets
> >>> where implementations usually do not speculate at all.
> >>>
> >>> In fact for those targets the builtin stays in the way of optimization on GIMPLE
> >>> as well so we should fold it away early if neither the target hook is
> >>> implemented
> >>> nor there is a speculation_barrier insn.
> >>>
> >>> So, please make resolve_overloaded_builtin return a no-op on such targets
> >>> which means you can remove the above warning.  Maybe such targets
> >>> shouldn't advertise / initialize the builtins at all?
> >>
> >> I disagree with your approach here.  Why would users not want to know
> >> when the compiler is failing to implement a security feature when it
> >> should?  As for targets that don't need something, they can easily
> >> define the hook as described to suppress the warning.
> >>
> >> Or are you just suggesting moving the warning to resolve overloaded builtin.
> >
> > Well.  You could argue I say we shouldn't even support
> > __builtin_sepeculation_safe_value
> > for archs that do not need it or have it not implemented.  That way users can
> > decide:
> >
> > #if __HAVE_SPECULATION_SAFE_VALUE
> >  ....
> > #else
> > #warning oops // or nothing
> > #endif
> >
>
> So how about removing the predefine of __HAVE_S_S_V when the builtin is
> a nop, but then leaving the warning in if people try to use it anyway?

Little bit inconsistent but I guess I could live with that.  It still leaves
the question open for how to declare you do not need speculation
barriers at all then.

> >> Other ports will need to take action, but in general, it can be as
> >> simple as, eg patch 2 or 3 do for the Arm and AArch64 backends - or
> >> simpler still if nothing is needed for that architecture.
> >
> > Then that should be the default.  You might argue we'll only see
> > __builtin_speculation_safe_value uses for things like Firefox which
> > is unlikely built for AVR (just to make an example).  But people
> > are going to test build just on x86 and if they build with -Werror
> > this will break builds on all targets that didn't even get the chance
> > to implement this feature.
> >
> >> There is a test which is intended to fail to targets that have not yet
> >> been patched - I thought that was better than hard-failing the build,
> >> especially given that we want to back-port.
> >>
> >> Port maintainers DO need to decide what to do about speculation, even if
> >> it is explicitly that no mitigation is needed.
> >
> > Agreed.  But I didn't yet see a request for maintainers to decide that?
> >
>
> consider it made, then :-)

I suspect that drew their attention ;)

So a different idea would be to produce patches implementing the hook for
each target "empty", CC the target maintainers and hope they quickly
ack if the target doesn't have a speculation problem.  Others then would
get no patch (from you) and thus raise a warning?

Maybe at least do that for all primary and secondary targets given we do
not want to regress diagnostic-wise (not get new _false_-positives) on
the branch.

> >>>
> >>> The builtins also have no attributes which mean they are assumed to be
> >>> 1) calling back into the CU via exported functions, 2) possibly throwing
> >>> exceptions, 3) affecting memory state.  I think you at least want
> >>> to use ATTR_NOTHROW_LEAF_LIST.
> >>>
> >>> The builtins are not designed to be optimization or memory barriers as
> >>> far as I can see and should thus be CONST as well.
> >>>
> >>
> >> I think they should be barriers.  They do need to ensure that they can't
> >> be moved past other operations that might depend on the speculation
> >> state.  Consider, for example,
> >
> > That makes eliding them for targets that do not need mitigation even
> > more important.
> >
> >>  ...
> >>  t = untrusted_value;
> >>  ...
> >>  if (t + 5 < limit)
> >>  {
> >>    v = mem[__builtin_speculation_safe_value (untrusted_value)];
> >>    ...
> >>
> >> The compiler must never lift the builtin outside the bounds check as
> >> that is part of the speculation state.
> >
> > OK, so you are relying on the fact that with the current setup GCC has
> > to assume the builtin has side-effects (GCC may not move it to a place that
> > the original location is not post-dominated on).  It doesn't explain
> > why you cannot set ECF_LEAF or why the builtin needs to be
> > considered affecting the memory state.  That is, ECF_NOVOPS
> > or ECF_LOOPING_CONST_OR_PURE (I don't think you can
> > set that manually) would work here, both keep the builtin as
> > having side-effects.
> >
>
> I wish some of this builtin gloop were better documented; at present you
> have to reverse engineer significant amounts of code just to decide
> whether or not you even have to think about whether or not it's relevant...
>
>
> > Btw, if you have an inline function with a pattern like above and
> > you use it multiple times in a row GCC should be able to
> > optimize this?  That is, optimizations like jump-threading also
> > affect the speculation state by modifying the controling
> > conditions.
>
> Ideally, if there's no control flow change, yes.  As soon as you insert
> another branch (in or out) then you might have another speculation path
> to consider.  Not sure how that can easily merging could be done, though.

The usual case would be

  if (cond)
   ... _b_s_s_v (x);
<code>
  if (cond)
    ... _b_s_s_v (x);

where jump-threading might decide to make that to

  if (cond)
   {
     ... _b_s_s_v (x);
     <copy of code>
     ... _b_s_s_v (x);
   }

now we might even be able to CSE the 2nd _b_s_s_v (x)
to the first?  That would mean using ECF_CONST|ECF_LOOPING_PURE_OR_CONST
is the best (but we currently have no attribute for the latter).

> >
> > You didn't answer my question about "what about C++"?
> >
>
> It didn't need a response at this point.  It's a reasonable one, as are
> some of your others...  I was focusing on the the comments that were
> potentially contentious.
>
> BTW, this bit:
>
> +    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);
>
> > resolve_size does that?  Why can that not return the built_in_function
> > itself or BUILT_IN_NONE on error to make that clearer?
>
> is essentially a clone of some existing code that already does it this
> way.  See BUILT_IN_SYNC_LOCK_RELEASE_N etc.  Admittedly, that hunk
> handles multiple origins so would be harder to rewrite as you suggest;
> it just seemed more appropriate to handle the cases similarly.

Yes, I realized you copied handling from that so I didn't look too closely...

These days we'd probably use an internal-function and spare us all
the resolving completely (besides a test for validity) ;)

Richard.

> R.
>
> > Richard.
> >
> >>
> >>
> >>> BUILT_IN_SPECULATION_SAFE_VALUE_PTR is declared but
> >>> nowhere generated?  Maybe
> >>>
> >>> +    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);
> >>>
> >>> resolve_size does that?  Why can that not return the built_in_function
> >>> itself or BUILT_IN_NONE on error to make that clearer?
> >>>
> >>> Otherwise it looks reasonable but C FE maintainers should comment.
> >>> I miss C++ testcases (or rather testcases should be in c-c++-common).
> >>>
> >>> Richard.
> >>>
> >>>> 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
> >>>>
> >>
>

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 1/7] Add __builtin_speculation_safe_value
  2018-07-24 17:26   ` Richard Biener
  2018-07-25  9:49     ` Richard Earnshaw (lists)
@ 2018-07-25 18:03     ` Richard Earnshaw (lists)
  2018-07-26  8:42       ` Richard Biener
  1 sibling, 1 reply; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-07-25 18:03 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

On 24/07/18 18:26, Richard Biener wrote:
> So, please make resolve_overloaded_builtin return a no-op on such targets
> which means you can remove the above warning.  Maybe such targets
> shouldn't advertise / initialize the builtins at all?

So I tried to make resolve_overloaded_builtin collapse the builtin
entirely if it's not needed by the machine, transforming

  x = __b_s_s_v (y);

into

  x = y;


but I can't see how to make any side-effects on the optional second
argument hang around.  It's somewhat obscure, but if the user does write

 x = __b_s_s_v (y, z++);

then z++ does still need to be performed.

The problem seems to be that the callers of resolve_overloaded_builtin
expect just a simple value result - they can't, for example, deal with a
statement list and just calling save_expr on the argument isn't enough;
so I can't see an obvious way to force the z++ expression back into the
token stream at this point.

Any ideas?  The alternative seems to be that we must keep the call until
such time as the builtins are lowered during expansion, which pretty
much loses all the benefits you were looking for.

R.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 1/7] Add __builtin_speculation_safe_value
  2018-07-25 18:03     ` Richard Earnshaw (lists)
@ 2018-07-26  8:42       ` Richard Biener
  0 siblings, 0 replies; 82+ messages in thread
From: Richard Biener @ 2018-07-26  8:42 UTC (permalink / raw)
  To: Richard Earnshaw; +Cc: GCC Patches

On Wed, Jul 25, 2018 at 8:03 PM Richard Earnshaw (lists)
<Richard.Earnshaw@arm.com> wrote:
>
> On 24/07/18 18:26, Richard Biener wrote:
> > So, please make resolve_overloaded_builtin return a no-op on such targets
> > which means you can remove the above warning.  Maybe such targets
> > shouldn't advertise / initialize the builtins at all?
>
> So I tried to make resolve_overloaded_builtin collapse the builtin
> entirely if it's not needed by the machine, transforming
>
>   x = __b_s_s_v (y);
>
> into
>
>   x = y;
>
>
> but I can't see how to make any side-effects on the optional second
> argument hang around.  It's somewhat obscure, but if the user does write
>
>  x = __b_s_s_v (y, z++);
>
> then z++ does still need to be performed.
>
> The problem seems to be that the callers of resolve_overloaded_builtin
> expect just a simple value result - they can't, for example, deal with a
> statement list and just calling save_expr on the argument isn't enough;
> so I can't see an obvious way to force the z++ expression back into the
> token stream at this point.
>
> Any ideas?  The alternative seems to be that we must keep the call until
> such time as the builtins are lowered during expansion, which pretty
> much loses all the benefits you were looking for.

Use a COMPOUND_EXPR: (z++, y).  So,

 if (TREE_SIDE_EFFECTS (2ndarg))
  res = build2_loc (loc, COMPOUND_EXPR, type, 2ndarg, 1starg);
 else
  res = 2starg;

Richard.

>
> R.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 1/7] Add __builtin_speculation_safe_value
  2018-07-25 13:47           ` Richard Biener
@ 2018-07-26 10:03             ` Richard Earnshaw (lists)
  2018-07-26 12:41               ` Richard Biener
  0 siblings, 1 reply; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-07-26 10:03 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 16105 bytes --]

On 25/07/18 14:47, Richard Biener wrote:
> On Wed, Jul 25, 2018 at 2:41 PM Richard Earnshaw (lists)
> <Richard.Earnshaw@arm.com> wrote:
>>
>> On 25/07/18 11:36, Richard Biener wrote:
>>> On Wed, Jul 25, 2018 at 11:49 AM Richard Earnshaw (lists)
>>> <Richard.Earnshaw@arm.com> wrote:
>>>>
>>>> On 24/07/18 18:26, Richard Biener wrote:
>>>>> On Mon, Jul 9, 2018 at 6:40 PM Richard Earnshaw
>>>>> <Richard.Earnshaw@arm.com> 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.
>>>>>
>>>>> So given this series is supposed to be backported I question
>>>>>
>>>>> +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;
>>>>>
>>>>> which makes all but aarch64 archs warn on __bultin_speculation_safe_value
>>>>> uses, even those that do not suffer from Spectre like all those embedded targets
>>>>> where implementations usually do not speculate at all.
>>>>>
>>>>> In fact for those targets the builtin stays in the way of optimization on GIMPLE
>>>>> as well so we should fold it away early if neither the target hook is
>>>>> implemented
>>>>> nor there is a speculation_barrier insn.
>>>>>
>>>>> So, please make resolve_overloaded_builtin return a no-op on such targets
>>>>> which means you can remove the above warning.  Maybe such targets
>>>>> shouldn't advertise / initialize the builtins at all?
>>>>
>>>> I disagree with your approach here.  Why would users not want to know
>>>> when the compiler is failing to implement a security feature when it
>>>> should?  As for targets that don't need something, they can easily
>>>> define the hook as described to suppress the warning.
>>>>
>>>> Or are you just suggesting moving the warning to resolve overloaded builtin.
>>>
>>> Well.  You could argue I say we shouldn't even support
>>> __builtin_sepeculation_safe_value
>>> for archs that do not need it or have it not implemented.  That way users can
>>> decide:
>>>
>>> #if __HAVE_SPECULATION_SAFE_VALUE
>>>  ....
>>> #else
>>> #warning oops // or nothing
>>> #endif
>>>
>>
>> So how about removing the predefine of __HAVE_S_S_V when the builtin is
>> a nop, but then leaving the warning in if people try to use it anyway?
> 
> Little bit inconsistent but I guess I could live with that.  It still leaves
> the question open for how to declare you do not need speculation
> barriers at all then.
> 
>>>> Other ports will need to take action, but in general, it can be as
>>>> simple as, eg patch 2 or 3 do for the Arm and AArch64 backends - or
>>>> simpler still if nothing is needed for that architecture.
>>>
>>> Then that should be the default.  You might argue we'll only see
>>> __builtin_speculation_safe_value uses for things like Firefox which
>>> is unlikely built for AVR (just to make an example).  But people
>>> are going to test build just on x86 and if they build with -Werror
>>> this will break builds on all targets that didn't even get the chance
>>> to implement this feature.
>>>
>>>> There is a test which is intended to fail to targets that have not yet
>>>> been patched - I thought that was better than hard-failing the build,
>>>> especially given that we want to back-port.
>>>>
>>>> Port maintainers DO need to decide what to do about speculation, even if
>>>> it is explicitly that no mitigation is needed.
>>>
>>> Agreed.  But I didn't yet see a request for maintainers to decide that?
>>>
>>
>> consider it made, then :-)
> 
> I suspect that drew their attention ;)
> 
> So a different idea would be to produce patches implementing the hook for
> each target "empty", CC the target maintainers and hope they quickly
> ack if the target doesn't have a speculation problem.  Others then would
> get no patch (from you) and thus raise a warning?
> 
> Maybe at least do that for all primary and secondary targets given we do
> not want to regress diagnostic-wise (not get new _false_-positives) on
> the branch.
> 
>>>>>
>>>>> The builtins also have no attributes which mean they are assumed to be
>>>>> 1) calling back into the CU via exported functions, 2) possibly throwing
>>>>> exceptions, 3) affecting memory state.  I think you at least want
>>>>> to use ATTR_NOTHROW_LEAF_LIST.
>>>>>
>>>>> The builtins are not designed to be optimization or memory barriers as
>>>>> far as I can see and should thus be CONST as well.
>>>>>
>>>>
>>>> I think they should be barriers.  They do need to ensure that they can't
>>>> be moved past other operations that might depend on the speculation
>>>> state.  Consider, for example,
>>>
>>> That makes eliding them for targets that do not need mitigation even
>>> more important.
>>>
>>>>  ...
>>>>  t = untrusted_value;
>>>>  ...
>>>>  if (t + 5 < limit)
>>>>  {
>>>>    v = mem[__builtin_speculation_safe_value (untrusted_value)];
>>>>    ...
>>>>
>>>> The compiler must never lift the builtin outside the bounds check as
>>>> that is part of the speculation state.
>>>
>>> OK, so you are relying on the fact that with the current setup GCC has
>>> to assume the builtin has side-effects (GCC may not move it to a place that
>>> the original location is not post-dominated on).  It doesn't explain
>>> why you cannot set ECF_LEAF or why the builtin needs to be
>>> considered affecting the memory state.  That is, ECF_NOVOPS
>>> or ECF_LOOPING_CONST_OR_PURE (I don't think you can
>>> set that manually) would work here, both keep the builtin as
>>> having side-effects.
>>>
>>
>> I wish some of this builtin gloop were better documented; at present you
>> have to reverse engineer significant amounts of code just to decide
>> whether or not you even have to think about whether or not it's relevant...
>>
>>
>>> Btw, if you have an inline function with a pattern like above and
>>> you use it multiple times in a row GCC should be able to
>>> optimize this?  That is, optimizations like jump-threading also
>>> affect the speculation state by modifying the controling
>>> conditions.
>>
>> Ideally, if there's no control flow change, yes.  As soon as you insert
>> another branch (in or out) then you might have another speculation path
>> to consider.  Not sure how that can easily merging could be done, though.
> 
> The usual case would be
> 
>   if (cond)
>    ... _b_s_s_v (x);
> <code>
>   if (cond)
>     ... _b_s_s_v (x);
> 
> where jump-threading might decide to make that to
> 
>   if (cond)
>    {
>      ... _b_s_s_v (x);
>      <copy of code>
>      ... _b_s_s_v (x);
>    }
> 
> now we might even be able to CSE the 2nd _b_s_s_v (x)
> to the first?  That would mean using ECF_CONST|ECF_LOOPING_PURE_OR_CONST
> is the best (but we currently have no attribute for the latter).
> 
>>>
>>> You didn't answer my question about "what about C++"?
>>>
>>
>> It didn't need a response at this point.  It's a reasonable one, as are
>> some of your others...  I was focusing on the the comments that were
>> potentially contentious.
>>
>> BTW, this bit:
>>
>> +    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);
>>
>>> resolve_size does that?  Why can that not return the built_in_function
>>> itself or BUILT_IN_NONE on error to make that clearer?
>>
>> is essentially a clone of some existing code that already does it this
>> way.  See BUILT_IN_SYNC_LOCK_RELEASE_N etc.  Admittedly, that hunk
>> handles multiple origins so would be harder to rewrite as you suggest;
>> it just seemed more appropriate to handle the cases similarly.
> 
> Yes, I realized you copied handling from that so I didn't look too closely...
> 
> These days we'd probably use an internal-function and spare us all
> the resolving completely (besides a test for validity) ;)
> 
> Richard.
> 
>> R.
>>
>>> Richard.
>>>
>>>>
>>>>
>>>>> BUILT_IN_SPECULATION_SAFE_VALUE_PTR is declared but
>>>>> nowhere generated?  Maybe
>>>>>
>>>>> +    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);
>>>>>
>>>>> resolve_size does that?  Why can that not return the built_in_function
>>>>> itself or BUILT_IN_NONE on error to make that clearer?
>>>>>
>>>>> Otherwise it looks reasonable but C FE maintainers should comment.
>>>>> I miss C++ testcases (or rather testcases should be in c-c++-common).
>>>>>
>>>>> Richard.
>>>>>
>>>>>> 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
>>>>>>
>>>>
>>

Here's an updated version of this patch, based on these discussions.
Notable changes since last time:
- __HAVE_SPECULATION_SAFE_VALUE is now only defined if the target has
been updated for this feature.
- Warnings are only issued if the builtin is used when
__HAVE_SPECULATION_SAFE_VALUE is not defined (so the builtin will always
generate a workable program, it just might not be protected in this case).
- Some of the tests moved to c-c++-common to improve C++ testing.
- The builtin is elided early on targets that do not need, or do not
provide a specific means to restrict speculative execution.

A full bootstrap has completed, but tests are still running.

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 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.

[-- Attachment #2: nospec.patch --]
[-- Type: text/x-diff, Size: 26382 bytes --]

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 839a818..40183fb 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -6881,6 +6881,52 @@ inline_expand_builtin_string_cmp (tree exp, rtx target, bool is_memcmp)
 			    const_str_n, mode, is_memcmp);
 }
 
+/* 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).
@@ -7992,6 +8038,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..6e8af2a 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -1003,6 +1003,28 @@ 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_NOTHROW_LEAF_LIST)
+
+DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_PTR,
+		 "speculation_safe_value_ptr", BT_FN_PTR_PTR_VAR,
+		 ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_1, "speculation_safe_value_1",
+		 BT_FN_I1_I1_VAR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_2, "speculation_safe_value_2",
+		 BT_FN_I2_I2_VAR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_4, "speculation_safe_value_4",
+		 BT_FN_I4_I4_VAR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_8, "speculation_safe_value_8",
+		 BT_FN_I8_I8_VAR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_16,
+		 "speculation_safe_value_16", BT_FN_I16_I16_VAR,
+		 ATTR_NOTHROW_LEAF_LIST)
+
 /* 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..e368fd2 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");
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 954e8a1..0ba1931 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10948,6 +10948,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
@@ -11592,6 +11593,96 @@ 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 built-in function 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.
+
+GCC defines the preprocessor macro
+@code{__HAVE_BUILTIN_SPECULATION_SAFE_VALUE} for targets that have been
+updated to support this builtin.
+
+The built-in function can be used where a variable appears to be used in a
+safe way, but the CPU, due to speculative execution may temporarily ignore
+the bounds checks.  Consider, for example, the following function:
+
+@smallexample
+int array[500];
+int f (unsigned untrusted_index)
+@{
+  if (untrusted_index < 500)
+    return array[untrusted_index];
+  return 0;
+@}
+@end smallexample
+
+If the function is called repeatedly with @code{untrusted_index} less
+than the limit of 500, then a branch predictor will learn that the
+block of code that returns a value stored in @code{array} will be
+executed.  If the function is subsequently called with an
+out-of-range value it will still try to execute that block of code
+first until the CPU determines that the prediction was incorrect
+(the CPU will unwind any incorrect operations at that point).
+However, depending on how the result of the function is used, it might be
+possible to leave traces in the cache that can reveal what was stored
+at the out-of-bounds location.  The built-in function can be used to
+provide some protection against leaking data in this way by changing
+the code to:
+
+@smallexample
+int array[500];
+int f (unsigned untrusted_index)
+@{
+  if (untrusted_index < 500)
+    return array[__builtin_speculation_safe_value (untrusted_index)];
+  return 0;
+@}
+@end smallexample
+
+The built-in function will either cause execution to stall until the
+conditional branch has been fully resolved, or it may permit
+speculative execution to continue, but using 0 instead of
+@code{untrusted_value} if that exceeds the limit.
+
+If accessing any memory location is potentially unsafe when speculative
+execution is incorrect, then the code can be rewritten as
+
+@smallexample
+int array[500];
+int f (unsigned untrusted_index)
+@{
+  if (untrusted_index < 500)
+    return *__builtin_speculation_safe_value (&array[untrusted_index], NULL);
+  return 0;
+@}
+@end smallexample
+
+which will cause a @code{NULL} pointer to be used for the unsafe case.
+
+@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 734bc76..00c1239 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -7032,6 +7032,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 ff6d514..ee3f55c 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -11948,6 +11948,36 @@ maintainer is familiar with.
 
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_SPECULATION_SAFE_VALUE (bool @var{active})
+This hook is used to determine the level of target support for
+ @code{__builtin_speculation_safe_value}.  If called with an argument
+ of false, it returns true if the target has been modified to support
+ this builtin.  If called with an argument of true, it returns true
+ if the target requires active mitigation execution might be speculative.
+ 
+ The default implementation returns true for the first case if the target
+ defines a pattern named @code{speculation_barrier}; for the second case
+ and if the pattern is enabled for the current compilation.
+@end deftypefn
+
+@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.
+@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 2f97151..94ad868 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -8109,4 +8109,8 @@ maintainer is familiar with.
 
 @end defmac
 
+@hook TARGET_HAVE_SPECULATION_SAFE_VALUE
+
+@hook TARGET_SPECULATION_SAFE_VALUE
+
 @hook TARGET_RUN_TARGET_SELFTESTS
diff --git a/gcc/target.def b/gcc/target.def
index ff89e72..3a9de78 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4196,6 +4196,40 @@ DEFHOOK
  hook_bool_void_true)
 
 DEFHOOK
+(have_speculation_safe_value,
+"This hook is used to determine the level of target support for\n\
+ @code{__builtin_speculation_safe_value}.  If called with an argument\n\
+ of false, it returns true if the target has been modified to support\n\
+ this builtin.  If called with an argument of true, it returns true\n\
+ if the target requires active mitigation execution might be speculative.\n\
+ \n\
+ The default implementation returns true for the first case if the target\n\
+ defines a pattern named @code{speculation_barrier}; for the second case\n\
+ and if the pattern is enabled for the current compilation.",
+bool, (bool active), default_have_speculation_safe_value)
+
+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.",
+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 9b06d7a..06de1e3 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -2314,4 +2314,36 @@ default_preferred_else_value (unsigned, tree type, unsigned, tree *)
   return build_zero_cst (type);
 }
 
+/* Default implementation of TARGET_HAVE_SPECULATION_SAFE_VALUE.  */
+bool
+default_have_speculation_safe_value (bool active)
+{
+#ifdef HAVE_speculation_barrier
+  return active ? HAVE_speculation_barrier : true;
+#else
+  return false;
+#endif
+}
+
+/* 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.  */
+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 ());
+#endif
+
+  return result;
+}
+
 #include "gt-targhooks.h"
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 8d234cf..74ffe5f 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -285,4 +285,7 @@ extern bool default_stack_clash_protection_final_dynamic_probe (rtx);
 extern void default_select_early_remat_modes (sbitmap);
 extern tree default_preferred_else_value (unsigned, tree, unsigned, tree *);
 
+extern bool default_have_speculation_safe_value (bool);
+extern rtx default_speculation_safe_value (machine_mode, rtx, rtx, rtx);
+
 #endif /* GCC_TARGHOOKS_H */
diff --git a/gcc/testsuite/c-c++-common/spec-barrier-1.c b/gcc/testsuite/c-c++-common/spec-barrier-1.c
new file mode 100644
index 0000000..e4b44f2
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/spec-barrier-1.c
@@ -0,0 +1,38 @@
+/* { 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
+
+int main ()
+{
+  if (__builtin_speculation_safe_value (a) != 1)
+    __builtin_abort ();
+  if (__builtin_speculation_safe_value (b) != 2)
+    __builtin_abort ();
+  if (__builtin_speculation_safe_value (c) != 3)
+    __builtin_abort ();
+  if (__builtin_speculation_safe_value (d) != 4)
+    __builtin_abort ();
+  if (__builtin_speculation_safe_value (e) != 5)
+    __builtin_abort ();
+  if (__builtin_speculation_safe_value (f) != &c)
+    __builtin_abort ();
+#ifdef __SIZEOF_INT128__
+  if (__builtin_speculation_safe_value (g) != 9)
+    __builtin_abort ();
+#endif
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/spec-barrier-2.c b/gcc/testsuite/c-c++-common/spec-barrier-2.c
new file mode 100644
index 0000000..b09567e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/spec-barrier-2.c
@@ -0,0 +1,17 @@
+/* { 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;
+
+int main ()
+{
+  int z = __builtin_speculation_safe_value (x, y++);
+  if (z != 3 || y != 10)
+    __builtin_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;" } */

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 1/7] Add __builtin_speculation_safe_value
  2018-07-26 10:03             ` Richard Earnshaw (lists)
@ 2018-07-26 12:41               ` Richard Biener
  2018-07-26 13:06                 ` Richard Earnshaw (lists)
  0 siblings, 1 reply; 82+ messages in thread
From: Richard Biener @ 2018-07-26 12:41 UTC (permalink / raw)
  To: Richard Earnshaw; +Cc: GCC Patches

On Thu, Jul 26, 2018 at 12:03 PM Richard Earnshaw (lists)
<Richard.Earnshaw@arm.com> wrote:
>
> On 25/07/18 14:47, Richard Biener wrote:
> > On Wed, Jul 25, 2018 at 2:41 PM Richard Earnshaw (lists)
> > <Richard.Earnshaw@arm.com> wrote:
> >>
> >> On 25/07/18 11:36, Richard Biener wrote:
> >>> On Wed, Jul 25, 2018 at 11:49 AM Richard Earnshaw (lists)
> >>> <Richard.Earnshaw@arm.com> wrote:
> >>>>
> >>>> On 24/07/18 18:26, Richard Biener wrote:
> >>>>> On Mon, Jul 9, 2018 at 6:40 PM Richard Earnshaw
> >>>>> <Richard.Earnshaw@arm.com> 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.
> >>>>>
> >>>>> So given this series is supposed to be backported I question
> >>>>>
> >>>>> +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;
> >>>>>
> >>>>> which makes all but aarch64 archs warn on __bultin_speculation_safe_value
> >>>>> uses, even those that do not suffer from Spectre like all those embedded targets
> >>>>> where implementations usually do not speculate at all.
> >>>>>
> >>>>> In fact for those targets the builtin stays in the way of optimization on GIMPLE
> >>>>> as well so we should fold it away early if neither the target hook is
> >>>>> implemented
> >>>>> nor there is a speculation_barrier insn.
> >>>>>
> >>>>> So, please make resolve_overloaded_builtin return a no-op on such targets
> >>>>> which means you can remove the above warning.  Maybe such targets
> >>>>> shouldn't advertise / initialize the builtins at all?
> >>>>
> >>>> I disagree with your approach here.  Why would users not want to know
> >>>> when the compiler is failing to implement a security feature when it
> >>>> should?  As for targets that don't need something, they can easily
> >>>> define the hook as described to suppress the warning.
> >>>>
> >>>> Or are you just suggesting moving the warning to resolve overloaded builtin.
> >>>
> >>> Well.  You could argue I say we shouldn't even support
> >>> __builtin_sepeculation_safe_value
> >>> for archs that do not need it or have it not implemented.  That way users can
> >>> decide:
> >>>
> >>> #if __HAVE_SPECULATION_SAFE_VALUE
> >>>  ....
> >>> #else
> >>> #warning oops // or nothing
> >>> #endif
> >>>
> >>
> >> So how about removing the predefine of __HAVE_S_S_V when the builtin is
> >> a nop, but then leaving the warning in if people try to use it anyway?
> >
> > Little bit inconsistent but I guess I could live with that.  It still leaves
> > the question open for how to declare you do not need speculation
> > barriers at all then.
> >
> >>>> Other ports will need to take action, but in general, it can be as
> >>>> simple as, eg patch 2 or 3 do for the Arm and AArch64 backends - or
> >>>> simpler still if nothing is needed for that architecture.
> >>>
> >>> Then that should be the default.  You might argue we'll only see
> >>> __builtin_speculation_safe_value uses for things like Firefox which
> >>> is unlikely built for AVR (just to make an example).  But people
> >>> are going to test build just on x86 and if they build with -Werror
> >>> this will break builds on all targets that didn't even get the chance
> >>> to implement this feature.
> >>>
> >>>> There is a test which is intended to fail to targets that have not yet
> >>>> been patched - I thought that was better than hard-failing the build,
> >>>> especially given that we want to back-port.
> >>>>
> >>>> Port maintainers DO need to decide what to do about speculation, even if
> >>>> it is explicitly that no mitigation is needed.
> >>>
> >>> Agreed.  But I didn't yet see a request for maintainers to decide that?
> >>>
> >>
> >> consider it made, then :-)
> >
> > I suspect that drew their attention ;)
> >
> > So a different idea would be to produce patches implementing the hook for
> > each target "empty", CC the target maintainers and hope they quickly
> > ack if the target doesn't have a speculation problem.  Others then would
> > get no patch (from you) and thus raise a warning?
> >
> > Maybe at least do that for all primary and secondary targets given we do
> > not want to regress diagnostic-wise (not get new _false_-positives) on
> > the branch.
> >
> >>>>>
> >>>>> The builtins also have no attributes which mean they are assumed to be
> >>>>> 1) calling back into the CU via exported functions, 2) possibly throwing
> >>>>> exceptions, 3) affecting memory state.  I think you at least want
> >>>>> to use ATTR_NOTHROW_LEAF_LIST.
> >>>>>
> >>>>> The builtins are not designed to be optimization or memory barriers as
> >>>>> far as I can see and should thus be CONST as well.
> >>>>>
> >>>>
> >>>> I think they should be barriers.  They do need to ensure that they can't
> >>>> be moved past other operations that might depend on the speculation
> >>>> state.  Consider, for example,
> >>>
> >>> That makes eliding them for targets that do not need mitigation even
> >>> more important.
> >>>
> >>>>  ...
> >>>>  t = untrusted_value;
> >>>>  ...
> >>>>  if (t + 5 < limit)
> >>>>  {
> >>>>    v = mem[__builtin_speculation_safe_value (untrusted_value)];
> >>>>    ...
> >>>>
> >>>> The compiler must never lift the builtin outside the bounds check as
> >>>> that is part of the speculation state.
> >>>
> >>> OK, so you are relying on the fact that with the current setup GCC has
> >>> to assume the builtin has side-effects (GCC may not move it to a place that
> >>> the original location is not post-dominated on).  It doesn't explain
> >>> why you cannot set ECF_LEAF or why the builtin needs to be
> >>> considered affecting the memory state.  That is, ECF_NOVOPS
> >>> or ECF_LOOPING_CONST_OR_PURE (I don't think you can
> >>> set that manually) would work here, both keep the builtin as
> >>> having side-effects.
> >>>
> >>
> >> I wish some of this builtin gloop were better documented; at present you
> >> have to reverse engineer significant amounts of code just to decide
> >> whether or not you even have to think about whether or not it's relevant...
> >>
> >>
> >>> Btw, if you have an inline function with a pattern like above and
> >>> you use it multiple times in a row GCC should be able to
> >>> optimize this?  That is, optimizations like jump-threading also
> >>> affect the speculation state by modifying the controling
> >>> conditions.
> >>
> >> Ideally, if there's no control flow change, yes.  As soon as you insert
> >> another branch (in or out) then you might have another speculation path
> >> to consider.  Not sure how that can easily merging could be done, though.
> >
> > The usual case would be
> >
> >   if (cond)
> >    ... _b_s_s_v (x);
> > <code>
> >   if (cond)
> >     ... _b_s_s_v (x);
> >
> > where jump-threading might decide to make that to
> >
> >   if (cond)
> >    {
> >      ... _b_s_s_v (x);
> >      <copy of code>
> >      ... _b_s_s_v (x);
> >    }
> >
> > now we might even be able to CSE the 2nd _b_s_s_v (x)
> > to the first?  That would mean using ECF_CONST|ECF_LOOPING_PURE_OR_CONST
> > is the best (but we currently have no attribute for the latter).
> >
> >>>
> >>> You didn't answer my question about "what about C++"?
> >>>
> >>
> >> It didn't need a response at this point.  It's a reasonable one, as are
> >> some of your others...  I was focusing on the the comments that were
> >> potentially contentious.
> >>
> >> BTW, this bit:
> >>
> >> +    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);
> >>
> >>> resolve_size does that?  Why can that not return the built_in_function
> >>> itself or BUILT_IN_NONE on error to make that clearer?
> >>
> >> is essentially a clone of some existing code that already does it this
> >> way.  See BUILT_IN_SYNC_LOCK_RELEASE_N etc.  Admittedly, that hunk
> >> handles multiple origins so would be harder to rewrite as you suggest;
> >> it just seemed more appropriate to handle the cases similarly.
> >
> > Yes, I realized you copied handling from that so I didn't look too closely...
> >
> > These days we'd probably use an internal-function and spare us all
> > the resolving completely (besides a test for validity) ;)
> >
> > Richard.
> >
> >> R.
> >>
> >>> Richard.
> >>>
> >>>>
> >>>>
> >>>>> BUILT_IN_SPECULATION_SAFE_VALUE_PTR is declared but
> >>>>> nowhere generated?  Maybe
> >>>>>
> >>>>> +    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);
> >>>>>
> >>>>> resolve_size does that?  Why can that not return the built_in_function
> >>>>> itself or BUILT_IN_NONE on error to make that clearer?
> >>>>>
> >>>>> Otherwise it looks reasonable but C FE maintainers should comment.
> >>>>> I miss C++ testcases (or rather testcases should be in c-c++-common).
> >>>>>
> >>>>> Richard.
> >>>>>
> >>>>>> 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
> >>>>>>
> >>>>
> >>
>
> Here's an updated version of this patch, based on these discussions.
> Notable changes since last time:
> - __HAVE_SPECULATION_SAFE_VALUE is now only defined if the target has
> been updated for this feature.
> - Warnings are only issued if the builtin is used when
> __HAVE_SPECULATION_SAFE_VALUE is not defined (so the builtin will always
> generate a workable program, it just might not be protected in this case).
> - Some of the tests moved to c-c++-common to improve C++ testing.
> - The builtin is elided early on targets that do not need, or do not
> provide a specific means to restrict speculative execution.
>
> A full bootstrap has completed, but tests are still running.

Please make the builtins NOVOPS as well by adding

DEF_ATTR_TREE_LIST (ATTR_NOVOPS_NOTHROW_LEAF_LIST, ATTR_NOVOPS,
ATTR_NULL, ATTR_NOTHROW_LEAF_LIST)

to builtin-attrs.def and using that.

+ The default implementation returns true for the first case if the target
+ defines a pattern named @code{speculation_barrier}; for the second case
+ and if the pattern is enabled for the current compilation.
+@end deftypefn

I do not understand the last sentence.  I suspect it shold be

"The default implementation returns false if the target does not define
a pattern named @code{speculation_barrier}.  Else it returns true
for the first case and whether the pattern is enabled for the current
compilation for the second case."

Otherwise the middle-end changes look OK to me.  The c-family changes
need review by a appropriate maintainer still.

Thanks,
Richard.

> 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 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.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 1/7] Add __builtin_speculation_safe_value
  2018-07-26 12:41               ` Richard Biener
@ 2018-07-26 13:06                 ` Richard Earnshaw (lists)
  2018-07-26 13:13                   ` Richard Biener
  0 siblings, 1 reply; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-07-26 13:06 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches

On 26/07/18 13:41, Richard Biener wrote:
> On Thu, Jul 26, 2018 at 12:03 PM Richard Earnshaw (lists)
> <Richard.Earnshaw@arm.com> wrote:
>>
>> On 25/07/18 14:47, Richard Biener wrote:
>>> On Wed, Jul 25, 2018 at 2:41 PM Richard Earnshaw (lists)
>>> <Richard.Earnshaw@arm.com> wrote:
>>>>
>>>> On 25/07/18 11:36, Richard Biener wrote:
>>>>> On Wed, Jul 25, 2018 at 11:49 AM Richard Earnshaw (lists)
>>>>> <Richard.Earnshaw@arm.com> wrote:
>>>>>>
>>>>>> On 24/07/18 18:26, Richard Biener wrote:
>>>>>>> On Mon, Jul 9, 2018 at 6:40 PM Richard Earnshaw
>>>>>>> <Richard.Earnshaw@arm.com> 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.
>>>>>>>
>>>>>>> So given this series is supposed to be backported I question
>>>>>>>
>>>>>>> +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;
>>>>>>>
>>>>>>> which makes all but aarch64 archs warn on __bultin_speculation_safe_value
>>>>>>> uses, even those that do not suffer from Spectre like all those embedded targets
>>>>>>> where implementations usually do not speculate at all.
>>>>>>>
>>>>>>> In fact for those targets the builtin stays in the way of optimization on GIMPLE
>>>>>>> as well so we should fold it away early if neither the target hook is
>>>>>>> implemented
>>>>>>> nor there is a speculation_barrier insn.
>>>>>>>
>>>>>>> So, please make resolve_overloaded_builtin return a no-op on such targets
>>>>>>> which means you can remove the above warning.  Maybe such targets
>>>>>>> shouldn't advertise / initialize the builtins at all?
>>>>>>
>>>>>> I disagree with your approach here.  Why would users not want to know
>>>>>> when the compiler is failing to implement a security feature when it
>>>>>> should?  As for targets that don't need something, they can easily
>>>>>> define the hook as described to suppress the warning.
>>>>>>
>>>>>> Or are you just suggesting moving the warning to resolve overloaded builtin.
>>>>>
>>>>> Well.  You could argue I say we shouldn't even support
>>>>> __builtin_sepeculation_safe_value
>>>>> for archs that do not need it or have it not implemented.  That way users can
>>>>> decide:
>>>>>
>>>>> #if __HAVE_SPECULATION_SAFE_VALUE
>>>>>  ....
>>>>> #else
>>>>> #warning oops // or nothing
>>>>> #endif
>>>>>
>>>>
>>>> So how about removing the predefine of __HAVE_S_S_V when the builtin is
>>>> a nop, but then leaving the warning in if people try to use it anyway?
>>>
>>> Little bit inconsistent but I guess I could live with that.  It still leaves
>>> the question open for how to declare you do not need speculation
>>> barriers at all then.
>>>
>>>>>> Other ports will need to take action, but in general, it can be as
>>>>>> simple as, eg patch 2 or 3 do for the Arm and AArch64 backends - or
>>>>>> simpler still if nothing is needed for that architecture.
>>>>>
>>>>> Then that should be the default.  You might argue we'll only see
>>>>> __builtin_speculation_safe_value uses for things like Firefox which
>>>>> is unlikely built for AVR (just to make an example).  But people
>>>>> are going to test build just on x86 and if they build with -Werror
>>>>> this will break builds on all targets that didn't even get the chance
>>>>> to implement this feature.
>>>>>
>>>>>> There is a test which is intended to fail to targets that have not yet
>>>>>> been patched - I thought that was better than hard-failing the build,
>>>>>> especially given that we want to back-port.
>>>>>>
>>>>>> Port maintainers DO need to decide what to do about speculation, even if
>>>>>> it is explicitly that no mitigation is needed.
>>>>>
>>>>> Agreed.  But I didn't yet see a request for maintainers to decide that?
>>>>>
>>>>
>>>> consider it made, then :-)
>>>
>>> I suspect that drew their attention ;)
>>>
>>> So a different idea would be to produce patches implementing the hook for
>>> each target "empty", CC the target maintainers and hope they quickly
>>> ack if the target doesn't have a speculation problem.  Others then would
>>> get no patch (from you) and thus raise a warning?
>>>
>>> Maybe at least do that for all primary and secondary targets given we do
>>> not want to regress diagnostic-wise (not get new _false_-positives) on
>>> the branch.
>>>
>>>>>>>
>>>>>>> The builtins also have no attributes which mean they are assumed to be
>>>>>>> 1) calling back into the CU via exported functions, 2) possibly throwing
>>>>>>> exceptions, 3) affecting memory state.  I think you at least want
>>>>>>> to use ATTR_NOTHROW_LEAF_LIST.
>>>>>>>
>>>>>>> The builtins are not designed to be optimization or memory barriers as
>>>>>>> far as I can see and should thus be CONST as well.
>>>>>>>
>>>>>>
>>>>>> I think they should be barriers.  They do need to ensure that they can't
>>>>>> be moved past other operations that might depend on the speculation
>>>>>> state.  Consider, for example,
>>>>>
>>>>> That makes eliding them for targets that do not need mitigation even
>>>>> more important.
>>>>>
>>>>>>  ...
>>>>>>  t = untrusted_value;
>>>>>>  ...
>>>>>>  if (t + 5 < limit)
>>>>>>  {
>>>>>>    v = mem[__builtin_speculation_safe_value (untrusted_value)];
>>>>>>    ...
>>>>>>
>>>>>> The compiler must never lift the builtin outside the bounds check as
>>>>>> that is part of the speculation state.
>>>>>
>>>>> OK, so you are relying on the fact that with the current setup GCC has
>>>>> to assume the builtin has side-effects (GCC may not move it to a place that
>>>>> the original location is not post-dominated on).  It doesn't explain
>>>>> why you cannot set ECF_LEAF or why the builtin needs to be
>>>>> considered affecting the memory state.  That is, ECF_NOVOPS
>>>>> or ECF_LOOPING_CONST_OR_PURE (I don't think you can
>>>>> set that manually) would work here, both keep the builtin as
>>>>> having side-effects.
>>>>>
>>>>
>>>> I wish some of this builtin gloop were better documented; at present you
>>>> have to reverse engineer significant amounts of code just to decide
>>>> whether or not you even have to think about whether or not it's relevant...
>>>>
>>>>
>>>>> Btw, if you have an inline function with a pattern like above and
>>>>> you use it multiple times in a row GCC should be able to
>>>>> optimize this?  That is, optimizations like jump-threading also
>>>>> affect the speculation state by modifying the controling
>>>>> conditions.
>>>>
>>>> Ideally, if there's no control flow change, yes.  As soon as you insert
>>>> another branch (in or out) then you might have another speculation path
>>>> to consider.  Not sure how that can easily merging could be done, though.
>>>
>>> The usual case would be
>>>
>>>   if (cond)
>>>    ... _b_s_s_v (x);
>>> <code>
>>>   if (cond)
>>>     ... _b_s_s_v (x);
>>>
>>> where jump-threading might decide to make that to
>>>
>>>   if (cond)
>>>    {
>>>      ... _b_s_s_v (x);
>>>      <copy of code>
>>>      ... _b_s_s_v (x);
>>>    }
>>>
>>> now we might even be able to CSE the 2nd _b_s_s_v (x)
>>> to the first?  That would mean using ECF_CONST|ECF_LOOPING_PURE_OR_CONST
>>> is the best (but we currently have no attribute for the latter).
>>>
>>>>>
>>>>> You didn't answer my question about "what about C++"?
>>>>>
>>>>
>>>> It didn't need a response at this point.  It's a reasonable one, as are
>>>> some of your others...  I was focusing on the the comments that were
>>>> potentially contentious.
>>>>
>>>> BTW, this bit:
>>>>
>>>> +    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);
>>>>
>>>>> resolve_size does that?  Why can that not return the built_in_function
>>>>> itself or BUILT_IN_NONE on error to make that clearer?
>>>>
>>>> is essentially a clone of some existing code that already does it this
>>>> way.  See BUILT_IN_SYNC_LOCK_RELEASE_N etc.  Admittedly, that hunk
>>>> handles multiple origins so would be harder to rewrite as you suggest;
>>>> it just seemed more appropriate to handle the cases similarly.
>>>
>>> Yes, I realized you copied handling from that so I didn't look too closely...
>>>
>>> These days we'd probably use an internal-function and spare us all
>>> the resolving completely (besides a test for validity) ;)
>>>
>>> Richard.
>>>
>>>> R.
>>>>
>>>>> Richard.
>>>>>
>>>>>>
>>>>>>
>>>>>>> BUILT_IN_SPECULATION_SAFE_VALUE_PTR is declared but
>>>>>>> nowhere generated?  Maybe
>>>>>>>
>>>>>>> +    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);
>>>>>>>
>>>>>>> resolve_size does that?  Why can that not return the built_in_function
>>>>>>> itself or BUILT_IN_NONE on error to make that clearer?
>>>>>>>
>>>>>>> Otherwise it looks reasonable but C FE maintainers should comment.
>>>>>>> I miss C++ testcases (or rather testcases should be in c-c++-common).
>>>>>>>
>>>>>>> Richard.
>>>>>>>
>>>>>>>> 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
>>>>>>>>
>>>>>>
>>>>
>>
>> Here's an updated version of this patch, based on these discussions.
>> Notable changes since last time:
>> - __HAVE_SPECULATION_SAFE_VALUE is now only defined if the target has
>> been updated for this feature.
>> - Warnings are only issued if the builtin is used when
>> __HAVE_SPECULATION_SAFE_VALUE is not defined (so the builtin will always
>> generate a workable program, it just might not be protected in this case).
>> - Some of the tests moved to c-c++-common to improve C++ testing.
>> - The builtin is elided early on targets that do not need, or do not
>> provide a specific means to restrict speculative execution.
>>
>> A full bootstrap has completed, but tests are still running.
> 
> Please make the builtins NOVOPS as well by adding
> 
> DEF_ATTR_TREE_LIST (ATTR_NOVOPS_NOTHROW_LEAF_LIST, ATTR_NOVOPS,
> ATTR_NULL, ATTR_NOTHROW_LEAF_LIST)
> 
> to builtin-attrs.def and using that.

This is an optimization right?  If so, can I defer that to a follow-up
patch?  Although the builtin doesn't touch memory, I need think very
carefully about whether or not it is safe to move other memory ops
across it.

> 
> + The default implementation returns true for the first case if the target
> + defines a pattern named @code{speculation_barrier}; for the second case
> + and if the pattern is enabled for the current compilation.
> +@end deftypefn
> 
> I do not understand the last sentence.  I suspect it shold be
> 
> "The default implementation returns false if the target does not define
> a pattern named @code{speculation_barrier}.  Else it returns true
> for the first case and whether the pattern is enabled for the current
> compilation for the second case."

Thanks, I like that wording better than mine.

R.

> 
> Otherwise the middle-end changes look OK to me.  The c-family changes
> need review by a appropriate maintainer still.
> 
> Thanks,
> Richard.
> 
>> 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 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.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 1/7] Add __builtin_speculation_safe_value
  2018-07-26 13:06                 ` Richard Earnshaw (lists)
@ 2018-07-26 13:13                   ` Richard Biener
  0 siblings, 0 replies; 82+ messages in thread
From: Richard Biener @ 2018-07-26 13:13 UTC (permalink / raw)
  To: Richard Earnshaw; +Cc: GCC Patches

On Thu, Jul 26, 2018 at 3:06 PM Richard Earnshaw (lists)
<Richard.Earnshaw@arm.com> wrote:
>
> On 26/07/18 13:41, Richard Biener wrote:
> > On Thu, Jul 26, 2018 at 12:03 PM Richard Earnshaw (lists)
> > <Richard.Earnshaw@arm.com> wrote:
> >>
> >> On 25/07/18 14:47, Richard Biener wrote:
> >>> On Wed, Jul 25, 2018 at 2:41 PM Richard Earnshaw (lists)
> >>> <Richard.Earnshaw@arm.com> wrote:
> >>>>
> >>>> On 25/07/18 11:36, Richard Biener wrote:
> >>>>> On Wed, Jul 25, 2018 at 11:49 AM Richard Earnshaw (lists)
> >>>>> <Richard.Earnshaw@arm.com> wrote:
> >>>>>>
> >>>>>> On 24/07/18 18:26, Richard Biener wrote:
> >>>>>>> On Mon, Jul 9, 2018 at 6:40 PM Richard Earnshaw
> >>>>>>> <Richard.Earnshaw@arm.com> 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.
> >>>>>>>
> >>>>>>> So given this series is supposed to be backported I question
> >>>>>>>
> >>>>>>> +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;
> >>>>>>>
> >>>>>>> which makes all but aarch64 archs warn on __bultin_speculation_safe_value
> >>>>>>> uses, even those that do not suffer from Spectre like all those embedded targets
> >>>>>>> where implementations usually do not speculate at all.
> >>>>>>>
> >>>>>>> In fact for those targets the builtin stays in the way of optimization on GIMPLE
> >>>>>>> as well so we should fold it away early if neither the target hook is
> >>>>>>> implemented
> >>>>>>> nor there is a speculation_barrier insn.
> >>>>>>>
> >>>>>>> So, please make resolve_overloaded_builtin return a no-op on such targets
> >>>>>>> which means you can remove the above warning.  Maybe such targets
> >>>>>>> shouldn't advertise / initialize the builtins at all?
> >>>>>>
> >>>>>> I disagree with your approach here.  Why would users not want to know
> >>>>>> when the compiler is failing to implement a security feature when it
> >>>>>> should?  As for targets that don't need something, they can easily
> >>>>>> define the hook as described to suppress the warning.
> >>>>>>
> >>>>>> Or are you just suggesting moving the warning to resolve overloaded builtin.
> >>>>>
> >>>>> Well.  You could argue I say we shouldn't even support
> >>>>> __builtin_sepeculation_safe_value
> >>>>> for archs that do not need it or have it not implemented.  That way users can
> >>>>> decide:
> >>>>>
> >>>>> #if __HAVE_SPECULATION_SAFE_VALUE
> >>>>>  ....
> >>>>> #else
> >>>>> #warning oops // or nothing
> >>>>> #endif
> >>>>>
> >>>>
> >>>> So how about removing the predefine of __HAVE_S_S_V when the builtin is
> >>>> a nop, but then leaving the warning in if people try to use it anyway?
> >>>
> >>> Little bit inconsistent but I guess I could live with that.  It still leaves
> >>> the question open for how to declare you do not need speculation
> >>> barriers at all then.
> >>>
> >>>>>> Other ports will need to take action, but in general, it can be as
> >>>>>> simple as, eg patch 2 or 3 do for the Arm and AArch64 backends - or
> >>>>>> simpler still if nothing is needed for that architecture.
> >>>>>
> >>>>> Then that should be the default.  You might argue we'll only see
> >>>>> __builtin_speculation_safe_value uses for things like Firefox which
> >>>>> is unlikely built for AVR (just to make an example).  But people
> >>>>> are going to test build just on x86 and if they build with -Werror
> >>>>> this will break builds on all targets that didn't even get the chance
> >>>>> to implement this feature.
> >>>>>
> >>>>>> There is a test which is intended to fail to targets that have not yet
> >>>>>> been patched - I thought that was better than hard-failing the build,
> >>>>>> especially given that we want to back-port.
> >>>>>>
> >>>>>> Port maintainers DO need to decide what to do about speculation, even if
> >>>>>> it is explicitly that no mitigation is needed.
> >>>>>
> >>>>> Agreed.  But I didn't yet see a request for maintainers to decide that?
> >>>>>
> >>>>
> >>>> consider it made, then :-)
> >>>
> >>> I suspect that drew their attention ;)
> >>>
> >>> So a different idea would be to produce patches implementing the hook for
> >>> each target "empty", CC the target maintainers and hope they quickly
> >>> ack if the target doesn't have a speculation problem.  Others then would
> >>> get no patch (from you) and thus raise a warning?
> >>>
> >>> Maybe at least do that for all primary and secondary targets given we do
> >>> not want to regress diagnostic-wise (not get new _false_-positives) on
> >>> the branch.
> >>>
> >>>>>>>
> >>>>>>> The builtins also have no attributes which mean they are assumed to be
> >>>>>>> 1) calling back into the CU via exported functions, 2) possibly throwing
> >>>>>>> exceptions, 3) affecting memory state.  I think you at least want
> >>>>>>> to use ATTR_NOTHROW_LEAF_LIST.
> >>>>>>>
> >>>>>>> The builtins are not designed to be optimization or memory barriers as
> >>>>>>> far as I can see and should thus be CONST as well.
> >>>>>>>
> >>>>>>
> >>>>>> I think they should be barriers.  They do need to ensure that they can't
> >>>>>> be moved past other operations that might depend on the speculation
> >>>>>> state.  Consider, for example,
> >>>>>
> >>>>> That makes eliding them for targets that do not need mitigation even
> >>>>> more important.
> >>>>>
> >>>>>>  ...
> >>>>>>  t = untrusted_value;
> >>>>>>  ...
> >>>>>>  if (t + 5 < limit)
> >>>>>>  {
> >>>>>>    v = mem[__builtin_speculation_safe_value (untrusted_value)];
> >>>>>>    ...
> >>>>>>
> >>>>>> The compiler must never lift the builtin outside the bounds check as
> >>>>>> that is part of the speculation state.
> >>>>>
> >>>>> OK, so you are relying on the fact that with the current setup GCC has
> >>>>> to assume the builtin has side-effects (GCC may not move it to a place that
> >>>>> the original location is not post-dominated on).  It doesn't explain
> >>>>> why you cannot set ECF_LEAF or why the builtin needs to be
> >>>>> considered affecting the memory state.  That is, ECF_NOVOPS
> >>>>> or ECF_LOOPING_CONST_OR_PURE (I don't think you can
> >>>>> set that manually) would work here, both keep the builtin as
> >>>>> having side-effects.
> >>>>>
> >>>>
> >>>> I wish some of this builtin gloop were better documented; at present you
> >>>> have to reverse engineer significant amounts of code just to decide
> >>>> whether or not you even have to think about whether or not it's relevant...
> >>>>
> >>>>
> >>>>> Btw, if you have an inline function with a pattern like above and
> >>>>> you use it multiple times in a row GCC should be able to
> >>>>> optimize this?  That is, optimizations like jump-threading also
> >>>>> affect the speculation state by modifying the controling
> >>>>> conditions.
> >>>>
> >>>> Ideally, if there's no control flow change, yes.  As soon as you insert
> >>>> another branch (in or out) then you might have another speculation path
> >>>> to consider.  Not sure how that can easily merging could be done, though.
> >>>
> >>> The usual case would be
> >>>
> >>>   if (cond)
> >>>    ... _b_s_s_v (x);
> >>> <code>
> >>>   if (cond)
> >>>     ... _b_s_s_v (x);
> >>>
> >>> where jump-threading might decide to make that to
> >>>
> >>>   if (cond)
> >>>    {
> >>>      ... _b_s_s_v (x);
> >>>      <copy of code>
> >>>      ... _b_s_s_v (x);
> >>>    }
> >>>
> >>> now we might even be able to CSE the 2nd _b_s_s_v (x)
> >>> to the first?  That would mean using ECF_CONST|ECF_LOOPING_PURE_OR_CONST
> >>> is the best (but we currently have no attribute for the latter).
> >>>
> >>>>>
> >>>>> You didn't answer my question about "what about C++"?
> >>>>>
> >>>>
> >>>> It didn't need a response at this point.  It's a reasonable one, as are
> >>>> some of your others...  I was focusing on the the comments that were
> >>>> potentially contentious.
> >>>>
> >>>> BTW, this bit:
> >>>>
> >>>> +    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);
> >>>>
> >>>>> resolve_size does that?  Why can that not return the built_in_function
> >>>>> itself or BUILT_IN_NONE on error to make that clearer?
> >>>>
> >>>> is essentially a clone of some existing code that already does it this
> >>>> way.  See BUILT_IN_SYNC_LOCK_RELEASE_N etc.  Admittedly, that hunk
> >>>> handles multiple origins so would be harder to rewrite as you suggest;
> >>>> it just seemed more appropriate to handle the cases similarly.
> >>>
> >>> Yes, I realized you copied handling from that so I didn't look too closely...
> >>>
> >>> These days we'd probably use an internal-function and spare us all
> >>> the resolving completely (besides a test for validity) ;)
> >>>
> >>> Richard.
> >>>
> >>>> R.
> >>>>
> >>>>> Richard.
> >>>>>
> >>>>>>
> >>>>>>
> >>>>>>> BUILT_IN_SPECULATION_SAFE_VALUE_PTR is declared but
> >>>>>>> nowhere generated?  Maybe
> >>>>>>>
> >>>>>>> +    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);
> >>>>>>>
> >>>>>>> resolve_size does that?  Why can that not return the built_in_function
> >>>>>>> itself or BUILT_IN_NONE on error to make that clearer?
> >>>>>>>
> >>>>>>> Otherwise it looks reasonable but C FE maintainers should comment.
> >>>>>>> I miss C++ testcases (or rather testcases should be in c-c++-common).
> >>>>>>>
> >>>>>>> Richard.
> >>>>>>>
> >>>>>>>> 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
> >>>>>>>>
> >>>>>>
> >>>>
> >>
> >> Here's an updated version of this patch, based on these discussions.
> >> Notable changes since last time:
> >> - __HAVE_SPECULATION_SAFE_VALUE is now only defined if the target has
> >> been updated for this feature.
> >> - Warnings are only issued if the builtin is used when
> >> __HAVE_SPECULATION_SAFE_VALUE is not defined (so the builtin will always
> >> generate a workable program, it just might not be protected in this case).
> >> - Some of the tests moved to c-c++-common to improve C++ testing.
> >> - The builtin is elided early on targets that do not need, or do not
> >> provide a specific means to restrict speculative execution.
> >>
> >> A full bootstrap has completed, but tests are still running.
> >
> > Please make the builtins NOVOPS as well by adding
> >
> > DEF_ATTR_TREE_LIST (ATTR_NOVOPS_NOTHROW_LEAF_LIST, ATTR_NOVOPS,
> > ATTR_NULL, ATTR_NOTHROW_LEAF_LIST)
> >
> > to builtin-attrs.def and using that.
>
> This is an optimization right?

So was adding LEAF and NOTHROW.

>  If so, can I defer that to a follow-up
> patch?  Although the builtin doesn't touch memory, I need think very
> carefully about whether or not it is safe to move other memory ops
> across it.

Well.  We cannot even DCE the thing if there is no use left of the result...
NOVOPS doesn't change that - we're still telling GCC that the builtin
has arbitrary non-memory side-effects.  But that's necessary to prevent
moving it to places where it wasn't executed before.

Throwing additional wrenches into the machiner in terms of making
the compiler think it has changes on escaped(!) memory state doesn't help,
it will just hide bugs.  Being not NOVOPS doesn't mean it is a
barrer for every memory access.

Richard.

> >
> > + The default implementation returns true for the first case if the target
> > + defines a pattern named @code{speculation_barrier}; for the second case
> > + and if the pattern is enabled for the current compilation.
> > +@end deftypefn
> >
> > I do not understand the last sentence.  I suspect it shold be
> >
> > "The default implementation returns false if the target does not define
> > a pattern named @code{speculation_barrier}.  Else it returns true
> > for the first case and whether the pattern is enabled for the current
> > compilation for the second case."
>
> Thanks, I like that wording better than mine.
>
> R.
>
> >
> > Otherwise the middle-end changes look OK to me.  The c-family changes
> > need review by a appropriate maintainer still.
> >
> > Thanks,
> > Richard.
> >
> >> 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 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.
>

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 1/7] Add __builtin_speculation_safe_value
  2018-07-25 12:41         ` Richard Earnshaw (lists)
  2018-07-25 13:47           ` Richard Biener
@ 2018-07-26 23:34           ` Joseph Myers
  2018-07-27  0:46             ` Paul Koning
  1 sibling, 1 reply; 82+ messages in thread
From: Joseph Myers @ 2018-07-26 23:34 UTC (permalink / raw)
  To: Richard Earnshaw (lists); +Cc: Richard Biener, GCC Patches

On Wed, 25 Jul 2018, Richard Earnshaw (lists) wrote:

> >> Port maintainers DO need to decide what to do about speculation, even if
> >> it is explicitly that no mitigation is needed.
> > 
> > Agreed.  But I didn't yet see a request for maintainers to decide that?
> > 
> 
> consider it made, then :-)

I suggest the following as an appropriate process for anything needing 
attention from architecture maintainers:

* Send a message to the gcc list, starting its own thread, CC:ed to all 
target architecture maintainers, stating explicitly in its first sentence 
that it is about something needing action from all such maintainers.  The 
message needs to give all the information required for those maintainers 
to work out what is appropriate for their ports, or point to a wiki page 
with that information.  For example, the message must not assume 
maintainer familiarity with Spectre - it must give sufficient information 
for maintainers unfamiliar with Spectre to work out what to do with their 
ports.

* If the messages to any maintainers bounce, actively seek out alternative 
contact details for them or alternative people who might be interested in 
maintaining those ports.  Likewise, it's necessary to check for any ports 
that do not have a listed maintainer in the MAINTAINERS file and find 
appropriate contacts for those.

* Over the next few months, send occasional reminders, each including a 
list of the ports that have not been updated.

* No backport should be considered for anything that might involve 
breakage, e.g. warnings, for unchanged ports, until either all ports have 
been updated or at least several months have passed.

(Normally, a change needing architecture maintainer attention would be 
something for which backports are obviously inappropriate, e.g. a new C / 
C++ language feature requiring ABI decisions to be made for which there 
isn't an obvious default that can safely be applied to all architectures.)

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 1/7] Add __builtin_speculation_safe_value
  2018-07-26 23:34           ` Joseph Myers
@ 2018-07-27  0:46             ` Paul Koning
  2018-07-27  8:59               ` Richard Earnshaw (lists)
  0 siblings, 1 reply; 82+ messages in thread
From: Paul Koning @ 2018-07-27  0:46 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Richard Earnshaw (lists), Richard Biener, GCC Patches



> On Jul 26, 2018, at 7:34 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> 
> On Wed, 25 Jul 2018, Richard Earnshaw (lists) wrote:
> 
>>>> Port maintainers DO need to decide what to do about speculation, even if
>>>> it is explicitly that no mitigation is needed.
>>> 
>>> Agreed.  But I didn't yet see a request for maintainers to decide that?
>>> 
>> 
>> consider it made, then :-)
> 
> I suggest the following as an appropriate process for anything needing 
> attention from architecture maintainers:
> 
> * Send a message to the gcc list, starting its own thread, CC:ed to all 
> target architecture maintainers, stating explicitly in its first sentence 
> that it is about something needing action from all such maintainers.

Yes, because it was not clear to me that a patch discussion about a speculation builtin was something that every target maintainer was supposed to look at.  "Speculation" is not a term that shows up in my target...

> ...
> * Over the next few months, send occasional reminders, each including a 
> list of the ports that have not been updated.

Would the GCC Wiki be a good place to collect all the responses and track what is still open?  If not, what is a good way to do the tracking?

	paul

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 1/7] Add __builtin_speculation_safe_value
  2018-07-27  0:46             ` Paul Koning
@ 2018-07-27  8:59               ` Richard Earnshaw (lists)
  2018-07-27 10:59                 ` Joseph Myers
  0 siblings, 1 reply; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-07-27  8:59 UTC (permalink / raw)
  To: Paul Koning, Joseph Myers; +Cc: Richard Biener, GCC Patches

On 27/07/18 01:46, Paul Koning wrote:
> 
> 
>> On Jul 26, 2018, at 7:34 PM, Joseph Myers <joseph@codesourcery.com> wrote:
>>
>> On Wed, 25 Jul 2018, Richard Earnshaw (lists) wrote:
>>
>>>>> Port maintainers DO need to decide what to do about speculation, even if
>>>>> it is explicitly that no mitigation is needed.
>>>>
>>>> Agreed.  But I didn't yet see a request for maintainers to decide that?
>>>>
>>>
>>> consider it made, then :-)
>>
>> I suggest the following as an appropriate process for anything needing 
>> attention from architecture maintainers:
>>
>> * Send a message to the gcc list, starting its own thread, CC:ed to all 
>> target architecture maintainers, stating explicitly in its first sentence 
>> that it is about something needing action from all such maintainers.
> 
> Yes, because it was not clear to me that a patch discussion about a speculation builtin was something that every target maintainer was supposed to look at.  "Speculation" is not a term that shows up in my target...
> 
>> ...
>> * Over the next few months, send occasional reminders, each including a 
>> list of the ports that have not been updated.
> 
> Would the GCC Wiki be a good place to collect all the responses and track what is still open?  If not, what is a good way to do the tracking?
> 
> 	paul
> 

The c-c++-common/spec-barrier-1.c test will fail on any target that has
not been updated (it deliberately doesn't check for
__HAVE_SPECULATION_BARRIER before trying to use the new intrinsic).  The
test contains a comment to that effect.  That should be enough to alert
maintainers if they are tracking testsuite errors.

I'll be posting some examples for how to handle various types of target
shortly.  Target maintainers should then be able to decide which action
they need to take.

R.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 02/11] Arm - add speculation_barrier pattern
  2018-07-27  9:38 ` [PATCH 00/11] (v2) " Richard Earnshaw
                     ` (9 preceding siblings ...)
  2018-07-27  9:38   ` [PATCH 03/11] AArch64 - add speculation barrier Richard Earnshaw
@ 2018-07-27  9:38   ` Richard Earnshaw
  2018-08-06 14:01     ` Christophe Lyon
  2018-07-27 19:49   ` [PATCH 00/11] (v2) Mitigation against unsafe data speculation (CVE-2017-5753) John David Anglin
  11 siblings, 1 reply; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-27  9:38 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Earnshaw

[-- Attachment #1: Type: text/plain, Size: 351 bytes --]


This patch defines a speculation barrier for AArch32.

	* config/arm/unspecs.md (unspecv): Add VUNSPEC_SPECULATION_BARRIER.
	* config/arm/arm.md (speculation_barrier): New expand.
	(speculation_barrier_insn): New pattern.
---
 gcc/config/arm/arm.md     | 21 +++++++++++++++++++++
 gcc/config/arm/unspecs.md |  1 +
 2 files changed, 22 insertions(+)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0002-Arm-add-speculation_barrier-pattern.patch --]
[-- Type: text/x-patch; name="0002-Arm-add-speculation_barrier-pattern.patch", Size: 1487 bytes --]

diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 361a026..ca2a2f5 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -12012,6 +12012,27 @@ (define_insn "<mrrc>"
   [(set_attr "length" "4")
    (set_attr "type" "coproc")])
 
+(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;
+  "
+)
+
+;; Generate a hard speculation barrier when we have not enabled speculation
+;; tracking.
+(define_insn "*speculation_barrier_insn"
+  [(unspec_volatile [(const_int 0)] VUNSPEC_SPECULATION_BARRIER)]
+  "TARGET_32BIT"
+  "isb\;dsb\\tsy"
+  [(set_attr "type" "block")
+   (set_attr "length" "8")]
+)
+
 ;; Vector bits common to IWMMXT and Neon
 (include "vec-common.md")
 ;; Load the Intel Wireless Multimedia Extension patterns
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index b05f85e..1941673 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -168,6 +168,7 @@ (define_c_enum "unspecv" [
   VUNSPEC_MCRR2		; Represent the coprocessor mcrr2 instruction.
   VUNSPEC_MRRC		; Represent the coprocessor mrrc instruction.
   VUNSPEC_MRRC2		; Represent the coprocessor mrrc2 instruction.
+  VUNSPEC_SPECULATION_BARRIER ; Represents an unconditional speculation barrier.
 ])
 
 ;; Enumerators for NEON unspecs.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 03/11] AArch64 - add speculation barrier
  2018-07-27  9:38 ` [PATCH 00/11] (v2) " Richard Earnshaw
                     ` (8 preceding siblings ...)
  2018-07-27  9:38   ` [PATCH 07/11] AArch64 - use CSDB based sequences if speculation tracking is enabled Richard Earnshaw
@ 2018-07-27  9:38   ` Richard Earnshaw
  2018-07-27  9:38   ` [PATCH 02/11] Arm - add speculation_barrier pattern Richard Earnshaw
  2018-07-27 19:49   ` [PATCH 00/11] (v2) Mitigation against unsafe data speculation (CVE-2017-5753) John David Anglin
  11 siblings, 0 replies; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-27  9:38 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Earnshaw

[-- Attachment #1: Type: text/plain, Size: 262 bytes --]


Similar to Arm, this adds an unconditional speculation barrier for AArch64.

	* config/aarch64.md (unspecv): Add UNSPECV_SPECULAION_BARRIER.
	(speculation_barrier): New insn.
---
 gcc/config/aarch64/aarch64.md | 10 ++++++++++
 1 file changed, 10 insertions(+)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0003-AArch64-add-speculation-barrier.patch --]
[-- Type: text/x-patch; name="0003-AArch64-add-speculation-barrier.patch", Size: 863 bytes --]

diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index a014a01..c135ada 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -205,6 +205,7 @@ (define_c_enum "unspecv" [
     UNSPECV_SET_FPSR		; Represent assign of FPSR content.
     UNSPECV_BLOCKAGE		; Represent a blockage
     UNSPECV_PROBE_STACK_RANGE	; Represent stack range probing.
+    UNSPECV_SPECULATION_BARRIER ; Represent speculation barrier.
   ]
 )
 
@@ -6093,6 +6094,15 @@ (define_expand "set_clobber_cc"
 		   (match_operand 1))
 	      (clobber (reg:CC CC_REGNUM))])])
 
+;; Hard speculation barrier.
+(define_insn "speculation_barrier"
+  [(unspec_volatile [(const_int 0)] UNSPECV_SPECULATION_BARRIER)]
+  ""
+  "isb\;dsb\\tsy"
+  [(set_attr "length" "8")
+   (set_attr "type" "block")]
+)
+
 ;; AdvSIMD Stuff
 (include "aarch64-simd.md")
 

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 00/11] (v2) Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-09 16:39 [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753) Richard Earnshaw
                   ` (8 preceding siblings ...)
  2018-07-10  7:19 ` Richard Biener
@ 2018-07-27  9:38 ` Richard Earnshaw
  2018-07-27  9:38   ` [PATCH 04/11] AArch64 - Add new option -mtrack-speculation Richard Earnshaw
                     ` (11 more replies)
  9 siblings, 12 replies; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-27  9:38 UTC (permalink / raw)
  To: gcc-patches
  Cc: Richard Earnshaw, andrew, andrew, aoliva, augustine.sterling,
	bernds_cb1, chertykov, cltang, dave.anglin, davem, dje.gcc,
	eager, ebotcazou, gnu, green, hepenner, hp, hp, hubicka,
	james.bowman, jasonwucj, jimw, jzhang918, kito.cheng, krebbel,
	law, matt, mfortune, ni1d, nickc, olegendo, palmer, rth, sandra,
	schwab, sebastien, segher, shiva0217, tdevries, trevor_smigiel,
	ubizjak, uweigand, walt, wilson

[-- Attachment #1: Type: text/plain, Size: 6857 bytes --]

Port Maintainers: You need to decide what action is required for your
port to handle speculative execution, even if that action is to use
the trivial no-speculation on this architecture.  You must also
consider whether or not a furture implementation of your architecture
might need to deal with this in making that decision.

The patches I posted earlier this year for mitigating against
CVE-2017-5753 (Spectre variant 1) attracted some useful feedback, from
which it became obvious that a rethink was needed.  This mail, and the
following patches attempt to address that feedback and present a new
approach to mitigating against this form of attack surface.

There were two major issues with the original approach:

- The speculation bounds were too tightly constrained - essentially
  they had to represent and upper and lower bound on a pointer, or a
  pointer offset.
- The speculation constraints could only cover the immediately preceding
  branch, which often did not fit well with the structure of the existing
  code.

An additional criticism was that the shape of the intrinsic did not
fit particularly well with systems that used a single speculation
barrier that essentially had to wait until all preceding speculation
had to be resolved.

To address all of the above, these patches adopt a new approach, based
in part on a posting by Chandler Carruth to the LLVM developers list
(https://lists.llvm.org/pipermail/llvm-dev/2018-March/122085.html),
but which we have extended to deal with inter-function speculation.
The patches divide the problem into two halves.

The first half is some target-specific code to track the speculation
condition through the generated code to provide an internal variable
which can tell us whether or not the CPU's control flow speculation
matches the data flow calculations.  The idea is that the internal
variable starts with the value TRUE and if the CPU's control flow
speculation ever causes a jump to the wrong block of code the variable
becomes false until such time as the incorrect control flow
speculation gets unwound.

The second half is that a new intrinsic function is introduced that is
much simpler than we had before.  The basic version of the intrinsic
is now simply:

      T var = __builtin_speculation_safe_value (T unsafe_var);

Full details of the syntax can be found in the documentation patch, in
patch 1.  In summary, when not speculating the intrinsic returns
unsafe_var; when speculating then if it can be shown that the
speculative flow has diverged from the intended control flow then zero
is returned.  An optional second argument can be used to return an
alternative value to zero.  The builtin may cause execution to pause
until the speculation state is resolved.

There are eleven patches in this set, as follows.

1) Introduces the new intrinsic __builtin_sepculation_safe_value.
2) Adds a basic hard barrier implementation for AArch32 (arm) state.
3) Adds a basic hard barrier implementation for AArch64 state.
4) Adds a new command-line option -mtrack-speculation (currently a no-op).
5) Disables CB[N]Z and TB[N]Z when -mtrack-speculation.
6) Adds the new speculation tracking pass for AArch64
7) Uses the new speculation tracking pass to generate CSDB-based barrier
   sequences
8) Provides an alternative hook implementation for use on targets that never
   speculatively execute
9) Provides an trivial example of using that hook in the pdp11 backend.
10) Provides a possible implementation of the hard barrier for x86
11) Updates the PowerPC backend which already had a suitable barrier under
    a different name.

I haven't added a speculation-tracking pass for AArch32 at this time.
It is possible to do this, but would require quite a lot of rework for
the arm backend due to the limited number of registers that are
available.

Although patch 6 is AArch64 specific, I'd appreciate a review from
someone more familiar with the branch edge code than myself.  There
appear to be a number of tricky issues with more complex edges so I'd
like a second opinion on that code in case I've missed an important
case.

R.

Richard Earnshaw (11):
  Add __builtin_speculation_safe_value
  Arm - add speculation_barrier pattern
  AArch64 - add speculation barrier
  AArch64 - Add new option -mtrack-speculation
  AArch64 - disable CB[N]Z TB[N]Z when tracking speculation
  AArch64 - new pass to add conditional-branch speculation tracking
  AArch64 - use CSDB based sequences if speculation tracking is enabled
  targhooks - provide an alternative hook for targets that never execute
    speculatively
  pdp11 - example of a port not needing a speculation barrier
  x86 - add speculation_barrier pattern
  rs6000 - add speculation_barrier pattern

 gcc/builtin-attrs.def                       |   2 +
 gcc/builtin-types.def                       |   6 +
 gcc/builtins.c                              |  60 ++++
 gcc/builtins.def                            |  22 ++
 gcc/c-family/c-common.c                     | 164 +++++++++
 gcc/c-family/c-cppbuiltin.c                 |   7 +-
 gcc/config.gcc                              |   2 +-
 gcc/config/aarch64/aarch64-passes.def       |   1 +
 gcc/config/aarch64/aarch64-protos.h         |   3 +-
 gcc/config/aarch64/aarch64-speculation.cc   | 494 ++++++++++++++++++++++++++++
 gcc/config/aarch64/aarch64.c                |  94 +++++-
 gcc/config/aarch64/aarch64.md               | 141 +++++++-
 gcc/config/aarch64/aarch64.opt              |   4 +
 gcc/config/aarch64/iterators.md             |   3 +
 gcc/config/aarch64/t-aarch64                |  10 +
 gcc/config/arm/arm.md                       |  21 ++
 gcc/config/arm/unspecs.md                   |   1 +
 gcc/config/i386/i386.md                     |  10 +
 gcc/config/pdp11/pdp11.c                    |   3 +
 gcc/config/rs6000/rs6000.c                  |   2 +-
 gcc/config/rs6000/rs6000.md                 |   2 +-
 gcc/doc/cpp.texi                            |   4 +
 gcc/doc/extend.texi                         |  91 +++++
 gcc/doc/invoke.texi                         |  10 +-
 gcc/doc/md.texi                             |  15 +
 gcc/doc/tm.texi                             |  36 ++
 gcc/doc/tm.texi.in                          |   4 +
 gcc/target.def                              |  40 +++
 gcc/targhooks.c                             |  39 +++
 gcc/targhooks.h                             |   4 +
 gcc/testsuite/c-c++-common/spec-barrier-1.c |  38 +++
 gcc/testsuite/c-c++-common/spec-barrier-2.c |  17 +
 gcc/testsuite/gcc.dg/spec-barrier-3.c       |  13 +
 33 files changed, 1350 insertions(+), 13 deletions(-)
 create mode 100644 gcc/config/aarch64/aarch64-speculation.cc
 create mode 100644 gcc/testsuite/c-c++-common/spec-barrier-1.c
 create mode 100644 gcc/testsuite/c-c++-common/spec-barrier-2.c
 create mode 100644 gcc/testsuite/gcc.dg/spec-barrier-3.c

-- 
2.7.4


^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 11/11] rs6000 - add speculation_barrier pattern
  2018-07-27  9:38 ` [PATCH 00/11] (v2) " Richard Earnshaw
                     ` (4 preceding siblings ...)
  2018-07-27  9:38   ` [PATCH 08/11] targhooks - provide an alternative hook for targets that never execute speculatively Richard Earnshaw
@ 2018-07-27  9:38   ` Richard Earnshaw
  2018-07-31 22:01     ` Bill Schmidt
  2018-07-27  9:38   ` [PATCH 10/11] x86 " Richard Earnshaw
                     ` (5 subsequent siblings)
  11 siblings, 1 reply; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-27  9:38 UTC (permalink / raw)
  To: gcc-patches, dje.gcc, segher; +Cc: Richard Earnshaw, wschmidt

[-- Attachment #1: Type: text/plain, Size: 605 bytes --]


This patch reworks the existing rs6000_speculation_barrier pattern to
work with the new __builtin_sepculation_safe_value() intrinsic.  The
change is trivial as it simply requires renaming the existing speculation
barrier pattern.

So the total patch is to delete 14 characters!

	* config/rs6000/rs6000.md (speculation_barrier): Renamed from
	rs6000_speculation_barrier.
	* config/rs6000/rs6000.c (rs6000_expand_builtin): Adjust for
	new barrier pattern name.
---
 gcc/config/rs6000/rs6000.c  | 2 +-
 gcc/config/rs6000/rs6000.md | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0011-rs6000-add-speculation_barrier-pattern.patch --]
[-- Type: text/x-patch; name="0011-rs6000-add-speculation_barrier-pattern.patch", Size: 882 bytes --]

diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 1976072..46c6838 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -16179,7 +16179,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 
     case MISC_BUILTIN_SPEC_BARRIER:
       {
-	emit_insn (gen_rs6000_speculation_barrier ());
+	emit_insn (gen_speculation_barrier ());
 	return NULL_RTX;
       }
 
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 44d32d9..03870e9 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -12614,7 +12614,7 @@ (define_insn "group_ending_nop"
   return "ori 2,2,0";
 })
 
-(define_insn "rs6000_speculation_barrier"
+(define_insn "speculation_barrier"
   [(unspec_volatile:BLK [(const_int 0)] UNSPECV_SPEC_BARRIER)]
   ""
   "ori 31,31,0")

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 05/11] AArch64 - disable CB[N]Z TB[N]Z when tracking speculation
  2018-07-27  9:38 ` [PATCH 00/11] (v2) " Richard Earnshaw
  2018-07-27  9:38   ` [PATCH 04/11] AArch64 - Add new option -mtrack-speculation Richard Earnshaw
@ 2018-07-27  9:38   ` Richard Earnshaw
  2018-07-27  9:38   ` [PATCH 06/11] AArch64 - new pass to add conditional-branch speculation tracking Richard Earnshaw
                     ` (9 subsequent siblings)
  11 siblings, 0 replies; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-27  9:38 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Earnshaw

[-- Attachment #1: Type: text/plain, Size: 957 bytes --]


The CB[N]Z and TB[N]Z instructions do not expose the comparison through
the condition code flags.  This makes it impossible to track speculative
execution through such a branch.  We can handle this relatively easily
by simply disabling the patterns in this case.

A side effect of this is that the split patterns for the atomic operations
need to also avoid generating these instructions.  They mostly have simple
fall-backs for this already.

	* config/aarch64/aarch64.md (cb<optab><mode>1): Disable when
	aarch64_track_speculation is true.
	(tb<optab><mode>1): Likewise.
	* config/aarch64/aarch64.c (aarch64_split_compare_regs): Do not
	generate CB[N]Z when tracking speculation.
	(aarch64_split_compare_and_swap): Likewise.
	(aarch64_split_atomic_op): Likewise.
---
 gcc/config/aarch64/aarch64.c  | 33 ++++++++++++++++++++++++++++++---
 gcc/config/aarch64/aarch64.md |  6 +++---
 2 files changed, 33 insertions(+), 6 deletions(-)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0005-AArch64-disable-CB-N-Z-TB-N-Z-when-tracking-speculat.patch --]
[-- Type: text/x-patch; name="0005-AArch64-disable-CB-N-Z-TB-N-Z-when-tracking-speculat.patch", Size: 3255 bytes --]

diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 1369704..90849b5 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -14479,7 +14479,16 @@ aarch64_split_compare_and_swap (rtx operands[])
 
   if (strong_zero_p)
     {
-      x = gen_rtx_NE (VOIDmode, rval, const0_rtx);
+      if (aarch64_track_speculation)
+	{
+	  /* Emit an explicit compare instruction, so that we can correctly
+	     track the condition codes.  */
+	  rtx cc_reg = aarch64_gen_compare_reg (NE, rval, const0_rtx);
+	  x = gen_rtx_NE (GET_MODE (cc_reg), cc_reg, const0_rtx);
+	}
+      else
+	x = gen_rtx_NE (VOIDmode, rval, const0_rtx);
+
       x = gen_rtx_IF_THEN_ELSE (VOIDmode, x,
 				gen_rtx_LABEL_REF (Pmode, label2), pc_rtx);
       aarch64_emit_unlikely_jump (gen_rtx_SET (pc_rtx, x));
@@ -14497,7 +14506,16 @@ aarch64_split_compare_and_swap (rtx operands[])
 
   if (!is_weak)
     {
-      x = gen_rtx_NE (VOIDmode, scratch, const0_rtx);
+      if (aarch64_track_speculation)
+	{
+	  /* Emit an explicit compare instruction, so that we can correctly
+	     track the condition codes.  */
+	  rtx cc_reg = aarch64_gen_compare_reg (NE, scratch, const0_rtx);
+	  x = gen_rtx_NE (GET_MODE (cc_reg), cc_reg, const0_rtx);
+	}
+      else
+	x = gen_rtx_NE (VOIDmode, scratch, const0_rtx);
+
       x = gen_rtx_IF_THEN_ELSE (VOIDmode, x,
 				gen_rtx_LABEL_REF (Pmode, label1), pc_rtx);
       aarch64_emit_unlikely_jump (gen_rtx_SET (pc_rtx, x));
@@ -14833,7 +14851,16 @@ aarch64_split_atomic_op (enum rtx_code code, rtx old_out, rtx new_out, rtx mem,
   aarch64_emit_store_exclusive (mode, cond, mem,
 				gen_lowpart (mode, new_out), model_rtx);
 
-  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
+  if (aarch64_track_speculation)
+    {
+      /* Emit an explicit compare instruction, so that we can correctly
+	 track the condition codes.  */
+      rtx cc_reg = aarch64_gen_compare_reg (NE, cond, const0_rtx);
+      x = gen_rtx_NE (GET_MODE (cc_reg), cc_reg, const0_rtx);
+    }
+  else
+    x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
+
   x = gen_rtx_IF_THEN_ELSE (VOIDmode, x,
 			    gen_rtx_LABEL_REF (Pmode, label), pc_rtx);
   aarch64_emit_unlikely_jump (gen_rtx_SET (pc_rtx, x));
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index c135ada..259a07d 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -690,7 +690,7 @@ (define_insn "*cb<optab><mode>1"
 				(const_int 0))
 			   (label_ref (match_operand 1 "" ""))
 			   (pc)))]
-  ""
+  "!aarch64_track_speculation"
   {
     if (get_attr_length (insn) == 8)
       return aarch64_gen_far_branch (operands, 1, "Lcb", "<inv_cb>\\t%<w>0, ");
@@ -720,7 +720,7 @@ (define_insn "*tb<optab><mode>1"
 	     (label_ref (match_operand 2 "" ""))
 	     (pc)))
    (clobber (reg:CC CC_REGNUM))]
-  ""
+  "!aarch64_track_speculation"
   {
     if (get_attr_length (insn) == 8)
       {
@@ -756,7 +756,7 @@ (define_insn "*cb<optab><mode>1"
 			   (label_ref (match_operand 1 "" ""))
 			   (pc)))
    (clobber (reg:CC CC_REGNUM))]
-  ""
+  "!aarch64_track_speculation"
   {
     if (get_attr_length (insn) == 8)
       {

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 10/11] x86 - add speculation_barrier pattern
  2018-07-27  9:38 ` [PATCH 00/11] (v2) " Richard Earnshaw
                     ` (5 preceding siblings ...)
  2018-07-27  9:38   ` [PATCH 11/11] rs6000 - add speculation_barrier pattern Richard Earnshaw
@ 2018-07-27  9:38   ` Richard Earnshaw
  2018-07-28  8:25     ` Uros Bizjak
  2018-07-27  9:38   ` [PATCH 01/11] Add __builtin_speculation_safe_value Richard Earnshaw
                     ` (4 subsequent siblings)
  11 siblings, 1 reply; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-27  9:38 UTC (permalink / raw)
  To: gcc-patches, hubicka, ubizjak; +Cc: Richard Earnshaw

[-- Attachment #1: Type: text/plain, Size: 633 bytes --]


This patch adds a speculation barrier for x86, based on my
understanding of the required mitigation for that CPU, which is to use
an lfence instruction.

This patch needs some review by an x86 expert and if adjustments are
needed, I'd appreciate it if they could be picked up by the port
maintainer.  This is supposed to serve as an example of how to deploy
the new __builtin_speculation_safe_value() intrinsic on this
architecture.

	* config/i386/i386.md (unspecv): Add UNSPECV_SPECULATION_BARRIER.
	(speculation_barrier): New insn.
---
 gcc/config/i386/i386.md | 10 ++++++++++
 1 file changed, 10 insertions(+)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0010-x86-add-speculation_barrier-pattern.patch --]
[-- Type: text/x-patch; name="0010-x86-add-speculation_barrier-pattern.patch", Size: 782 bytes --]

diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 559ad93..73948c1 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -301,6 +301,9 @@ (define_c_enum "unspecv" [
 
   ;; For CLDEMOTE support
   UNSPECV_CLDEMOTE
+
+  ;; For Speculation Barrier support
+  UNSPECV_SPECULATION_BARRIER
 ])
 
 ;; Constants to represent rounding modes in the ROUND instruction
@@ -20979,6 +20982,13 @@ (define_insn "cldemote"
   [(set_attr "type" "other")
    (set_attr "memory" "unknown")])
 
+(define_insn "speculation_barrier"
+  [(unspec_volatile [(const_int 0)] UNSPECV_SPECULATION_BARRIER)]
+  ""
+  "lfence"
+  [(set_attr "type" "other")
+   (set_attr "length" "3")])
+
 (include "mmx.md")
 (include "sse.md")
 (include "sync.md")

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 01/11] Add __builtin_speculation_safe_value
  2018-07-27  9:38 ` [PATCH 00/11] (v2) " Richard Earnshaw
                     ` (6 preceding siblings ...)
  2018-07-27  9:38   ` [PATCH 10/11] x86 " Richard Earnshaw
@ 2018-07-27  9:38   ` Richard Earnshaw
  2018-07-27 12:11     ` Nathan Sidwell
  2018-07-30 13:16     ` Richard Biener
  2018-07-27  9:38   ` [PATCH 07/11] AArch64 - use CSDB based sequences if speculation tracking is enabled Richard Earnshaw
                     ` (3 subsequent siblings)
  11 siblings, 2 replies; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-27  9:38 UTC (permalink / raw)
  To: gcc-patches, joseph, jason, nathan; +Cc: Richard Earnshaw, rguenther

[-- Attachment #1: Type: text/plain, Size: 3542 bytes --]


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.
---
 gcc/builtin-attrs.def                       |   2 +
 gcc/builtin-types.def                       |   6 +
 gcc/builtins.c                              |  60 ++++++++++
 gcc/builtins.def                            |  22 ++++
 gcc/c-family/c-common.c                     | 164 ++++++++++++++++++++++++++++
 gcc/c-family/c-cppbuiltin.c                 |   7 +-
 gcc/doc/cpp.texi                            |   4 +
 gcc/doc/extend.texi                         |  91 +++++++++++++++
 gcc/doc/md.texi                             |  15 +++
 gcc/doc/tm.texi                             |  31 ++++++
 gcc/doc/tm.texi.in                          |   4 +
 gcc/target.def                              |  35 ++++++
 gcc/targhooks.c                             |  32 ++++++
 gcc/targhooks.h                             |   3 +
 gcc/testsuite/c-c++-common/spec-barrier-1.c |  38 +++++++
 gcc/testsuite/c-c++-common/spec-barrier-2.c |  17 +++
 gcc/testsuite/gcc.dg/spec-barrier-3.c       |  13 +++
 17 files changed, 543 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/c-c++-common/spec-barrier-1.c
 create mode 100644 gcc/testsuite/c-c++-common/spec-barrier-2.c
 create mode 100644 gcc/testsuite/gcc.dg/spec-barrier-3.c


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-__builtin_speculation_safe_value.patch --]
[-- Type: text/x-patch; name="0001-Add-__builtin_speculation_safe_value.patch", Size: 27259 bytes --]

diff --git a/gcc/builtin-attrs.def b/gcc/builtin-attrs.def
index 300ba65..e245e4d 100644
--- a/gcc/builtin-attrs.def
+++ b/gcc/builtin-attrs.def
@@ -129,6 +129,8 @@ DEF_ATTR_TREE_LIST (ATTR_NOTHROW_LIST, ATTR_NOTHROW, ATTR_NULL, ATTR_NULL)
 
 DEF_ATTR_TREE_LIST (ATTR_NOTHROW_LEAF_LIST, ATTR_LEAF, ATTR_NULL, ATTR_NOTHROW_LIST)
 
+DEF_ATTR_TREE_LIST (ATTR_NOVOPS_NOTHROW_LEAF_LIST, ATTR_NOVOPS, \
+		        ATTR_NULL, ATTR_NOTHROW_LEAF_LIST)
 DEF_ATTR_TREE_LIST (ATTR_CONST_NOTHROW_LIST, ATTR_CONST,	\
 			ATTR_NULL, ATTR_NOTHROW_LIST)
 DEF_ATTR_TREE_LIST (ATTR_CONST_NOTHROW_LEAF_LIST, ATTR_CONST,	\
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 839a818..c954f11 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -6881,6 +6881,55 @@ inline_expand_builtin_string_cmp (tree exp, rtx target, bool is_memcmp)
 			    const_str_n, mode, is_memcmp);
 }
 
+/* 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 || GET_MODE (target) != mode)
+    target = gen_reg_rtx (mode);
+
+  if (GET_MODE (val) != mode && GET_MODE (val) != VOIDmode)
+    val = convert_modes (mode, VOIDmode, val, false);
+
+  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).
@@ -7992,6 +8041,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..ad90d44 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -1003,6 +1003,28 @@ 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_NOVOPS_NOTHROW_LEAF_LIST)
+
+DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_PTR,
+		 "speculation_safe_value_ptr", BT_FN_PTR_PTR_VAR,
+		 ATTR_NOVOPS_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_1, "speculation_safe_value_1",
+		 BT_FN_I1_I1_VAR, ATTR_NOVOPS_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_2, "speculation_safe_value_2",
+		 BT_FN_I2_I2_VAR, ATTR_NOVOPS_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_4, "speculation_safe_value_4",
+		 BT_FN_I4_I4_VAR, ATTR_NOVOPS_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_8, "speculation_safe_value_8",
+		 BT_FN_I8_I8_VAR, ATTR_NOVOPS_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_SPECULATION_SAFE_VALUE_16,
+		 "speculation_safe_value_16", BT_FN_I16_I16_VAR,
+		 ATTR_NOVOPS_NOTHROW_LEAF_LIST)
+
 /* 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..e368fd2 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");
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 954e8a1..0ba1931 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10948,6 +10948,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
@@ -11592,6 +11593,96 @@ 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 built-in function 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.
+
+GCC defines the preprocessor macro
+@code{__HAVE_BUILTIN_SPECULATION_SAFE_VALUE} for targets that have been
+updated to support this builtin.
+
+The built-in function can be used where a variable appears to be used in a
+safe way, but the CPU, due to speculative execution may temporarily ignore
+the bounds checks.  Consider, for example, the following function:
+
+@smallexample
+int array[500];
+int f (unsigned untrusted_index)
+@{
+  if (untrusted_index < 500)
+    return array[untrusted_index];
+  return 0;
+@}
+@end smallexample
+
+If the function is called repeatedly with @code{untrusted_index} less
+than the limit of 500, then a branch predictor will learn that the
+block of code that returns a value stored in @code{array} will be
+executed.  If the function is subsequently called with an
+out-of-range value it will still try to execute that block of code
+first until the CPU determines that the prediction was incorrect
+(the CPU will unwind any incorrect operations at that point).
+However, depending on how the result of the function is used, it might be
+possible to leave traces in the cache that can reveal what was stored
+at the out-of-bounds location.  The built-in function can be used to
+provide some protection against leaking data in this way by changing
+the code to:
+
+@smallexample
+int array[500];
+int f (unsigned untrusted_index)
+@{
+  if (untrusted_index < 500)
+    return array[__builtin_speculation_safe_value (untrusted_index)];
+  return 0;
+@}
+@end smallexample
+
+The built-in function will either cause execution to stall until the
+conditional branch has been fully resolved, or it may permit
+speculative execution to continue, but using 0 instead of
+@code{untrusted_value} if that exceeds the limit.
+
+If accessing any memory location is potentially unsafe when speculative
+execution is incorrect, then the code can be rewritten as
+
+@smallexample
+int array[500];
+int f (unsigned untrusted_index)
+@{
+  if (untrusted_index < 500)
+    return *__builtin_speculation_safe_value (&array[untrusted_index], NULL);
+  return 0;
+@}
+@end smallexample
+
+which will cause a @code{NULL} pointer to be used for the unsafe case.
+
+@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 734bc76..00c1239 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -7032,6 +7032,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 ff6d514..15b0ab8 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -11948,6 +11948,37 @@ maintainer is familiar with.
 
 @end defmac
 
+@deftypefn {Target Hook} bool TARGET_HAVE_SPECULATION_SAFE_VALUE (bool @var{active})
+This hook is used to determine the level of target support for
+ @code{__builtin_speculation_safe_value}.  If called with an argument
+ of false, it returns true if the target has been modified to support
+ this builtin.  If called with an argument of true, it returns true
+ if the target requires active mitigation execution might be speculative.
+ 
+ The default implementation returns false if the target does not define
+ a pattern named @code{speculation_barrier}.  Else it returns true
+ for the first case and whether the pattern is enabled for the current
+ compilation for the second case.
+@end deftypefn
+
+@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.
+@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 2f97151..94ad868 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -8109,4 +8109,8 @@ maintainer is familiar with.
 
 @end defmac
 
+@hook TARGET_HAVE_SPECULATION_SAFE_VALUE
+
+@hook TARGET_SPECULATION_SAFE_VALUE
+
 @hook TARGET_RUN_TARGET_SELFTESTS
diff --git a/gcc/target.def b/gcc/target.def
index ff89e72..d598067 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4196,6 +4196,41 @@ DEFHOOK
  hook_bool_void_true)
 
 DEFHOOK
+(have_speculation_safe_value,
+"This hook is used to determine the level of target support for\n\
+ @code{__builtin_speculation_safe_value}.  If called with an argument\n\
+ of false, it returns true if the target has been modified to support\n\
+ this builtin.  If called with an argument of true, it returns true\n\
+ if the target requires active mitigation execution might be speculative.\n\
+ \n\
+ The default implementation returns false if the target does not define\n\
+ a pattern named @code{speculation_barrier}.  Else it returns true\n\
+ for the first case and whether the pattern is enabled for the current\n\
+ compilation for the second case.",
+bool, (bool active), default_have_speculation_safe_value)
+
+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.",
+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 9b06d7a..06de1e3 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -2314,4 +2314,36 @@ default_preferred_else_value (unsigned, tree type, unsigned, tree *)
   return build_zero_cst (type);
 }
 
+/* Default implementation of TARGET_HAVE_SPECULATION_SAFE_VALUE.  */
+bool
+default_have_speculation_safe_value (bool active)
+{
+#ifdef HAVE_speculation_barrier
+  return active ? HAVE_speculation_barrier : true;
+#else
+  return false;
+#endif
+}
+
+/* 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.  */
+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 ());
+#endif
+
+  return result;
+}
+
 #include "gt-targhooks.h"
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 8d234cf..74ffe5f 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -285,4 +285,7 @@ extern bool default_stack_clash_protection_final_dynamic_probe (rtx);
 extern void default_select_early_remat_modes (sbitmap);
 extern tree default_preferred_else_value (unsigned, tree, unsigned, tree *);
 
+extern bool default_have_speculation_safe_value (bool);
+extern rtx default_speculation_safe_value (machine_mode, rtx, rtx, rtx);
+
 #endif /* GCC_TARGHOOKS_H */
diff --git a/gcc/testsuite/c-c++-common/spec-barrier-1.c b/gcc/testsuite/c-c++-common/spec-barrier-1.c
new file mode 100644
index 0000000..e4b44f2
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/spec-barrier-1.c
@@ -0,0 +1,38 @@
+/* { 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
+
+int main ()
+{
+  if (__builtin_speculation_safe_value (a) != 1)
+    __builtin_abort ();
+  if (__builtin_speculation_safe_value (b) != 2)
+    __builtin_abort ();
+  if (__builtin_speculation_safe_value (c) != 3)
+    __builtin_abort ();
+  if (__builtin_speculation_safe_value (d) != 4)
+    __builtin_abort ();
+  if (__builtin_speculation_safe_value (e) != 5)
+    __builtin_abort ();
+  if (__builtin_speculation_safe_value (f) != &c)
+    __builtin_abort ();
+#ifdef __SIZEOF_INT128__
+  if (__builtin_speculation_safe_value (g) != 9)
+    __builtin_abort ();
+#endif
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/spec-barrier-2.c b/gcc/testsuite/c-c++-common/spec-barrier-2.c
new file mode 100644
index 0000000..b09567e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/spec-barrier-2.c
@@ -0,0 +1,17 @@
+/* { 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;
+
+int main ()
+{
+  int z = __builtin_speculation_safe_value (x, y++);
+  if (z != 3 || y != 10)
+    __builtin_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;" } */

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 09/11] pdp11 - example of a port not needing a speculation barrier
  2018-07-27  9:38 ` [PATCH 00/11] (v2) " Richard Earnshaw
                     ` (2 preceding siblings ...)
  2018-07-27  9:38   ` [PATCH 06/11] AArch64 - new pass to add conditional-branch speculation tracking Richard Earnshaw
@ 2018-07-27  9:38   ` Richard Earnshaw
  2018-07-27 13:27     ` Paul Koning
  2018-07-27  9:38   ` [PATCH 08/11] targhooks - provide an alternative hook for targets that never execute speculatively Richard Earnshaw
                     ` (7 subsequent siblings)
  11 siblings, 1 reply; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-27  9:38 UTC (permalink / raw)
  To: gcc-patches, ni1d; +Cc: Richard Earnshaw

[-- Attachment #1: Type: text/plain, Size: 521 bytes --]


This patch is intended as an example of all that is needed if the
target system doesn't support CPUs that have speculative execution.
I've chosen the pdp11 port on the basis that it's old enough that this
is likely to be true for all existing implementations and that there
is also little chance of that changing in future!

	* config/pdp11/pdp11.c (TARGET_HAVE_SPECULATION_SAFE_VALUE): Redefine
	to speculation_safe_value_not_needed.
---
 gcc/config/pdp11/pdp11.c | 3 +++
 1 file changed, 3 insertions(+)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0009-pdp11-example-of-a-port-not-needing-a-speculation-ba.patch --]
[-- Type: text/x-patch; name="0009-pdp11-example-of-a-port-not-needing-a-speculation-ba.patch", Size: 596 bytes --]

diff --git a/gcc/config/pdp11/pdp11.c b/gcc/config/pdp11/pdp11.c
index 1bcdaed..62c653f 100644
--- a/gcc/config/pdp11/pdp11.c
+++ b/gcc/config/pdp11/pdp11.c
@@ -291,6 +291,9 @@ static bool pdp11_scalar_mode_supported_p (scalar_mode);
 
 #undef TARGET_INVALID_WITHIN_DOLOOP
 #define TARGET_INVALID_WITHIN_DOLOOP hook_constcharptr_const_rtx_insn_null
+
+#undef TARGET_HAVE_SPECULATION_SAFE_VALUE
+#define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
 \f
 /* A helper function to determine if REGNO should be saved in the
    current function's stack frame.  */

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 07/11] AArch64 - use CSDB based sequences if speculation tracking is enabled
  2018-07-27  9:38 ` [PATCH 00/11] (v2) " Richard Earnshaw
                     ` (7 preceding siblings ...)
  2018-07-27  9:38   ` [PATCH 01/11] Add __builtin_speculation_safe_value Richard Earnshaw
@ 2018-07-27  9:38   ` Richard Earnshaw
  2018-07-27  9:38   ` [PATCH 03/11] AArch64 - add speculation barrier Richard Earnshaw
                     ` (2 subsequent siblings)
  11 siblings, 0 replies; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-27  9:38 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Earnshaw

[-- Attachment #1: Type: text/plain, Size: 927 bytes --]


In this final patch, now that we can track speculation through conditional
branches, we can use this information to use a less expensive CSDB based
speculation barrier.

	* config/aarch64/iterators.md (ALLI_TI): New iterator.
	* config/aarch64/aarch64.md (despeculate_copy<ALLI_TI:mode>): New
	expand.
	(despeculate_copy<ALLI:mode>_insn): New insn.
	(despeculate_copyti_insn): New insn.
	(despeculate_simple<ALLI:mode>): New insn
	(despeculate_simpleti): New insn.
	* config/aarch64/aarch64.c (aarch64_speculation_safe_value): New
	function.
	(TARGET_SPECULATION_SAFE_VALUE): Redefine to
	aarch64_speculation_safe_value.
	(aarch64_print_operand): Handle const0_rtx in modifier 'H'.
---
 gcc/config/aarch64/aarch64.c    | 48 ++++++++++++++++++++
 gcc/config/aarch64/aarch64.md   | 97 +++++++++++++++++++++++++++++++++++++++++
 gcc/config/aarch64/iterators.md |  3 ++
 3 files changed, 148 insertions(+)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0007-AArch64-use-CSDB-based-sequences-if-speculation-trac.patch --]
[-- Type: text/x-patch; name="0007-AArch64-use-CSDB-based-sequences-if-speculation-trac.patch", Size: 6607 bytes --]

diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index cca465e..fc6eb1c 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -6760,6 +6760,12 @@ aarch64_print_operand (FILE *f, rtx x, int code)
       break;
 
     case 'H':
+      if (x == const0_rtx)
+	{
+	  asm_fprintf (f, "xzr");
+	  break;
+	}
+
       if (!REG_P (x) || !GP_REGNUM_P (REGNO (x) + 1))
 	{
 	  output_operand_lossage ("invalid operand for '%%%c'", code);
@@ -17638,6 +17644,45 @@ aarch64_select_early_remat_modes (sbitmap modes)
     }
 }
 
+/* Override the default target speculation_safe_value.  */
+static rtx
+aarch64_speculation_safe_value (machine_mode mode,
+				rtx result, rtx val, rtx failval)
+{
+  /* Maybe we should warn if falling back to hard barriers.  They are
+     likely to be noticably more expensive than the alternative below.  */
+  if (!aarch64_track_speculation)
+    return default_speculation_safe_value (mode, result, val, failval);
+
+  if (!REG_P (val))
+    val = copy_to_mode_reg (mode, val);
+
+  if (!aarch64_reg_or_zero (failval, mode))
+    failval = copy_to_mode_reg (mode, failval);
+
+  switch (mode)
+    {
+    case E_QImode:
+      emit_insn (gen_despeculate_copyqi (result, val, failval));
+      break;
+    case E_HImode:
+      emit_insn (gen_despeculate_copyhi (result, val, failval));
+      break;
+    case E_SImode:
+      emit_insn (gen_despeculate_copysi (result, val, failval));
+      break;
+    case E_DImode:
+      emit_insn (gen_despeculate_copydi (result, val, failval));
+      break;
+    case E_TImode:
+      emit_insn (gen_despeculate_copyti (result, val, failval));
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  return result;
+}
+
 /* Target-specific selftests.  */
 
 #if CHECKING_P
@@ -18110,6 +18155,9 @@ aarch64_libgcc_floating_mode_supported_p
 #undef TARGET_SELECT_EARLY_REMAT_MODES
 #define TARGET_SELECT_EARLY_REMAT_MODES aarch64_select_early_remat_modes
 
+#undef TARGET_SPECULATION_SAFE_VALUE
+#define TARGET_SPECULATION_SAFE_VALUE aarch64_speculation_safe_value
+
 #if CHECKING_P
 #undef TARGET_RUN_TARGET_SELFTESTS
 #define TARGET_RUN_TARGET_SELFTESTS selftest::aarch64_run_selftests
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 528d03d..321a674 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -6129,6 +6129,103 @@ (define_insn "speculation_barrier"
    (set_attr "speculation_barrier" "true")]
 )
 
+;; Support for __builtin_speculation_safe_value when we have speculation
+;; tracking enabled.  Use the speculation tracker to decide whether to
+;; copy operand 1 to the target, or to copy the fail value (operand 2).
+(define_expand "despeculate_copy<ALLI_TI:mode>"
+  [(set (match_operand:ALLI_TI 0 "register_operand" "=r")
+	(unspec_volatile:ALLI_TI
+	 [(match_operand:ALLI_TI 1 "register_operand" "r")
+	  (match_operand:ALLI_TI 2 "aarch64_reg_or_zero" "rZ")
+	  (use (reg:DI SPECULATION_TRACKER_REGNUM))
+	  (clobber (reg:CC CC_REGNUM))] UNSPECV_SPECULATION_BARRIER))]
+  ""
+  "
+  {
+    if (operands[2] == const0_rtx)
+      {
+	rtx tracker;
+	if (<MODE>mode == TImode)
+	  tracker = gen_rtx_REG (DImode, SPECULATION_TRACKER_REGNUM);
+	else
+	  tracker = gen_rtx_REG (<MODE>mode, SPECULATION_TRACKER_REGNUM);
+
+	emit_insn (gen_despeculate_simple<mode> (operands[0], operands[1],
+						 tracker));
+	DONE;
+      }
+  }
+  "
+)
+
+;; Patterns to match despeculate_copy<mode>.  Note that "hint 0x14" is the
+;; encoding for CSDB, but will work in older versions of the assembler.
+(define_insn "*despeculate_copy<ALLI:mode>_insn"
+  [(set (match_operand:ALLI 0 "register_operand" "=r")
+	(unspec_volatile:ALLI
+	 [(match_operand:ALLI 1 "register_operand" "r")
+	  (match_operand:ALLI 2 "aarch64_reg_or_zero" "rZ")
+	  (use (reg:DI SPECULATION_TRACKER_REGNUM))
+	  (clobber (reg:CC CC_REGNUM))] UNSPECV_SPECULATION_BARRIER))]
+  ""
+  {
+    operands[3] = gen_rtx_REG (DImode, SPECULATION_TRACKER_REGNUM);
+    output_asm_insn ("cmp\\t%3, #0\;csel\\t%<w>0, %<w>1, %<w>2, ne\;hint\t0x14 // csdb",
+		     operands);
+    return "";
+  }
+  [(set_attr "length" "12")
+   (set_attr "type" "block")
+   (set_attr "speculation_barrier" "true")]
+)
+
+;; Pattern to match despeculate_copyti
+(define_insn "*despeculate_copyti_insn"
+  [(set (match_operand:TI 0 "register_operand" "=r")
+	(unspec_volatile:TI
+	 [(match_operand:TI 1 "register_operand" "r")
+	  (match_operand:TI 2 "aarch64_reg_or_zero" "rZ")
+	  (use (reg:DI SPECULATION_TRACKER_REGNUM))
+	  (clobber (reg:CC CC_REGNUM))] UNSPECV_SPECULATION_BARRIER))]
+  ""
+  {
+    operands[3] = gen_rtx_REG (DImode, SPECULATION_TRACKER_REGNUM);
+    output_asm_insn
+      ("cmp\\t%3, #0\;csel\\t%0, %1, %2, ne\;csel\\t%H0, %H1, %H2, ne\;hint\t0x14 // csdb",
+       operands);
+    return "";
+  }
+  [(set_attr "length" "16")
+   (set_attr "type" "block")
+   (set_attr "speculation_barrier" "true")]
+)
+
+(define_insn "despeculate_simple<ALLI:mode>"
+  [(set (match_operand:ALLI 0 "register_operand" "=r")
+	(unspec_volatile:ALLI
+	 [(match_operand:ALLI 1 "register_operand" "r")
+	  (use (match_operand:ALLI 2 "register_operand" ""))]
+	 UNSPECV_SPECULATION_BARRIER))]
+  ""
+  "and\\t%<w>0, %<w>1, %<w>2\;hint\t0x14 // csdb"
+  [(set_attr "type" "block")
+   (set_attr "length" "8")
+   (set_attr "speculation_barrier" "true")]
+)
+
+(define_insn "despeculate_simpleti"
+  [(set (match_operand:TI 0 "register_operand" "=r")
+	(unspec_volatile:TI
+	 [(match_operand:TI 1 "register_operand" "r")
+	  (use (match_operand:DI 2 "register_operand" ""))]
+	 UNSPECV_SPECULATION_BARRIER))]
+  ""
+  "and\\t%0, %1, %2\;and\\t%H0, %H1, %2\;hint\t0x14 // csdb"
+  [(set_attr "type" "block")
+   (set_attr "length" "12")
+   (set_attr "speculation_barrier" "true")]
+)
+
 ;; AdvSIMD Stuff
 (include "aarch64-simd.md")
 
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index d846118..450edea 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -35,6 +35,9 @@ (define_mode_iterator SHORT [QI HI])
 ;; Iterator for all integer modes (up to 64-bit)
 (define_mode_iterator ALLI [QI HI SI DI])
 
+;; Iterator for all integer modes (up to 128-bit)
+(define_mode_iterator ALLI_TI [QI HI SI DI TI])
+
 ;; Iterator for all integer modes that can be extended (up to 64-bit)
 (define_mode_iterator ALLX [QI HI SI])
 

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 06/11] AArch64 - new pass to add conditional-branch speculation tracking
  2018-07-27  9:38 ` [PATCH 00/11] (v2) " Richard Earnshaw
  2018-07-27  9:38   ` [PATCH 04/11] AArch64 - Add new option -mtrack-speculation Richard Earnshaw
  2018-07-27  9:38   ` [PATCH 05/11] AArch64 - disable CB[N]Z TB[N]Z when tracking speculation Richard Earnshaw
@ 2018-07-27  9:38   ` Richard Earnshaw
  2018-07-27  9:38   ` [PATCH 09/11] pdp11 - example of a port not needing a speculation barrier Richard Earnshaw
                     ` (8 subsequent siblings)
  11 siblings, 0 replies; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-27  9:38 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Earnshaw

[-- Attachment #1: Type: text/plain, Size: 1987 bytes --]


This patch is the main part of the speculation tracking code.  It adds
a new target-specific pass that is run just before the final branch
reorg pass (so that it can clean up any new edge insertions we make).
The pass is only run with -mtrack-speculation is passed on the command
line.

One thing that did come to light as part of this was that the stack pointer
register was not being permitted in comparision instructions.  We rely on
that for moving the tracking state between SP and the scratch register at
function call boundaries.

	* config/aarch64/aarch64-speculation.cc: New file.
	* config/aarch64/aarch64-passes.def (pass_track_speculation): Add before
	pass_reorder_blocks.
	* config/aarch64/aarch64-protos.h (make_pass_track_speculation): Add
	prototype.
	* config/aarch64/aarch64.c (aarch64_conditional_register_usage): Fix
	X14 and X15 when tracking speculation.
	* config/aarch64/aarch64.md (register name constants): Add
	SPECULATION_TRACKER_REGNUM and SPECULATION_SCRATCH_REGNUM.
	(unspec): Add UNSPEC_SPECULATION_TRACKER.
	(speculation_barrier): New insn attribute.
	(cmp<mode>): Allow SP in comparisons.
	(speculation_tracker): New insn.
	(speculation_barrier): Add speculation_barrier attribute.
	* config/aarch64/t-aarch64: Add make rule for aarch64-speculation.o.
	* config.gcc (aarch64*-*-*): Add aarch64-speculation.o to extra_objs.
	* doc/invoke.texi (AArch64 Options): Document -mtrack-speculation.
---
 gcc/config.gcc                            |   2 +-
 gcc/config/aarch64/aarch64-passes.def     |   1 +
 gcc/config/aarch64/aarch64-protos.h       |   3 +-
 gcc/config/aarch64/aarch64-speculation.cc | 494 ++++++++++++++++++++++++++++++
 gcc/config/aarch64/aarch64.c              |  13 +
 gcc/config/aarch64/aarch64.md             |  30 +-
 gcc/config/aarch64/t-aarch64              |  10 +
 gcc/doc/invoke.texi                       |  10 +-
 8 files changed, 558 insertions(+), 5 deletions(-)
 create mode 100644 gcc/config/aarch64/aarch64-speculation.cc


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0006-AArch64-new-pass-to-add-conditional-branch-speculati.patch --]
[-- Type: text/x-patch; name="0006-AArch64-new-pass-to-add-conditional-branch-speculati.patch", Size: 23645 bytes --]

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 78e84c2..b17fdba 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -304,7 +304,7 @@ aarch64*-*-*)
 	extra_headers="arm_fp16.h arm_neon.h arm_acle.h"
 	c_target_objs="aarch64-c.o"
 	cxx_target_objs="aarch64-c.o"
-	extra_objs="aarch64-builtins.o aarch-common.o cortex-a57-fma-steering.o"
+	extra_objs="aarch64-builtins.o aarch-common.o cortex-a57-fma-steering.o aarch64-speculation.o"
 	target_gtfiles="\$(srcdir)/config/aarch64/aarch64-builtins.c"
 	target_has_targetm_common=yes
 	;;
diff --git a/gcc/config/aarch64/aarch64-passes.def b/gcc/config/aarch64/aarch64-passes.def
index 87747b4..3d6a254 100644
--- a/gcc/config/aarch64/aarch64-passes.def
+++ b/gcc/config/aarch64/aarch64-passes.def
@@ -19,3 +19,4 @@
    <http://www.gnu.org/licenses/>.  */
 
 INSERT_PASS_AFTER (pass_regrename, 1, pass_fma_steering);
+INSERT_PASS_BEFORE (pass_reorder_blocks, 1, pass_track_speculation);
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index bc11a78..e80ffcf 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -554,7 +554,8 @@ enum aarch64_parse_opt_result aarch64_parse_extension (const char *,
 std::string aarch64_get_extension_string_for_isa_flags (unsigned long,
 							unsigned long);
 
-rtl_opt_pass *make_pass_fma_steering (gcc::context *ctxt);
+rtl_opt_pass *make_pass_fma_steering (gcc::context *);
+rtl_opt_pass *make_pass_track_speculation (gcc::context *);
 
 poly_uint64 aarch64_regmode_natural_size (machine_mode);
 
diff --git a/gcc/config/aarch64/aarch64-speculation.cc b/gcc/config/aarch64/aarch64-speculation.cc
new file mode 100644
index 0000000..2dd06ae
--- /dev/null
+++ b/gcc/config/aarch64/aarch64-speculation.cc
@@ -0,0 +1,494 @@
+/* Speculation tracking and mitigation (e.g. CVE 2017-5753) for AArch64.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "rtl.h"
+#include "tree-pass.h"
+#include "profile-count.h"
+#include "cfg.h"
+#include "cfgbuild.h"
+#include "print-rtl.h"
+#include "cfgrtl.h"
+#include "function.h"
+#include "basic-block.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
+#include "insn-attr.h"
+#include "df.h"
+#include "tm_p.h"
+#include "insn-config.h"
+#include "recog.h"
+
+/* This pass scans the RTL just before the final branch
+   re-organisation pass.  The aim is to identify all places where
+   there is conditional control flow and to insert code that tracks
+   any speculative execution of a conditional branch.
+
+   To do this we reserve a call-clobbered register (so that it can be
+   initialized very early in the function prologue) that can then be
+   updated each time there is a conditional branch.  At each such
+   branch we then generate a code sequence that uses conditional
+   select operations that are not subject to speculation themselves
+   (we ignore for the moment situations where that might not always be
+   strictly true).  For example, a branch sequence such as:
+
+	B.EQ	<dst>
+	...
+   <dst>:
+
+   is transformed to:
+
+	B.EQ	<dst>
+	CSEL	tracker, tracker, XZr, ne
+	...
+   <dst>:
+	CSEL	tracker, tracker, XZr, eq
+
+   Since we start with the tracker initialized to all bits one, if at any
+   time the predicted control flow diverges from the architectural program
+   behavior, then the tracker will become zero (but not otherwise).
+
+   The tracker value can be used at any time at which a value needs
+   guarding against incorrect speculation.  This can be done in
+   several ways, but they all amount to the same thing.  For an
+   untrusted address, or an untrusted offset to a trusted address, we
+   can simply mask the address with the tracker with the untrusted
+   value.  If the CPU is not speculating, or speculating correctly,
+   then the value will remain unchanged, otherwise it will be clamped
+   to zero.  For more complex scenarios we can compare the tracker
+   against zero and use the flags to form a new selection with an
+   alternate safe value.
+
+   On implementations where the data processing instructions may
+   themselves produce speculative values, the architecture requires
+   that a CSDB instruction will resolve such data speculation, so each
+   time we use the tracker for protecting a vulnerable value we also
+   emit a CSDB: we do not need to do that each time the tracker itself
+   is updated.
+
+   At function boundaries, we need to communicate the speculation
+   tracking state with the caller or the callee.  This is tricky
+   because there is no register available for such a purpose without
+   creating a new ABI.  We deal with this by relying on the principle
+   that in all real programs the stack pointer, SP will never be NULL
+   at a function boundary; we can thus encode the speculation state in
+   SP by clearing SP if the speculation tracker itself is NULL.  After
+   the call we recover the tracking state back from SP into the
+   tracker register.  The results is that a function call sequence is
+   transformed to
+
+	MOV	tmp, SP
+	AND	tmp, tmp, tracker
+	MOV	SP, tmp
+	BL	<callee>
+	CMP	SP, #0
+	CSETM	tracker, ne
+
+   The additional MOV instructions in the pre-call sequence are needed
+   because SP cannot be used directly with the AND instruction.
+
+   The code inside a function body uses the post-call sequence in the
+   prologue to establish the tracker and the pre-call sequence in the
+   epilogue to re-encode the state for the return.
+
+   The code sequences have the nice property that if called from, or
+   calling a function that does not track speculation then the stack pointer
+   will always be non-NULL and hence the tracker will be initialized to all
+   bits one as we need: we lose the ability to fully track speculation in that
+   case, but we are still architecturally safe.
+
+   Tracking speculation in this way is quite expensive, both in code
+   size and execution time.  We employ a number of tricks to try to
+   limit this:
+
+   1) Simple leaf functions with no conditional branches (or use of
+   the tracker) do not need to establish a new tracker: they simply
+   carry the tracking state through SP for the duration of the call.
+   The same is also true for leaf functions that end in a tail-call.
+
+   2) Back-to-back function calls in a single basic block also do not
+   need to re-establish the tracker between the calls.  Again, we can
+   carry the tracking state in SP for this period of time unless the
+   tracker value is needed at that point in time.
+
+   We run the pass just before the final branch reorganization pass so
+   that we can handle most of the conditional branch cases using the
+   standard edge insertion code.  The reorg pass will hopefully clean
+   things up for afterwards so that the results aren't too
+   horrible.  */
+
+/* Generate a code sequence to clobber SP if speculating incorreclty.  */
+static rtx_insn *
+aarch64_speculation_clobber_sp ()
+{
+  rtx sp = gen_rtx_REG (DImode, SP_REGNUM);
+  rtx tracker = gen_rtx_REG (DImode, SPECULATION_TRACKER_REGNUM);
+  rtx scratch = gen_rtx_REG (DImode, SPECULATION_SCRATCH_REGNUM);
+
+  start_sequence ();
+  emit_insn (gen_rtx_SET (scratch, sp));
+  emit_insn (gen_anddi3 (scratch, scratch, tracker));
+  emit_insn (gen_rtx_SET (sp, scratch));
+  rtx_insn *seq = get_insns ();
+  end_sequence ();
+  return seq;
+}
+
+/* Generate a code sequence to establish the tracker variable from the
+   contents of SP.  */
+static rtx_insn *
+aarch64_speculation_establish_tracker ()
+{
+  rtx sp = gen_rtx_REG (DImode, SP_REGNUM);
+  rtx tracker = gen_rtx_REG (DImode, SPECULATION_TRACKER_REGNUM);
+  start_sequence ();
+  rtx cc = aarch64_gen_compare_reg (EQ, sp, const0_rtx);
+  emit_insn (gen_cstoredi_neg (tracker,
+			       gen_rtx_NE (CCmode, cc, const0_rtx), cc));
+  rtx_insn *seq = get_insns ();
+  end_sequence ();
+  return seq;
+}
+
+/* Main speculation tracking pass.  */
+unsigned int
+aarch64_do_track_speculation ()
+{
+  basic_block bb;
+  bool needs_tracking = false;
+  bool need_second_pass = false;
+  rtx_insn *insn;
+  int fixups_pending = 0;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      insn = BB_END (bb);
+
+      if (dump_file)
+	fprintf (dump_file, "Basic block %d:\n", bb->index);
+
+      while (insn != BB_HEAD (bb)
+	     && NOTE_P (insn))
+	insn = PREV_INSN (insn);
+
+      if (control_flow_insn_p (insn))
+	{
+	  if (any_condjump_p (insn))
+	    {
+	      if (dump_file)
+		{
+		  fprintf (dump_file, "  condjump\n");
+		  dump_insn_slim (dump_file, insn);
+		}
+
+	      rtx src = SET_SRC (pc_set (insn));
+
+	      /* Check for an inverted jump, where the fall-through edge
+		 appears first.  */
+	      bool inverted = GET_CODE (XEXP (src, 2)) != PC;
+	      /* The other edge must be the PC (we assume that we don't
+		 have conditional return instructions).  */
+	      gcc_assert (GET_CODE (XEXP (src, 1 + !inverted)) == PC);
+
+	      rtx cond = copy_rtx (XEXP (src, 0));
+	      gcc_assert (COMPARISON_P (cond)
+			  && REG_P (XEXP (cond, 0))
+			  && REGNO (XEXP (cond, 0)) == CC_REGNUM
+			  && XEXP (cond, 1) == const0_rtx);
+	      enum rtx_code inv_cond_code
+		= reversed_comparison_code (cond, insn);
+	      /* We should be able to reverse all conditions.  */
+	      gcc_assert (inv_cond_code != UNKNOWN);
+	      rtx inv_cond = gen_rtx_fmt_ee (inv_cond_code, GET_MODE (cond),
+					     copy_rtx (XEXP (cond, 0)),
+					     copy_rtx (XEXP (cond, 1)));
+	      if (inverted)
+		std::swap (cond, inv_cond);
+
+	      insert_insn_on_edge (gen_speculation_tracker (cond),
+				   BRANCH_EDGE (bb));
+	      insert_insn_on_edge (gen_speculation_tracker (inv_cond),
+				   FALLTHRU_EDGE (bb));
+	      needs_tracking = true;
+	    }
+	  else if (GET_CODE (PATTERN (insn)) == RETURN)
+	    {
+	      /* If we already know we'll need a second pass, don't put
+		 out the return sequence now, or we might end up with
+		 two copies.  Instead, we'll do all return statements
+		 during the second pass.  However, if this is the
+		 first return insn we've found and we already
+		 know that we'll need to emit the code, we can save a
+		 second pass by emitting the code now.  */
+	      if (needs_tracking && ! need_second_pass)
+		{
+		  rtx_insn *seq = aarch64_speculation_clobber_sp ();
+		  emit_insn_before (seq, insn);
+		}
+	      else
+		{
+		  fixups_pending++;
+		  need_second_pass = true;
+		}
+	    }
+	  else if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
+	    {
+	      rtx_insn *seq = aarch64_speculation_clobber_sp ();
+	      emit_insn_before (seq, insn);
+	      needs_tracking = true;
+	    }
+	}
+      else
+	{
+	  if (dump_file)
+	    {
+	      fprintf (dump_file, "  other\n");
+	      dump_insn_slim (dump_file, insn);
+	    }
+	}
+    }
+
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      rtx_insn *end = BB_END (bb);
+      rtx_insn *call_insn = NULL;
+
+      if (bb->flags & BB_NON_LOCAL_GOTO_TARGET)
+	{
+	  rtx_insn *label = NULL;
+	  /* For non-local goto targets we have to recover the
+	     speculation state from SP.  Find the last code label at
+	     the head of the block and place the fixup sequence after
+	     that.  */
+	  for (insn = BB_HEAD (bb); insn != end; insn = NEXT_INSN (insn))
+	    {
+	      if (LABEL_P (insn))
+		label = insn;
+	      /* Never put anything before the basic block note.  */
+	      if (NOTE_INSN_BASIC_BLOCK_P (insn))
+		label = insn;
+	      if (INSN_P (insn))
+		break;
+	    }
+
+	  gcc_assert (label);
+	  emit_insn_after (aarch64_speculation_establish_tracker (), label);
+	}
+
+      /* Scan the insns looking for calls.  We need to pass the
+	 speculation tracking state encoded in to SP.  After a call we
+	 restore the speculation tracking into the tracker register.
+	 To avoid unnecessary transfers we look for two or more calls
+	 within a single basic block and eliminate, where possible,
+	 any redundant operations.  */
+      for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn))
+	{
+	  if (NONDEBUG_INSN_P (insn)
+	      && recog_memoized (insn) >= 0
+	      && (get_attr_speculation_barrier (insn)
+		  == SPECULATION_BARRIER_TRUE))
+	    {
+	      if (call_insn)
+		{
+		  /* This instruction requires the speculation
+		     tracking to be in the tracker register.  If there
+		     was an earlier call in this block, we need to
+		     copy the speculation tracking back there.  */
+		  emit_insn_after (aarch64_speculation_establish_tracker (),
+				   call_insn);
+		  call_insn = NULL;
+		}
+
+	      needs_tracking = true;
+	    }
+
+	  if (CALL_P (insn))
+	    {
+	      bool tailcall
+		= (SIBLING_CALL_P (insn)
+		   || find_reg_note (insn, REG_NORETURN, NULL_RTX));
+
+	      /* Tailcalls are like returns, we can eliminate the
+		 transfer between the tracker register and SP if we
+		 know that this function does not itself need
+		 tracking.  */
+	      if (tailcall && (need_second_pass || !needs_tracking))
+		{
+		  /* Don't clear call_insn if it is set - needs_tracking
+		     will be true in that case and so we will end
+		     up putting out mitigation sequences.  */
+		  fixups_pending++;
+		  need_second_pass = true;
+		  break;
+		}
+
+	      needs_tracking = true;
+
+	      /* We always need a transfer before the first call in a BB.  */
+	      if (!call_insn)
+		emit_insn_before (aarch64_speculation_clobber_sp (), insn);
+
+	      /* Tail-calls and no-return calls don't need any post-call
+		 reestablishment of the tracker.  */
+	      if (! tailcall)
+		call_insn = insn;
+	      else
+		call_insn = NULL;
+	    }
+
+	  if (insn == end)
+	    break;
+	}
+
+      if (call_insn)
+	{
+	  rtx_insn *seq = aarch64_speculation_establish_tracker ();
+
+	  /* Handle debug insns at the end of the BB.  Put the extra
+	     insns after them.  This ensures that we have consistent
+	     behaviour for the placement of the extra insns between
+	     debug and non-debug builds.  */
+	  for (insn = call_insn;
+	       insn != end && DEBUG_INSN_P (NEXT_INSN (insn));
+	       insn = NEXT_INSN (insn))
+	    ;
+
+	  if (insn == end)
+	    {
+	      edge e = find_fallthru_edge (bb->succs);
+	      /* We need to be very careful about some calls that
+		 appear at the end of a basic block.  If the call
+		 involves exceptions, then the compiler may depend on
+		 this being the last instruction in the block.  The
+		 easiest way to handle this is to commit the new
+		 instructions on the fall-through edge and to let
+		 commit_edge_insertions clean things up for us.
+
+		 Sometimes, eg with OMP, there may not even be an
+		 outgoing edge after the call.  In that case, there's
+		 not much we can do, presumably the compiler has
+		 decided that the call can never return in this
+		 context.  */
+	      if (e)
+		{
+		  /* We need to set the location lists explicitly in
+		     this case.  */
+		  if (! INSN_P (seq))
+		    {
+		      start_sequence ();
+		      emit_insn (seq);
+		      seq = get_insns ();
+		      end_sequence ();
+		    }
+
+		  for (rtx_insn *list = seq; list; list = NEXT_INSN (list))
+		    INSN_LOCATION (list) = INSN_LOCATION (call_insn);
+
+		  insert_insn_on_edge (seq, e);
+		}
+	    }
+	  else
+	    emit_insn_after (seq, call_insn);
+	}
+    }
+
+  if (needs_tracking)
+    {
+      if (need_second_pass)
+	{
+	  /* We found a return instruction before we found out whether
+	     or not we need to emit the tracking code, but we now
+	     know we do.  Run quickly over the basic blocks and
+	     fix up the return insns.  */
+	  FOR_EACH_BB_FN (bb, cfun)
+	    {
+	      insn = BB_END (bb);
+
+	      while (insn != BB_HEAD (bb)
+		     && NOTE_P (insn))
+		insn = PREV_INSN (insn);
+
+	      if ((control_flow_insn_p (insn)
+		   && GET_CODE (PATTERN (insn)) == RETURN)
+		  || (CALL_P (insn)
+		      && (SIBLING_CALL_P (insn)
+			  || find_reg_note (insn, REG_NORETURN, NULL_RTX))))
+		{
+		  rtx_insn *seq = aarch64_speculation_clobber_sp ();
+		  emit_insn_before (seq, insn);
+		  fixups_pending--;
+		}
+	    }
+	  gcc_assert (fixups_pending == 0);
+	}
+
+      /* Set up the initial value of the tracker, using the incoming SP.  */
+      insert_insn_on_edge (aarch64_speculation_establish_tracker (),
+			   single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+      commit_edge_insertions ();
+    }
+
+  return 0;
+}
+
+namespace {
+
+const pass_data pass_data_aarch64_track_speculation =
+{
+  RTL_PASS,		/* type.  */
+  "speculation",	/* name.  */
+  OPTGROUP_NONE,	/* optinfo_flags.  */
+  TV_MACH_DEP,		/* tv_id.  */
+  0,			/* properties_required.  */
+  0,			/* properties_provided.  */
+  0,			/* properties_destroyed.  */
+  0,			/* todo_flags_start.  */
+  0			/* todo_flags_finish.  */
+};
+
+class pass_track_speculation : public rtl_opt_pass
+{
+ public:
+  pass_track_speculation(gcc::context *ctxt)
+    : rtl_opt_pass(pass_data_aarch64_track_speculation, ctxt)
+    {}
+
+  /* opt_pass methods:  */
+  virtual bool gate (function *)
+    {
+      return aarch64_track_speculation;
+    }
+
+  virtual unsigned int execute (function *)
+    {
+      return aarch64_do_track_speculation ();
+    }
+}; // class pass_track_speculation.
+} // anon namespace.
+
+/* Create a new pass instance.  */
+rtl_opt_pass *
+make_pass_track_speculation (gcc::context *ctxt)
+{
+  return new pass_track_speculation (ctxt);
+}
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 90849b5..cca465e 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -12587,6 +12587,19 @@ aarch64_conditional_register_usage (void)
 	fixed_regs[i] = 1;
 	call_used_regs[i] = 1;
       }
+
+  /* When tracking speculation, we need a couple of call-clobbered registers
+     to track the speculation state.  It would be nice to just use
+     IP0 and IP1, but currently there are numerous places that just
+     assume these registers are free for other uses (eg pointer
+     authentication).  */
+  if (aarch64_track_speculation)
+    {
+      fixed_regs[SPECULATION_TRACKER_REGNUM] = 1;
+      call_used_regs[SPECULATION_TRACKER_REGNUM] = 1;
+      fixed_regs[SPECULATION_SCRATCH_REGNUM] = 1;
+      call_used_regs[SPECULATION_SCRATCH_REGNUM] = 1;
+    }
 }
 
 /* Walk down the type tree of TYPE counting consecutive base elements.
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 259a07d..528d03d 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -88,6 +88,10 @@ (define_constants
     (P13_REGNUM		81)
     (P14_REGNUM		82)
     (P15_REGNUM		83)
+    ;; A couple of call-clobbered registers that we need to reserve when
+    ;; tracking speculation this is not ABI, so is subject to change.
+    (SPECULATION_TRACKER_REGNUM 15)
+    (SPECULATION_SCRATCH_REGNUM 14)
   ]
 )
 
@@ -195,6 +199,7 @@ (define_c_enum "unspec" [
     UNSPEC_CLASTB
     UNSPEC_FADDA
     UNSPEC_REV_SUBREG
+    UNSPEC_SPECULATION_TRACKER
 ])
 
 (define_c_enum "unspecv" [
@@ -287,6 +292,11 @@ (define_attr "length" ""
 ;; no predicated insns.
 (define_attr "predicated" "yes,no" (const_string "no"))
 
+;; Set to true on an insn that requires the speculation tracking state to be
+;; in the tracking register before the insn issues.  Otherwise the compiler
+;; may chose to hold the tracking state encoded in SP.
+(define_attr "speculation_barrier" "true,false" (const_string "false"))
+
 ;; -------------------------------------------------------------------
 ;; Pipeline descriptions and scheduling
 ;; -------------------------------------------------------------------
@@ -3079,7 +3089,7 @@ (define_insn "*<su_optab>divsi3_uxtw"
 
 (define_insn "cmp<mode>"
   [(set (reg:CC CC_REGNUM)
-	(compare:CC (match_operand:GPI 0 "register_operand" "r,r,r")
+	(compare:CC (match_operand:GPI 0 "register_operand" "rk,rk,rk")
 		    (match_operand:GPI 1 "aarch64_plus_operand" "r,I,J")))]
   ""
   "@
@@ -6088,6 +6098,21 @@ (define_expand "doloop_end"
   DONE;
 })
 
+;; Track speculation through conditional branches.  We assume that
+;; SPECULATION_TRACKER_REGNUM is reserved for this purpose when necessary.
+(define_insn "speculation_tracker"
+  [(set (reg:DI SPECULATION_TRACKER_REGNUM)
+	(unspec [(reg:DI SPECULATION_TRACKER_REGNUM) (match_operand 0)]
+	 UNSPEC_SPECULATION_TRACKER))]
+  ""
+  {
+    operands[1] = gen_rtx_REG (DImode, SPECULATION_TRACKER_REGNUM);
+    output_asm_insn ("csel\\t%1, %1, xzr, %m0", operands);
+    return "";
+  }
+  [(set_attr "type" "csel")]
+)
+
 ;; Helper for aarch64.c code.
 (define_expand "set_clobber_cc"
   [(parallel [(set (match_operand 0)
@@ -6100,7 +6125,8 @@ (define_insn "speculation_barrier"
   ""
   "isb\;dsb\\tsy"
   [(set_attr "length" "8")
-   (set_attr "type" "block")]
+   (set_attr "type" "block")
+   (set_attr "speculation_barrier" "true")]
 )
 
 ;; AdvSIMD Stuff
diff --git a/gcc/config/aarch64/t-aarch64 b/gcc/config/aarch64/t-aarch64
index 0be1f0d..5d54853 100644
--- a/gcc/config/aarch64/t-aarch64
+++ b/gcc/config/aarch64/t-aarch64
@@ -67,6 +67,16 @@ cortex-a57-fma-steering.o: $(srcdir)/config/aarch64/cortex-a57-fma-steering.c \
 	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 		$(srcdir)/config/aarch64/cortex-a57-fma-steering.c
 
+aarch64-speculation.o: $(srcdir)/config/aarch64/aarch64-speculation.cc \
+    $(CONFIG_H) \
+    $(SYSTEM_H) \
+    $(TM_H) \
+    $(TARGET_H) \
+    $(RTL_BASE_H) \
+    $(TREE_PASS_H)
+	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_SPPFLAGS) $(INCLUDES) \
+	  $(srcdir)/config/aarch64/aarch64-speculation.cc
+
 comma=,
 MULTILIB_OPTIONS    = $(subst $(comma),/, $(patsubst %, mabi=%, $(subst $(comma),$(comma)mabi=,$(TM_MULTILIB_CONFIG))))
 MULTILIB_DIRNAMES   = $(subst $(comma), ,$(TM_MULTILIB_CONFIG))
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 9804808..ddba9c8 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -598,7 +598,7 @@ Objective-C and Objective-C++ Dialects}.
 -mpc-relative-literal-loads @gol
 -msign-return-address=@var{scope} @gol
 -march=@var{name}  -mcpu=@var{name}  -mtune=@var{name}  @gol
--moverride=@var{string}  -mverbose-cost-dump}
+-moverride=@var{string}  -mverbose-cost-dump -mtrack-speculation} 
 
 @emph{Adapteva Epiphany Options}
 @gccoptlist{-mhalf-reg-file  -mprefer-short-insn-regs @gol
@@ -14654,6 +14654,14 @@ This option only has an effect if @option{-ffast-math} or
 precision of division results to about 16 bits for
 single precision and to 32 bits for double precision.
 
+@item -mtrack-speculation
+@itemx -mno-track-speculation
+Enable or disable generation of additional code to track speculative
+execution through conditional branches.  The tracking state can then
+be used by the compiler when expanding calls to
+@code{__builtin_speculation_safe_copy} to permit a more efficient code
+sequence to be generated.
+
 @item -march=@var{name}
 @opindex march
 Specify the name of the target architecture and, optionally, one or

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 08/11] targhooks - provide an alternative hook for targets that never execute speculatively
  2018-07-27  9:38 ` [PATCH 00/11] (v2) " Richard Earnshaw
                     ` (3 preceding siblings ...)
  2018-07-27  9:38   ` [PATCH 09/11] pdp11 - example of a port not needing a speculation barrier Richard Earnshaw
@ 2018-07-27  9:38   ` Richard Earnshaw
  2018-07-30 13:17     ` Richard Biener
  2018-07-27  9:38   ` [PATCH 11/11] rs6000 - add speculation_barrier pattern Richard Earnshaw
                     ` (6 subsequent siblings)
  11 siblings, 1 reply; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-27  9:38 UTC (permalink / raw)
  To: gcc-patches, rguenther; +Cc: Richard Earnshaw

[-- Attachment #1: Type: text/plain, Size: 850 bytes --]


This hook adds an alternative implementation for the target hook
TARGET_HAVE_SPECULATION_SAFE_VALUE; it can be used by targets that have no
CPU implementations that execute code speculatively.  All that is needed for
such targets now is to add:

 #undef TARGET_HAVE_SPECULATION_SAFE_VALUE
 #define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed.

to where you have your other target hooks and you're done.

gcc:
	* targhooks.h (speculation_safe_value_not_needed): New prototype.
	* targhooks.c (speculation_safe_value_not_needed): New function.
	* target.def (have_speculation_safe_value): Update documentation.
	* doc/tm.texi: Regenerated.
---
 gcc/doc/tm.texi | 5 +++++
 gcc/target.def  | 7 ++++++-
 gcc/targhooks.c | 7 +++++++
 gcc/targhooks.h | 1 +
 4 files changed, 19 insertions(+), 1 deletion(-)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0008-targhooks-provide-an-alternative-hook-for-targets-th.patch --]
[-- Type: text/x-patch; name="0008-targhooks-provide-an-alternative-hook-for-targets-th.patch", Size: 2716 bytes --]

diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 15b0ab8..f36e376 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -11959,6 +11959,11 @@ This hook is used to determine the level of target support for
  a pattern named @code{speculation_barrier}.  Else it returns true
  for the first case and whether the pattern is enabled for the current
  compilation for the second case.
+ 
+ For targets that have no processors that can execute instructions
+ speculatively an alternative implemenation of this hook is available:
+ simply redefine this hook to @code{speculation_safe_value_not_needed}
+ along with your other target hooks.
 @end deftypefn
 
 @deftypefn {Target Hook} rtx TARGET_SPECULATION_SAFE_VALUE (machine_mode @var{mode}, rtx @var{result}, rtx @var{val}, rtx @var{failval})
diff --git a/gcc/target.def b/gcc/target.def
index d598067..5599eb4 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4206,7 +4206,12 @@ DEFHOOK
  The default implementation returns false if the target does not define\n\
  a pattern named @code{speculation_barrier}.  Else it returns true\n\
  for the first case and whether the pattern is enabled for the current\n\
- compilation for the second case.",
+ compilation for the second case.\n\
+ \n\
+ For targets that have no processors that can execute instructions\n\
+ speculatively an alternative implemenation of this hook is available:\n\
+ simply redefine this hook to @code{speculation_safe_value_not_needed}\n\
+ along with your other target hooks.",
 bool, (bool active), default_have_speculation_safe_value)
 
 DEFHOOK
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index 06de1e3..62051a9 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -2324,6 +2324,13 @@ default_have_speculation_safe_value (bool active)
   return false;
 #endif
 }
+/* Alternative implementation of TARGET_HAVE_SPECULATION_SAFE_VALUE
+   that can be used on targets that never have speculative execution.  */
+bool
+speculation_safe_value_not_needed (bool active)
+{
+  return !active;
+}
 
 /* Default implementation of the speculation-safe-load builtin.  This
    implementation simply copies val to result and generates a
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 74ffe5f..b716b97 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -286,6 +286,7 @@ extern void default_select_early_remat_modes (sbitmap);
 extern tree default_preferred_else_value (unsigned, tree, unsigned, tree *);
 
 extern bool default_have_speculation_safe_value (bool);
+extern bool speculation_safe_value_not_needed (bool);
 extern rtx default_speculation_safe_value (machine_mode, rtx, rtx, rtx);
 
 #endif /* GCC_TARGHOOKS_H */

^ permalink raw reply	[flat|nested] 82+ messages in thread

* [PATCH 04/11] AArch64 - Add new option -mtrack-speculation
  2018-07-27  9:38 ` [PATCH 00/11] (v2) " Richard Earnshaw
@ 2018-07-27  9:38   ` Richard Earnshaw
  2018-07-27  9:38   ` [PATCH 05/11] AArch64 - disable CB[N]Z TB[N]Z when tracking speculation Richard Earnshaw
                     ` (10 subsequent siblings)
  11 siblings, 0 replies; 82+ messages in thread
From: Richard Earnshaw @ 2018-07-27  9:38 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Earnshaw

[-- Attachment #1: Type: text/plain, Size: 308 bytes --]


This patch doesn't do anything useful, it simply adds a new command-line
option -mtrack-speculation to AArch64.  Subsequent patches build on this.

	* config/aarch64/aarch64.opt (mtrack-speculation): New target option.
---
 gcc/config/aarch64/aarch64.opt | 4 ++++
 1 file changed, 4 insertions(+)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0004-AArch64-Add-new-option-mtrack-speculation.patch --]
[-- Type: text/x-patch; name="0004-AArch64-Add-new-option-mtrack-speculation.patch", Size: 558 bytes --]

diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt
index 1426b45..bc9b22a 100644
--- a/gcc/config/aarch64/aarch64.opt
+++ b/gcc/config/aarch64/aarch64.opt
@@ -214,3 +214,7 @@ Target RejectNegative Joined Enum(sve_vector_bits) Var(aarch64_sve_vector_bits)
 mverbose-cost-dump
 Common Undocumented Var(flag_aarch64_verbose_cost)
 Enables verbose cost model dumping in the debug dump files.
+
+mtrack-speculation
+Target Var(aarch64_track_speculation)
+Generate code to track when the CPU might be speculating incorrectly.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 1/7] Add __builtin_speculation_safe_value
  2018-07-27  8:59               ` Richard Earnshaw (lists)
@ 2018-07-27 10:59                 ` Joseph Myers
  0 siblings, 0 replies; 82+ messages in thread
From: Joseph Myers @ 2018-07-27 10:59 UTC (permalink / raw)
  To: Richard Earnshaw (lists); +Cc: Paul Koning, Richard Biener, GCC Patches

On Fri, 27 Jul 2018, Richard Earnshaw (lists) wrote:

> The c-c++-common/spec-barrier-1.c test will fail on any target that has
> not been updated (it deliberately doesn't check for
> __HAVE_SPECULATION_BARRIER before trying to use the new intrinsic).  The
> test contains a comment to that effect.  That should be enough to alert
> maintainers if they are tracking testsuite errors.

Introducing a test failure is not enough.  You need to *explicitly* alert 
target maintainers to the need for action, with a self-contained 
explanation not assuming any prior understanding of Spectre and its 
mitigations, and if any backport is to be considered you'll then need to 
track the status of different targets and remind maintainers as needed (so 
that you know when all targets have been updated, or not updated despite 
maintainers having been informed a few months previously without the 
emails bouncing and reminded a few times since, or not updated and the 
maintainers have explicitly acknowledged this and given their OK to a 
backport without updates for their architectures).

A mail to the gcc list (that draws attention in the subject line and the 
first sentence to the need for architecture maintainer action) is the bare 
minimum (you should not assume target maintainers read gcc-patches 
discussions not mentioning their architecture in the subject), but CC:ing 
the architecture maintainers (immediately, or for those not fixed within a 
month or two) provides better assurance that the issue has been properly 
drawn to their attention.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 01/11] Add __builtin_speculation_safe_value
  2018-07-27  9:38   ` [PATCH 01/11] Add __builtin_speculation_safe_value Richard Earnshaw
@ 2018-07-27 12:11     ` Nathan Sidwell
  2018-07-27 12:32       ` Richard Earnshaw (lists)
  2018-07-27 12:53       ` Richard Earnshaw (lists)
  2018-07-30 13:16     ` Richard Biener
  1 sibling, 2 replies; 82+ messages in thread
From: Nathan Sidwell @ 2018-07-27 12:11 UTC (permalink / raw)
  To: Richard Earnshaw, gcc-patches, joseph, jason; +Cc: rguenther

On 07/27/2018 05:37 AM, Richard Earnshaw wrote:

+/* 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)

If I'm reading the expander correctly, isn't it 'pointers to integral 
types', not any old pointer?

so the following needs some adjustment...

+  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;

Are incomplete integral types a thing? (forward enum extension?)

I presume resolve_overloaded_builtin already works correctly with 
template instantiations, but a templatatized testcase would be nice -- 
shout if you'd like help constructing one.

nathan

-- 
Nathan Sidwell

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 01/11] Add __builtin_speculation_safe_value
  2018-07-27 12:11     ` Nathan Sidwell
@ 2018-07-27 12:32       ` Richard Earnshaw (lists)
  2018-07-27 12:49         ` Nathan Sidwell
  2018-07-27 12:53       ` Richard Earnshaw (lists)
  1 sibling, 1 reply; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-07-27 12:32 UTC (permalink / raw)
  To: Nathan Sidwell, gcc-patches, joseph, jason; +Cc: rguenther

On 27/07/18 13:11, Nathan Sidwell wrote:
> On 07/27/2018 05:37 AM, Richard Earnshaw wrote:
> 
> +/* 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)
> 
> If I'm reading the expander correctly, isn't it 'pointers to integral
> types', not any old pointer?
> 

The intention is to allow pointer to anything.

> so the following needs some adjustment...
> 
> +  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;
> 
> Are incomplete integral types a thing? (forward enum extension?)
> 
> I presume resolve_overloaded_builtin already works correctly with
> template instantiations, but a templatatized testcase would be nice --
> shout if you'd like help constructing one.
> 

Yelp!

> nathan
> 

R.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 01/11] Add __builtin_speculation_safe_value
  2018-07-27 12:32       ` Richard Earnshaw (lists)
@ 2018-07-27 12:49         ` Nathan Sidwell
  0 siblings, 0 replies; 82+ messages in thread
From: Nathan Sidwell @ 2018-07-27 12:49 UTC (permalink / raw)
  To: Richard Earnshaw (lists), gcc-patches, joseph, jason; +Cc: rguenther

On 07/27/2018 08:32 AM, Richard Earnshaw (lists) wrote:

> The intention is to allow pointer to anything.

Oh, the speculation safe fetch is of the pointer itself, not the thing 
being pointed to.  I'd missed that.  I'm not sure I understand why that 
needs special casing down to the expander (why can't the resolver figure 
the mode?), but you're the expert in that kind of stuff.

>> I presume resolve_overloaded_builtin already works correctly with
>> template instantiations, but a templatatized testcase would be nice --
>> shout if you'd like help constructing one.
>>
> 
> Yelp!

added to todo list.

nathan

-- 
Nathan Sidwell

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 01/11] Add __builtin_speculation_safe_value
  2018-07-27 12:11     ` Nathan Sidwell
  2018-07-27 12:32       ` Richard Earnshaw (lists)
@ 2018-07-27 12:53       ` Richard Earnshaw (lists)
  1 sibling, 0 replies; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-07-27 12:53 UTC (permalink / raw)
  To: Nathan Sidwell, gcc-patches, joseph, jason; +Cc: rguenther

On 27/07/18 13:11, Nathan Sidwell wrote:

> +  if (!COMPLETE_TYPE_P (type))
> +    goto incompatible;
> 
> Are incomplete integral types a thing? (forward enum extension?)
> 

I don't think so, at least not at the level of having an instance of
such a type (as opposed to a pointer to one).  Enums, for example, might
be packed by default, so until the type is complete you don't know its
size or alignment.

Anyway, this bit of code is essentially lifted from sync_resolve_size.

R.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 09/11] pdp11 - example of a port not needing a speculation barrier
  2018-07-27  9:38   ` [PATCH 09/11] pdp11 - example of a port not needing a speculation barrier Richard Earnshaw
@ 2018-07-27 13:27     ` Paul Koning
  2018-07-27 15:19       ` Richard Biener
  0 siblings, 1 reply; 82+ messages in thread
From: Paul Koning @ 2018-07-27 13:27 UTC (permalink / raw)
  To: Richard Earnshaw; +Cc: GCC Patches



> On Jul 27, 2018, at 5:37 AM, Richard Earnshaw <Richard.Earnshaw@arm.com> wrote:
> 
> 
> This patch is intended as an example of all that is needed if the
> target system doesn't support CPUs that have speculative execution.
> I've chosen the pdp11 port on the basis that it's old enough that this
> is likely to be true for all existing implementations and that there
> is also little chance of that changing in future!
> 
> 	* config/pdp11/pdp11.c (TARGET_HAVE_SPECULATION_SAFE_VALUE): Redefine
> 	to speculation_safe_value_not_needed.
> ---
> gcc/config/pdp11/pdp11.c | 3 +++
> 1 file changed, 3 insertions(+)
> 
> <0009-pdp11-example-of-a-port-not-needing-a-speculation-ba.patch>

Correct, no speculative instruction now, and I don't think any of the people constructing PDP11s (yes there are some) are going to be adding it.

Thanks Richard.

	paul

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 09/11] pdp11 - example of a port not needing a speculation barrier
  2018-07-27 13:27     ` Paul Koning
@ 2018-07-27 15:19       ` Richard Biener
  0 siblings, 0 replies; 82+ messages in thread
From: Richard Biener @ 2018-07-27 15:19 UTC (permalink / raw)
  To: gcc-patches, Paul Koning, Richard Earnshaw; +Cc: GCC Patches

On July 27, 2018 3:27:49 PM GMT+02:00, Paul Koning <paulkoning@comcast.net> wrote:
>
>
>> On Jul 27, 2018, at 5:37 AM, Richard Earnshaw
><Richard.Earnshaw@arm.com> wrote:
>> 
>> 
>> This patch is intended as an example of all that is needed if the
>> target system doesn't support CPUs that have speculative execution.
>> I've chosen the pdp11 port on the basis that it's old enough that
>this
>> is likely to be true for all existing implementations and that there
>> is also little chance of that changing in future!
>> 
>> 	* config/pdp11/pdp11.c (TARGET_HAVE_SPECULATION_SAFE_VALUE):
>Redefine
>> 	to speculation_safe_value_not_needed.
>> ---
>> gcc/config/pdp11/pdp11.c | 3 +++
>> 1 file changed, 3 insertions(+)
>> 
>> <0009-pdp11-example-of-a-port-not-needing-a-speculation-ba.patch>
>
>Correct, no speculative instruction now, and I don't think any of the
>people constructing PDP11s (yes there are some) are going to be adding
>it.

It's not really about speculative instructions but about things like having a branch predictor and ways to recover from badly predicted ones and thus from wrongly speculatively executed regular instructions. 

Probably every pipelined CPU implementation nowadays has speculative execution. 

Richard. 

>Thanks Richard.
>
>	paul

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 00/11] (v2) Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-27  9:38 ` [PATCH 00/11] (v2) " Richard Earnshaw
                     ` (10 preceding siblings ...)
  2018-07-27  9:38   ` [PATCH 02/11] Arm - add speculation_barrier pattern Richard Earnshaw
@ 2018-07-27 19:49   ` John David Anglin
  2018-08-02 18:40     ` Jeff Law
  11 siblings, 1 reply; 82+ messages in thread
From: John David Anglin @ 2018-07-27 19:49 UTC (permalink / raw)
  To: Richard Earnshaw; +Cc: GCC Patches, law

On 2018-07-27 5:37 AM, Richard Earnshaw wrote:
> Port Maintainers: You need to decide what action is required for your
> port to handle speculative execution, even if that action is to use
> the trivial no-speculation on this architecture.  You must also
> consider whether or not a furture implementation of your architecture
> might need to deal with this in making that decision.
On hppa, I think we should go with the hook that assumes there is no 
speculative execution.

Nominally, there is branch prediction and speculative execution; but the 
spectre test program
was not able to successfully access memory on my rp3440.

As far as I know, the details of speculative execution on PA-RISC are 
not public.  Jeff would know
best.

Dave

-- 
John David Anglin  dave.anglin@bell.net

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 10/11] x86 - add speculation_barrier pattern
  2018-07-27  9:38   ` [PATCH 10/11] x86 " Richard Earnshaw
@ 2018-07-28  8:25     ` Uros Bizjak
  2018-07-31 23:15       ` H.J. Lu
  0 siblings, 1 reply; 82+ messages in thread
From: Uros Bizjak @ 2018-07-28  8:25 UTC (permalink / raw)
  To: Richard Earnshaw; +Cc: gcc-patches, Jan Hubicka, H. J. Lu

On Fri, Jul 27, 2018 at 11:37 AM, Richard Earnshaw
<Richard.Earnshaw@arm.com> wrote:
>
> This patch adds a speculation barrier for x86, based on my
> understanding of the required mitigation for that CPU, which is to use
> an lfence instruction.
>
> This patch needs some review by an x86 expert and if adjustments are
> needed, I'd appreciate it if they could be picked up by the port
> maintainer.  This is supposed to serve as an example of how to deploy
> the new __builtin_speculation_safe_value() intrinsic on this
> architecture.
>
>         * config/i386/i386.md (unspecv): Add UNSPECV_SPECULATION_BARRIER.
>         (speculation_barrier): New insn.

The implementation is OK, but someone from Intel (CC'd) should clarify
if lfence is the correct insn.

Uros.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 01/11] Add __builtin_speculation_safe_value
  2018-07-27  9:38   ` [PATCH 01/11] Add __builtin_speculation_safe_value Richard Earnshaw
  2018-07-27 12:11     ` Nathan Sidwell
@ 2018-07-30 13:16     ` Richard Biener
  2018-07-31 19:25       ` H.J. Lu
  1 sibling, 1 reply; 82+ messages in thread
From: Richard Biener @ 2018-07-30 13:16 UTC (permalink / raw)
  To: Richard Earnshaw; +Cc: gcc-patches, joseph, jason, nathan

On Fri, 27 Jul 2018, 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.

OK.

Thanks,
Richard.

> 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.
> ---
>  gcc/builtin-attrs.def                       |   2 +
>  gcc/builtin-types.def                       |   6 +
>  gcc/builtins.c                              |  60 ++++++++++
>  gcc/builtins.def                            |  22 ++++
>  gcc/c-family/c-common.c                     | 164 ++++++++++++++++++++++++++++
>  gcc/c-family/c-cppbuiltin.c                 |   7 +-
>  gcc/doc/cpp.texi                            |   4 +
>  gcc/doc/extend.texi                         |  91 +++++++++++++++
>  gcc/doc/md.texi                             |  15 +++
>  gcc/doc/tm.texi                             |  31 ++++++
>  gcc/doc/tm.texi.in                          |   4 +
>  gcc/target.def                              |  35 ++++++
>  gcc/targhooks.c                             |  32 ++++++
>  gcc/targhooks.h                             |   3 +
>  gcc/testsuite/c-c++-common/spec-barrier-1.c |  38 +++++++
>  gcc/testsuite/c-c++-common/spec-barrier-2.c |  17 +++
>  gcc/testsuite/gcc.dg/spec-barrier-3.c       |  13 +++
>  17 files changed, 543 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/c-c++-common/spec-barrier-1.c
>  create mode 100644 gcc/testsuite/c-c++-common/spec-barrier-2.c
>  create mode 100644 gcc/testsuite/gcc.dg/spec-barrier-3.c
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 08/11] targhooks - provide an alternative hook for targets that never execute speculatively
  2018-07-27  9:38   ` [PATCH 08/11] targhooks - provide an alternative hook for targets that never execute speculatively Richard Earnshaw
@ 2018-07-30 13:17     ` Richard Biener
  0 siblings, 0 replies; 82+ messages in thread
From: Richard Biener @ 2018-07-30 13:17 UTC (permalink / raw)
  To: Richard Earnshaw; +Cc: gcc-patches

On Fri, 27 Jul 2018, Richard Earnshaw wrote:

> 
> This hook adds an alternative implementation for the target hook
> TARGET_HAVE_SPECULATION_SAFE_VALUE; it can be used by targets that have no
> CPU implementations that execute code speculatively.  All that is needed for
> such targets now is to add:
> 
>  #undef TARGET_HAVE_SPECULATION_SAFE_VALUE
>  #define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed.
> 
> to where you have your other target hooks and you're done.

OK.

> gcc:
> 	* targhooks.h (speculation_safe_value_not_needed): New prototype.
> 	* targhooks.c (speculation_safe_value_not_needed): New function.
> 	* target.def (have_speculation_safe_value): Update documentation.
> 	* doc/tm.texi: Regenerated.
> ---
>  gcc/doc/tm.texi | 5 +++++
>  gcc/target.def  | 7 ++++++-
>  gcc/targhooks.c | 7 +++++++
>  gcc/targhooks.h | 1 +
>  4 files changed, 19 insertions(+), 1 deletion(-)
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 01/11] Add __builtin_speculation_safe_value
  2018-07-30 13:16     ` Richard Biener
@ 2018-07-31 19:25       ` H.J. Lu
  2018-07-31 20:51         ` Ian Lance Taylor via gcc-patches
  0 siblings, 1 reply; 82+ messages in thread
From: H.J. Lu @ 2018-07-31 19:25 UTC (permalink / raw)
  To: Richard Biener
  Cc: Richard Earnshaw, GCC Patches, Joseph S. Myers, Jason Merrill,
	Nathan Sidwell

On Mon, Jul 30, 2018 at 6:16 AM, Richard Biener <rguenther@suse.de> wrote:
> On Fri, 27 Jul 2018, 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.
>
> OK.
>
> Thanks,
> Richard.
>
>> 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.
>>

I got

../../src-trunk/gcc/targhooks.c: In function ‘bool
default_have_speculation_safe_value(bool)’:
../../src-trunk/gcc/targhooks.c:2319:43: error: unused parameter
‘active’ [-Werror=unused-parameter]
 default_have_speculation_safe_value (bool active)
                                      ~~~~~^~~~~~

-- 
H.J.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 01/11] Add __builtin_speculation_safe_value
  2018-07-31 19:25       ` H.J. Lu
@ 2018-07-31 20:51         ` Ian Lance Taylor via gcc-patches
  2018-08-01  8:50           ` Richard Earnshaw (lists)
  0 siblings, 1 reply; 82+ messages in thread
From: Ian Lance Taylor via gcc-patches @ 2018-07-31 20:51 UTC (permalink / raw)
  To: H.J. Lu
  Cc: Richard Biener, Richard Earnshaw, GCC Patches, Joseph S. Myers,
	Jason Merrill, Nathan Sidwell

[-- Attachment #1: Type: text/plain, Size: 2944 bytes --]

On Tue, Jul 31, 2018 at 12:25 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Mon, Jul 30, 2018 at 6:16 AM, Richard Biener <rguenther@suse.de> wrote:
>> On Fri, 27 Jul 2018, 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.
>>
>> OK.
>>
>> Thanks,
>> Richard.
>>
>>> 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.
>>>
>
> I got
>
> ../../src-trunk/gcc/targhooks.c: In function ‘bool
> default_have_speculation_safe_value(bool)’:
> ../../src-trunk/gcc/targhooks.c:2319:43: error: unused parameter
> ‘active’ [-Werror=unused-parameter]
>  default_have_speculation_safe_value (bool active)
>                                       ~~~~~^~~~~~


Me too.

Committed this patch as obvious.

Ian


2018-07-31  Ian Lance Taylor  <iant@golang.org>

* targhooks.c (default_have_speculation_safe_value): Add
ATTRIBUTE_UNUSED.

[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 511 bytes --]

Index: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c	(revision 263179)
+++ gcc/targhooks.c	(working copy)
@@ -2316,7 +2316,7 @@ default_preferred_else_value (unsigned,
 
 /* Default implementation of TARGET_HAVE_SPECULATION_SAFE_VALUE.  */
 bool
-default_have_speculation_safe_value (bool active)
+default_have_speculation_safe_value (bool active ATTRIBUTE_UNUSED)
 {
 #ifdef HAVE_speculation_barrier
   return active ? HAVE_speculation_barrier : true;

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 11/11] rs6000 - add speculation_barrier pattern
  2018-07-27  9:38   ` [PATCH 11/11] rs6000 - add speculation_barrier pattern Richard Earnshaw
@ 2018-07-31 22:01     ` Bill Schmidt
  2018-07-31 23:31       ` Segher Boessenkool
  0 siblings, 1 reply; 82+ messages in thread
From: Bill Schmidt @ 2018-07-31 22:01 UTC (permalink / raw)
  To: Richard Earnshaw; +Cc: gcc-patches, dje.gcc, segher

Hi Richard,

I can't ack the patch, but I am happy with it.  Thank you for this work!

-- Bill

Bill Schmidt, Ph.D.
STSM, GCC Architect for Linux on Power
IBM Linux Technology Center
wschmidt@linux.vnet.ibm.com

> On Jul 27, 2018, at 4:37 AM, Richard Earnshaw <richard.earnshaw@arm.com> wrote:
> 
> 
> This patch reworks the existing rs6000_speculation_barrier pattern to
> work with the new __builtin_sepculation_safe_value() intrinsic.  The
> change is trivial as it simply requires renaming the existing speculation
> barrier pattern.
> 
> So the total patch is to delete 14 characters!
> 
> 	* config/rs6000/rs6000.md (speculation_barrier): Renamed from
> 	rs6000_speculation_barrier.
> 	* config/rs6000/rs6000.c (rs6000_expand_builtin): Adjust for
> 	new barrier pattern name.
> ---
> gcc/config/rs6000/rs6000.c  | 2 +-
> gcc/config/rs6000/rs6000.md | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
> 
> <0011-rs6000-add-speculation_barrier-pattern.patch>

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 10/11] x86 - add speculation_barrier pattern
  2018-07-28  8:25     ` Uros Bizjak
@ 2018-07-31 23:15       ` H.J. Lu
  0 siblings, 0 replies; 82+ messages in thread
From: H.J. Lu @ 2018-07-31 23:15 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: Richard Earnshaw, gcc-patches, Jan Hubicka

On Sat, Jul 28, 2018 at 1:25 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
> On Fri, Jul 27, 2018 at 11:37 AM, Richard Earnshaw
> <Richard.Earnshaw@arm.com> wrote:
>>
>> This patch adds a speculation barrier for x86, based on my
>> understanding of the required mitigation for that CPU, which is to use
>> an lfence instruction.
>>
>> This patch needs some review by an x86 expert and if adjustments are
>> needed, I'd appreciate it if they could be picked up by the port
>> maintainer.  This is supposed to serve as an example of how to deploy
>> the new __builtin_speculation_safe_value() intrinsic on this
>> architecture.
>>
>>         * config/i386/i386.md (unspecv): Add UNSPECV_SPECULATION_BARRIER.
>>         (speculation_barrier): New insn.
>
> The implementation is OK, but someone from Intel (CC'd) should clarify
> if lfence is the correct insn.
>

I checked with our people.  lfence is OK.

Thanks.

-- 
H.J.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 11/11] rs6000 - add speculation_barrier pattern
  2018-07-31 22:01     ` Bill Schmidt
@ 2018-07-31 23:31       ` Segher Boessenkool
  0 siblings, 0 replies; 82+ messages in thread
From: Segher Boessenkool @ 2018-07-31 23:31 UTC (permalink / raw)
  To: Bill Schmidt; +Cc: Richard Earnshaw, gcc-patches, dje.gcc

On Tue, Jul 31, 2018 at 05:01:02PM -0500, Bill Schmidt wrote:
> > On Jul 27, 2018, at 4:37 AM, Richard Earnshaw <richard.earnshaw@arm.com> wrote:
> > This patch reworks the existing rs6000_speculation_barrier pattern to
> > work with the new __builtin_sepculation_safe_value() intrinsic.  The
> > change is trivial as it simply requires renaming the existing speculation
> > barrier pattern.
> > 
> > So the total patch is to delete 14 characters!

> I can't ack the patch, but I am happy with it.  Thank you for this work!

Looks fine to me, too.  I'm sure someone has tested it by now, too ;-)
Okay for trunk.  Thanks!


Segher


> > 	* config/rs6000/rs6000.md (speculation_barrier): Renamed from
> > 	rs6000_speculation_barrier.
> > 	* config/rs6000/rs6000.c (rs6000_expand_builtin): Adjust for
> > 	new barrier pattern name.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 01/11] Add __builtin_speculation_safe_value
  2018-07-31 20:51         ` Ian Lance Taylor via gcc-patches
@ 2018-08-01  8:50           ` Richard Earnshaw (lists)
  2018-08-01  8:54             ` Jakub Jelinek
  0 siblings, 1 reply; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-08-01  8:50 UTC (permalink / raw)
  To: Ian Lance Taylor, H.J. Lu
  Cc: Richard Biener, GCC Patches, Joseph S. Myers, Jason Merrill,
	Nathan Sidwell

On 31/07/18 21:51, Ian Lance Taylor via gcc-patches wrote:
> On Tue, Jul 31, 2018 at 12:25 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Mon, Jul 30, 2018 at 6:16 AM, Richard Biener <rguenther@suse.de> wrote:
>>> On Fri, 27 Jul 2018, 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.
>>>
>>> OK.
>>>
>>> Thanks,
>>> Richard.
>>>
>>>> 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.
>>>>
>>
>> I got
>>
>> ../../src-trunk/gcc/targhooks.c: In function ‘bool
>> default_have_speculation_safe_value(bool)’:
>> ../../src-trunk/gcc/targhooks.c:2319:43: error: unused parameter
>> ‘active’ [-Werror=unused-parameter]
>>  default_have_speculation_safe_value (bool active)
>>                                       ~~~~~^~~~~~
> 
> 
> Me too.
> 
> Committed this patch as obvious.
> 

Thanks.

Sorry about that, I did run a full bootstrap on x86, but I had the x86
mitigation patch applied, so it didn't trip this.

R.

> Ian
> 
> 
> 2018-07-31  Ian Lance Taylor  <iant@golang.org>
> 
> * targhooks.c (default_have_speculation_safe_value): Add
> ATTRIBUTE_UNUSED.
> 

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 01/11] Add __builtin_speculation_safe_value
  2018-08-01  8:50           ` Richard Earnshaw (lists)
@ 2018-08-01  8:54             ` Jakub Jelinek
  2018-08-01  9:25               ` Richard Earnshaw (lists)
  0 siblings, 1 reply; 82+ messages in thread
From: Jakub Jelinek @ 2018-08-01  8:54 UTC (permalink / raw)
  To: Richard Earnshaw (lists)
  Cc: Ian Lance Taylor, H.J. Lu, Richard Biener, GCC Patches,
	Joseph S. Myers, Jason Merrill, Nathan Sidwell

On Wed, Aug 01, 2018 at 09:48:50AM +0100, Richard Earnshaw (lists) wrote:
> Sorry about that, I did run a full bootstrap on x86, but I had the x86
> mitigation patch applied, so it didn't trip this.

Also, I see
FAIL: c-c++-common/spec-barrier-1.c  -Wc++-compat  (test for excess errors)
FAIL: c-c++-common/spec-barrier-1.c  -std=gnu++11 (test for excess errors)
FAIL: c-c++-common/spec-barrier-1.c  -std=gnu++14 (test for excess errors)
FAIL: c-c++-common/spec-barrier-1.c  -std=gnu++98 (test for excess errors)
If some targets are expected to emit a warning on this test and you don't
want to maintain exact list of targets which warn in the testsuite,
shouldn't the test use -w in dg-options?

	Jakub

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 01/11] Add __builtin_speculation_safe_value
  2018-08-01  8:54             ` Jakub Jelinek
@ 2018-08-01  9:25               ` Richard Earnshaw (lists)
  0 siblings, 0 replies; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-08-01  9:25 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Ian Lance Taylor, H.J. Lu, Richard Biener, GCC Patches,
	Joseph S. Myers, Jason Merrill, Nathan Sidwell

On 01/08/18 09:54, Jakub Jelinek wrote:
> On Wed, Aug 01, 2018 at 09:48:50AM +0100, Richard Earnshaw (lists) wrote:
>> Sorry about that, I did run a full bootstrap on x86, but I had the x86
>> mitigation patch applied, so it didn't trip this.
> 
> Also, I see
> FAIL: c-c++-common/spec-barrier-1.c  -Wc++-compat  (test for excess errors)
> FAIL: c-c++-common/spec-barrier-1.c  -std=gnu++11 (test for excess errors)
> FAIL: c-c++-common/spec-barrier-1.c  -std=gnu++14 (test for excess errors)
> FAIL: c-c++-common/spec-barrier-1.c  -std=gnu++98 (test for excess errors)
> If some targets are expected to emit a warning on this test and you don't
> want to maintain exact list of targets which warn in the testsuite,
> shouldn't the test use -w in dg-options?
> 
> 	Jakub
> 

As explained (both here on the list and in the test).  This is
deliberate.  The test is expected to fail on targets that have not yet
been updated to state what action (including nothing needed) is needed
to mitigate against speculation vulnerabilities.

I'll create a set of bugzilla entries shortly, and a meta bug to hold
them, to track each unfixed port's status.

A major reason for this test is avoid having ports silently ignore the
problem.

R.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 00/11] (v2) Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-07-27 19:49   ` [PATCH 00/11] (v2) Mitigation against unsafe data speculation (CVE-2017-5753) John David Anglin
@ 2018-08-02 18:40     ` Jeff Law
  2018-08-02 20:19       ` John David Anglin
  0 siblings, 1 reply; 82+ messages in thread
From: Jeff Law @ 2018-08-02 18:40 UTC (permalink / raw)
  To: John David Anglin, Richard Earnshaw; +Cc: GCC Patches

On 07/27/2018 01:48 PM, John David Anglin wrote:
> On 2018-07-27 5:37 AM, Richard Earnshaw wrote:
>> Port Maintainers: You need to decide what action is required for your
>> port to handle speculative execution, even if that action is to use
>> the trivial no-speculation on this architecture.  You must also
>> consider whether or not a furture implementation of your architecture
>> might need to deal with this in making that decision.
> On hppa, I think we should go with the hook that assumes there is no
> speculative execution.
> 
> Nominally, there is branch prediction and speculative execution; but the
> spectre test program
> was not able to successfully access memory on my rp3440.
> 
> As far as I know, the details of speculative execution on PA-RISC are
> not public.  Jeff would know
It's been eons.   I think there's enough building blocks on the PA to
mount a spectre v1 attack.  They've got branch prediction with varying
degress of speculative execution, caches and user accessable cycle timers.

There's varying degrees of out of order execution all the way back in
the PA7xxx processors (hit-under-miss) to full o-o-o execution in the
PA8xxx series (including the PA8900 that's in the rp3440).

I suspect that given enough time we could figure out why the test didn't
indicate spectre v1 vulnerability on your system and twiddle it, but
given it's a dead processor, I doubt it's worth the effort.

jeff

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 00/11] (v2) Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-08-02 18:40     ` Jeff Law
@ 2018-08-02 20:19       ` John David Anglin
  2018-08-03  9:06         ` Richard Earnshaw (lists)
  2018-08-03 17:26         ` Jeff Law
  0 siblings, 2 replies; 82+ messages in thread
From: John David Anglin @ 2018-08-02 20:19 UTC (permalink / raw)
  To: Jeff Law, Richard Earnshaw; +Cc: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 1372 bytes --]

On 2018-08-02 2:40 PM, Jeff Law wrote:
> It's been eons.   I think there's enough building blocks on the PA to
> mount a spectre v1 attack.  They've got branch prediction with varying
> degress of speculative execution, caches and user accessable cycle timers.
Yes.
>
> There's varying degrees of out of order execution all the way back in
> the PA7xxx processors (hit-under-miss) to full o-o-o execution in the
> PA8xxx series (including the PA8900 that's in the rp3440).
However, as far as I know, loads and stores are always ordered.
>
> I suspect that given enough time we could figure out why the test didn't
> indicate spectre v1 vulnerability on your system and twiddle it, but
> given it's a dead processor, I doubt it's worth the effort.
Spectre output looks like this:
dave@mx3210:~/meltdown$ ./spectre
Reading 40 bytes:
Reading at malicious_x = 0xffffef10... Unclear: 0xFE='?' score=999    
(second best: 0xFC score=999)
Reading at malicious_x = 0xffffef11... Unclear: 0xFC='?' score=999    
(second best: 0xFB score=999)
Reading at malicious_x = 0xffffef12... Unclear: 0xFE='?' score=999    
(second best: 0xFC score=999)

I don't think there's a suitable barrier.  The sync instruction seems 
like overkill.

So, I'm going to install attached change after testing is complete.

Dave

-- 
John David Anglin  dave.anglin@bell.net


[-- Attachment #2: pa-spectre.d --]
[-- Type: text/plain, Size: 506 bytes --]

Index: config/pa/pa.c
===================================================================
--- config/pa/pa.c	(revision 263228)
+++ config/pa/pa.c	(working copy)
@@ -428,6 +428,9 @@
 #undef TARGET_STARTING_FRAME_OFFSET
 #define TARGET_STARTING_FRAME_OFFSET pa_starting_frame_offset
 
+#undef TARGET_HAVE_SPECULATION_SAFE_VALUE
+#define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Parse the -mfixed-range= option string.  */

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 00/11] (v2) Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-08-02 20:19       ` John David Anglin
@ 2018-08-03  9:06         ` Richard Earnshaw (lists)
  2018-08-06 21:52           ` John David Anglin
  2018-08-03 17:26         ` Jeff Law
  1 sibling, 1 reply; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-08-03  9:06 UTC (permalink / raw)
  To: John David Anglin, Jeff Law; +Cc: GCC Patches

On 02/08/18 21:19, John David Anglin wrote:
> On 2018-08-02 2:40 PM, Jeff Law wrote:
>> It's been eons.   I think there's enough building blocks on the PA to
>> mount a spectre v1 attack.  They've got branch prediction with varying
>> degress of speculative execution, caches and user accessable cycle
>> timers.
> Yes.
>>
>> There's varying degrees of out of order execution all the way back in
>> the PA7xxx processors (hit-under-miss) to full o-o-o execution in the
>> PA8xxx series (including the PA8900 that's in the rp3440).
> However, as far as I know, loads and stores are always ordered.
>>
>> I suspect that given enough time we could figure out why the test didn't
>> indicate spectre v1 vulnerability on your system and twiddle it, but
>> given it's a dead processor, I doubt it's worth the effort.
> Spectre output looks like this:
> dave@mx3210:~/meltdown$ ./spectre
> Reading 40 bytes:
> Reading at malicious_x = 0xffffef10... Unclear: 0xFE='?' score=999   
> (second best: 0xFC score=999)
> Reading at malicious_x = 0xffffef11... Unclear: 0xFC='?' score=999   
> (second best: 0xFB score=999)
> Reading at malicious_x = 0xffffef12... Unclear: 0xFE='?' score=999   
> (second best: 0xFC score=999)
> 
> I don't think there's a suitable barrier.  The sync instruction seems
> like overkill.
> 
> So, I'm going to install attached change after testing is complete.
> 

It's your call as port maintainers.

I've created a PR for each unfixed architecture.  Please can you commit
the patch against that so that I can track things for back-porting.

Thanks,

R.

> Dave
> 
> 
> pa-spectre.d
> 
> 
> Index: config/pa/pa.c
> ===================================================================
> --- config/pa/pa.c	(revision 263228)
> +++ config/pa/pa.c	(working copy)
> @@ -428,6 +428,9 @@
>  #undef TARGET_STARTING_FRAME_OFFSET
>  #define TARGET_STARTING_FRAME_OFFSET pa_starting_frame_offset
>  
> +#undef TARGET_HAVE_SPECULATION_SAFE_VALUE
> +#define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
> +
>  struct gcc_target targetm = TARGET_INITIALIZER;
>  \f
>  /* Parse the -mfixed-range= option string.  */
> 

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 00/11] (v2) Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-08-02 20:19       ` John David Anglin
  2018-08-03  9:06         ` Richard Earnshaw (lists)
@ 2018-08-03 17:26         ` Jeff Law
  1 sibling, 0 replies; 82+ messages in thread
From: Jeff Law @ 2018-08-03 17:26 UTC (permalink / raw)
  To: John David Anglin, Richard Earnshaw; +Cc: GCC Patches

On 08/02/2018 02:19 PM, John David Anglin wrote:
> On 2018-08-02 2:40 PM, Jeff Law wrote:
>> It's been eons.   I think there's enough building blocks on the PA to
>> mount a spectre v1 attack.  They've got branch prediction with varying
>> degress of speculative execution, caches and user accessable cycle
>> timers.
> Yes.
>>
>> There's varying degrees of out of order execution all the way back in
>> the PA7xxx processors (hit-under-miss) to full o-o-o execution in the
>> PA8xxx series (including the PA8900 that's in the rp3440).
> However, as far as I know, loads and stores are always ordered.
I'm pretty sure that's not true on PA8000 class machines:

You can get the details here:

http://web.archive.org/web/20040214092531/http://www.cpus.hp.com/technical_references/advperf.shtml

It describes in reasonable detail how the load/store reorder buffer and
the address reorder buffer works as well as the tag checking to detect
when a speculative load was executed and its results had to be thrown
away due to a store-to-load dependency check in the ARB.

But again, given the state of the target, I'm not at all concerned about
mitigating spectre v1.

Jeff

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 02/11] Arm - add speculation_barrier pattern
  2018-07-27  9:38   ` [PATCH 02/11] Arm - add speculation_barrier pattern Richard Earnshaw
@ 2018-08-06 14:01     ` Christophe Lyon
  2018-08-06 15:59       ` Richard Earnshaw (lists)
  0 siblings, 1 reply; 82+ messages in thread
From: Christophe Lyon @ 2018-08-06 14:01 UTC (permalink / raw)
  To: Richard Earnshaw; +Cc: gcc Patches

On Fri, 27 Jul 2018 at 11:38, Richard Earnshaw <Richard.Earnshaw@arm.com> wrote:
>
>
> This patch defines a speculation barrier for AArch32.
>
>         * config/arm/unspecs.md (unspecv): Add VUNSPEC_SPECULATION_BARRIER.
>         * config/arm/arm.md (speculation_barrier): New expand.
>         (speculation_barrier_insn): New pattern.
> ---

Hi Richard,

This patch causes compilation errors for c-c++-common/spec-barrier-2.c
when compiled for old architectures (eg -march=armv5t):
/ccrf2LoR.s:49: Error: selected processor does not support `isb' in ARM mode
/ccrf2LoR.s:50: Error: selected processor does not support `dsb sy' in ARM mode

Does this belong to the kind of failures you still expect from this
patch series?

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 02/11] Arm - add speculation_barrier pattern
  2018-08-06 14:01     ` Christophe Lyon
@ 2018-08-06 15:59       ` Richard Earnshaw (lists)
  0 siblings, 0 replies; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-08-06 15:59 UTC (permalink / raw)
  To: Christophe Lyon; +Cc: gcc Patches

On 06/08/18 15:00, Christophe Lyon wrote:
> On Fri, 27 Jul 2018 at 11:38, Richard Earnshaw <Richard.Earnshaw@arm.com> wrote:
>>
>>
>> This patch defines a speculation barrier for AArch32.
>>
>>         * config/arm/unspecs.md (unspecv): Add VUNSPEC_SPECULATION_BARRIER.
>>         * config/arm/arm.md (speculation_barrier): New expand.
>>         (speculation_barrier_insn): New pattern.
>> ---
> 
> Hi Richard,
> 
> This patch causes compilation errors for c-c++-common/spec-barrier-2.c
> when compiled for old architectures (eg -march=armv5t):
> /ccrf2LoR.s:49: Error: selected processor does not support `isb' in ARM mode
> /ccrf2LoR.s:50: Error: selected processor does not support `dsb sy' in ARM mode
> 
> Does this belong to the kind of failures you still expect from this
> patch series?
> 

Nope :-(

I'll look into it.  We may need to just disable these patterns for
architectures that old.  Thumb1 code on pre-v6t2 similarly can't be
protected.

Thanks for reporting.

R.

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 00/11] (v2) Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-08-03  9:06         ` Richard Earnshaw (lists)
@ 2018-08-06 21:52           ` John David Anglin
  2018-08-07 14:05             ` Richard Earnshaw (lists)
  0 siblings, 1 reply; 82+ messages in thread
From: John David Anglin @ 2018-08-06 21:52 UTC (permalink / raw)
  To: Richard Earnshaw (lists), Jeff Law; +Cc: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 387 bytes --]

On 2018-08-03 5:06 AM, Richard Earnshaw (lists) wrote:
>> I don't think there's a suitable barrier.  The sync instruction seems
>> like overkill.
>>
>> So, I'm going to install attached change after testing is complete.
>>
> It's your call as port maintainers.
I committed the attached change after testing on hppa-unknown-linux-gnu.

Dave

-- 
John David Anglin  dave.anglin@bell.net


[-- Attachment #2: pa-spectre.d --]
[-- Type: text/plain, Size: 680 bytes --]

2018-08-06  John David Anglin  <danglin@gcc.gnu.org>

	PR target/86807
	* config/pa/pa.c (TARGET_HAVE_SPECULATION_SAFE_VALUE):
	Define to speculation_safe_value_not_needed.

Index: config/pa/pa.c
===================================================================
--- config/pa/pa.c	(revision 263228)
+++ config/pa/pa.c	(working copy)
@@ -428,6 +428,9 @@
 #undef TARGET_STARTING_FRAME_OFFSET
 #define TARGET_STARTING_FRAME_OFFSET pa_starting_frame_offset
 
+#undef TARGET_HAVE_SPECULATION_SAFE_VALUE
+#define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Parse the -mfixed-range= option string.  */

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 00/11] (v2) Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-08-06 21:52           ` John David Anglin
@ 2018-08-07 14:05             ` Richard Earnshaw (lists)
  2018-08-07 14:56               ` John David Anglin
  0 siblings, 1 reply; 82+ messages in thread
From: Richard Earnshaw (lists) @ 2018-08-07 14:05 UTC (permalink / raw)
  To: John David Anglin, Jeff Law; +Cc: GCC Patches

On 06/08/18 22:52, John David Anglin wrote:
> On 2018-08-03 5:06 AM, Richard Earnshaw (lists) wrote:
>>> I don't think there's a suitable barrier.  The sync instruction seems
>>> like overkill.
>>>
>>> So, I'm going to install attached change after testing is complete.
>>>
>> It's your call as port maintainers.
> I committed the attached change after testing on hppa-unknown-linux-gnu.
> 

Thanks.  Wrong PR, though: that was for the SPU port.  The hppa PR is 86785.

R.

> Dave
> 
> 
> pa-spectre.d
> 
> 
> 2018-08-06  John David Anglin  <danglin@gcc.gnu.org>
> 
> 	PR target/86807
> 	* config/pa/pa.c (TARGET_HAVE_SPECULATION_SAFE_VALUE):
> 	Define to speculation_safe_value_not_needed.
> 
> Index: config/pa/pa.c
> ===================================================================
> --- config/pa/pa.c	(revision 263228)
> +++ config/pa/pa.c	(working copy)
> @@ -428,6 +428,9 @@
>  #undef TARGET_STARTING_FRAME_OFFSET
>  #define TARGET_STARTING_FRAME_OFFSET pa_starting_frame_offset
>  
> +#undef TARGET_HAVE_SPECULATION_SAFE_VALUE
> +#define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
> +
>  struct gcc_target targetm = TARGET_INITIALIZER;
>  \f
>  /* Parse the -mfixed-range= option string.  */
> 

^ permalink raw reply	[flat|nested] 82+ messages in thread

* Re: [PATCH 00/11] (v2) Mitigation against unsafe data speculation (CVE-2017-5753)
  2018-08-07 14:05             ` Richard Earnshaw (lists)
@ 2018-08-07 14:56               ` John David Anglin
  0 siblings, 0 replies; 82+ messages in thread
From: John David Anglin @ 2018-08-07 14:56 UTC (permalink / raw)
  To: Richard Earnshaw (lists), Jeff Law; +Cc: GCC Patches

On 2018-08-07 10:05 AM, Richard Earnshaw (lists) wrote:
> Thanks.  Wrong PR, though: that was for the SPU port.  The hppa PR is 86785.
Oops, sorry for extra work.

Dave

-- 
John David Anglin  dave.anglin@bell.net

^ permalink raw reply	[flat|nested] 82+ messages in thread

end of thread, other threads:[~2018-08-07 14:56 UTC | newest]

Thread overview: 82+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-09 16:39 [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753) Richard Earnshaw
2018-07-09 16:39 ` [PATCH 5/7] AArch64 - disable CB[N]Z TB[N]Z when tracking speculation Richard Earnshaw
2018-07-09 16:39 ` [PATCH 2/7] Arm - add speculation_barrier pattern Richard Earnshaw
2018-07-09 16:39 ` [PATCH 4/7] AArch64 - Add new option -mtrack-speculation Richard Earnshaw
2018-07-09 16:39 ` [PATCH 1/7] Add __builtin_speculation_safe_value Richard Earnshaw
2018-07-23 14:28   ` Richard Earnshaw (lists)
2018-07-24 17:26   ` Richard Biener
2018-07-25  9:49     ` Richard Earnshaw (lists)
2018-07-25 10:36       ` Richard Biener
2018-07-25 12:41         ` Richard Earnshaw (lists)
2018-07-25 13:47           ` Richard Biener
2018-07-26 10:03             ` Richard Earnshaw (lists)
2018-07-26 12:41               ` Richard Biener
2018-07-26 13:06                 ` Richard Earnshaw (lists)
2018-07-26 13:13                   ` Richard Biener
2018-07-26 23:34           ` Joseph Myers
2018-07-27  0:46             ` Paul Koning
2018-07-27  8:59               ` Richard Earnshaw (lists)
2018-07-27 10:59                 ` Joseph Myers
2018-07-25 18:03     ` Richard Earnshaw (lists)
2018-07-26  8:42       ` Richard Biener
2018-07-09 16:39 ` [PATCH 6/7] AArch64 - new pass to add conditional-branch speculation tracking Richard Earnshaw
2018-07-11 21:01   ` Jeff Law
2018-07-23 14:33     ` Richard Earnshaw (lists)
2018-07-24 21:31       ` Jeff Law
2018-07-09 16:39 ` [PATCH 3/7] AArch64 - add speculation barrier Richard Earnshaw
2018-07-09 16:39 ` [PATCH 7/7] AArch64 - use CSDB based sequences if speculation tracking is enabled Richard Earnshaw
2018-07-09 23:13 ` [PATCH 0/7] Mitigation against unsafe data speculation (CVE-2017-5753) Jeff Law
2018-07-10  8:49   ` Richard Earnshaw (lists)
2018-07-10 13:48     ` Bill Schmidt
2018-07-10 14:14       ` Richard Earnshaw (lists)
2018-07-10 15:44         ` Jeff Law
2018-07-10 15:42     ` Jeff Law
2018-07-10 16:43       ` Richard Earnshaw (lists)
2018-07-11 20:47         ` Jeff Law
2018-07-11 22:31           ` Richard Earnshaw (lists)
2018-07-10  7:19 ` Richard Biener
2018-07-10  8:39   ` Richard Earnshaw (lists)
2018-07-10 10:10     ` Richard Biener
2018-07-10 10:53       ` Richard Earnshaw (lists)
2018-07-10 11:22         ` Richard Biener
2018-07-10 13:43           ` Richard Earnshaw (lists)
2018-07-10 15:56         ` Jeff Law
2018-07-27  9:38 ` [PATCH 00/11] (v2) " Richard Earnshaw
2018-07-27  9:38   ` [PATCH 04/11] AArch64 - Add new option -mtrack-speculation Richard Earnshaw
2018-07-27  9:38   ` [PATCH 05/11] AArch64 - disable CB[N]Z TB[N]Z when tracking speculation Richard Earnshaw
2018-07-27  9:38   ` [PATCH 06/11] AArch64 - new pass to add conditional-branch speculation tracking Richard Earnshaw
2018-07-27  9:38   ` [PATCH 09/11] pdp11 - example of a port not needing a speculation barrier Richard Earnshaw
2018-07-27 13:27     ` Paul Koning
2018-07-27 15:19       ` Richard Biener
2018-07-27  9:38   ` [PATCH 08/11] targhooks - provide an alternative hook for targets that never execute speculatively Richard Earnshaw
2018-07-30 13:17     ` Richard Biener
2018-07-27  9:38   ` [PATCH 11/11] rs6000 - add speculation_barrier pattern Richard Earnshaw
2018-07-31 22:01     ` Bill Schmidt
2018-07-31 23:31       ` Segher Boessenkool
2018-07-27  9:38   ` [PATCH 10/11] x86 " Richard Earnshaw
2018-07-28  8:25     ` Uros Bizjak
2018-07-31 23:15       ` H.J. Lu
2018-07-27  9:38   ` [PATCH 01/11] Add __builtin_speculation_safe_value Richard Earnshaw
2018-07-27 12:11     ` Nathan Sidwell
2018-07-27 12:32       ` Richard Earnshaw (lists)
2018-07-27 12:49         ` Nathan Sidwell
2018-07-27 12:53       ` Richard Earnshaw (lists)
2018-07-30 13:16     ` Richard Biener
2018-07-31 19:25       ` H.J. Lu
2018-07-31 20:51         ` Ian Lance Taylor via gcc-patches
2018-08-01  8:50           ` Richard Earnshaw (lists)
2018-08-01  8:54             ` Jakub Jelinek
2018-08-01  9:25               ` Richard Earnshaw (lists)
2018-07-27  9:38   ` [PATCH 07/11] AArch64 - use CSDB based sequences if speculation tracking is enabled Richard Earnshaw
2018-07-27  9:38   ` [PATCH 03/11] AArch64 - add speculation barrier Richard Earnshaw
2018-07-27  9:38   ` [PATCH 02/11] Arm - add speculation_barrier pattern Richard Earnshaw
2018-08-06 14:01     ` Christophe Lyon
2018-08-06 15:59       ` Richard Earnshaw (lists)
2018-07-27 19:49   ` [PATCH 00/11] (v2) Mitigation against unsafe data speculation (CVE-2017-5753) John David Anglin
2018-08-02 18:40     ` Jeff Law
2018-08-02 20:19       ` John David Anglin
2018-08-03  9:06         ` Richard Earnshaw (lists)
2018-08-06 21:52           ` John David Anglin
2018-08-07 14:05             ` Richard Earnshaw (lists)
2018-08-07 14:56               ` John David Anglin
2018-08-03 17:26         ` Jeff Law

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).