cris: Fix addi insn mult vs. shift canonicalization

Message ID 20210222170239.A26D4203BE@pchp3.se.axis.com
State New
Headers show
Series
  • cris: Fix addi insn mult vs. shift canonicalization
Related show

Commit Message

Kewen.Lin via Gcc-patches Feb. 22, 2021, 5:02 p.m.
Ever since the canonicalization clean-up of (mult X (1 << N)) into
(ashift X N) outside addresses, the CRIS addi patterns have been
unmatched.  No big deal.

Unfortunately, nobody thought of adjusting reloaded addresses, so
transforming mult into a shift has to be a kludged for when reload
decides that it has to move an address like (plus (mult reg0 4) reg1)
into a register, as happens building libgfortran.  (No, simplify_rtx
et al don't automatically DTRT.)  Something less kludgy would make
sense if it wasn't for the current late development stage and reload
being deprecated.  I don't know whether this issue is absent for LRA,
though.

I added a testsuite for the reload issue, despite being exposed by a
libgfortran build, so the issue would be covered by C/C++ builds, but
to the CRIS test-suite, not as a generic test, to avoid bad feelings
from anyone preferring short test-times to redundant coverage.

Committed.

gcc:
	* config/cris/cris.c (cris_print_operand) <'T'>: Change
	valid operand from is now an addi mult-value to shift-value.
	* config/cris/cris.md (*addi): Change expression of scaled
	operand from mult to ashift.
	* config/cris/cris.md (*addi_reload): New insn_and_split.

gcc/testsuite:
	* gcc.target/cris/torture/sync-reload-mul-1.c: New test.
---
 gcc/config/cris/cris.c                             | 23 +++++++++------
 gcc/config/cris/cris.md                            | 33 +++++++++++++++++++---
 .../gcc.target/cris/torture/sync-reload-mul-1.c    | 13 +++++++++
 3 files changed, 57 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/cris/torture/sync-reload-mul-1.c

-- 
2.11.0

Patch

diff --git a/gcc/config/cris/cris.c b/gcc/config/cris/cris.c
index 48ea8552e593..8a42aa16da13 100644
--- a/gcc/config/cris/cris.c
+++ b/gcc/config/cris/cris.c
@@ -880,9 +880,6 @@  cris_print_operand (FILE *file, rtx x, int code)
 {
   rtx operand = x;
 
-  /* Size-strings corresponding to MULT expressions.  */
-  static const char *const mults[] = { "BAD:0", ".b", ".w", "BAD:3", ".d" };
-
   /* New code entries should just be added to the switch below.  If
      handling is finished, just return.  If handling was just a
      modification of the operand, the modified operand should be put in
@@ -1212,11 +1209,21 @@  cris_print_operand (FILE *file, rtx x, int code)
       return;
 
     case 'T':
-      /* Print the size letter for an operand to a MULT, which must be a
-	 const_int with a suitable value.  */
-      if (!CONST_INT_P (operand) || INTVAL (operand) > 4)
-	LOSE_AND_RETURN ("invalid operand for 'T' modifier", x);
-      fprintf (file, "%s", mults[INTVAL (operand)]);
+      {
+	/* Print the size letter for an operand to a ASHIFT, which must be a
+	   const_int with a suitable value.  */
+	int shiftval;
+
+	if (!CONST_INT_P (operand))
+	  LOSE_AND_RETURN ("invalid operand for 'T' modifier", x);
+
+	shiftval = INTVAL (operand);
+
+	if (!(shiftval == 1 || shiftval == 2))
+	  LOSE_AND_RETURN ("invalid operand for 'T' modifier", x);
+
+	fprintf (file, "%s", shiftval == 1 ? ".w" : ".d");
+      }
       return;
 
     case 0:
diff --git a/gcc/config/cris/cris.md b/gcc/config/cris/cris.md
index 0fd29f99ba99..069f7e00b6db 100644
--- a/gcc/config/cris/cris.md
+++ b/gcc/config/cris/cris.md
@@ -1278,18 +1278,43 @@  (define_insn "addi_mul"
 (define_insn "*addi"
   [(set (match_operand:SI 0 "register_operand" "=r")
 	(plus:SI
-	 (mult:SI (match_operand:SI 2 "register_operand" "r")
-		  (match_operand:SI 3 "const_int_operand" "n"))
+	 (ashift:SI (match_operand:SI 2 "register_operand" "r")
+		    (match_operand:SI 3 "const_int_operand" "n"))
 	 (match_operand:SI 1 "register_operand" "0")))]
   "operands[0] != frame_pointer_rtx
    && operands[1] != frame_pointer_rtx
    && CONST_INT_P (operands[3])
-   && (INTVAL (operands[3]) == 1
-       || INTVAL (operands[3]) == 2 || INTVAL (operands[3]) == 4)"
+   && (INTVAL (operands[3]) == 1 || INTVAL (operands[3]) == 2)"
   "addi %2%T3,%0"
   [(set_attr "slottable" "yes")
    (set_attr "cc" "none")])
 
+;; The mult-vs-ashift canonicalization-cleanup plagues us: nothing in
+;; reload transforms a "scaled multiplication" into an ashift in a
+;; reloaded address; it's passed as-is and expected to be recognized,
+;; or else we get a tell-tale "unrecognizable insn".
+;; On top of that, we *should* match the bare insn, as a *matching
+;; pattern* (as opposed to e.g. a reload_load_address expander
+;; changing the mul into an ashift), so can_reload_into will re-use
+;; registers in the reloaded expression instead of allocating a new
+;; register.
+(define_insn_and_split "*addi_reload"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(plus:SI
+	 (mult:SI (match_operand:SI 2 "register_operand" "r")
+		  (match_operand:SI 3 "const_int_operand" "n"))
+	 (match_operand:SI 1 "register_operand" "0")))]
+  "operands[0] != frame_pointer_rtx
+   && operands[1] != frame_pointer_rtx
+   && CONST_INT_P (operands[3])
+   && (INTVAL (operands[3]) == 2 || INTVAL (operands[3]) == 4)
+   && (reload_in_progress || reload_completed)"
+  "#"
+  ""
+  [(set (match_dup 0)
+	(plus:SI (ashift:SI (match_dup 2) (match_dup 3)) (match_dup 1)))]
+  "operands[3] = operands[3] == const2_rtx ? const1_rtx : const2_rtx;")
+
 ;; This pattern is usually generated after reload, so a '%' is
 ;; ineffective; use explicit combinations.
 (define_insn "*addi_b_<mode>"
diff --git a/gcc/testsuite/gcc.target/cris/torture/sync-reload-mul-1.c b/gcc/testsuite/gcc.target/cris/torture/sync-reload-mul-1.c
new file mode 100644
index 000000000000..836633f19998
--- /dev/null
+++ b/gcc/testsuite/gcc.target/cris/torture/sync-reload-mul-1.c
@@ -0,0 +1,13 @@ 
+void
+_gfortran_caf_event_post (unsigned int **pp, unsigned int index,
+     int image_index __attribute__ ((unused)),
+     int *stat, char *errmsg __attribute__ ((unused)),
+     unsigned int errmsg_len __attribute__ ((unused)))
+{
+  unsigned int value = 1;
+  unsigned int *event = *pp + index;
+  __atomic_fetch_add (event, value, 0);
+
+  if(stat)
+    *stat = 0;
+}