arc: Avoid store/load pipeline hazard
authorAndrew Burgess <aburgess@gcc.gnu.org>
Wed, 30 Nov 2016 11:08:06 +0000 (11:08 +0000)
committerAndrew Burgess <aburgess@gcc.gnu.org>
Wed, 30 Nov 2016 11:08:06 +0000 (11:08 +0000)
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.

From-SVN: r243007

gcc/ChangeLog
gcc/config/arc/arc-protos.h
gcc/config/arc/arc.c
gcc/config/arc/arc700.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arc/arc700-stld-hazard.c [new file with mode: 0644]

index da94944da1d34050db8807f6d5e14564edf3f49d..4f3c77382087b1c9fa8b8708e63fc4b0d1eb79d6 100644 (file)
@@ -1,3 +1,11 @@
+2016-11-30  Claudiu Zissulescu  <claziss@synopsys.com>
+           Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * 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.
+
 2016-11-30  Martin Liska  <mliska@suse.cz>
 
        * cgraph.c (symbol_table::initialize): Initialize
index d1266b4a6dbf92635d03257c8a792c711d1bc6c4..83a0b731e7055cd48e0382b6ed1c66ac233c00e3 100644 (file)
@@ -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 *);
index dce66a1a7d6ab08af4606b8d47f450cfa2f013f3..832f567a79b4a8104e02caf41f47d9c516fa7e25 100644 (file)
@@ -6504,6 +6504,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.  */
@@ -6522,6 +6574,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;
index 4d9bddfdb351347cda96aaa72b266e9364548bf8..3eb51999004c485c8ac18c46d5cb460c1a70c944 100644 (file)
        (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")
index 3ed27c4c2359d75d8dd3275398aeb76c9e840fae..5532ed19495eec4551f5b13420fcf9f72c73c436 100644 (file)
@@ -1,3 +1,7 @@
+2016-11-30  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * gcc.target/arc/arc700-stld-hazard.c: New file.
+
 2016-11-30  Janus Weil  <janus@gcc.gnu.org>
 
        PR fortran/78592
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 (file)
index 0000000..bf6ae33
--- /dev/null
@@ -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\\\]" } } */