[PATCH v5 02/18] RISC-V: Refine macro-fusion helper predicates

Jin Ma <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.