Factor common RTL parsing out of the existing macro-fusion
recognizers.  Preserve aggressive destination overmatching before
register allocation while checking real producer-consumer dependencies
in both scheduling passes.

Use parameterized arithmetic and memory classifiers so later fusion
recognizers can share structural matching without duplicating
microarchitecture-specific constraints.

gcc/ChangeLog:

        * config/riscv/riscv-fusion.cc: Include insn-attr.h.
        (riscv_fuse_sets_p): New function.
        (riscv_set_extract_word_binary_p): Likewise.
        (riscv_regno): Likewise.
        (riscv_fuse_same_reg_p): Likewise.
        (riscv_fuse_same_dest_p): Rename from
        riscv_fusion_same_dest_p and handle hard-register SUBREGs.  Preserve
        preallocation destination overmatching and optionally check the
        first-source dependency.
        (riscv_set_is_addiw_p): New function.
        (riscv_insn_is_mv_li_p): Likewise.
        (riscv_insn_is_addi_type_p): Likewise.
        (riscv_set_is_shift_p): Likewise.
        (riscv_set_is_slli_p): Likewise.
        (riscv_set_is_srli_p): Likewise.
        (riscv_set_is_srai_p): Likewise.
        (enum sched_fusion_type): New enum.
        (riscv_fusion_mem_info): New struct.
        (riscv_fuse_extract_address): New function.
        (riscv_fuse_mem_p): Likewise.
        (riscv_fuse_zext_common): Require RV64 and use the common
        helpers.
        (riscv_fuse_zextw): Update accordingly.
        (riscv_fuse_zextws): Likewise.
        (riscv_fuse_zexth): Likewise.
        (riscv_fuse_ldindexed): Use the common helpers.
        (riscv_fuse_expanded_ld): Likewise.
        (riscv_fuse_ldpreincrement): Likewise.  Check the update dependency.
        (riscv_fuse_lui_addi): Reuse the ADDI matcher, check the source
        dependency, and reject zero-valued LUI patterns.
        (riscv_fuse_auipc_addi): Reuse the ADDI matcher and check the source
        dependency.
        (riscv_fuse_lui_ld): Use the common helpers.
        (riscv_fuse_auipc_ld): Likewise.  Check the address dependency.
        (riscv_fuse_aligned_std): Use the common helpers.
        (riscv_fuse_bfext): Likewise.
        (riscv_fuse_b_alui): Likewise.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/fusion-lui-addi-prera-rtl.c: New test.

Signed-off-by: Jin Ma <[email protected]>
---
 gcc/config/riscv/riscv-fusion.cc              | 847 ++++++++++++------
 .../riscv/fusion-lui-addi-prera-rtl.c         |  63 ++
 2 files changed, 648 insertions(+), 262 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-lui-addi-prera-rtl.c

diff --git a/gcc/config/riscv/riscv-fusion.cc b/gcc/config/riscv/riscv-fusion.cc
index 2ce9b965974..88735b580f1 100644
--- a/gcc/config/riscv/riscv-fusion.cc
+++ b/gcc/config/riscv/riscv-fusion.cc
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "rtl.h"
 #include "regs.h"
 #include "insn-config.h"
+#include "insn-attr.h"
 #include "recog.h"
 #include "function.h"
 #include "memmodel.h"
@@ -51,25 +52,160 @@ riscv_fusion_enabled_p (enum riscv_fusion_pairs op)
   return riscv_get_fusible_ops () & op;
 }
 
-/* Return true if PREV_SET and CURR_SET satisfy the same-dest constraint
-   required by most fusion rules: when we are past register allocation
-   (i.e. can_create_pseudo_p () is false), the destination registers of
-   the two sets must be the same physical register.  */
+/* Extract the single sets from PREV and CURR.  Reject conditional jumps,
+   which cannot form a fusion pair.  */
 
 static bool
-riscv_fusion_same_dest_p (rtx prev_set, rtx curr_set)
+riscv_fuse_sets_p (rtx_insn *prev, rtx_insn *curr,
+                    rtx *prev_set_out = NULL,
+                    rtx *curr_set_out = NULL)
 {
+  rtx prev_set = single_set (prev);
+  rtx curr_set = single_set (curr);
+  if (prev_set_out)
+    *prev_set_out = prev_set;
+  if (curr_set_out)
+    *curr_set_out = curr_set;
+  return prev_set && curr_set && !any_condjump_p (curr);
+}
+
+/* Extract a word-form binary operation with code CODE:
+    (set (reg:DI rd)
+        (sign_extend:DI (op:SI operand1 operand2)))
+   or
+    (set (reg:DI rd)
+         (sign_extend:DI (truncate:SI (op:DI operand1 operand2))))
+   or
+    (set (reg:DI rd)
+         (sign_extend:DI (subreg:SI (op:DI operand1 operand2) 0)))
+   Store the binary operation in *BINARY_SRC.  */
+
+static bool
+riscv_set_extract_word_binary_p (rtx set, rtx_code code, rtx *binary_src)
+{
+  if (!TARGET_64BIT)
+    return false;
+
+  rtx src = SET_SRC (set);
+  *binary_src = NULL_RTX;
+
+  if (GET_CODE (src) != SIGN_EXTEND
+      || GET_MODE (src) != DImode)
+    return false;
+
+  src = XEXP (src, 0);
+  if (GET_CODE (src) == code && GET_MODE (src) == SImode)
+    {
+      *binary_src = src;
+      return true;
+    }
+
+  if (GET_MODE (src) != SImode)
+    return false;
+
+  if (GET_CODE (src) == TRUNCATE)
+    src = XEXP (src, 0);
+  else if (SUBREG_P (src) && subreg_lowpart_p (src))
+    src = SUBREG_REG (src);
+  else
+    return false;
+
+  if (GET_CODE (src) == code && GET_MODE (src) == DImode)
+    {
+      *binary_src = src;
+      return true;
+    }
+
+  return false;
+}
+
+/* Return a comparable register number for X, accounting for hard-register
+   SUBREG offsets, or INVALID_REGNUM.  */
+
+static unsigned int
+riscv_regno (rtx x)
+{
+  int regno = true_regnum (x);
+  if (regno >= 0
+      && (can_create_pseudo_p () || regno < FIRST_PSEUDO_REGISTER))
+    return regno;
+
+  /* Before allocation, use an unassigned pseudo's identity.  Treat every
+     SUBREG of the pseudo alike so that matching remains deliberately
+     permissive until the final hard register is known.  */
   if (can_create_pseudo_p ())
-    return true;
+    {
+      rtx reg = SUBREG_P (x) ? SUBREG_REG (x) : x;
+      if (REG_P (reg) && !HARD_REGISTER_P (reg))
+       return REGNO (reg);
+    }
+
+  return INVALID_REGNUM;
+}
+
+/* Return true if X and Y refer to the same comparable register.  */
 
-  unsigned int prev_dest_regno = (REG_P (SET_DEST (prev_set))
-                                 ? REGNO (SET_DEST (prev_set))
-                                 : FIRST_PSEUDO_REGISTER);
-  unsigned int curr_dest_regno = (REG_P (SET_DEST (curr_set))
-                                 ? REGNO (SET_DEST (curr_set))
-                                 : FIRST_PSEUDO_REGISTER);
+static bool
+riscv_fuse_same_reg_p (rtx x, rtx y)
+{
+  unsigned int x_regno = riscv_regno (x);
+  unsigned int y_regno = riscv_regno (y);
 
-  return prev_dest_regno == curr_dest_regno;
+  return (x_regno != INVALID_REGNUM
+         && y_regno != INVALID_REGNUM
+         && x_regno == y_regno);
+}
+
+/* Return true if PREV_SET and CURR_SET satisfy the same-destination
+   constraint.  Before allocation, defer the destination-register comparison
+   so that the scheduler can keep potential fusion pairs together.  If
+   USED_IN_SRC_P, always require CURR_SET to use PREV_SET's destination as its
+   first source operand.  After allocation, also require the hard-register
+   destinations to match.  */
+
+static bool
+riscv_fuse_same_dest_p (rtx prev_set, rtx curr_set,
+                         bool used_in_src_p = false)
+{
+  rtx prev_dest = SET_DEST (prev_set);
+  rtx curr_dest = SET_DEST (curr_set);
+  unsigned int prev_dest_regno = riscv_regno (prev_dest);
+  if (prev_dest_regno == INVALID_REGNUM
+      || riscv_regno (curr_dest) == INVALID_REGNUM)
+    return false;
+
+  if (used_in_src_p)
+    {
+      rtx src = SET_SRC (curr_set);
+      rtx word_add_src;
+      if (riscv_set_extract_word_binary_p (curr_set, PLUS,
+                                          &word_add_src))
+       src = XEXP (word_add_src, 0);
+      else
+       {
+         while (GET_CODE (src) == SIGN_EXTEND
+                || GET_CODE (src) == ZERO_EXTEND)
+           src = XEXP (src, 0);
+
+         if (GET_CODE (src) == NOT
+             || BINARY_P (src)
+             || GET_CODE (src) == LO_SUM
+             || GET_CODE (src) == ZERO_EXTRACT)
+           src = XEXP (src, 0);
+
+         while (GET_CODE (src) == SIGN_EXTEND
+                || GET_CODE (src) == ZERO_EXTEND)
+           src = XEXP (src, 0);
+       }
+
+      if (!riscv_fuse_same_reg_p (src, prev_dest))
+       return false;
+    }
+
+  if (can_create_pseudo_p ())
+    return true;
+
+  return riscv_fuse_same_reg_p (prev_dest, curr_dest);
 }
 
 /* Matches an add:
@@ -147,28 +283,324 @@ riscv_set_is_shNadduw_p (rtx set)
          && REG_P (SET_DEST (set)));
 }
 
+/* Matches an addiw:
+     (set (reg:DI rd)
+         (sign_extend:DI (plus:SI (reg:SI rs1) (const_int imm12))))
+   or an equivalent word-add RTL form.  */
+
+static bool
+riscv_set_is_addiw_p (rtx set, rtx *src0 = NULL)
+{
+  if (!TARGET_64BIT)
+    return false;
+
+  rtx src;
+  if (riscv_set_extract_word_binary_p (set, PLUS, &src)
+      && REG_P (XEXP (src, 0))
+      && CONST_INT_P (XEXP (src, 1))
+      && REG_P (SET_DEST (set)))
+    {
+      if (src0)
+       *src0 = XEXP (src, 0);
+      return true;
+    }
+
+  return false;
+}
+
+/* Matches an mv or li instruction:
+     (set (reg rd) (reg rs1))
+   or:
+     (set (reg rd) (const_int imm12)).  */
+
+static bool
+riscv_insn_is_mv_li_p (rtx_insn *insn)
+{
+  rtx set = single_set (insn);
+  if (!set)
+    return false;
+
+  rtx dest = SET_DEST (set);
+  rtx src = SET_SRC (set);
+
+  /* Pseudos are valid GPR candidates before register allocation.  */
+  if (get_attr_type (insn) != TYPE_MOVE
+      || get_attr_length (insn) > 4
+      || !REG_P (dest)
+      || (HARD_REGISTER_P (dest) && !GP_REG_P (REGNO (dest))))
+    return false;
+
+  enum attr_move_type move_type = get_attr_move_type (insn);
+  if (move_type == MOVE_TYPE_MOVE
+      && REG_P (src)
+      && (!HARD_REGISTER_P (src)
+         || GP_REG_P (REGNO (src))))
+    return true;
+
+  if (move_type == MOVE_TYPE_CONST
+      && CONST_INT_P (src)
+      /* Distinguish an ADDI-based LI from other single-insn constants.  */
+      && SMALL_OPERAND (INTVAL (src)))
+    return true;
+
+  return false;
+}
+
+/* Matches an addi-type instruction:
+     (set (reg rd) (plus (reg rs1) (const_int imm12)))
+   or:
+     (set (reg rd) (lo_sum (reg rs1) symbol))
+   or an accepted addiw, mv, or li form.  ALLOW_WORD_P controls whether
+   ADDIW is accepted.  Store the register source in *SRC0 when available.  */
+
+static bool
+riscv_insn_is_addi_type_p (rtx_insn *insn, bool allow_word_p = true,
+                          rtx *src0 = NULL)
+{
+  rtx set = single_set (insn);
+  if (!set)
+    return false;
+
+  rtx src = SET_SRC (set);
+  if (riscv_insn_is_mv_li_p (insn))
+    {
+      if (src0 && REG_P (src))
+       *src0 = src;
+      return true;
+    }
+
+  if (get_attr_type (insn) != TYPE_ARITH)
+    return false;
+
+  if (GET_CODE (src) == LO_SUM
+      && GET_MODE (src) == Pmode
+      && REG_P (XEXP (src, 0)))
+    {
+      if (src0)
+       *src0 = XEXP (src, 0);
+      return true;
+    }
+
+  if (riscv_set_is_addi_p (set))
+    {
+      if (!allow_word_p && GET_MODE (src) != Pmode)
+       return false;
+      if (src0)
+       *src0 = XEXP (src, 0);
+      return true;
+    }
+
+  if (allow_word_p
+      && riscv_set_is_addiw_p (set, src0))
+    return true;
+
+  return false;
+}
+
+/* Return true if SET is a non-wrapped scalar shift of CODE.  */
+
+static bool
+riscv_set_is_shift_p (rtx set, rtx_code code)
+{
+  rtx src = SET_SRC (set);
+  machine_mode mode = GET_MODE (src);
+
+  if (GET_CODE (src) != code || !CONST_INT_P (XEXP (src, 1)))
+    return false;
+
+  if (((TARGET_64BIT && mode == DImode) || mode == SImode)
+      && riscv_regno (XEXP (src, 0)) != INVALID_REGNUM
+      && REG_P (SET_DEST (set)))
+    return true;
+
+  return false;
+}
+
+/* Matches an slli:
+     (set (reg rd) (ashift (reg rs1) (const_int shamt))).  */
+
+static bool
+riscv_set_is_slli_p (rtx set)
+{
+  return riscv_set_is_shift_p (set, ASHIFT);
+}
+
+/* Matches an srli:
+     (set (reg rd) (lshiftrt (reg rs1) (const_int shamt))).  */
+
+static bool
+riscv_set_is_srli_p (rtx set)
+{
+  return riscv_set_is_shift_p (set, LSHIFTRT);
+}
+
+/* Matches an srai:
+     (set (reg rd) (ashiftrt (reg rs1) (const_int shamt))).  */
+
+static bool
+riscv_set_is_srai_p (rtx set)
+{
+  return riscv_set_is_shift_p (set, ASHIFTRT);
+}
+
+/* Load/store classes used by fusion checks.  */
+enum sched_fusion_type
+{
+  SCHED_FUSION_LD_SIGN_EXTEND = 0,
+  SCHED_FUSION_LD_ZERO_EXTEND,
+  SCHED_FUSION_LD,
+  SCHED_FUSION_ST
+};
+
+/* Fusion-relevant information about a scalar load or store.  */
+
+struct riscv_fusion_mem_info
+{
+  enum sched_fusion_type type;
+  struct riscv_address_info addr;
+  machine_mode mode;
+  bool fp_p;
+};
+
+/* Extract fusion-relevant information from scalar load/store address X.  */
+
+static bool
+riscv_fuse_extract_address (rtx x, struct riscv_address_info *addr)
+{
+  switch (GET_CODE (x))
+    {
+    case REG:
+    case SUBREG:
+      addr->type = ADDRESS_REG;
+      addr->reg = x;
+      addr->offset = const0_rtx;
+      break;
+
+    case PLUS:
+      if (!CONST_INT_P (XEXP (x, 1)))
+       return false;
+
+      addr->type = ADDRESS_REG;
+      addr->reg = XEXP (x, 0);
+      addr->offset = XEXP (x, 1);
+      break;
+
+    case LO_SUM:
+      addr->type = ADDRESS_LO_SUM;
+      addr->reg = XEXP (x, 0);
+      addr->offset = XEXP (x, 1);
+      break;
+
+    default:
+      return false;
+    }
+
+  return riscv_regno (addr->reg) != INVALID_REGNUM;
+}
+
+/* Extract a scalar integer or floating-point load/store into *INFO:
+     (set (reg rd) (mem addr))
+   or:
+     (set (reg rd) (any_extend (mem addr)))
+   or:
+     (set (reg frd) (mem addr))
+   or:
+     (set (mem addr) (reg rs1))
+   or:
+     (set (mem addr) (const_int 0))
+   or:
+     (set (mem addr) (reg frs1)).  */
+
+static bool
+riscv_fuse_mem_p (rtx_insn *insn, struct riscv_fusion_mem_info *info)
+{
+  gcc_assert (INSN_P (insn));
+
+  rtx set = single_set (insn);
+  if (!set)
+    return false;
+
+  rtx dest = SET_DEST (set);
+  rtx src = SET_SRC (set);
+  info->type = SCHED_FUSION_LD;
+
+  if (GET_CODE (src) == SIGN_EXTEND
+      || GET_CODE (src) == ZERO_EXTEND)
+    {
+      info->type = (GET_CODE (src) == SIGN_EXTEND
+                   ? SCHED_FUSION_LD_SIGN_EXTEND
+                   : SCHED_FUSION_LD_ZERO_EXTEND);
+      src = XEXP (src, 0);
+      if (!MEM_P (src))
+       return false;
+    }
+
+  /* Exclude RVV loads and stores.  */
+  if (riscv_vector_mode_p (GET_MODE (dest))
+      || riscv_vector_mode_p (GET_MODE (src)))
+    return false;
+
+  if (!MEM_P (src) && !MEM_P (dest))
+    return false;
+
+  rtx mem = MEM_P (src) ? src : dest;
+  poly_uint64 mode_size = GET_MODE_SIZE (GET_MODE (mem));
+  /* Reject wide moves that split into multiple instructions, except for
+     single 64-bit FPR or Zilsd moves on RV32.  */
+  if (get_attr_length (insn) > 4
+      && known_gt (mode_size, 0U + UNITS_PER_WORD)
+      && (!known_eq (mode_size, 8U)
+         || riscv_split_64bit_move_p (dest, src)))
+    return false;
+
+  bool isload_p = MEM_P (src);
+  if (isload_p)
+    {
+      if (riscv_regno (dest) == INVALID_REGNUM)
+       return false;
+    }
+  else
+    {
+      if (src != const0_rtx && riscv_regno (src) == INVALID_REGNUM)
+       return false;
+      info->type = SCHED_FUSION_ST;
+    }
+
+  info->mode = GET_MODE (mem);
+  if (!riscv_fuse_extract_address (XEXP (mem, 0), &info->addr))
+    return false;
+
+  enum attr_type type = get_attr_type (insn);
+  if (type == (isload_p ? TYPE_LOAD : TYPE_STORE))
+    info->fp_p = false;
+  else if (type == (isload_p ? TYPE_FPLOAD : TYPE_FPSTORE))
+    info->fp_p = true;
+  else
+    return false;
+
+  return true;
+}
+
 /* Check the common RTL for ZEXTW, ZEXTWS and ZEXTH fusion.  */
 
 static bool
 riscv_fuse_zext_common (rtx_insn *prev, rtx_insn *curr,
-                       int shl_amount, bool zextws_p)
+                    int shl_amount, bool zextws_p)
 {
-  rtx prev_set = single_set (prev);
-  rtx curr_set = single_set (curr);
-  if (!prev_set || !curr_set || any_condjump_p (curr))
+  if (!TARGET_64BIT)
     return false;
 
-  if (!riscv_fusion_same_dest_p (prev_set, curr_set))
+  rtx prev_set, curr_set;
+  if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set))
     return false;
 
-  if (GET_CODE (SET_SRC (prev_set)) == ASHIFT
-      && GET_CODE (SET_SRC (curr_set)) == LSHIFTRT
-      && REG_P (SET_DEST (prev_set))
-      && REG_P (SET_DEST (curr_set))
-      && REG_P (XEXP (SET_SRC (curr_set), 0))
-      && REGNO (XEXP (SET_SRC (curr_set), 0)) == REGNO (SET_DEST (curr_set))
-      && CONST_INT_P (XEXP (SET_SRC (prev_set), 1))
-      && CONST_INT_P (XEXP (SET_SRC (curr_set), 1))
+  if (!riscv_fuse_same_dest_p (prev_set, curr_set, true))
+    return false;
+
+  if (riscv_set_is_slli_p (prev_set)
+      && riscv_set_is_srli_p (curr_set)
+      && GET_MODE (SET_SRC (prev_set)) == DImode
+      && GET_MODE (SET_SRC (curr_set)) == DImode
       && INTVAL (XEXP (SET_SRC (prev_set), 1)) == shl_amount
       && (zextws_p
          ? INTVAL (XEXP (SET_SRC (curr_set), 1)) < shl_amount
@@ -178,6 +610,8 @@ riscv_fuse_zext_common (rtx_insn *prev, rtx_insn *curr,
   return false;
 }
 
+/* Fusion recognizers.  */
+
 /* Check for RISCV_FUSE_ZEXTW fusion.
    prev (slli) == (set (reg:DI rd1)
                       (ashift:DI (reg:DI rs1) (const_int 32)))
@@ -237,35 +671,22 @@ riscv_fuse_zexth (rtx_insn *prev, rtx_insn *curr)
 static bool
 riscv_fuse_ldindexed (rtx_insn *prev, rtx_insn *curr)
 {
-  rtx prev_set = single_set (prev);
-  rtx curr_set = single_set (curr);
-  if (!prev_set || !curr_set || any_condjump_p (curr))
+  rtx prev_set, curr_set;
+  if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set))
     return false;
 
-  if (!riscv_fusion_same_dest_p (prev_set, curr_set))
+  if (!riscv_fuse_same_dest_p (prev_set, curr_set))
     return false;
 
-  if (MEM_P (SET_SRC (curr_set))
-      && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))
-      && REG_P (XEXP (SET_SRC (curr_set), 0))
-      && REGNO (XEXP (SET_SRC (curr_set), 0)) == REGNO (SET_DEST (prev_set))
-      && GET_CODE (SET_SRC (prev_set)) == PLUS
-      && REG_P (XEXP (SET_SRC (prev_set), 0))
-      && REG_P (XEXP (SET_SRC (prev_set), 1)))
-    return true;
+  struct riscv_fusion_mem_info mem;
 
-  /* curr (lw) == (set (reg:DI rd2)
-                      (any_extend:DI (mem:SUBX (reg:DI rd1)))).  */
-  if ((GET_CODE (SET_SRC (curr_set)) == SIGN_EXTEND
-       || (GET_CODE (SET_SRC (curr_set)) == ZERO_EXTEND))
-      && MEM_P (XEXP (SET_SRC (curr_set), 0))
-      && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))
-      && REG_P (XEXP (XEXP (SET_SRC (curr_set), 0), 0))
-      && (REGNO (XEXP (XEXP (SET_SRC (curr_set), 0), 0))
-         == REGNO (SET_DEST (prev_set)))
-      && GET_CODE (SET_SRC (prev_set)) == PLUS
-      && REG_P (XEXP (SET_SRC (prev_set), 0))
-      && REG_P (XEXP (SET_SRC (prev_set), 1)))
+  if (riscv_fuse_mem_p (curr, &mem)
+      && mem.type != SCHED_FUSION_ST
+      && !mem.fp_p
+      && mem.addr.type == ADDRESS_REG
+      && INTVAL (mem.addr.offset) == 0
+      && riscv_set_is_add_p (prev_set)
+      && riscv_fuse_same_reg_p (mem.addr.reg, SET_DEST (prev_set)))
     return true;
 
   return false;
@@ -299,72 +720,29 @@ riscv_fuse_ldindexed (rtx_insn *prev, rtx_insn *curr)
 static bool
 riscv_fuse_expanded_ld (rtx_insn *prev, rtx_insn *curr)
 {
-  rtx prev_set = single_set (prev);
-  rtx curr_set = single_set (curr);
-  if (!prev_set || !curr_set || any_condjump_p (curr))
+  rtx prev_set, curr_set;
+  if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set))
     return false;
 
-  if (!riscv_fusion_same_dest_p (prev_set, curr_set))
+  if (!riscv_fuse_same_dest_p (prev_set, curr_set))
     return false;
 
-  /* Match a load with displacement:
-     curr (load) == (set (reg rd2)
-                        (mem (plus (reg rd1) (const_int offset))))  */
-  if (MEM_P (SET_SRC (curr_set))
-      && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))
-      && GET_CODE (XEXP (SET_SRC (curr_set), 0)) == PLUS
-      && REG_P (XEXP (XEXP (SET_SRC (curr_set), 0), 0))
-      && (REGNO (XEXP (XEXP (SET_SRC (curr_set), 0), 0))
-         == REGNO (SET_DEST (prev_set))))
-    {
-      if (riscv_set_is_add_p (prev_set)
-         || riscv_set_is_addi_p (prev_set)
-         || riscv_set_is_shNadd_p (prev_set))
-       return true;
-    }
-
-  /* Match a load without displacement:
-     curr (load) == (set (reg rd2) (mem (reg rd1))).  */
-  if (MEM_P (SET_SRC (curr_set))
-      && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))
-      && REG_P (XEXP (SET_SRC (curr_set), 0))
-      && REGNO (XEXP (SET_SRC (curr_set), 0)) == REGNO (SET_DEST (prev_set)))
-    {
-      if (riscv_set_is_addi_p (prev_set)
-         || riscv_set_is_shNadd_p (prev_set))
-       return true;
-    }
+  struct riscv_fusion_mem_info mem;
+  if (!riscv_fuse_mem_p (curr, &mem)
+      || mem.type == SCHED_FUSION_ST
+      || mem.fp_p
+      || mem.addr.type != ADDRESS_REG
+      || !riscv_fuse_same_reg_p (mem.addr.reg, SET_DEST (prev_set)))
+    return false;
 
-  /* Match lw with displacement.  */
-  if ((GET_CODE (SET_SRC (curr_set)) == SIGN_EXTEND
-       || (GET_CODE (SET_SRC (curr_set)) == ZERO_EXTEND))
-      && MEM_P (XEXP (SET_SRC (curr_set), 0))
-      && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))
-      && GET_CODE (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == PLUS
-      && REG_P (XEXP (XEXP (XEXP (SET_SRC (curr_set), 0), 0), 0))
-      && (REGNO (XEXP (XEXP (XEXP (SET_SRC (curr_set), 0), 0), 0))
-         == REGNO (SET_DEST (prev_set))))
-    {
-      if (riscv_set_is_adduw_p (prev_set)
-         || riscv_set_is_shNadduw_p (prev_set))
-       return true;
-    }
+  bool displaced_p = INTVAL (mem.addr.offset) != 0;
+  if (mem.type == SCHED_FUSION_LD)
+    return ((displaced_p && riscv_set_is_add_p (prev_set))
+           || riscv_set_is_addi_p (prev_set)
+           || riscv_set_is_shNadd_p (prev_set));
 
-  /* Match lw without displacement.  */
-  if ((GET_CODE (SET_SRC (curr_set)) == SIGN_EXTEND
-       || (GET_CODE (SET_SRC (curr_set)) == ZERO_EXTEND))
-      && MEM_P (XEXP (SET_SRC (curr_set), 0))
-      && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))
-      && REG_P (XEXP (XEXP (SET_SRC (curr_set), 0), 0))
-      && (REGNO (XEXP (XEXP (SET_SRC (curr_set), 0), 0))
-         == REGNO (SET_DEST (prev_set))))
-    {
-      if (riscv_set_is_adduw_p (prev_set)
-         || riscv_set_is_shNadduw_p (prev_set))
-       return true;
-    }
-
-  return false;
+  return (riscv_set_is_adduw_p (prev_set)
+         || riscv_set_is_shNadduw_p (prev_set));
 }
 
 /* Check for RISCV_FUSE_LDPREINCREMENT fusion.
@@ -378,21 +756,24 @@ riscv_fuse_expanded_ld (rtx_insn *prev, rtx_insn *curr)
 static bool
 riscv_fuse_ldpreincrement (rtx_insn *prev, rtx_insn *curr)
 {
-  rtx prev_set = single_set (prev);
-  rtx curr_set = single_set (curr);
-  if (!prev_set || !curr_set || any_condjump_p (curr))
+  rtx prev_set, curr_set;
+  if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set))
     return false;
 
-  if (!riscv_fusion_same_dest_p (prev_set, curr_set))
+  if (!riscv_fuse_same_dest_p (prev_set, curr_set))
     return false;
 
-  if (MEM_P (SET_SRC (curr_set))
-      && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))
-      && REG_P (XEXP (SET_SRC (curr_set), 0))
-      && REGNO (XEXP (SET_SRC (curr_set), 0)) == REGNO (SET_DEST (prev_set))
-      && GET_CODE (SET_SRC (prev_set)) == PLUS
-      && REG_P (XEXP (SET_SRC (prev_set), 0))
-      && CONST_INT_P (XEXP (SET_SRC (prev_set), 1)))
+  struct riscv_fusion_mem_info mem;
+
+  if (riscv_fuse_mem_p (curr, &mem)
+      && mem.type == SCHED_FUSION_LD
+      && !mem.fp_p
+      && mem.addr.type == ADDRESS_REG
+      && INTVAL (mem.addr.offset) == 0
+      && riscv_set_is_addi_p (prev_set)
+      && riscv_fuse_same_reg_p (XEXP (SET_SRC (prev_set), 0),
+                                 SET_DEST (prev_set))
+      && riscv_fuse_same_reg_p (mem.addr.reg, SET_DEST (prev_set)))
     return true;
 
   return false;
@@ -403,33 +784,31 @@ riscv_fuse_ldpreincrement (rtx_insn *prev, rtx_insn *curr)
      (lui) == (set (reg rd1) (const_int imm20))
      (lui) == (set (reg rd1) (high symbol1))
    curr (one of the following):
-     (addi) == (set (reg rd2)
-                   (plus (reg rd1) (const_int imm12)))
+     (addi/addiw) == (set (reg rd2)
+                         (plus (reg rd1) (const_int imm12)))
      (addi) == (set (reg rd2)
                    (lo_sum (reg rd1) symbol2))
+     (self-mv) == (set (reg rd2) (reg rd1))
 
    Constraints:
      rd1 == rd2
-     rd1 != x0
      imm20 != 0 for the constant form.  */
 
 static bool
 riscv_fuse_lui_addi (rtx_insn *prev, rtx_insn *curr)
 {
-  rtx prev_set = single_set (prev);
-  rtx curr_set = single_set (curr);
-  if (!prev_set || !curr_set || any_condjump_p (curr))
+  rtx prev_set, curr_set;
+  if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set))
     return false;
 
-  if (!riscv_fusion_same_dest_p (prev_set, curr_set))
+  if (!riscv_fuse_same_dest_p (prev_set, curr_set, true))
     return false;
 
-  if ((GET_CODE (SET_SRC (curr_set)) == LO_SUM
-       || (GET_CODE (SET_SRC (curr_set)) == PLUS
-          && CONST_INT_P (XEXP (SET_SRC (curr_set), 1))
-          && SMALL_OPERAND (INTVAL (XEXP (SET_SRC (curr_set), 1)))))
+  if (riscv_insn_is_addi_type_p (curr)
       && (GET_CODE (SET_SRC (prev_set)) == HIGH
          || (CONST_INT_P (SET_SRC (prev_set))
+             && (SET_SRC (prev_set)
+                 != CONST0_RTX (GET_MODE (SET_DEST (prev_set))))
              && LUI_OPERAND (INTVAL (SET_SRC (prev_set))))))
     return true;
 
@@ -443,28 +822,24 @@ riscv_fuse_lui_addi (rtx_insn *prev, rtx_insn *curr)
                    (plus (reg rd1) (const_int imm12)))
      (addi) == (set (reg rd2)
                    (lo_sum (reg rd1) symbol))
+     (self-mv) == (set (reg rd2) (reg rd1))
 
    Constraints:
-     rd1 == rd2
-     rd1 != x0.  */
+     rd1 == rd2.  */
 
 static bool
 riscv_fuse_auipc_addi (rtx_insn *prev, rtx_insn *curr)
 {
-  rtx prev_set = single_set (prev);
-  rtx curr_set = single_set (curr);
-  if (!prev_set || !curr_set || any_condjump_p (curr))
+  rtx prev_set, curr_set;
+  if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set))
     return false;
 
-  if (!riscv_fusion_same_dest_p (prev_set, curr_set))
+  if (!riscv_fuse_same_dest_p (prev_set, curr_set, true))
     return false;
 
-  if (GET_CODE (SET_SRC (prev_set)) == UNSPEC
-      && XINT (SET_SRC (prev_set), 1) == UNSPEC_AUIPC
-      && (GET_CODE (SET_SRC (curr_set)) == LO_SUM
-         || (GET_CODE (SET_SRC (curr_set)) == PLUS
-             && CONST_INT_P (XEXP (SET_SRC (curr_set), 1))
-             && SMALL_OPERAND (INTVAL (XEXP (SET_SRC (curr_set), 1))))))
+  if (riscv_insn_is_addi_type_p (curr, false)
+      && GET_CODE (SET_SRC (prev_set)) == UNSPEC
+      && XINT (SET_SRC (prev_set), 1) == UNSPEC_AUIPC)
     return true;
 
   return false;
@@ -489,12 +864,18 @@ riscv_fuse_auipc_addi (rtx_insn *prev, rtx_insn *curr)
 static bool
 riscv_fuse_lui_ld (rtx_insn *prev, rtx_insn *curr)
 {
-  rtx prev_set = single_set (prev);
-  rtx curr_set = single_set (curr);
-  if (!prev_set || !curr_set || any_condjump_p (curr))
+  rtx prev_set, curr_set;
+  if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set))
+    return false;
+
+  if (!riscv_fuse_same_dest_p (prev_set, curr_set))
     return false;
 
-  if (!riscv_fusion_same_dest_p (prev_set, curr_set))
+  struct riscv_fusion_mem_info mem;
+  if (!riscv_fuse_mem_p (curr, &mem)
+      || mem.type == SCHED_FUSION_ST
+      || mem.fp_p
+      || !riscv_fuse_same_reg_p (mem.addr.reg, SET_DEST (prev_set)))
     return false;
 
   /* A LUI_OPERAND accepts (const_int 0), but we won't emit that as LUI.
@@ -502,32 +883,13 @@ riscv_fuse_lui_ld (rtx_insn *prev, rtx_insn *curr)
   if (CONST_INT_P (SET_SRC (prev_set))
       && SET_SRC (prev_set) != CONST0_RTX (GET_MODE (SET_DEST (prev_set)))
       && LUI_OPERAND (INTVAL (SET_SRC (prev_set)))
-      && MEM_P (SET_SRC (curr_set))
-      && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))
-      && GET_CODE (XEXP (SET_SRC (curr_set), 0)) == PLUS
-      && REG_P (XEXP (XEXP (SET_SRC (curr_set), 0), 0))
-      && (REGNO (XEXP (XEXP (SET_SRC (curr_set), 0), 0))
-         == REGNO (SET_DEST (prev_set))))
-    return true;
-
-  if (GET_CODE (SET_SRC (prev_set)) == HIGH
-      && MEM_P (SET_SRC (curr_set))
-      && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))
-      && GET_CODE (XEXP (SET_SRC (curr_set), 0)) == LO_SUM
-      && REG_P (XEXP (XEXP (SET_SRC (curr_set), 0), 0))
-      && (REGNO (XEXP (XEXP (SET_SRC (curr_set), 0), 0))
-         == REGNO (SET_DEST (prev_set))))
+      && mem.type == SCHED_FUSION_LD
+      && mem.addr.type == ADDRESS_REG
+      && GET_CODE (XEXP (SET_SRC (curr_set), 0)) == PLUS)
     return true;
 
   if (GET_CODE (SET_SRC (prev_set)) == HIGH
-      && (GET_CODE (SET_SRC (curr_set)) == SIGN_EXTEND
-         || GET_CODE (SET_SRC (curr_set)) == ZERO_EXTEND)
-      && MEM_P (XEXP (SET_SRC (curr_set), 0))
-      && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))
-      && (GET_CODE (XEXP (XEXP (SET_SRC (curr_set), 0), 0)) == LO_SUM
-         && REG_P (XEXP (XEXP (XEXP (SET_SRC (curr_set), 0), 0), 0))
-         && (REGNO (XEXP (XEXP (XEXP (SET_SRC (curr_set), 0), 0), 0))
-             == REGNO (SET_DEST (prev_set)))))
+      && mem.addr.type == ADDRESS_LO_SUM)
     return true;
 
   return false;
@@ -543,19 +905,23 @@ riscv_fuse_lui_ld (rtx_insn *prev, rtx_insn *curr)
 static bool
 riscv_fuse_auipc_ld (rtx_insn *prev, rtx_insn *curr)
 {
-  rtx prev_set = single_set (prev);
-  rtx curr_set = single_set (curr);
-  if (!prev_set || !curr_set || any_condjump_p (curr))
+  rtx prev_set, curr_set;
+  if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set))
     return false;
 
-  if (!riscv_fusion_same_dest_p (prev_set, curr_set))
+  if (!riscv_fuse_same_dest_p (prev_set, curr_set))
     return false;
 
+  struct riscv_fusion_mem_info mem;
+
   if (GET_CODE (SET_SRC (prev_set)) == UNSPEC
       && XINT (SET_SRC (prev_set), 1) == UNSPEC_AUIPC
-      && MEM_P (SET_SRC (curr_set))
-      && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))
-      && GET_CODE (XEXP (SET_SRC (curr_set), 0)) == PLUS)
+      && riscv_fuse_mem_p (curr, &mem)
+      && mem.type == SCHED_FUSION_LD
+      && !mem.fp_p
+      && mem.addr.type == ADDRESS_REG
+      && GET_CODE (XEXP (SET_SRC (curr_set), 0)) == PLUS
+      && riscv_fuse_same_reg_p (mem.addr.reg, SET_DEST (prev_set)))
     return true;
 
   return false;
@@ -573,50 +939,34 @@ riscv_fuse_auipc_ld (rtx_insn *prev, rtx_insn *curr)
 static bool
 riscv_fuse_aligned_std (rtx_insn *prev, rtx_insn *curr)
 {
-  rtx prev_set = single_set (prev);
-  rtx curr_set = single_set (curr);
-  if (!prev_set || !curr_set || any_condjump_p (curr))
+  if (!riscv_fuse_sets_p (prev, curr))
     return false;
 
-  if (MEM_P (SET_DEST (prev_set))
-      && SCALAR_INT_MODE_P (GET_MODE (SET_DEST (curr_set)))
-      && MEM_P (SET_DEST (curr_set))
-      /* Stores must have the same width.  */
-      && GET_MODE (SET_DEST (curr_set)) == GET_MODE (SET_DEST (prev_set)))
-    {
-      rtx base_prev, base_curr, offset_prev, offset_curr;
-      unsigned mode_size;
-
-      extract_base_offset_in_addr (SET_DEST (prev_set),
-                                  &base_prev, &offset_prev);
-      extract_base_offset_in_addr (SET_DEST (curr_set),
-                                  &base_curr, &offset_curr);
-
-      /* Proceed only if we find both bases, both bases
-        are registers and bases are the same register.  */
-      if (base_prev != NULL_RTX && base_curr != NULL_RTX
-         && REG_P (base_prev) && REG_P (base_curr)
-         && REGNO (base_prev) == REGNO (base_curr))
-       {
-         machine_mode mode = GET_MODE (SET_DEST (curr_set));
-         mode_size = estimated_poly_value (GET_MODE_SIZE (mode));
-
-         HOST_WIDE_INT offset_prev_int = INTVAL (offset_prev);
-         HOST_WIDE_INT offset_curr_int = INTVAL (offset_curr);
-
-         /* Get the smaller offset into OFFSET_PREV_INT.  */
-         if (offset_prev_int > offset_curr_int)
-           std::swap (offset_prev_int, offset_curr_int);
-
-         /* We've normalized, so we need to check that the lower
-            address is aligned to 2X the size of the object.  The
-            higher address must be the lower address plus the
-            size of the object.  */
-         if (((offset_prev_int % (2 * mode_size)) == 0)
-             && offset_prev_int + mode_size == offset_curr_int)
-           return true;
-       }
-    }
+  struct riscv_fusion_mem_info prev_mem, curr_mem;
+
+  if (!riscv_fuse_mem_p (prev, &prev_mem)
+      || !riscv_fuse_mem_p (curr, &curr_mem)
+      || prev_mem.type != SCHED_FUSION_ST
+      || curr_mem.type != SCHED_FUSION_ST
+      || prev_mem.fp_p
+      || curr_mem.fp_p
+      || !SCALAR_INT_MODE_P (prev_mem.mode)
+      || prev_mem.mode != curr_mem.mode
+      || prev_mem.addr.type != ADDRESS_REG
+      || curr_mem.addr.type != ADDRESS_REG
+      || !riscv_fuse_same_reg_p (prev_mem.addr.reg, curr_mem.addr.reg))
+    return false;
+
+  unsigned int mode_size
+    = estimated_poly_value (GET_MODE_SIZE (curr_mem.mode));
+  HOST_WIDE_INT prev_offset = INTVAL (prev_mem.addr.offset);
+  HOST_WIDE_INT curr_offset = INTVAL (curr_mem.addr.offset);
+  if (prev_offset > curr_offset)
+    std::swap (prev_offset, curr_offset);
+
+  if (prev_offset % (2 * mode_size) == 0
+      && prev_offset + mode_size == curr_offset)
+    return true;
 
   return false;
 }
@@ -638,22 +988,16 @@ riscv_fuse_aligned_std (rtx_insn *prev, rtx_insn *curr)
 static bool
 riscv_fuse_bfext (rtx_insn *prev, rtx_insn *curr)
 {
-  rtx prev_set = single_set (prev);
-  rtx curr_set = single_set (curr);
-  if (!prev_set || !curr_set || any_condjump_p (curr))
+  rtx prev_set, curr_set;
+  if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set))
     return false;
 
-  if (!riscv_fusion_same_dest_p (prev_set, curr_set))
+  if (!riscv_fuse_same_dest_p (prev_set, curr_set, true))
     return false;
 
-  if (GET_CODE (SET_SRC (prev_set)) == ASHIFT
-      && (GET_CODE (SET_SRC (curr_set)) == LSHIFTRT
-         || GET_CODE (SET_SRC (curr_set)) == ASHIFTRT)
-      && REG_P (SET_DEST (prev_set))
-      && REG_P (SET_DEST (curr_set))
-      && REGNO (XEXP (SET_SRC (curr_set), 0)) == REGNO (SET_DEST (prev_set))
-      && CONST_INT_P (XEXP (SET_SRC (prev_set), 1))
-      && CONST_INT_P (XEXP (SET_SRC (curr_set), 1)))
+  if (riscv_set_is_slli_p (prev_set)
+      && (riscv_set_is_srli_p (curr_set)
+         || riscv_set_is_srai_p (curr_set)))
     return true;
 
   return false;
@@ -684,33 +1028,24 @@ riscv_fuse_bfext (rtx_insn *prev, rtx_insn *curr)
 static bool
 riscv_fuse_b_alui (rtx_insn *prev, rtx_insn *curr)
 {
-  rtx prev_set = single_set (prev);
-  rtx curr_set = single_set (curr);
-  if (!prev_set || !curr_set || any_condjump_p (curr))
+  rtx prev_set, curr_set;
+  if (!riscv_fuse_sets_p (prev, curr, &prev_set, &curr_set))
     return false;
 
-  if (!riscv_fusion_same_dest_p (prev_set, curr_set))
+  if (!riscv_fuse_same_dest_p (prev_set, curr_set, true))
     return false;
 
   /* orc.b + not.  */
   if (GET_CODE (SET_SRC (prev_set)) == UNSPEC
       && GET_CODE (SET_SRC (curr_set)) == NOT
-      && XINT (SET_SRC (prev_set), 1) == UNSPEC_ORC_B
-      && REG_P (SET_DEST (prev_set))
-      && REG_P (SET_DEST (curr_set))
-      && REG_P (XEXP (SET_SRC (curr_set), 0))
-      && REGNO (XEXP (SET_SRC (curr_set), 0)) == REGNO (SET_DEST (prev_set)))
+      && XINT (SET_SRC (prev_set), 1) == UNSPEC_ORC_B)
     return true;
 
   /* ctz + andi.  */
   if (GET_CODE (SET_SRC (prev_set)) == CTZ
       && GET_CODE (SET_SRC (curr_set)) == AND
       && CONST_INT_P (XEXP (SET_SRC (curr_set), 1))
-      && INTVAL (XEXP (SET_SRC (curr_set), 1)) == 63
-      && REG_P (SET_DEST (prev_set))
-      && REG_P (SET_DEST (curr_set))
-      && REG_P (XEXP (SET_SRC (curr_set), 0))
-      && REGNO (XEXP (SET_SRC (curr_set), 0)) == REGNO (SET_DEST (prev_set)))
+      && INTVAL (XEXP (SET_SRC (curr_set), 1)) == 63)
     return true;
 
   /* sub + smax (abs pattern).  */
@@ -718,27 +1053,15 @@ riscv_fuse_b_alui (rtx_insn *prev, rtx_insn *curr)
       && (XEXP (SET_SRC (prev_set), 0)
          == CONST0_RTX (GET_MODE (SET_SRC (prev_set))))
       && GET_CODE (SET_SRC (curr_set)) == SMAX
-      && REG_P (SET_DEST (prev_set))
-      && REG_P (SET_DEST (curr_set))
-      && REG_P (XEXP (SET_SRC (curr_set), 0))
-      && REGNO (XEXP (SET_SRC (curr_set), 0)) == REGNO (SET_DEST (prev_set))
-      && REG_P (XEXP (SET_SRC (prev_set), 1))
-      && REG_P (XEXP (SET_SRC (curr_set), 1))
-      && (REGNO (XEXP (SET_SRC (prev_set), 1))
-         == REGNO (XEXP (SET_SRC (curr_set), 1))))
+      && riscv_fuse_same_reg_p (XEXP (SET_SRC (prev_set), 1),
+                                 XEXP (SET_SRC (curr_set), 1)))
     return true;
 
   /* neg + smax (abs pattern).  */
   if (GET_CODE (SET_SRC (prev_set)) == NEG
       && GET_CODE (SET_SRC (curr_set)) == SMAX
-      && REG_P (SET_DEST (prev_set))
-      && REG_P (SET_DEST (curr_set))
-      && REG_P (XEXP (SET_SRC (curr_set), 0))
-      && REGNO (XEXP (SET_SRC (curr_set), 0)) == REGNO (SET_DEST (prev_set))
-      && REG_P (XEXP (SET_SRC (prev_set), 0))
-      && REG_P (XEXP (SET_SRC (curr_set), 1))
-      && (REGNO (XEXP (SET_SRC (prev_set), 0))
-         == REGNO (XEXP (SET_SRC (curr_set), 1))))
+      && riscv_fuse_same_reg_p (XEXP (SET_SRC (prev_set), 0),
+                                 XEXP (SET_SRC (curr_set), 1)))
     return true;
 
   return false;
diff --git a/gcc/testsuite/gcc.target/riscv/fusion-lui-addi-prera-rtl.c 
b/gcc/testsuite/gcc.target/riscv/fusion-lui-addi-prera-rtl.c
new file mode 100644
index 00000000000..187be1c24f7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fusion-lui-addi-prera-rtl.c
@@ -0,0 +1,63 @@
+/* Check preallocation overmatching without dropping source dependencies.  */
+/* { dg-do compile { target { rv64 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-O3" "-O[sgz]" "-flto" } } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -O2 -fno-dce -mcmodel=medany 
-mexplicit-relocs -mtune=sifive-p600-series -fdump-rtl-sched1-details 
-fdump-rtl-sched2-details" } */
+/* { dg-final { scan-rtl-dump-times "RISCV_FUSE_LUI_ADDI" 1 "sched1" } } */
+/* { dg-final { scan-rtl-dump-not "RISCV_FUSE_LUI_ADDI" "sched2" } } */
+
+long __RTL (startwith ("sched1"))
+test_lui_addi_prera (void)
+{
+(function "test_lui_addi_prera"
+  (insn-chain
+    (block 2
+      (edge-from entry (flags "FALLTHRU"))
+      (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK)
+      (cnote 2 NOTE_INSN_FUNCTION_BEG)
+      (cinsn 3 (set (reg:DI a1)
+                    (const_int 305418240)))
+      (cinsn 4 (set (reg:DI a0)
+                    (plus:DI (reg:DI a1)
+                             (const_int 1656))))
+      (cinsn 5 (use (reg:DI a0)))
+      (cinsn 6 (use (reg:DI a1)))
+      (cjump_insn 7 (simple_return))
+      (edge-to exit)
+    ) ;; block 2
+    (cbarrier 8)
+  ) ;; insn-chain
+  (crtl
+    (return_rtx
+      (reg/i:DI a0)
+    ) ;; return_rtx
+  ) ;; crtl
+) ;; function "test_lui_addi_prera"
+}
+
+long __RTL (startwith ("sched1"))
+test_lui_addi_source_mismatch (void)
+{
+(function "test_lui_addi_source_mismatch"
+  (insn-chain
+    (block 2
+      (edge-from entry (flags "FALLTHRU"))
+      (cnote 1 [bb 2] NOTE_INSN_BASIC_BLOCK)
+      (cnote 2 NOTE_INSN_FUNCTION_BEG)
+      (cinsn 3 (set (reg:DI a0)
+                    (const_int 305418240)))
+      (cinsn 4 (set (reg:DI a0)
+                    (plus:DI (reg:DI a1)
+                             (const_int 1656))))
+      (cinsn 5 (use (reg:DI a0)))
+      (cjump_insn 6 (simple_return))
+      (edge-to exit)
+    ) ;; block 2
+    (cbarrier 7)
+  ) ;; insn-chain
+  (crtl
+    (return_rtx
+      (reg/i:DI a0)
+    ) ;; return_rtx
+  ) ;; crtl
+) ;; function "test_lui_addi_source_mismatch"
+}
-- 
2.52.0

Reply via email to