diff mbox series

[v2,3/4,SPARC] Errata workaround for GRLIB-TN-0010

Message ID 20171127095715.5938-4-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-0010.

If the workaround is enabled it will:

* Insert a NOP between load instruction and atomic
  instruction (swap, ldstub, casa).

* Insert a NOP at branch target if load in delay slot
  and atomic instruction at branch target.

It is applicable to UT700.

gcc/ChangeLog:

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

	* config/sparc/sparc.c (atomic_insn_p): New function.
	(sparc_do_work_around_errata): Insert NOP instructions to
	prevent sequences that could trigger the TN-0010 errata for
	UT700.
	* config/sparc/sync.md (atomic_compare_and_swap_leon3_1): Make
	instruction referable in atomic_insns_p.
---
 gcc/config/sparc/sparc.c | 41 +++++++++++++++++++++++++++++++++++++++++
 gcc/config/sparc/sync.md |  2 +-
 2 files changed, 42 insertions(+), 1 deletion(-)

Comments

Eric Botcazou Nov. 28, 2017, 10 a.m. UTC | #1
> 2017-11-17  Daniel Cederman  <cederman@gaisler.com>
> 
> 	* config/sparc/sparc.c (atomic_insn_p): New function.
> 	(sparc_do_work_around_errata): Insert NOP instructions to
> 	prevent sequences that could trigger the TN-0010 errata for
> 	UT700.
> 	* config/sparc/sync.md (atomic_compare_and_swap_leon3_1): Make
> 	instruction referable in atomic_insns_p.

OK for mainline and 7 branch, thanks.
Eric Botcazou Dec. 4, 2017, 11:06 a.m. UTC | #2
> @@ -1024,6 +1040,31 @@ sparc_do_work_around_errata (void)
>  	    emit_insn_before (gen_nop (), target);
>  	}
> 
> +      /* Insert a NOP between load instruction and atomic
> +	 instruction.  Insert a NOP at branch target if load
> +	 in delay slot and atomic instruction at branch target.  */
> +      if (sparc_fix_ut700
> +	  && NONJUMP_INSN_P (insn)
> +	  && (set = single_set (insn)) != NULL_RTX
> +	  && MEM_P (SET_SRC (set))
> +	  && REG_P (SET_DEST (set)))

Any particular reason to use MEM_P instead of mem_ref here?  It looks like 
there is also a case for the b2bst workaround (only loads are concerned).

If no, I'll make the changes along with more cosmetic fixes.
Daniel Cederman Dec. 4, 2017, 12:24 p.m. UTC | #3
> Any particular reason to use MEM_P instead of mem_ref here?  It looks like
> there is also a case for the b2bst workaround (only loads are concerned).

No, there was no particular reason. mem_ref seems like a better choice 
if it detects more types of loads.

/Daniel C
Eric Botcazou Dec. 4, 2017, 11:14 p.m. UTC | #4
> No, there was no particular reason. mem_ref seems like a better choice
> if it detects more types of loads.

Right, it's supposed to detect all types of loads.  Here's what I have 
installed on the mainline and 7 branch.


2017-12-04  Eric Botcazou  <ebotcazou@adacore.com>

	* config/sparc/sparc.c (sparc_do_work_around_errata): Use mem_ref
	instead of MEM_P in a couple more places.  Fix formatting issues.
diff mbox series

Patch

diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 51045db..401dfcb 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -970,6 +970,22 @@  fpop_insn_p (rtx_insn *insn)
     }
 }
 
+/* True if INSN is an atomic instruction.  */
+
+static bool
+atomic_insn_for_leon3_p (rtx_insn *insn)
+{
+  switch (INSN_CODE (insn))
+    {
+    case CODE_FOR_swapsi:
+    case CODE_FOR_ldstub:
+    case CODE_FOR_atomic_compare_and_swap_leon3_1:
+      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
@@ -1024,6 +1040,31 @@  sparc_do_work_around_errata (void)
 	    emit_insn_before (gen_nop (), target);
 	}
 
+      /* Insert a NOP between load instruction and atomic
+	 instruction.  Insert a NOP at branch target if load
+	 in delay slot and atomic instruction at branch target.  */
+      if (sparc_fix_ut700
+	  && NONJUMP_INSN_P (insn)
+	  && (set = single_set (insn)) != NULL_RTX
+	  && MEM_P (SET_SRC (set))
+	  && REG_P (SET_DEST (set)))
+	{
+	  if (jump)
+	    {
+	      rtx_insn *target = next_active_insn (JUMP_LABEL_AS_INSN (jump));
+	      if (target
+		  && atomic_insn_for_leon3_p (target))
+		emit_insn_before (gen_nop (), target);
+	    }
+
+	  next = next_active_insn (insn);
+	  if (!next)
+	    break;
+
+	  if (atomic_insn_for_leon3_p (next))
+	    insert_nop = true;
+	}
+
       /* Look for either of these two sequences:
 
 	 Sequence A:
diff --git a/gcc/config/sparc/sync.md b/gcc/config/sparc/sync.md
index ead7c77..43c66e9 100644
--- a/gcc/config/sparc/sync.md
+++ b/gcc/config/sparc/sync.md
@@ -212,7 +212,7 @@ 
   "cas<modesuffix>\t%1, %2, %0"
   [(set_attr "type" "multi")])
 
-(define_insn "*atomic_compare_and_swap_leon3_1"
+(define_insn "atomic_compare_and_swap_leon3_1"
   [(set (match_operand:SI 0 "register_operand" "=r")
 	(match_operand:SI 1 "mem_noofs_operand" "+w"))
    (set (match_dup 1)