From 6cb68940dcf9d80ff60576a1b5769cb12d195a03 Mon Sep 17 00:00:00 2001 From: Hans-Peter Nilsson Date: Wed, 17 Feb 2021 19:37:18 +0100 Subject: [PATCH] cris: Fix addi insn mult vs. shift canonicalization 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. 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 diff --git a/gcc/config/cris/cris.c b/gcc/config/cris/cris.c index 48ea855..8a42aa1 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 0fd29f9..069f7e0 100644 --- a/gcc/config/cris/cris.md +++ b/gcc/config/cris/cris.md @@ -1278,18 +1278,43 @@ (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_" 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 0000000..836633f --- /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; +} -- 2.7.4