This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] arc: Avoid store/load pipeline hazard
- From: Andrew Burgess <andrew dot burgess at embecosm dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: noamca at mellanox dot com, guybe at mellanox dot com, Claudiu dot Zissulescu at synopsys dot com, Andrew Burgess <andrew dot burgess at embecosm dot com>
- Date: Thu, 24 Nov 2016 22:10:30 +0000
- Subject: [PATCH] arc: Avoid store/load pipeline hazard
- Authentication-results: sourceware.org; auth=none
The patch below was primarily written (over several patches) by
Claudiu (CC'd) as part of an out-of-tree ARC GCC port. I've pulled
the work together into a single patch, and added a test. Claudiu is
happy for this to be posted upstream.
---
ARC700 targets have a store/load pipeline hazard, if we load within 2
cycles of a store, and the load/store are at the same address, then we
pay a multi-cycle penalty.
This commit avoids this by inserting nop instructions between the store
and the load.
gcc/ChangeLog:
* config/arc/arc-protos.h (arc_store_addr_hazard_p): Declare.
* config/arc/arc.c (arc_store_addr_hazard_p): New function.
(workaround_arc_anomaly): Call arc_store_addr_hazard_p for ARC700.
* config/arc/arc700.md: Add define_bypass for store/load.
gcc/testsuite/ChangeLog:
* gcc.target/arc/arc700-stld-hazard.c: New file.
---
gcc/ChangeLog | 8 +++
gcc/config/arc/arc-protos.h | 1 +
gcc/config/arc/arc.c | 75 +++++++++++++++++++++++
gcc/config/arc/arc700.md | 2 +
gcc/testsuite/ChangeLog | 4 ++
gcc/testsuite/gcc.target/arc/arc700-stld-hazard.c | 14 +++++
6 files changed, 104 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/arc/arc700-stld-hazard.c
diff --git a/gcc/config/arc/arc-protos.h b/gcc/config/arc/arc-protos.h
index d1266b4..83a0b73 100644
--- a/gcc/config/arc/arc-protos.h
+++ b/gcc/config/arc/arc-protos.h
@@ -123,3 +123,4 @@ extern bool arc_legitimize_reload_address (rtx *, machine_mode, int, int);
extern void arc_secondary_reload_conv (rtx, rtx, rtx, bool);
extern bool insn_is_tls_gd_dispatch (rtx_insn *);
extern void arc_cpu_cpp_builtins (cpp_reader *);
+extern bool arc_store_addr_hazard_p (rtx_insn *, rtx_insn *);
diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
index 98c7298..d778279 100644
--- a/gcc/config/arc/arc.c
+++ b/gcc/config/arc/arc.c
@@ -6483,6 +6483,58 @@ arc_invalid_within_doloop (const rtx_insn *insn)
return NULL;
}
+/* Return true if a load instruction (CONSUMER) uses the same address
+ as a store instruction (PRODUCER). This function is used to avoid
+ st/ld address hazard in ARC700 cores. */
+bool
+arc_store_addr_hazard_p (rtx_insn* producer, rtx_insn* consumer)
+{
+ rtx in_set, out_set;
+ rtx out_addr, in_addr;
+
+ if (!producer)
+ return false;
+
+ if (!consumer)
+ return false;
+
+ /* Peel the producer and the consumer for the address. */
+ out_set = single_set (producer);
+ if (out_set)
+ {
+ out_addr = SET_DEST (out_set);
+ if (!out_addr)
+ return false;
+ if (GET_CODE (out_addr) == ZERO_EXTEND
+ || GET_CODE (out_addr) == SIGN_EXTEND)
+ out_addr = XEXP (out_addr, 0);
+
+ if (!MEM_P(out_addr))
+ return false;
+
+ in_set = single_set (consumer);
+ if (in_set)
+ {
+ in_addr = SET_SRC (in_set);
+ if (!in_addr)
+ return false;
+ if (GET_CODE (in_addr) == ZERO_EXTEND
+ || GET_CODE (in_addr) == SIGN_EXTEND)
+ in_addr = XEXP (in_addr, 0);
+
+ if (!MEM_P(in_addr))
+ return false;
+ /* Get rid of the MEM() and check if the addresses are
+ equivalent. */
+ in_addr = XEXP (in_addr, 0);
+ out_addr = XEXP (out_addr, 0);
+
+ return exp_equiv_p (in_addr, out_addr, 0, true);
+ }
+ }
+ return false;
+}
+
/* The same functionality as arc_hazard. It is called in machine
reorg before any other optimization. Hence, the NOP size is taken
into account when doing branch shortening. */
@@ -6501,6 +6553,29 @@ workaround_arc_anomaly (void)
emit_insn_before (gen_nopv (), succ0);
}
}
+
+ if (TARGET_ARC700)
+ {
+ rtx_insn *succ1;
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ succ0 = next_real_insn(insn);
+ if (arc_store_addr_hazard_p (insn, succ0))
+ {
+ emit_insn_after (gen_nopv (), insn);
+ emit_insn_after (gen_nopv (), insn);
+ continue;
+ }
+
+ /* Avoid adding nops if the instruction between the ST and LD is
+ a call or jump. */
+ succ1 = next_real_insn(succ0);
+ if (succ0 && !JUMP_P (succ0) && !CALL_P (succ0)
+ && arc_store_addr_hazard_p (insn, succ1))
+ emit_insn_after (gen_nopv (), insn);
+ }
+ }
}
static int arc_reorg_in_progress = 0;
diff --git a/gcc/config/arc/arc700.md b/gcc/config/arc/arc700.md
index 4d9bddf..3eb5199 100644
--- a/gcc/config/arc/arc700.md
+++ b/gcc/config/arc/arc700.md
@@ -168,3 +168,5 @@
(eq_attr "type" "store")
(not (match_operand:DI 0 "" "")))
"issue+dmp_write_port")
+
+(define_bypass 3 "data_store" "data_load" "arc_store_addr_hazard_p")
diff --git a/gcc/testsuite/gcc.target/arc/arc700-stld-hazard.c b/gcc/testsuite/gcc.target/arc/arc700-stld-hazard.c
new file mode 100644
index 0000000..bf6ae33
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/arc700-stld-hazard.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-mcpu=arc700" } */
+
+volatile int a;
+volatile int b;
+
+void
+foo ()
+{
+ a = 1;
+ b = a;
+}
+
+/* { dg-final { scan-assembler "st r\[0-9\]+,\\\[@a\\\]\[^\n\]*\n\[ \t\]+nop_s\[^\n\]*\n\[ \t\]+nop_s\[^\n\]*\n\[ \t\]+ld r\[0-9\]+,\\\[@a\\\]" } } */
--
2.5.1