rs6000.c (rs6000_opt_vars): Add entry for -mspeculate-indirect-jumps.
authorBill Schmidt <wschmidt@linux.vnet.ibm.com>
Tue, 16 Jan 2018 16:49:39 +0000 (16:49 +0000)
committerWilliam Schmidt <wschmidt@gcc.gnu.org>
Tue, 16 Jan 2018 16:49:39 +0000 (16:49 +0000)
[gcc]

2018-01-16  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>

* config/rs6000/rs6000.c (rs6000_opt_vars): Add entry for
-mspeculate-indirect-jumps.
* config/rs6000/rs6000.md (*call_indirect_elfv2<mode>): Disable
for -mno-speculate-indirect-jumps.
(*call_indirect_elfv2<mode>_nospec): New define_insn.
(*call_value_indirect_elfv2<mode>): Disable for
-mno-speculate-indirect-jumps.
(*call_value_indirect_elfv2<mode>_nospec): New define_insn.
(indirect_jump): Emit different RTL for
-mno-speculate-indirect-jumps.
(*indirect_jump<mode>): Disable for
-mno-speculate-indirect-jumps.
(*indirect_jump<mode>_nospec): New define_insn.
(tablejump): Emit different RTL for
-mno-speculate-indirect-jumps.
(tablejumpsi): Disable for -mno-speculate-indirect-jumps.
(tablejumpsi_nospec): New define_expand.
(tablejumpdi): Disable for -mno-speculate-indirect-jumps.
(tablejumpdi_nospec): New define_expand.
(*tablejump<mode>_internal1): Disable for
-mno-speculate-indirect-jumps.
(*tablejump<mode>_internal1_nospec): New define_insn.
* config/rs6000/rs6000.opt (mspeculate-indirect-jumps): New
option.

[gcc/testsuite]

2018-01-16  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>

* gcc.target/powerpc/safe-indirect-jump-1.c: New file.
* gcc.target/powerpc/safe-indirect-jump-2.c: New file.
* gcc.target/powerpc/safe-indirect-jump-3.c: New file.
* gcc.target/powerpc/safe-indirect-jump-4.c: New file.
* gcc.target/powerpc/safe-indirect-jump-5.c: New file.
* gcc.target/powerpc/safe-indirect-jump-6.c: New file.

From-SVN: r256753

gcc/ChangeLog
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.md
gcc/config/rs6000/rs6000.opt
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-6.c [new file with mode: 0644]

index 53be60b004d7ec957d0837e599e2634c6c14108a..65135664b8b98ac73162fd66368c48061bf66900 100644 (file)
@@ -1,3 +1,30 @@
+2018-01-16  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
+
+       * config/rs6000/rs6000.c (rs6000_opt_vars): Add entry for
+       -mspeculate-indirect-jumps.
+       * config/rs6000/rs6000.md (*call_indirect_elfv2<mode>): Disable
+       for -mno-speculate-indirect-jumps.
+       (*call_indirect_elfv2<mode>_nospec): New define_insn.
+       (*call_value_indirect_elfv2<mode>): Disable for
+       -mno-speculate-indirect-jumps.
+       (*call_value_indirect_elfv2<mode>_nospec): New define_insn.
+       (indirect_jump): Emit different RTL for
+       -mno-speculate-indirect-jumps.
+       (*indirect_jump<mode>): Disable for
+       -mno-speculate-indirect-jumps.
+       (*indirect_jump<mode>_nospec): New define_insn.
+       (tablejump): Emit different RTL for
+       -mno-speculate-indirect-jumps.
+       (tablejumpsi): Disable for -mno-speculate-indirect-jumps.
+       (tablejumpsi_nospec): New define_expand.
+       (tablejumpdi): Disable for -mno-speculate-indirect-jumps.
+       (tablejumpdi_nospec): New define_expand.
+       (*tablejump<mode>_internal1): Disable for
+       -mno-speculate-indirect-jumps.
+       (*tablejump<mode>_internal1_nospec): New define_insn.
+       * config/rs6000/rs6000.opt (mspeculate-indirect-jumps): New
+       option.
+
 2018-01-16  Artyom Skrobov tyomitch@gmail.com
 
         * caller-save.c (insert_save): Drop unnecessary parameter.  All
index 8cda17febc9f821d7d2d6f3c191565b4d4717ec6..2c22c63d74cd6260b603a3d7d051c5e3fcb1c389 100644 (file)
@@ -36716,6 +36716,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), },
+  { "speculate-indirect-jumps",
+    offsetof (struct gcc_options, x_rs6000_speculate_indirect_jumps),
+    offsetof (struct cl_target_option, x_rs6000_speculate_indirect_jumps), },
 };
 
 /* Inner function to handle attribute((target("..."))) and #pragma GCC target
index dc8745ca038eaabb05d2190136e8bf5a57f45319..fe027343fd28848a890c921443c2aef5f5745095 100644 (file)
         (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_speculate_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>_nospec"
+  [(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_speculate_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"))
              (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_speculate_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>_nospec"
+  [(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_speculate_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"
   [(set_attr "type" "jmpreg")])
 
 (define_expand "indirect_jump"
-  [(set (pc) (match_operand 0 "register_operand"))])
+  [(set (pc) (match_operand 0 "register_operand"))]
+ ""
+{
+  if (!rs6000_speculate_indirect_jumps) {
+    rtx ccreg = gen_reg_rtx (CCmode);
+    if (Pmode == DImode)
+      emit_jump_insn (gen_indirect_jumpdi_nospec (operands[0], ccreg));
+    else
+      emit_jump_insn (gen_indirect_jumpsi_nospec (operands[0], ccreg));
+    DONE;
+  }
+})
 
 (define_insn "*indirect_jump<mode>"
   [(set (pc)
        (match_operand:P 0 "register_operand" "c,*l"))]
-  ""
+  "rs6000_speculate_indirect_jumps"
   "b%T0"
   [(set_attr "type" "jmpreg")])
 
+(define_insn "indirect_jump<mode>_nospec"
+  [(set (pc) (match_operand:P 0 "register_operand" "c,*l"))
+   (clobber (match_operand:CC 1 "cc_reg_operand" "=y,y"))]
+  "!rs6000_speculate_indirect_jumps"
+  "crset %E1\;beq%T0- %1\;b ."
+  [(set_attr "type" "jmpreg")
+   (set_attr "length" "12")])
+
 ;; Table jump for switch statements:
 (define_expand "tablejump"
   [(use (match_operand 0))
    (use (label_ref (match_operand 1)))]
   ""
 {
-  if (TARGET_32BIT)
-    emit_jump_insn (gen_tablejumpsi (operands[0], operands[1]));
+  if (rs6000_speculate_indirect_jumps)
+    {
+      if (TARGET_32BIT)
+       emit_jump_insn (gen_tablejumpsi (operands[0], operands[1]));
+      else
+       emit_jump_insn (gen_tablejumpdi (operands[0], operands[1]));
+    }
   else
-    emit_jump_insn (gen_tablejumpdi (operands[0], operands[1]));
+    {
+      rtx ccreg = gen_reg_rtx (CCmode);
+      rtx jump;
+      if (TARGET_32BIT)
+       jump = gen_tablejumpsi_nospec (operands[0], operands[1], ccreg);
+      else
+       jump = gen_tablejumpdi_nospec (operands[0], operands[1], ccreg);
+      emit_jump_insn (jump);
+    }
   DONE;
 })
 
    (parallel [(set (pc)
                   (match_dup 3))
              (use (label_ref (match_operand 1)))])]
-  "TARGET_32BIT"
+  "TARGET_32BIT && rs6000_speculate_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);
 })
 
+(define_expand "tablejumpsi_nospec"
+  [(set (match_dup 4)
+       (plus:SI (match_operand:SI 0)
+                (match_dup 3)))
+   (parallel [(set (pc)
+                  (match_dup 4))
+             (use (label_ref (match_operand 1)))
+             (clobber (match_operand 2))])]
+  "TARGET_32BIT && !rs6000_speculate_indirect_jumps"
+{
+  operands[0] = force_reg (SImode, operands[0]);
+  operands[3] = force_reg (SImode, gen_rtx_LABEL_REF (SImode, operands[1]));
+  operands[4] = gen_reg_rtx (SImode);
+})
+
 (define_expand "tablejumpdi"
   [(set (match_dup 4)
         (sign_extend:DI (match_operand:SI 0 "lwa_operand")))
    (parallel [(set (pc)
                   (match_dup 3))
              (use (label_ref (match_operand 1)))])]
-  "TARGET_64BIT"
+  "TARGET_64BIT && rs6000_speculate_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);
 })
 
+(define_expand "tablejumpdi_nospec"
+  [(set (match_dup 5)
+        (sign_extend:DI (match_operand:SI 0 "lwa_operand")))
+   (set (match_dup 4)
+       (plus:DI (match_dup 5)
+                (match_dup 3)))
+   (parallel [(set (pc)
+                  (match_dup 4))
+             (use (label_ref (match_operand 1)))
+             (clobber (match_operand 2))])]
+  "TARGET_64BIT && !rs6000_speculate_indirect_jumps"
+{
+  operands[3] = force_reg (DImode, gen_rtx_LABEL_REF (DImode, operands[1]));
+  operands[4] = gen_reg_rtx (DImode);
+  operands[5] = gen_reg_rtx (DImode);
+})
+
 (define_insn "*tablejump<mode>_internal1"
   [(set (pc)
        (match_operand:P 0 "register_operand" "c,*l"))
    (use (label_ref (match_operand 1)))]
-  ""
+  "rs6000_speculate_indirect_jumps"
   "b%T0"
   [(set_attr "type" "jmpreg")])
 
+(define_insn "*tablejump<mode>_internal1_nospec"
+  [(set (pc)
+       (match_operand:P 0 "register_operand" "c,*l"))
+   (use (label_ref (match_operand 1)))
+   (clobber (match_operand:CC 2 "cc_reg_operand" "=y,y"))]
+  "!rs6000_speculate_indirect_jumps"
+  "crset %E2\;beq%T0- %2\;b ."
+  [(set_attr "type" "jmpreg")
+   (set_attr "length" "12")])
+
 (define_insn "nop"
   [(unspec [(const_int 0)] UNSPEC_NOP)]
   ""
index 54643802f8f9af194c2dde27cf0bd822a533ba3f..20162121a46383157739304eec1ddfe782cff3da 100644 (file)
@@ -620,3 +620,8 @@ Use the given offset for addressing the stack-protector guard.
 
 TargetVariable
 long rs6000_stack_protector_guard_offset = 0
+
+;; -mno-speculate-indirect-jumps adds deliberate misprediction to indirect
+;; branches via the CTR.
+mspeculate-indirect-jumps
+Target Undocumented Var(rs6000_speculate_indirect_jumps) Init(1) Save
index 0e24ae440bd8d8627c428edd5b212931a33077b0..8dfea56bcae4e68a22c128352cd3783ea30bd395 100644 (file)
@@ -1,3 +1,12 @@
+2018-01-16  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
+
+       * gcc.target/powerpc/safe-indirect-jump-1.c: New file.
+       * gcc.target/powerpc/safe-indirect-jump-2.c: New file.
+       * gcc.target/powerpc/safe-indirect-jump-3.c: New file.
+       * gcc.target/powerpc/safe-indirect-jump-4.c: New file.
+       * gcc.target/powerpc/safe-indirect-jump-5.c: New file.
+       * gcc.target/powerpc/safe-indirect-jump-6.c: New file.
+
 2018-01-16  Richard Sandiford  <richard.sandiford@linaro.org>
 
        PR tree-optimization/83857
diff --git a/gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-1.c b/gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-1.c
new file mode 100644 (file)
index 0000000..1a0cc88
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-do compile { target { powerpc64le-*-* } } } */
+/* { dg-additional-options "-mno-speculate-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-" } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-2.c b/gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-2.c
new file mode 100644 (file)
index 0000000..b51034f
--- /dev/null
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-mno-speculate-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 ." } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-3.c b/gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-3.c
new file mode 100644 (file)
index 0000000..81da127
--- /dev/null
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-options "-mno-speculate-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 ." } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-4.c b/gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-4.c
new file mode 100644 (file)
index 0000000..ed00007
--- /dev/null
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-additional-options "-mno-speculate-indirect-jumps" } */
+
+/* Test for deliberate misprediction of indirect calls for ELFv2.  */
+
+int (*f)();
+
+int __attribute__((noinline)) bar ()
+{
+  return (*f) ();
+}
+
+int g ()
+{
+  return 26;
+}
+
+int main ()
+{
+  f = &g;
+  if (bar () != 26)
+    __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-5.c b/gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-5.c
new file mode 100644 (file)
index 0000000..5a4cd9a
--- /dev/null
@@ -0,0 +1,55 @@
+/* { dg-do run } */
+/* { dg-additional-options "-mno-speculate-indirect-jumps -Wno-pedantic" } */
+
+/* Test for deliberate misprediction of computed goto.  */
+
+int __attribute__((noinline)) bar (int i)
+{
+  return 1960 + i;
+}
+
+int __attribute__((noinline)) baz (int i)
+{
+  return i * i;
+}
+
+int __attribute__((noinline)) spaz (int i)
+{
+  return i + 1;
+}
+
+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;
+}
+
+int main ()
+{
+  if (foo (0) != 1960)
+    __builtin_abort ();
+
+  if (foo (1) != 2)
+    __builtin_abort ();
+
+  if (foo (2) != 1)
+    __builtin_abort ();
+
+  if (foo (3) != -1)
+    __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-6.c b/gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-6.c
new file mode 100644 (file)
index 0000000..a78e468
--- /dev/null
@@ -0,0 +1,80 @@
+/* { dg-do run } */
+/* { dg-additional-options "-mno-speculate-indirect-jumps" } */
+
+/* Test for deliberate misprediction of jump tables.  */
+
+void __attribute__((noinline)) bar ()
+{
+}
+
+int foo (int x)
+{
+  int a;
+  
+  switch (x)
+    {
+    default:
+      a = -1;
+      break;
+    case 0:
+      a = x * x + 3;
+      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;
+}
+
+int main ()
+{
+  if (foo (0) != 3)
+    __builtin_abort ();
+  
+  if (foo (1) != 2)
+    __builtin_abort ();
+  
+  if (foo (2) != 4)
+    __builtin_abort ();
+  
+  if (foo (3) != 24)
+    __builtin_abort ();
+  
+  if (foo (4) != 2)
+    __builtin_abort ();
+  
+  if (foo (5) != 5)
+    __builtin_abort ();
+  
+  if (foo (6) != 0)
+    __builtin_abort ();
+  
+  if (foo (7) != 56)
+    __builtin_abort ();
+  
+  if (foo (8) != -1)
+    __builtin_abort ();
+  
+  return 0;
+}