diff mbox series

[v2,1/4,SPARC] Errata workaround for GRLIB-TN-0012

Message ID 20171127095715.5938-2-cederman@gaisler.com
State New
Headers show
Series Workarounds for UT699, UT700, and GR712RC errata | expand

Commit Message

Daniel Cederman Nov. 27, 2017, 9:57 a.m. UTC
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.

gcc/ChangeLog:

2017-11-17  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.
---
 gcc/config/sparc/sparc.c  | 57 +++++++++++++++++++++++++++++++++++++++++++----
 gcc/config/sparc/sparc.md | 28 +++++++++++++++++++++++
 2 files changed, 81 insertions(+), 4 deletions(-)

Comments

Eric Botcazou Nov. 28, 2017, 9:57 a.m. UTC | #1
> 2017-11-17  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.

Sorry, I should have been more explicit in my first reply, because:

> @@ -590,6 +594,26 @@
>  	   (const_string "true")
>  	] (const_string "false")))
> 
> +(define_attr "in_integer_branch_annul_delay" "false,true"
> +  (cond [(eq_attr "type"
> "uncond_branch,branch,cbcond,uncond_cbcond,call,sibcall,call_no_delay_slot,
> multi") +	   (const_string "false")
> +	 (and (eq_attr "fix_gr712rc" "true")
> +	      (eq_attr "type" "fp,fpcmp,fpmove,fpcmove,fpmul,
> +			       fpdivs,fpsqrts,fpdivd,fpsqrtd"))
> +	   (const_string "false")
> +	 (and (eq_attr "fix_b2bst" "true") (eq_attr "type" "store,fpstore"))
> +	   (const_string "false")
> +	 (and (eq_attr "fix_ut699" "true") (eq_attr "type" "load,sload"))
> +	   (const_string "false")
> +	 (and (eq_attr "fix_ut699" "true")
> +	      (and (eq_attr "type" "fpload,fp,fpmove,fpmul,fpdivs,fpsqrts")
> +		   (ior (eq_attr "fptype" "single")
> +		        (eq_attr "fptype_ut699" "single"))))
> +	   (const_string "false")
> +	 (eq_attr "length" "1")
> +	   (const_string "true")
> +	] (const_string "false")))
> +
>  (define_delay (eq_attr "type" "call")
>    [(eq_attr "in_call_delay" "true") (nil) (nil)])

is barely maintainable.  So let's go back to the original version and...

> @@ -602,6 +626,10 @@
>  (define_delay (eq_attr "type" "branch")
>    [(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)])

...add (and (.) (not (eq_attr "branch_type" "icc")) to the first define_delay.
Daniel Cederman Nov. 28, 2017, 12:23 p.m. UTC | #2
> ...add (and (.) (not (eq_attr "branch_type" "icc")) to the first define_delay.

Ah, OK, that makes more sense. I will submit an updated version. Thanks 
for getting back so quickly.

Daniel C
diff mbox series

Patch

diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index a9945e2..51045db 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -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 *)
diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md
index d9cbd4f..7e03bda 100644
--- a/gcc/config/sparc/sparc.md
+++ b/gcc/config/sparc/sparc.md
@@ -430,6 +430,10 @@ 
    (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).
@@ -590,6 +594,26 @@ 
 	   (const_string "true")
 	] (const_string "false")))
 
+(define_attr "in_integer_branch_annul_delay" "false,true"
+  (cond [(eq_attr "type" "uncond_branch,branch,cbcond,uncond_cbcond,call,sibcall,call_no_delay_slot,multi")
+	   (const_string "false")
+	 (and (eq_attr "fix_gr712rc" "true")
+	      (eq_attr "type" "fp,fpcmp,fpmove,fpcmove,fpmul,
+			       fpdivs,fpsqrts,fpdivd,fpsqrtd"))
+	   (const_string "false")
+	 (and (eq_attr "fix_b2bst" "true") (eq_attr "type" "store,fpstore"))
+	   (const_string "false")
+	 (and (eq_attr "fix_ut699" "true") (eq_attr "type" "load,sload"))
+	   (const_string "false")
+	 (and (eq_attr "fix_ut699" "true")
+	      (and (eq_attr "type" "fpload,fp,fpmove,fpmul,fpdivs,fpsqrts")
+		   (ior (eq_attr "fptype" "single")
+		        (eq_attr "fptype_ut699" "single"))))
+	   (const_string "false")
+	 (eq_attr "length" "1")
+	   (const_string "true")
+	] (const_string "false")))
+
 (define_delay (eq_attr "type" "call")
   [(eq_attr "in_call_delay" "true") (nil) (nil)])
 
@@ -602,6 +626,10 @@ 
 (define_delay (eq_attr "type" "branch")
   [(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)])