diff options
author | Daniel Cederman <cederman@gaisler.com> | 2017-11-29 15:23:40 +0000 |
---|---|---|
committer | Daniel Hellstrom <danielh@gcc.gnu.org> | 2017-11-29 16:23:40 +0100 |
commit | 47c72733ab0cc1ca5b7bb196298ce9ecd91c1896 (patch) | |
tree | 6d04b95f61c870986f2a7454cab083392e50b7d0 | |
parent | aed173734df52b9c48425840c0977c34c23a882a (diff) | |
download | gcc-47c72733ab0cc1ca5b7bb196298ce9ecd91c1896.zip gcc-47c72733ab0cc1ca5b7bb196298ce9ecd91c1896.tar.gz gcc-47c72733ab0cc1ca5b7bb196298ce9ecd91c1896.tar.bz2 |
[SPARC] Errata workaround for GRLIB-TN-0010
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.
2017-11-29 Daniel Cederman <cederman@gaisler.com>
gcc/
* 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.
From-SVN: r255236
-rw-r--r-- | gcc/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.c | 43 | ||||
-rw-r--r-- | gcc/config/sparc/sync.md | 2 |
3 files changed, 52 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 02cb730..53f4b45 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,14 @@ 2017-11-29 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. + +2017-11-29 Daniel Cederman <cederman@gaisler.com> + * config/sparc/sync.md (swapsi): 16-byte align if sparc_fix_gr712rc. (atomic_compare_and_swap_leon3_1): Likewise. (ldstub): Likewise. diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 3208165..7ba3fbf 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: @@ -1352,7 +1393,7 @@ public: virtual bool gate (function *) { return sparc_fix_at697f || sparc_fix_ut699 || sparc_fix_b2bst - || sparc_fix_gr712rc; + || sparc_fix_gr712rc || sparc_fix_ut700; } virtual unsigned int execute (function *) 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) |