[SPARC] Errata workaround for GRLIB-TN-0012
authorDaniel Cederman <cederman@gaisler.com>
Wed, 29 Nov 2017 15:15:48 +0000 (15:15 +0000)
committerDaniel Hellstrom <danielh@gcc.gnu.org>
Wed, 29 Nov 2017 15:15:48 +0000 (16:15 +0100)
This patch provides a workaround for the errata described in GRLIB-TN-0012.

If the workaround is enabled it will:

 * Prevent any floating-point operation from being placed in the
   delay slot of an annulled integer branch.

 * Place a NOP at the branch target of an integer branch if it is
   a floating-point operation or a floating-point branch.

It is applicable to GR712RC.

2017-11-29  Daniel Cederman  <cederman@gaisler.com>

gcc/
* config/sparc/sparc.c (fpop_insn_p): New function.
(sparc_do_work_around_errata): Insert NOP instructions to
prevent sequences that could trigger the TN-0012 errata for
GR712RC.
(pass_work_around_errata::gate): Also test sparc_fix_gr712rc.
* config/sparc/sparc.md (fix_gr712rc): New attribute.
(in_branch_annul_delay): Prevent floating-point instructions
in delay slot of annulled integer branch.

From-SVN: r255234

gcc/ChangeLog
gcc/config/sparc/sparc.c
gcc/config/sparc/sparc.md

index 003b6b161e5a25d839bd58cfdc80ba4bd102e380..390a0b79b1e1098696cc2305737b05033cca333f 100644 (file)
@@ -1,3 +1,14 @@
+2017-11-29  Daniel Cederman  <cederman@gaisler.com>
+
+       * config/sparc/sparc.c (fpop_insn_p): New function.
+       (sparc_do_work_around_errata): Insert NOP instructions to
+       prevent sequences that could trigger the TN-0012 errata for
+       GR712RC.
+       (pass_work_around_errata::gate): Also test sparc_fix_gr712rc.
+       * config/sparc/sparc.md (fix_gr712rc): New attribute.
+       (in_branch_annul_delay): Prevent floating-point instructions
+       in delay slot of annulled integer branch.
+
 2017-11-29  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/83202
index a9945e2b13bd62b19daf688c8bf4d3f5eab3f0c2..32081659e99dd794c0e39fa0bdc714107f7ffe46 100644 (file)
@@ -945,6 +945,31 @@ mem_ref (rtx x)
   return NULL_RTX;
 }
 
+/* True if INSN is a floating-point instruction.  */
+
+static bool
+fpop_insn_p (rtx_insn *insn)
+{
+  if (GET_CODE (PATTERN (insn)) != SET)
+    return false;
+
+  switch (get_attr_type (insn))
+    {
+    case TYPE_FPMOVE:
+    case TYPE_FPCMOVE:
+    case TYPE_FP:
+    case TYPE_FPCMP:
+    case TYPE_FPMUL:
+    case TYPE_FPDIVS:
+    case TYPE_FPSQRTS:
+    case TYPE_FPDIVD:
+    case TYPE_FPSQRTD:
+      return true;
+    default:
+      return false;
+    }
+}
+
 /* We use a machine specific pass to enable workarounds for errata.
 
    We need to have the (essentially) final form of the insn stream in order
@@ -970,11 +995,34 @@ sparc_do_work_around_errata (void)
     {
       bool insert_nop = false;
       rtx set;
+      rtx_insn *jump;
+      rtx_sequence *seq;
 
       /* Look into the instruction in a delay slot.  */
-      if (NONJUMP_INSN_P (insn))
-       if (rtx_sequence *seq = dyn_cast <rtx_sequence *> (PATTERN (insn)))
-         insn = seq->insn (1);
+      if (NONJUMP_INSN_P (insn)
+         && (seq = dyn_cast <rtx_sequence *> (PATTERN (insn))))
+         {
+           jump = seq->insn (0);
+           insn = seq->insn (1);
+         }
+      else if (JUMP_P (insn))
+       jump = insn;
+      else
+       jump = NULL;
+
+      /* Place a NOP at the branch target of an integer branch if it is
+        a floating-point operation or a floating-point branch.  */
+      if (sparc_fix_gr712rc
+         && jump != NULL_RTX
+         && get_attr_branch_type (jump) == BRANCH_TYPE_ICC)
+       {
+         rtx_insn *target = next_active_insn (JUMP_LABEL_AS_INSN (jump));
+         if (target
+             && (fpop_insn_p (target)
+                 || ((JUMP_P (target)
+                      && get_attr_branch_type (target) == BRANCH_TYPE_FCC))))
+           emit_insn_before (gen_nop (), target);
+       }
 
       /* Look for either of these two sequences:
 
@@ -1303,7 +1351,8 @@ public:
   /* opt_pass methods: */
   virtual bool gate (function *)
     {
-      return sparc_fix_at697f || sparc_fix_ut699 || sparc_fix_b2bst;
+      return sparc_fix_at697f || sparc_fix_ut699 || sparc_fix_b2bst
+         || sparc_fix_gr712rc;
     }
 
   virtual unsigned int execute (function *)
index d9cbd4fb10d69955f4584391ffcfc62c23c8f008..c6f3b61ad6a115e7e04268673637b9b6d02807f7 100644 (file)
    (symbol_ref "(sparc_fix_b2bst != 0
                 ? FIX_B2BST_TRUE : FIX_B2BST_FALSE)"))
 
+(define_attr "fix_gr712rc" "false,true"
+   (symbol_ref "(sparc_fix_gr712rc != 0
+                ? FIX_GR712RC_TRUE : FIX_GR712RC_FALSE)"))
+
 ;; Length (in # of insns).
 ;; Beware that setting a length greater or equal to 3 for conditional branches
 ;; has a side-effect (see output_cbranch and output_v9branch).
           (const_string "true")
        ] (const_string "false")))
 
+(define_attr "in_integer_branch_annul_delay" "false,true"
+  (cond [(and (eq_attr "fix_gr712rc" "true")
+             (eq_attr "type" "fp,fpcmp,fpmove,fpcmove,fpmul,
+                              fpdivs,fpsqrts,fpdivd,fpsqrtd"))
+          (const_string "false")
+        (eq_attr "in_branch_delay" "true")
+          (const_string "true")
+       ] (const_string "false")))
+
 (define_delay (eq_attr "type" "call")
   [(eq_attr "in_call_delay" "true") (nil) (nil)])
 
 (define_delay (eq_attr "type" "return")
   [(eq_attr "in_return_delay" "true") (nil) (nil)])
 
-(define_delay (eq_attr "type" "branch")
+(define_delay (and (eq_attr "type" "branch")
+             (not (eq_attr "branch_type" "icc")))
   [(eq_attr "in_branch_delay" "true") (nil) (eq_attr "in_branch_delay" "true")])
 
+(define_delay (and (eq_attr "type" "branch")
+             (eq_attr "branch_type" "icc"))
+  [(eq_attr "in_branch_delay" "true") (nil)
+  (eq_attr "in_integer_branch_annul_delay" "true")])
+
 (define_delay (eq_attr "type" "uncond_branch")
   [(eq_attr "in_branch_delay" "true") (nil) (nil)])