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 <ceder...@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 | 43 +++++++++++++++++++++++++++++++++++++++++++ gcc/config/sparc/sync.md | 2 +- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 8f6eb48..9faf774 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 complex atomic instruction. */ + +static int +atomic_insn_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 @@ -1021,6 +1037,33 @@ 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; + + target = next_active_insn (JUMP_LABEL_AS_INSN (jump)); + if (target + && atomic_insn_p (target)) + emit_insn_before (gen_nop (), target); + } + + next = next_active_insn (insn); + if (!next) + break; + + if (atomic_insn_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 d5c505b..b1baa73 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) -- 2.9.3