Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 256364)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -36726,6 +36726,9 @@ static struct rs6000_opt_var const rs6000_opt_vars
   { "sched-epilog",
     offsetof (struct gcc_options, x_TARGET_SCHED_PROLOG),
     offsetof (struct cl_target_option, x_TARGET_SCHED_PROLOG), },
+  { "safe-indirect-jumps",
+    offsetof (struct gcc_options, x_rs6000_safe_indirect_jumps),
+    offsetof (struct cl_target_option, x_rs6000_safe_indirect_jumps), },
 };
 
 /* Inner function to handle attribute((target("..."))) and #pragma GCC target
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md	(revision 256364)
+++ gcc/config/rs6000/rs6000.md	(working copy)
@@ -150,6 +150,8 @@
    UNSPEC_SIGNBIT
    UNSPEC_SF_FROM_SI
    UNSPEC_SI_FROM_SF
+   UNSPEC_CRSET_EQ
+   UNSPEC_COMP_GOTO_CR
   ])
 
 ;;
@@ -11222,11 +11224,22 @@
 	 (match_operand 1 "" "g,g"))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_ELFv2"
+  "DEFAULT_ABI == ABI_ELFv2 && !rs6000_safe_indirect_jumps"
   "b%T0l\;<ptrload> 2,%2(1)"
   [(set_attr "type" "jmpreg")
    (set_attr "length" "8")])
 
+;; Variant with deliberate misprediction.
+(define_insn "*call_indirect_elfv2<mode>_safe"
+  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
+	 (match_operand 1 "" "g,g"))
+   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_ELFv2 && rs6000_safe_indirect_jumps"
+  "crset eq\;beq%T0l-\;<ptrload> 2,%2(1)"
+  [(set_attr "type" "jmpreg")
+   (set_attr "length" "12")])
+
 (define_insn "*call_value_indirect_elfv2<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
@@ -11233,11 +11246,22 @@
 	      (match_operand 2 "" "g,g")))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_ELFv2"
+  "DEFAULT_ABI == ABI_ELFv2 && !rs6000_safe_indirect_jumps"
   "b%T1l\;<ptrload> 2,%3(1)"
   [(set_attr "type" "jmpreg")
    (set_attr "length" "8")])
 
+; Variant with deliberate misprediction.
+(define_insn "*call_value_indirect_elfv2<mode>_safe"
+  [(set (match_operand 0 "" "")
+	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
+	      (match_operand 2 "" "g,g")))
+   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_ELFv2 && rs6000_safe_indirect_jumps"
+  "crset eq\;beq%T1l-\;<ptrload> 2,%3(1)"
+  [(set_attr "type" "jmpreg")
+   (set_attr "length" "12")])
 
 ;; Call subroutine returning any type.
 (define_expand "untyped_call"
@@ -12917,15 +12941,50 @@
   [(set_attr "type" "jmpreg")])
 
 (define_expand "indirect_jump"
-  [(set (pc) (match_operand 0 "register_operand"))])
+  [(set (pc) (match_operand 0 "register_operand"))]
+ ""
+{
+  /* We need to reserve a CR when forcing a mispredicted jump.  */
+  if (rs6000_safe_indirect_jumps) {
+    rtx ccreg = gen_reg_rtx (CCmode);
+    emit_insn (gen_rtx_SET (ccreg,
+			    gen_rtx_UNSPEC (CCmode,
+					    gen_rtvec (1, const0_rtx),
+					    UNSPEC_CRSET_EQ)));
+    rtvec v = rtvec_alloc (2);
+    RTVEC_ELT (v, 0) = operands[0];
+    RTVEC_ELT (v, 1) = ccreg;
+    emit_jump_insn (gen_rtx_SET (pc_rtx,
+				 gen_rtx_UNSPEC (Pmode, v,
+						 UNSPEC_COMP_GOTO_CR)));
+    DONE;
+  }
+})
 
 (define_insn "*indirect_jump<mode>"
   [(set (pc)
 	(match_operand:P 0 "register_operand" "c,*l"))]
-  ""
+  "!rs6000_safe_indirect_jumps"
   "b%T0"
   [(set_attr "type" "jmpreg")])
 
+(define_insn "*indirect_jump<mode>_safe"
+  [(set (pc)
+	(unspec:P [(match_operand:P 0 "register_operand" "c,*l")
+		   (match_operand:CC 1 "cc_reg_operand" "y,y")]
+		   UNSPEC_COMP_GOTO_CR))]
+  "rs6000_safe_indirect_jumps"
+  "beq%T0- %1\;b ."
+  [(set_attr "type" "jmpreg")
+   (set_attr "length" "8")])
+
+(define_insn "*set_cr_eq"
+  [(set (match_operand:CC 0 "cc_reg_operand" "=y")
+	(unspec:CC [(const_int 0)] UNSPEC_CRSET_EQ))]
+  "rs6000_safe_indirect_jumps"
+  "crset %E0"
+  [(set_attr "type" "cr_logical")])
+
 ;; Table jump for switch statements:
 (define_expand "tablejump"
   [(use (match_operand 0))
@@ -12933,9 +12992,19 @@
   ""
 {
   if (TARGET_32BIT)
-    emit_jump_insn (gen_tablejumpsi (operands[0], operands[1]));
+    {
+      if (rs6000_safe_indirect_jumps)
+	emit_jump_insn (gen_tablejumpsi_safe (operands[0], operands[1]));
+      else
+	emit_jump_insn (gen_tablejumpsi (operands[0], operands[1]));
+    }
   else
-    emit_jump_insn (gen_tablejumpdi (operands[0], operands[1]));
+    {
+      if (rs6000_safe_indirect_jumps)
+	emit_jump_insn (gen_tablejumpdi_safe (operands[0], operands[1]));
+      else
+	emit_jump_insn (gen_tablejumpdi (operands[0], operands[1]));
+    }
   DONE;
 })
 
@@ -12946,7 +13015,7 @@
    (parallel [(set (pc)
 		   (match_dup 3))
 	      (use (label_ref (match_operand 1)))])]
-  "TARGET_32BIT"
+  "TARGET_32BIT && !rs6000_safe_indirect_jumps"
 {
   operands[0] = force_reg (SImode, operands[0]);
   operands[2] = force_reg (SImode, gen_rtx_LABEL_REF (SImode, operands[1]));
@@ -12953,6 +13022,23 @@
   operands[3] = gen_reg_rtx (SImode);
 })
 
+(define_expand "tablejumpsi_safe"
+  [(set (match_dup 3)
+	(plus:SI (match_operand:SI 0)
+		 (match_dup 2)))
+   (set (match_dup 4) (unspec:CC [(const_int 0)] UNSPEC_CRSET_EQ))
+   (parallel [(set (pc)
+		   (match_dup 3))
+	      (use (label_ref (match_operand 1)))
+	      (use (match_dup 4))])]
+  "TARGET_32BIT && rs6000_safe_indirect_jumps"
+{
+  operands[0] = force_reg (SImode, operands[0]);
+  operands[2] = force_reg (SImode, gen_rtx_LABEL_REF (SImode, operands[1]));
+  operands[3] = gen_reg_rtx (SImode);
+  operands[4] = gen_reg_rtx (CCmode);
+})
+
 (define_expand "tablejumpdi"
   [(set (match_dup 4)
         (sign_extend:DI (match_operand:SI 0 "lwa_operand")))
@@ -12962,7 +13048,7 @@
    (parallel [(set (pc)
 		   (match_dup 3))
 	      (use (label_ref (match_operand 1)))])]
-  "TARGET_64BIT"
+  "TARGET_64BIT && !rs6000_safe_indirect_jumps"
 {
   operands[2] = force_reg (DImode, gen_rtx_LABEL_REF (DImode, operands[1]));
   operands[3] = gen_reg_rtx (DImode);
@@ -12969,14 +13055,43 @@
   operands[4] = gen_reg_rtx (DImode);
 })
 
+(define_expand "tablejumpdi_safe"
+  [(set (match_dup 4)
+        (sign_extend:DI (match_operand:SI 0 "lwa_operand")))
+   (set (match_dup 5) (unspec:CC [(const_int 0)] UNSPEC_CRSET_EQ))
+   (set (match_dup 3)
+	(plus:DI (match_dup 4)
+		 (match_dup 2)))
+   (parallel [(set (pc)
+		   (match_dup 3))
+	      (use (label_ref (match_operand 1)))
+	      (use (match_dup 5))])]
+  "TARGET_64BIT && rs6000_safe_indirect_jumps"
+{
+  operands[2] = force_reg (DImode, gen_rtx_LABEL_REF (DImode, operands[1]));
+  operands[3] = gen_reg_rtx (DImode);
+  operands[4] = gen_reg_rtx (DImode);
+  operands[5] = gen_reg_rtx (CCmode);
+})
+
 (define_insn "*tablejump<mode>_internal1"
   [(set (pc)
 	(match_operand:P 0 "register_operand" "c,*l"))
    (use (label_ref (match_operand 1)))]
-  ""
+  "!rs6000_safe_indirect_jumps"
   "b%T0"
   [(set_attr "type" "jmpreg")])
 
+(define_insn "*tablejump<mode>_internal1_safe"
+  [(set (pc)
+	(match_operand:P 0 "register_operand" "c,*l"))
+   (use (label_ref (match_operand 1)))
+   (use (match_operand:CC 2 "cc_reg_operand" "y,y"))]
+  "rs6000_safe_indirect_jumps"
+  "beq%T0- %2\;b ."
+  [(set_attr "type" "jmpreg")
+   (set_attr "length" "8")])
+
 (define_insn "nop"
   [(unspec [(const_int 0)] UNSPEC_NOP)]
   ""
Index: gcc/config/rs6000/rs6000.opt
===================================================================
--- gcc/config/rs6000/rs6000.opt	(revision 256364)
+++ gcc/config/rs6000/rs6000.opt	(working copy)
@@ -617,3 +617,8 @@ Use the given offset for addressing the stack-prot
 
 TargetVariable
 long rs6000_stack_protector_guard_offset = 0
+
+;; -msafe-indirect-jumps adds deliberate misprediction to indirect
+;; branches via the CTR.
+msafe-indirect-jumps
+Target Undocumented Var(rs6000_safe_indirect_jumps) Init(0) Save
Index: gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-1.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-1.c	(nonexistent)
+++ gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-1.c	(working copy)
@@ -0,0 +1,14 @@
+/* { dg-do compile { target { powerpc64le-*-* } } } */
+/* { dg-options "-msafe-indirect-jumps" } */
+
+/* Test for deliberate misprediction of indirect calls for ELFv2.  */
+
+extern int (*f)();
+
+int bar ()
+{
+  return (*f) ();
+}
+
+/* { dg-final { scan-assembler "crset eq" } } */
+/* { dg-final { scan-assembler "beqctrl-" } } */
Index: gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-2.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-2.c	(nonexistent)
+++ gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-2.c	(working copy)
@@ -0,0 +1,33 @@
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-options "-msafe-indirect-jumps" } */
+
+/* Test for deliberate misprediction of computed goto.  */
+
+int bar (int);
+int baz (int);
+int spaz (int);
+
+int foo (int x)
+{
+  static void *labptr[] = { &&lab0, &&lab1, &&lab2 };
+
+  if (x < 0 || x > 2)
+    return -1;
+
+  goto *labptr[x];
+
+ lab0:
+  return bar (x);
+
+ lab1:
+  return baz (x) + 1;
+
+ lab2:
+  return spaz (x) / 2;
+}
+
+/* The following assumes CR7 as the first chosen volatile.  */
+
+/* { dg-final { scan-assembler "crset 30" } } */
+/* { dg-final { scan-assembler "beqctr- 7" } } */
+/* { dg-final { scan-assembler "b ." } } */
Index: gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-3.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-3.c	(nonexistent)
+++ gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-3.c	(working copy)
@@ -0,0 +1,52 @@
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-options "-msafe-indirect-jumps" } */
+
+/* Test for deliberate misprediction of jump tables.  */
+
+void bar (void);
+
+int foo (int x)
+{
+  int a;
+  
+  switch (x)
+    {
+    default:
+      a = -1;
+      break;
+    case 0:
+      a = x * x;
+      break;
+    case 1:
+      a = x + 1;
+      break;
+    case 2:
+      a = x + x;
+      break;
+    case 3:
+      a = x << 3;
+      break;
+    case 4:
+      a = x >> 1;
+      break;
+    case 5:
+      a = x;
+      break;
+    case 6:
+      a = 0;
+      break;
+    case 7:
+      a = x * x + x;
+      break;
+    }
+
+  bar();
+
+  return a;
+}
+
+/* The following assumes CR7 as the first chosen volatile.  */
+
+/* { dg-final { scan-assembler "crset 30" } } */
+/* { dg-final { scan-assembler "beqctr- 7" } } */
+/* { dg-final { scan-assembler "b ." } } */
