From: wengliqin <[email protected]>

gcc/ChangeLog:

        * config.gcc: Add riscv-fold-base-idx.cc to riscv extra_objs.
        * config/riscv/bitmanip.md: Update sh1add/sh2add/sh3add/add.uw patterns.
        * config/riscv/riscv-passes.def:  Add fold-base-idx pass.
        * config/riscv/riscv-protos.h: Add fold_base_idx_pass prototype.
        * config/riscv/riscv.cc: Add base_idx_add symbol.
        * config/riscv/riscv.md: Update add patterns.
        * config/riscv/t-riscv: Add riscv-fold-base-idx.cc to build rules.
        * config/riscv/riscv-fold-base-idx.cc: Implement fold-base-idx 
optimization pass for RISC-V to optimize global array accesses.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/fold-base-idx-array-1.c: New test.
        * gcc.target/riscv/fold-base-idx-array-2.c: New test.
        * gcc.target/riscv/fold-base-idx-array-3.c: New test.
        * gcc.target/riscv/fold-base-idx-array-4.c: New test.
        * gcc.target/riscv/fold-base-idx-array-5.c: New test.
        * gcc.target/riscv/fold-base-idx-array-6.c: New test.
        * gcc.target/riscv/fold-base-idx-array-7.c: New test.
        * gcc.target/riscv/fold-base-idx-strcut-1.c: New test.
        * gcc.target/riscv/fold-base-idx-strcut-2.c: New test.
---
This Patch update:
1. clang-format && remove changeLog change

 gcc/config.gcc                                |   2 +-
 gcc/config/riscv/bitmanip.md                  |  40 +
 gcc/config/riscv/riscv-fold-base-idx.cc       | 737 ++++++++++++++++++
 gcc/config/riscv/riscv-passes.def             |   1 +
 gcc/config/riscv/riscv-protos.h               |   4 +-
 gcc/config/riscv/riscv.cc                     |   9 +
 gcc/config/riscv/riscv.md                     |  14 +
 gcc/config/riscv/t-riscv                      |   5 +
 .../gcc.target/riscv/fold-base-idx-array-1.c  |  68 ++
 .../gcc.target/riscv/fold-base-idx-array-2.c  |  73 ++
 .../gcc.target/riscv/fold-base-idx-array-3.c  |  67 ++
 .../gcc.target/riscv/fold-base-idx-array-4.c  |  80 ++
 .../gcc.target/riscv/fold-base-idx-array-5.c  |  72 ++
 .../gcc.target/riscv/fold-base-idx-array-6.c  |  79 ++
 .../gcc.target/riscv/fold-base-idx-array-7.c  |  73 ++
 .../gcc.target/riscv/fold-base-idx-strcut-1.c |  86 ++
 .../gcc.target/riscv/fold-base-idx-strcut-2.c |  86 ++
 17 files changed, 1494 insertions(+), 2 deletions(-)
 create mode 100644 gcc/config/riscv/riscv-fold-base-idx.cc
 create mode 100644 gcc/testsuite/gcc.target/riscv/fold-base-idx-array-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/fold-base-idx-array-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/fold-base-idx-array-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/fold-base-idx-array-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/fold-base-idx-array-5.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/fold-base-idx-array-6.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/fold-base-idx-array-7.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/fold-base-idx-strcut-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/fold-base-idx-strcut-2.c

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 8fe99616f82..52dd48fc8e0 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -569,7 +569,7 @@ pru-*-*)
        ;;
 riscv*)
        cpu_type=riscv
-       extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o 
riscv-shorten-memrefs.o riscv-selftests.o riscv-string.o"
+       extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o 
riscv-shorten-memrefs.o riscv-fold-base-idx.o riscv-selftests.o riscv-string.o"
        extra_objs="${extra_objs} riscv-v.o riscv-vsetvl.o riscv-vector-costs.o 
riscv-avlprop.o riscv-vect-permconst.o"
        extra_objs="${extra_objs} riscv-vector-builtins.o 
riscv-vector-builtins-shapes.o riscv-vector-builtins-bases.o 
sifive-vector-builtins-bases.o andes-vector-builtins-bases.o"
        extra_objs="${extra_objs} thead.o riscv-target-attr.o riscv-zicfilp.o 
riscv-bclr-lowest-set-bit.o riscv-opt-popretz.o"
diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index 0d16d79df3a..11c303a759c 100644
--- a/gcc/config/riscv/bitmanip.md
+++ b/gcc/config/riscv/bitmanip.md
@@ -39,6 +39,19 @@ (define_insn "*shNadd"
   [(set_attr "type" "bitmanip")
    (set_attr "mode" "<X:MODE>")])
 
+(define_insn "@base_idx_shxadd<X:MODE>"
+  [(set (match_operand:X 0 "register_operand" "=r")
+  (unspec:X
+    [(ashift:X (match_operand:X 1 "register_operand" "r")
+                    (match_operand:QI 2 "imm123_operand" "Ds3"))
+         (match_operand:X 3 "register_operand" "r")
+    (match_operand:X 4 "symbolic_operand" "")]
+  UNSPEC_BASE_IDX_ADD))]
+  "TARGET_ZBA"
+  "sh%2add\t%0,%1,%3,%%base_idx_add(%4)"
+  [(set_attr "type" "bitmanip")
+   (set_attr "mode" "<X:MODE>")])
+
 ; When using strength-reduction, we will reduce a multiplication to a
 ; sequence of shifts and adds.  If this is performed with 32-bit types
 ; and followed by a division, the lack of w-form sh[123]add will make
@@ -123,6 +136,21 @@ (define_insn "*shNadduw"
   [(set_attr "type" "bitmanip")
    (set_attr "mode" "DI")])
 
+(define_insn "base_idx_shxadduw"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (unspec:DI
+         [(and:DI (ashift:DI (match_operand:DI 1 "register_operand" "r")
+                            (match_operand:QI 2 "imm123_operand" "Ds3"))
+                  (match_operand 3 "immediate_operand" "n"))
+          (match_operand:DI 4 "register_operand" "r")
+          (match_operand:DI 5 "symbolic_operand" "")]
+         UNSPEC_BASE_IDX_ADD))]
+  "TARGET_64BIT && TARGET_ZBA
+   && (INTVAL (operands[3]) >> INTVAL (operands[2])) == 0xffffffff"
+  "sh%2add.uw\t%0,%1,%4,%%base_idx_add(%5)"
+  [(set_attr "type" "bitmanip")
+   (set_attr "mode" "DI")])
+
 ;; During combine, we may encounter an attempt to combine
 ;;   slli rtmp, rs, #imm
 ;;   zext.w rtmp, rtmp
@@ -177,6 +205,18 @@ (define_insn "*add.uw"
   [(set_attr "type" "bitmanip")
    (set_attr "mode" "DI")])
 
+(define_insn "base_idx_adduw"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+         (unspec:DI
+          [(zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+           (match_operand:DI 2 "register_operand" "r")
+           (match_operand:DI 3 "symbolic_operand" "")]
+          UNSPEC_BASE_IDX_ADD))]
+  "TARGET_64BIT && TARGET_ZBA"
+  "add.uw\t%0,%1,%2,%%base_idx_add(%3)"
+  [(set_attr "type" "bitmanip")
+   (set_attr "mode" "DI")])
+
 (define_insn "*slliuw"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (and:DI (ashift:DI (match_operand:DI 1 "register_operand" "r")
diff --git a/gcc/config/riscv/riscv-fold-base-idx.cc 
b/gcc/config/riscv/riscv-fold-base-idx.cc
new file mode 100644
index 00000000000..4326c2adb18
--- /dev/null
+++ b/gcc/config/riscv/riscv-fold-base-idx.cc
@@ -0,0 +1,737 @@
+/* fold-base-idx pass for RISC-V.
+   Copyright (C) 2018-2024 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#define IN_TARGET_CODE 1
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "backend.h"
+#include "regs.h"
+#include "target.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
+#include "df.h"
+#include "predict.h"
+#include "tree-pass.h"
+#include "cfgrtl.h"
+#include "riscv-protos.h"
+#include "insn-opinit.h"
+
+/* This optimization folds the low immediate of an ADDI into the memory
+   offset of the following ld/st, removing the extra low-address
+   calculation instruction(s).
+
+   1. Without GP relaxation:
+
+      lui + addi + add/add.uw/shxadd/shxadd.uw + ld/st
+      -->
+      lui + add/add.uw/shxadd/shxadd.uw + ld/st   (iff addend == 0)
+
+      lui + addi + addi + add/add.uw/shxadd/shxadd.uw + ld/st
+      -->
+      lui + add/add.uw/shxadd/shxadd.uw + ld/st   (iff addend > 0)
+
+   2. With GP relaxation:
+
+      lui + addi + add/add.uw/shxadd/shxadd.uw + ld/st
+      -->
+      add/add.uw/shxadd/shxadd.uw + ld/st.  */
+
+namespace {
+
+const pass_data pass_data_fold_base_idx = {
+    RTL_PASS,        /* type */
+    "fold_base_idx", /* name */
+    OPTGROUP_NONE,   /* optinfo_flags */
+    TV_NONE,         /* tv_id */
+    0,               /* properties_required */
+    0,               /* properties_provided */
+    0,               /* properties_destroyed */
+    0,               /* todo_flags_start */
+    0,               /* todo_flags_finish */
+};
+
+class pass_fold_base_idx : public rtl_opt_pass {
+public:
+  pass_fold_base_idx (gcc::context *ctxt)
+      : rtl_opt_pass (pass_data_fold_base_idx, ctxt) {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *) { return optimize > 0; }
+  virtual unsigned int execute (function *);
+
+private:
+  void analyze_and_transform (rtx_insn *hi, rtx_insn *lo, rtx_insn *add,
+                             rtx_insn *mem);
+  bool detect_can_fold (rtx_insn *high_insn, rtx_insn *&lo_insn);
+
+  // In this case, where a struct accesses a non-first element, the memory's
+  // Offset is not zero, we can update the hi/lo's symbol with the memory's
+  // offset.
+  void merge_mem_offset_into_symbol (rtx_insn *&hi, rtx_insn *&lo,
+                                    rtx_insn *mem);
+  // In this case, where the addi offset is not zero and addi only oneUse in 
add
+  // insn, we can directly remove the addi insn and update the hi/lo's symbol
+  // with the addi's offset.
+  void remove_addi_and_merge_addioff (rtx_insn *&hi_insn, rtx_insn *&lo_insn,
+                                     rtx_insn *&add_insn);
+  bool fold_base_idx_into_mem_ops (rtx_insn *lo, rtx_insn *&add,
+                                   rtx_insn *&mem);
+}; // class pass_fold_base_idx
+
+/*
+  Iff the insn has only one used insn, and use_insn can't be used in JUMP or
+  CALL, and except the DEBUG Insn.
+*/
+static bool has_one_use (rtx_insn *insn, rtx dest, rtx_insn *&use_insn)
+{
+  if (!REG_P (dest))
+    return false;
+
+  df_ref use;
+  int use_count = 0;
+  unsigned int regno = REGNO (dest);
+
+  for (use = DF_REG_USE_CHAIN (regno); use; use = DF_REF_NEXT_REG (use))
+  {
+    if (!DF_REF_INSN_INFO (use))
+      continue;
+
+    if (CALL_P (DF_REF_INSN (use)) || JUMP_P (DF_REF_INSN (use)))
+      return false;
+
+    if (DEBUG_INSN_P (DF_REF_INSN (use)))
+      continue;
+
+    use_count++;
+    use_insn = DF_REF_INSN (use);
+  }
+
+  if (use_count == 1 && use_insn)
+    return true;
+
+  return false;
+}
+
+/* Symbol Bind is not local can be optimize. */
+static bool symbol_binds_local_p (const_rtx x)
+{
+  if (SYMBOL_REF_P (x))
+    return (SYMBOL_REF_DECL (x) ? targetm.binds_local_p (SYMBOL_REF_DECL (x))
+                              : SYMBOL_REF_LOCAL_P (x));
+  else
+    return false;
+}
+
+/*
+Detect the patterns:
+(set (reg/f:DI high_dst)
+     (high:DI (symbol_ref:DI ("sym"))))
+(set (reg/f:DI lo_dst)
+     (lo_sum:DI (reg/f:DI high_dst) (symbol_ref:DI ("sym"))))
+
+The pattern is only accepted if:
+1.The first instruction has only one use, which is in the LO_SUM
+2.The symbol need is the Global Address or anchor symbols
+*/
+bool pass_fold_base_idx::detect_can_fold (rtx_insn *hi_insn,
+                                         rtx_insn *&lo_insn)
+{
+  rtx hi_set = single_set (hi_insn);
+  if (hi_set == NULL_RTX)
+    return false;
+
+  if (GET_CODE (SET_SRC (hi_set)) != HIGH)
+    return false;
+
+  rtx hi_sym = XEXP (SET_SRC (hi_set), 0);
+  if (GET_CODE (hi_sym) != SYMBOL_REF)
+    return false;
+
+  // Allow non-local symbols or anchor symbols
+  if (symbol_binds_local_p (hi_sym) && !SYMBOL_REF_ANCHOR_P (hi_sym))
+    return false;
+
+  if (!has_one_use (hi_insn, SET_DEST (hi_set), lo_insn))
+    return false;
+
+  rtx lo_set = single_set (lo_insn);
+  if (lo_set == NULL_RTX)
+    return false;
+
+  if (GET_CODE (SET_SRC (lo_set)) != LO_SUM)
+    return false;
+
+  rtx lo_sym = XEXP (SET_SRC (lo_set), 1);
+  if (GET_CODE (lo_sym) != SYMBOL_REF)
+    return false;
+
+  // Allow non-local symbols or anchor symbols
+  if (symbol_binds_local_p (lo_sym) && !SYMBOL_REF_ANCHOR_P (lo_sym))
+    return false;
+
+  return true;
+}
+
+// Update symbol with mem's offset:
+// 1.update the symbol with mem's offset
+// 2.remove addi and update the symbol with addi's offset
+static void update_symbol_offset (rtx_insn *&hi, rtx_insn *&lo,
+                                 HOST_WIDE_INT offset)
+{
+  rtx sym = XEXP (SET_SRC (PATTERN (hi)), 0);
+
+  // if the symbol is already a plus of symbol with offset, we can directly
+  // update the offset of the plus.
+  if (GET_CODE (sym) == CONST && GET_CODE (XEXP (sym, 0)) == PLUS)
+  {
+    HOST_WIDE_INT old_off = INTVAL (XEXP (XEXP (sym, 0), 1));
+    XEXP (XEXP (sym, 0), 1) = GEN_INT (old_off + offset);
+  } else
+{
+    machine_mode mode = GET_MODE (sym);
+    rtx plus = gen_rtx_PLUS (mode, sym, GEN_INT (offset));
+    sym = gen_rtx_CONST (mode, plus);
+  }
+
+  // update hi and lo symbol
+  XEXP (SET_SRC (PATTERN (hi)), 0) = sym;
+  XEXP (SET_SRC (PATTERN (lo)), 1) = sym;
+}
+
+static rtx get_mem_addr (rtx_insn *mem)
+{
+  if (!mem)
+    return NULL_RTX;
+
+  rtx mem_dst = SET_DEST (PATTERN (mem));
+  rtx mem_src = SET_SRC (PATTERN (mem));
+
+  if (MEM_P (mem_src))
+    return XEXP (mem_src, 0);
+  else if (MEM_P (mem_dst))
+    return XEXP (mem_dst, 0);
+  else if ((GET_CODE (mem_src) == ZERO_EXTEND
+           || GET_CODE (mem_src) == SIGN_EXTEND)
+          && MEM_P (XEXP (mem_src, 0)))
+    return XEXP (XEXP (mem_src, 0), 0);
+
+  return NULL_RTX;
+}
+
+/*
+mainly deal with access the struct member varival which not the first.
+
+example as:
+struct bin_info_s {
+  int reg_size;
+  int slab_size;
+};
+typedef struct bin_info_s bin_info_t;
+extern bin_info_t bin_infos[100];
+int  __attribute__((noinline))
+test_gp (int i)
+{
+  return bin_infos[i].slab_size;
+}
+
+Pattern Transform:
+(set (reg/f:DI hi_dst)
+     (high:DI (symbol_ref:DI ("bin_infos"))))
+(set (reg/f:DI lo_dst)
+     (lo_sum:DI (reg/f:DI hi_dst)
+               (symbol_ref:DI ("bin_infos"))))
+(set (reg/f:DI plus_dst)
+     (plus:DI (reg/f:DI lo_dst) (reg:DI plus_src1)))
+(set (reg/i:DI 10 a0)
+     (zero_extend:DI (mem:QI (plus:DI (reg/f:DI plus_dst) (const_int 
mem_off)))))
+
+------- Transform --------
+
+(set (reg/f:DI hi_dst)
+     (high:DI (const:DI (plus:DI (symbol_ref:DI ("bin_infos"))
+                                (const_int mem_off)))))
+(set (reg/f:DI lo_dst)
+     (lo_sum:DI (reg/f:DI hi_dst)
+               (const:DI (plus:DI (symbol_ref:DI ("bin_infos"))
+                                  (const_int mem_off)))))
+(set (reg/f:DI plus_dst)
+     (plus:DI (reg/f:DI hi_dst) (reg:DI plus_src1)))
+(set (reg/i:DI 10 a0)
+     (zero_extend:DI (mem:QI (plus:DI (reg/f:DI plus_dst) (const_int 
mem_off)))))
+*/
+void pass_fold_base_idx::merge_mem_offset_into_symbol (rtx_insn *&hi,
+                                                      rtx_insn *&lo,
+                                                      rtx_insn *mem)
+{
+  rtx mem_addr = get_mem_addr (mem);
+  // if mem_off is zero, we don't need to update the symbol, just return.
+  if (REG_P (mem_addr))
+    return;
+
+  // mem (plus reg/f:DI src1, (const_int mem_off))
+  update_symbol_offset (hi, lo, INTVAL (XEXP (mem_addr, 1)));
+}
+
+/*
+Example as:
+extern long long sym[100];
+long long __attribute__((noinline)) foo (int i)
+{
+  return sym[i + 3];
+}
+
+(set (reg/f:DI hi_dst)
+     (high:DI (symbol_ref:DI ("sym"))))
+(set (reg/f:DI lo_dst)
+     (lo_sum:DI (reg/f:DI hi_dst)
+               (symbol_ref:DI ("sym"))))
+(set (reg:DI remove_addi_dst)
+     (sign_extend:DI (plus:SI (subreg:SI (reg:DI remove_addi_src) 0)
+                             (const_int addi_offset))))
+(set (reg/f:DI plus_dst)
+     (plus:DI (ashift:DI (reg:DI remove_addi_dst) (const_int ashift_num[0x3]))
+                        (reg/f:DI lo_dst)))
+(set (reg/i:DI 10 a0)
+     (mem:DI (reg/f:DI plus_dst) [2 sym[_1]+0 S8 A64]))
+
+------ Transform -------
+
+(set (reg/f:DI hi_dst)
+     (high:DI (const:DI (plus:DI (symbol_ref:DI ("sym"))
+                                (const_int (addi_offset << ashift_num))))))
+(set (reg/f:DI lo_dst)
+     (lo_sum:DI (reg/f:DI hi_dst)
+     (const:DI (plus:DI (symbol_ref:DI ("sym"))
+                       (const_int (addi_offset << ashift_num))))))
+(set (reg/f:DI plus_dst)
+     (plus:DI (ashift:DI (reg:DI remove_addi_src) (const_int ashift_num))
+                        (reg/f:DI lo_dst)))
+(set (reg/i:DI 10 a0) (mem:DI (reg/f:DI plus_dst) [2 sym[_1]+0 S8 A64]))
+*/
+void pass_fold_base_idx::remove_addi_and_merge_addioff (rtx_insn *&hi_insn,
+                                                       rtx_insn *&lo_insn,
+                                                       rtx_insn *&add_insn)
+{
+  rtx add_src = SET_SRC (PATTERN (add_insn));
+  // only add Op0 is LO_Dest, other is Op1 is LO_Dest
+  rtx addi_exp = XEXP (add_src, 0) == SET_DEST (PATTERN (lo_insn))
+                    ? XEXP (add_src, 1)
+                    : XEXP (add_src, 0);
+  HOST_WIDE_INT shift_num = 0;
+  rtx_insn *def_insn = NULL;
+  df_ref def;
+  bool add_ashift_sep = false;
+
+  // plus pattern 1: (plus:DI (reg/f:DI x) (reg:DI y))
+  if (GET_CODE (addi_exp) == REG)
+  {
+    def = DF_REG_DEF_CHAIN (REGNO (addi_exp));
+    def_insn = DF_REF_INSN (def);
+    // When Target not support zba && split the shift and plus insn,
+    // we need update the ashift src'0.Otherwise only deal with the plus
+    // 1.zba not enable
+    // (set (reg:DI shift_dst)
+    //      (ashift:DI (reg:DI x)
+    //                 (const_int shift_num)))
+    // (set (reg/f:DI plus_dst)
+    //      (plus:DI (reg/f:DI  lo_dst)
+    //               (reg:DI shift_dst)))
+    // 2.zba enable
+    // (set (reg/f:DI plus_dst)
+    //      (plus:DI (ashift:DI (reg:DI shift_src]) (const_int shift_num))
+    //               (reg/f:DI lo_dst)))
+    if (def_insn && GET_CODE (PATTERN (def_insn)) == SET
+       && GET_CODE (SET_SRC (PATTERN (def_insn))) == ASHIFT)
+    {
+      add_src = SET_SRC (PATTERN (def_insn));
+      shift_num = INTVAL (XEXP (SET_SRC (PATTERN (def_insn)), 1));
+      def = DF_REG_DEF_CHAIN (REGNO (XEXP (SET_SRC (PATTERN (def_insn)), 0)));
+      add_ashift_sep = true;
+    }
+  }
+  // plus pattern 2:
+  // (plus:DI (ashift:DI (reg:DI x) (const_int c[0xx]))
+  else if (GET_CODE (addi_exp) == ASHIFT)
+  {
+    shift_num = INTVAL (XEXP (addi_exp, 1));
+    def = DF_REG_DEF_CHAIN (REGNO (XEXP (addi_exp, 0)));
+  }
+  // plus pattern 3:
+  // (plus:DI (zero_extend:DI (subreg:SI (reg:DI x) 0))
+  else if (GET_CODE (addi_exp) == ZERO_EXTEND
+          && GET_CODE (XEXP (addi_exp, 0)) == SUBREG)
+  {
+    def = DF_REG_DEF_CHAIN (REGNO (XEXP (XEXP (addi_exp, 0), 0)));
+  }
+  // plus pattern 4:
+  // (plus:DI (and:DI (ashift:DI (reg:DI x) (const_int c[0xxx]))
+  else if (GET_CODE (addi_exp) == AND)
+  {
+    rtx ashift = XEXP (addi_exp, 0);
+    if (GET_CODE (ashift) == ASHIFT && GET_CODE (XEXP (ashift, 0)) == REG)
+ {
+      shift_num = INTVAL (XEXP (ashift, 1));
+      def = DF_REG_DEF_CHAIN (REGNO (XEXP (ashift, 0)));
+    }
+  }
+
+  if (def)
+  {
+    def_insn = DF_REF_INSN (def);
+    rtx def_pat = PATTERN (def_insn);
+    rtx def_src = SET_SRC (def_pat);
+    rtx def_dst = SET_DEST (def_pat);
+    rtx_insn *def_insn_use = NULL;
+    // Find addi and only oneUse in add insn
+    if (!has_one_use (def_insn, def_dst, def_insn_use))
+      return;
+
+    machine_mode mode = GET_MODE (def_dst);
+    if (GET_CODE (def_src) == SIGN_EXTEND
+       && GET_CODE (XEXP (def_src, 0)) == PLUS
+       && GET_CODE (XEXP (XEXP (def_src, 0), 1)) == CONST_INT)
+    {
+      HOST_WIDE_INT off = INTVAL (XEXP (XEXP (def_src, 0), 1)) << shift_num;
+      rtx addi_src = XEXP (XEXP (XEXP (def_src, 0), 0), 0);
+      // FIXME: pr68619-2.c will failed
+      if (!SUBREG_P (XEXP (XEXP (def_src, 0), 0)))
+       return;
+
+      if (SMALL_OPERAND (off))
+      {
+       // update the hi/lo symbol with the offset, update the add src reg by
+       // addi src reg, and remove the addi insn
+       update_symbol_offset (hi_insn, lo_insn, off);
+       if (add_ashift_sep)
+       {
+         XEXP (add_src, 0) = addi_src;
+       } else
+       {
+         if (GET_CODE (addi_exp) == ASHIFT)
+           XEXP (addi_exp, 0) = addi_src;
+         else if (GET_CODE (addi_exp) == AND
+                  || GET_CODE (addi_exp) == ZERO_EXTEND)
+           XEXP (XEXP (addi_exp, 0), 0) = addi_src;
+         else if (addi_exp == XEXP (add_src, 0))
+           XEXP (add_src, 0) = addi_src;
+         else if (addi_exp == XEXP (add_src, 1))
+           XEXP (add_src, 1) = addi_src;
+       }
+       // Remove the addi or ashift insn and update the rescan list
+       delete_insn (def_insn);
+       df_insn_rescan (add_insn);
+      }
+    }
+  }
+}
+
+static bool is_shxadd (rtx shift_amount)
+{
+  if (GET_CODE (shift_amount) != CONST_INT)
+    return false;
+
+  HOST_WIDE_INT val = INTVAL (shift_amount);
+  return val == 1 || val == 2 || val == 3;
+}
+
+static bool validate_plus_pattern (rtx add_src)
+{
+  if (GET_CODE (add_src) != PLUS)
+    return false;
+
+  rtx op0 = XEXP (add_src, 0);
+  rtx op1 = XEXP (add_src, 1);
+
+  if (GET_CODE (op1) != REG)
+    return false;
+
+  if (GET_CODE (op0) == REG)
+    return true;
+
+  if (GET_CODE (op0) == ASHIFT)
+  {
+    rtx asfhift_op0 = XEXP (op0, 0);
+    rtx asfhift_amount = XEXP (op0, 1);
+    return (GET_CODE (asfhift_op0) == REG && is_shxadd (asfhift_amount));
+  }
+
+  if (GET_CODE (op0) == ZERO_EXTEND && GET_CODE (XEXP (op0, 0)) == SUBREG)
+    return true;
+
+  if (GET_CODE (op0) == AND)
+  {
+    rtx ashift = XEXP (op0, 0);
+
+    return GET_CODE (ashift) == ASHIFT && GET_CODE (XEXP (ashift, 0)) == REG
+          && is_shxadd (XEXP (ashift, 1));
+  }
+
+  return false;
+}
+
+/*
+C example as:
+
+extern char arr[42];
+char foo (int i)
+{
+  return arr[i];
+}
+
+Insn Pattern as:
+(set (reg/f:DI hi_dst)
+     (high:DI (symbol_ref:DI ("sym"))))
+(set (reg/f:DI lo_dst)
+     (lo_sum:DI (reg/f:DI hi_dst) (symbol_ref:DI ("sym"))))
+(set (reg/f:DI plus_dst)
+     (plus:DI (reg/f:DI lo_dst) (reg:DI plus_src1)))
+(set (reg/i:DI a0)
+     (zero_extend:DI (mem:QI (reg/f:DI plus_dst)
+*/
+bool pass_fold_base_idx::fold_base_idx_into_mem_ops (rtx_insn *lo,
+                                                    rtx_insn *&add,
+                                                    rtx_insn *&mem)
+{
+  rtx lo_set = single_set (lo);
+  if (lo_set == NULL_RTX)
+    return false;
+
+  if (!has_one_use (lo, SET_DEST (lo_set), add))
+    return false;
+
+  if (GET_CODE (PATTERN (add)) != SET)
+    return false;
+
+  // Support Plus Pattern:
+  // 1. (plus:DI (reg/f:DI x) (reg:DI y))
+  // 2. (plus:DI (ashift:DI (reg:DI x) (const_int c[0xx]))
+  //             (reg/f:DI y)) && c is 1/2/3
+  // 3. (plus:DI (zero_extend:DI (subreg:SI (reg:DI x) 0))
+  //             (reg/f:DI y))
+  // 4. (plus:DI (and:DI (ashift:DI (reg:DI x) (const_int c[0xxx]))
+  //                     (const_int 34359738360[0x7fffffff8]))
+  //             (reg/f:DI y))) && c is 1/2/3
+  rtx add_src = SET_SRC (PATTERN (add));
+  rtx add_dst = SET_DEST (PATTERN (add));
+
+  if (!validate_plus_pattern (add_src))
+    return false;
+
+  if (!has_one_use (add, SET_DEST (PATTERN (add)), mem))
+    return false;
+
+  if (GET_CODE (PATTERN (mem)) != SET)
+    return false;
+
+  rtx mem_dst = SET_DEST (PATTERN (mem));
+  rtx mem_src = SET_SRC (PATTERN (mem));
+
+  // Support Mem Pattern as:
+  // 1. (set (mem:SI (reg/f:DI mem_addr)))
+  // 2. (set (reg/i:DI 10 a0) (mem:DI (reg/f:DI mem_addr)))
+  // 3. (set (reg/i:DI 10 a0) (zero_extend:DI (mem:QI (reg/f:DI mem_addr))))
+  // 4. (set (reg/i:DI 10 a0) (sign_extend:DI (mem:SI (reg/f:DI mem_addr))))
+  if (!MEM_P (mem_dst) && !MEM_P (mem_src)
+      && !((GET_CODE (mem_src) == ZERO_EXTEND
+           || GET_CODE (mem_src) == SIGN_EXTEND)
+       && MEM_P (XEXP (mem_src, 0))))
+    return false;
+
+  // mem (reg/f:DI mem_addr) or mem (plus:DI (reg/f:DI mem_addr) (const_int
+  // mem_offset)), so mem_addr maybe plus or reg, we need get the real reg for
+  // checking.mem_addr must be the same as add_dst, and can't be the frame
+  // pointer.
+  rtx mem_addr = get_mem_addr (mem);
+  rtx mem_reg = GET_CODE (mem_addr) == PLUS ? XEXP (mem_addr, 0) : mem_addr;
+
+  if (mem_reg != add_dst || REGNO (mem_reg) == FRAME_POINTER_REGNUM)
+    return false;
+
+  // Remove the vector mode, which is not supported by gp-relax currently, and
+  // may cause some issues like non-canonical expression.
+  machine_mode mem_mode;
+  if (MEM_P (mem_dst))
+    mem_mode = GET_MODE (mem_dst);
+
+  else if (MEM_P (mem_src))
+    mem_mode = GET_MODE (mem_src);
+
+  else if ((GET_CODE (mem_src) == ZERO_EXTEND
+           || GET_CODE (mem_src) == SIGN_EXTEND)
+          && MEM_P (XEXP (mem_src, 0)))
+    mem_mode = GET_MODE (XEXP (mem_src, 0));
+
+  if (VECTOR_MODE_P (mem_mode))
+    return false;
+
+  return true;
+}
+
+// Mem Pattern as and support mode include DImode/SImode/HImode/QImode:
+// 1. (set (mem:SI (reg/f:DI mem_addr)))
+// 2. (set (reg/i:DI 10 a0) (mem:DI (reg/f:DI mem_addr)))
+// 3. (set (reg/i:DI 10 a0) (zero_extend:DI (mem:QI (reg/f:DI mem_addr)
+// 4. (set (reg/i:DI 10 a0) (sign_extend:DI (mem:SI (reg/f:DI mem_addr)
+static void set_mem_address (rtx_insn *&mem, rtx addr)
+{
+  if (GET_CODE (PATTERN (mem)) != SET)
+    return;
+
+  rtx dst = SET_DEST (PATTERN (mem));
+  rtx src = SET_SRC (PATTERN (mem));
+
+  if (MEM_P (src))
+    XEXP (src, 0) = addr;
+  else if (MEM_P (dst))
+    XEXP (dst, 0) = addr;
+  else if ((GET_CODE (src) == ZERO_EXTEND || GET_CODE (src) == SIGN_EXTEND)
+          && MEM_P (XEXP (src, 0)))
+    XEXP (XEXP (src, 0), 0) = addr;
+}
+
+// Add new relocation types for add and ld/st memory instructions to
+// ensure that subsequent address calculations are correct.
+// 1.Relace the add insn by new add insn with base idx relocation type.
+// 2.Update the add insn which uses lo_sum dst to use high dst instead.
+// 3.Update the mem_addr to use lo_sum of new add insn dst and new relocation
+//   type.
+static void base_idx_sym_emit (rtx_insn *hi, rtx_insn *lo, rtx_insn *add,
+                              rtx_insn *mem)
+{
+  rtx_insn *mem_insn = NULL;
+
+  rtx hi_set = single_set (hi);
+  rtx lo_set = single_set (lo);
+  rtx add_set = single_set (add);
+
+  rtx hi_dst = SET_DEST (hi_set);
+  rtx lo_dst = SET_DEST (lo_set);
+  rtx lo_src = SET_SRC (lo_set);
+  // get symbol operand
+  rtx lo_op1 = XEXP (lo_src, 1);
+
+  rtx add_dst = SET_DEST (add_set);
+  rtx add_src = SET_SRC (add_set);
+  rtx add_op0 = XEXP (add_src, 0);
+  rtx add_op1 = XEXP (add_src, 1);
+
+  machine_mode mode = GET_MODE (add_dst);
+  enum riscv_symbol_type symbol_type;
+
+  // get the insert place for add_insn
+  rtx_insn *add_prev = PREV_INSN (add);
+  rtx add_with_rel = NULL_RTX;
+  if (TARGET_ZBA && GET_CODE (add_op0) == ASHIFT)
+  {
+    // lo_sum will lowering to mem_addr, so we need to update inst that uses
+    // lo_sum dst to use high dst instead Replace shxadd dst, src0, hi_dst,
+    // %shxadd_regrel to shxadd dst, src0, lo_dst
+    add_with_rel = gen_base_idx_shxadd (Pmode, add_dst, XEXP (add_op0, 0),
+                                       XEXP (add_op0, 1), hi_dst, lo_op1);
+  } else if (GET_CODE (add_op0) == REG)
+  {
+    // Replace add dst, src1, hi_dst, %base_idx_add (sym) to add dst, lo_dst,
+    // src1
+    // To ensure consistent output across all assembly code,
+    // swap the positions of the two operands of plus.
+    add_with_rel = gen_base_idx_add (Pmode, add_dst, add_op1, hi_dst, lo_op1);
+  } else if (TARGET_64BIT && TARGET_ZBA && GET_CODE (add_op0) == AND)
+  {
+    rtx ashift = XEXP (add_op0, 0);
+    rtx and_mask = XEXP (add_op0, 1);
+    // Replace shxadd.uw dst, src0, hi_dst, %shxadd_regrel to shxadd dst, src0,
+    // lo_dst
+    add_with_rel = gen_base_idx_shxadduw (
+       add_dst, XEXP (ashift, 0), XEXP (ashift, 1), and_mask, hi_dst, lo_op1);
+  } else if (TARGET_64BIT && TARGET_ZBA && GET_CODE (add_op0) == ZERO_EXTEND)
+  {
+    // add_op0 is (zero_extend:DI (SI_operand))
+    rtx si_operand = XEXP (add_op0, 0);
+    // Replace add.uw dst, src0, hi_dst, %add_regrel to add dst, src0, lo_dst.
+    add_with_rel = gen_base_idx_adduw (add_dst, si_operand, hi_dst, lo_op1);
+  }
+
+  if (add_with_rel)
+  {
+    symbol_type = SYMBOL_BASE_IDX_ADD;
+    emit_insn_after (add_with_rel, add_prev);
+  }
+
+  // Update mem_addr to use lo_sum of new add insn dst and relocation
+  rtx addr =
+      gen_rtx_LO_SUM (mode, add_dst, riscv_unspec_address (lo_op1, 
symbol_type));
+  // lo_sum will lowering to mem_addr
+  set_mem_address (mem, addr);
+
+  rtx_insn *mem_prev = PREV_INSN (mem);
+  mem_insn = emit_insn_after (single_set (mem), mem_prev);
+  if (INSN_P (mem_insn))
+  {
+    rtx note = find_reg_note (mem, REG_DEAD, NULL_RTX);
+    if (note)
+    {
+      add_reg_note (mem_insn, REG_DEAD, XEXP (note, 0));
+    }
+  }
+
+  delete_insn (add);
+  delete_insn (lo);
+  delete_insn (mem);
+  df_insn_rescan (mem_insn);
+  df_analyze ();
+}
+
+void pass_fold_base_idx::analyze_and_transform (rtx_insn *hi, rtx_insn *lo,
+                                                rtx_insn *add, rtx_insn *mem)
+{
+  if (!detect_can_fold (hi, lo))
+    return;
+
+  if (fold_base_idx_into_mem_ops (lo, add, mem))
+  {
+    merge_mem_offset_into_symbol (hi, lo, mem);
+    remove_addi_and_merge_addioff (hi, lo, add);
+    base_idx_sym_emit (hi, lo, add, mem);
+  }
+}
+
+unsigned int pass_fold_base_idx::execute (function *fn)
+{
+  basic_block bb;
+  rtx_insn *insn;
+  FOR_ALL_BB_FN (bb, fn)
+  {
+    FOR_BB_INSNS (bb, insn)
+    analyze_and_transform (insn, NULL, NULL, NULL);
+  }
+
+  return 0;
+}
+
+} // namespace
+
+rtl_opt_pass
+*make_pass_fold_base_idx (gcc::context *ctxt)
+{
+  return new pass_fold_base_idx (ctxt);
+}
diff --git a/gcc/config/riscv/riscv-passes.def 
b/gcc/config/riscv/riscv-passes.def
index bc6b3c8b98d..4ff5ee5cc13 100644
--- a/gcc/config/riscv/riscv-passes.def
+++ b/gcc/config/riscv/riscv-passes.def
@@ -17,6 +17,7 @@
    along with GCC; see the file COPYING3.  If not see
    <http://www.gnu.org/licenses/>.  */
 
+INSERT_PASS_AFTER (pass_combine, 1, pass_fold_base_idx);
 INSERT_PASS_AFTER (pass_combine, 1, pass_bclr_lowest_set_bit);
 INSERT_PASS_AFTER (pass_rtl_store_motion, 1, pass_shorten_memrefs);
 INSERT_PASS_AFTER (pass_split_all_insns, 1, pass_avlprop);
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index dd029c70413..a0bf2677957 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -36,8 +36,9 @@ enum riscv_symbol_type {
   SYMBOL_TLS_IE,
   SYMBOL_TLS_GD,
   SYMBOL_TLSDESC,
+  SYMBOL_BASE_IDX_ADD,
 };
-#define NUM_SYMBOL_TYPES (SYMBOL_TLSDESC + 1)
+#define NUM_SYMBOL_TYPES (SYMBOL_BASE_IDX_ADD + 1)
 
 /* Classifies an address.
 
@@ -202,6 +203,7 @@ extern void riscv_parse_arch_string (const char *, struct 
gcc_options *, locatio
 
 extern bool riscv_hard_regno_rename_ok (unsigned, unsigned);
 
+rtl_opt_pass *make_pass_fold_base_idx (gcc::context *ctxt);
 rtl_opt_pass * make_pass_shorten_memrefs (gcc::context *ctxt);
 rtl_opt_pass * make_pass_avlprop (gcc::context *ctxt);
 rtl_opt_pass * make_pass_vsetvl (gcc::context *ctxt);
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 8a39c791c26..a2da38b2708 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -1878,6 +1878,8 @@ static int riscv_symbol_insns (enum riscv_symbol_type 
type)
     case SYMBOL_TLSDESC: return 6; /* 4-instruction call + ADD TP + the 
reference.  */
     case SYMBOL_GOT_DISP: return 3; /* AUIPC + LD GOT + the reference.  */
     case SYMBOL_FORCE_TO_MEM: return 3; /* AUIPC + LD + the reference.  */
+    case SYMBOL_BASE_IDX_ADD:
+      return 3; /* LUI + the reference + ADD/SHXADD/ADD_UW/SHXADD_UW. */
     default: gcc_unreachable ();
     }
 }
@@ -2178,6 +2180,9 @@ riscv_split_symbol_type (enum riscv_symbol_type 
symbol_type)
   if (!TARGET_EXPLICIT_RELOCS)
     return false;
 
+  if (symbol_type == SYMBOL_BASE_IDX_ADD)
+    return true;
+
   return symbol_type == SYMBOL_ABSOLUTE || symbol_type == SYMBOL_PCREL;
 }
 
@@ -7780,6 +7785,10 @@ riscv_print_operand_reloc (FILE *file, rtx op, bool 
hi_reloc)
        reloc = hi_reloc ? "%hi" : "%lo";
        break;
 
+      case SYMBOL_BASE_IDX_ADD:
+       reloc = hi_reloc ? "%base_idx_add" : "%base_idx_lo";
+       break;
+
       case SYMBOL_PCREL:
        reloc = hi_reloc ? "%pcrel_hi" : "%pcrel_lo";
        break;
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 3fe0ad0ccdf..733bd672f52 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -49,6 +49,8 @@ (define_c_enum "unspec" [
   UNSPEC_TLS_IE
   UNSPEC_TLS_GD
   UNSPEC_TLSDESC
+  ;; Relax the non-constant subscript addressing of global arrays
+  UNSPEC_BASE_IDX_ADD
   ;; High part of PC-relative address.
   UNSPEC_AUIPC
 
@@ -2602,6 +2604,18 @@ (define_insn "*add<mode>hi3"
   [(set_attr "type" "arith")
    (set_attr "mode" "HI")])
 
+(define_insn "@base_idx_add<mode>"
+  [(set (match_operand:P   0 "register_operand" "=r")
+       (unspec:P
+        [(match_operand:P 1 "register_operand" "r")
+         (match_operand:P 2 "register_operand" "r")
+         (match_operand:P 3 "symbolic_operand" "")]
+        UNSPEC_BASE_IDX_ADD))]
+  ""
+  "add\t%0,%1,%2,%%base_idx_add(%3)"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "<MODE>")])
+
 (define_insn "*xor<mode>hi3"
   [(set (match_operand:HI 0 "register_operand"           "=r,r")
        (xor:HI (match_operand:HISI 1 "register_operand" " r,r")
diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv
index 2761e5e20c0..cc665542f57 100644
--- a/gcc/config/riscv/t-riscv
+++ b/gcc/config/riscv/t-riscv
@@ -142,6 +142,11 @@ riscv-bclr-lowest-set-bit.o: 
$(srcdir)/config/riscv/riscv-bclr-lowest-set-bit.cc
        $(COMPILE) $<
        $(POSTCOMPILE)
 
+riscv-fold-base-idx.o: $(srcdir)/config/riscv/riscv-fold-base-idx.cc \
+  $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TARGET_H)
+       $(COMPILE) $<
+       $(POSTCOMPILE)
+
 riscv-shorten-memrefs.o: $(srcdir)/config/riscv/riscv-shorten-memrefs.cc \
   $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TARGET_H)
        $(COMPILE) $<
diff --git a/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-1.c 
b/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-1.c
new file mode 100644
index 00000000000..6298fbd79db
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-1.c
@@ -0,0 +1,68 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -fno-pic -mcmodel=medlow" } */
+
+extern char arr1[100];
+extern short arr2[100];
+extern int arr3[100];
+extern long long arr4[100];
+extern float arr5[100];
+extern double arr6[100];
+
+char __attribute__((noinline)) ld_char(int i) { return arr1[i]; }
+
+char __attribute__((noinline)) ld_uchar(unsigned int i) { return arr1[i]; }
+
+short __attribute__((noinline)) ld_short(int i) { return arr2[i]; }
+
+short __attribute__((noinline)) ld_ushort(unsigned int i) { return arr2[i]; }
+
+int __attribute__((noinline)) ld_int(int i) { return arr3[i]; }
+
+int __attribute__((noinline)) ld_uint(unsigned int i) { return arr3[i]; }
+
+long long __attribute__((noinline)) ld_long(int i) { return arr4[i]; }
+
+long long __attribute__((noinline)) ld_ulong(unsigned int i) { return arr4[i]; 
}
+
+float __attribute__((noinline)) ld_float(int i) { return arr5[i]; }
+
+double __attribute__((noinline)) ld_double(int i) { return arr6[i]; }
+
+void __attribute__((noinline)) st_char(int i) { arr1[i] = 30; }
+
+void __attribute__((noinline)) st_uchar(unsigned int i) { arr1[i] = 30; }
+
+void __attribute__((noinline)) st_short(int i) { arr2[i] = 30; }
+
+void __attribute__((noinline)) st_ushort(unsigned int i) { arr2[i] = 30; }
+
+void __attribute__((noinline)) st_int(int i) { arr3[i] = 30; }
+
+void __attribute__((noinline)) st_uint(unsigned int i) { arr3[i] = 30; }
+
+void __attribute__((noinline)) st_long(int i) { arr4[i] = 30; }
+
+void __attribute__((noinline)) st_ulong(unsigned int i) { arr4[i] = 30; }
+
+void __attribute__((noinline)) st_float(int i) { arr5[i] = 30.0f; }
+
+void __attribute__((noinline)) st_double(int i) { arr6[i] = 30.0; }
+
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr1\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr1\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr2\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr2\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr3\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr3\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr4\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr4\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr5\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr5\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr6\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr6\\)" 2 } } */
+/* { dg-final { scan-assembler-not "sh\[1-3\]add\t" } } */
+/* { dg-final { scan-assembler-not "sh\[1-3\].uw\t" } } */
+/* { dg-final { scan-assembler-not "add.uw\t" } } */
+/* { dg-final { scan-assembler-not "addi\t\[a-x0-9\]+,\[a-x0-9\]+,\[0-9\]+" } }
+ */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-2.c 
b/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-2.c
new file mode 100644
index 00000000000..3f890468132
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-2.c
@@ -0,0 +1,73 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+/* { dg-options "-march=rv64gc_zba -mabi=lp64d -fno-pic -mcmodel=medlow" } */
+
+extern char arr1[100];
+extern short arr2[100];
+extern int arr3[100];
+extern long long arr4[100];
+extern float arr5[100];
+extern double arr6[100];
+
+char __attribute__((noinline)) ld_char(int i) { return arr1[i]; }
+
+char __attribute__((noinline)) ld_uchar(unsigned int i) { return arr1[i]; }
+
+short __attribute__((noinline)) ld_short(int i) { return arr2[i]; }
+
+short __attribute__((noinline)) ld_ushort(unsigned int i) { return arr2[i]; }
+
+int __attribute__((noinline)) ld_int(int i) { return arr3[i]; }
+
+int __attribute__((noinline)) ld_uint(unsigned int i) { return arr3[i]; }
+
+long long __attribute__((noinline)) ld_long(int i) { return arr4[i]; }
+
+long long __attribute__((noinline)) ld_ulong(unsigned int i) { return arr4[i]; 
}
+
+float __attribute__((noinline)) ld_float(int i) { return arr5[i]; }
+
+double __attribute__((noinline)) ld_double(int i) { return arr6[i]; }
+
+void __attribute__((noinline)) st_char(int i) { arr1[i] = 30; }
+
+void __attribute__((noinline)) st_uchar(unsigned int i) { arr1[i] = 30; }
+
+void __attribute__((noinline)) st_short(int i) { arr2[i] = 30; }
+
+void __attribute__((noinline)) st_ushort(unsigned int i) { arr2[i] = 30; }
+
+void __attribute__((noinline)) st_int(int i) { arr3[i] = 30; }
+
+void __attribute__((noinline)) st_uint(unsigned int i) { arr3[i] = 30; }
+
+void __attribute__((noinline)) st_long(int i) { arr4[i] = 30; }
+
+void __attribute__((noinline)) st_ulong(unsigned int i) { arr4[i] = 30; }
+
+void __attribute__((noinline)) st_float(int i) { arr5[i] = 30.0f; }
+
+void __attribute__((noinline)) st_double(int i) { arr6[i] = 30.0; }
+
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr1\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr1\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr2\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr2\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr3\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr3\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr4\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr4\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr5\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr5\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr6\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr6\\)" 2 } } */
+/* { dg-final { scan-assembler-times
+ * "add\\.uw\t\[^\n\]*\\%base_idx_add\\(arr1\\)" 2 } } */
+/* { dg-final { scan-assembler-times
+ * "sh1add\\.uw\t\[^\n\]*\\%base_idx_add\\(arr2\\)" 2 } } */
+/* { dg-final { scan-assembler-times
+ * "sh2add\\.uw\t\[^\n\]*\\%base_idx_add\\(arr3\\)" 2 } } */
+/* { dg-final { scan-assembler-times
+ * "sh3add\\.uw\t\[^\n\]*\\%base_idx_add\\(arr4\\)" 2 } } */
+/* { dg-final { scan-assembler-not "addi\t\[a-x0-9\]+,\[a-x0-9\]+,\[0-9\]+" } }
+ */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-3.c 
b/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-3.c
new file mode 100644
index 00000000000..73d93034b5c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-3.c
@@ -0,0 +1,67 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -fno-pic -mcmodel=medlow" } */
+
+char arr1[100];
+short arr2[100];
+int arr3[100];
+long long arr4[100];
+float arr5[100];
+double arr6[100];
+
+char __attribute__((noinline)) ld_char(int i) { return arr1[i]; }
+
+char __attribute__((noinline)) ld_uchar(unsigned int i) { return arr1[i]; }
+
+short __attribute__((noinline)) ld_short(int i) { return arr2[i]; }
+
+short __attribute__((noinline)) ld_ushort(unsigned int i) { return arr2[i]; }
+
+int __attribute__((noinline)) ld_int(int i) { return arr3[i]; }
+
+int __attribute__((noinline)) ld_uint(unsigned int i) { return arr3[i]; }
+
+long long __attribute__((noinline)) ld_long(int i) { return arr4[i]; }
+
+long long __attribute__((noinline)) ld_ulong(unsigned int i) { return arr4[i]; 
}
+
+float __attribute__((noinline)) ld_float(int i) { return arr5[i]; }
+
+double __attribute__((noinline)) ld_double(int i) { return arr6[i]; }
+
+void __attribute__((noinline)) st_char(int i) { arr1[i] = 30; }
+
+void __attribute__((noinline)) st_uchar(unsigned int i) { arr1[i] = 30; }
+
+void __attribute__((noinline)) st_short(int i) { arr2[i] = 30; }
+
+void __attribute__((noinline)) st_ushort(unsigned int i) { arr2[i] = 30; }
+
+void __attribute__((noinline)) st_int(int i) { arr3[i] = 30; }
+
+void __attribute__((noinline)) st_uint(unsigned int i) { arr3[i] = 30; }
+
+void __attribute__((noinline)) st_long(int i) { arr4[i] = 30; }
+
+void __attribute__((noinline)) st_ulong(unsigned int i) { arr4[i] = 30; }
+
+void __attribute__((noinline)) st_float(int i) { arr5[i] = 30.0f; }
+
+void __attribute__((noinline)) st_double(int i) { arr6[i] = 30.0; }
+
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\)" 4 } } 
*/
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+104\\)" 
4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+104\\)" 4 
} } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+304\\)" 
4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+304\\)" 4 
} } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+704\\)" 
4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+704\\)" 4 
} } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+1504\\)" 
2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+1504\\)" 
2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+1904\\)" 
2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+1904\\)" 
2 } } */
+/* { dg-final { scan-assembler-not "sh\[1-3\]add\t" } } */
+/* { dg-final { scan-assembler-not "sh\[1-3\].uw\t" } } */
+/* { dg-final { scan-assembler-not "add.uw\t" } } */
+/* { dg-final { scan-assembler-not "addi\t\[a-x0-9\]+,\[a-x0-9\]+,\[0-9\]+" } 
} */
diff --git a/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-4.c 
b/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-4.c
new file mode 100644
index 00000000000..68c8f79b7d7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-4.c
@@ -0,0 +1,80 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -fno-pic -mcmodel=medlow" } */
+
+extern char arr1[100];
+extern short arr2[100];
+extern int arr3[100];
+extern long long arr4[100];
+extern float arr5[100];
+extern double arr6[100];
+
+char __attribute__((noinline)) ld_char(int i) { return arr1[i + 3]; }
+
+char __attribute__((noinline)) ld_uchar(unsigned int i) { return arr1[i + 3]; }
+
+short __attribute__((noinline)) ld_short(int i) { return arr2[i + 3]; }
+
+short __attribute__((noinline)) ld_ushort(unsigned int i) {
+  return arr2[i + 3];
+}
+
+int __attribute__((noinline)) ld_int(int i) { return arr3[i + 3]; }
+
+int __attribute__((noinline)) ld_uint(unsigned int i) { return arr3[i + 3]; }
+
+long long __attribute__((noinline)) ld_long(int i) { return arr4[i + 3]; }
+
+long long __attribute__((noinline)) ld_ulong(unsigned int i) {
+  return arr4[i + 3];
+}
+
+float __attribute__((noinline)) ld_float(int i) { return arr5[i + 3]; }
+
+double __attribute__((noinline)) ld_double(int i) { return arr6[i + 3]; }
+
+void __attribute__((noinline)) st_char(int i) { arr1[i + 3] = 30; }
+
+void __attribute__((noinline)) st_uchar(unsigned int i) { arr1[i + 3] = 30; }
+
+void __attribute__((noinline)) st_short(int i) { arr2[i + 3] = 30; }
+
+void __attribute__((noinline)) st_ushort(unsigned int i) { arr2[i + 3] = 30; }
+
+void __attribute__((noinline)) st_int(int i) { arr3[i + 3] = 30; }
+
+void __attribute__((noinline)) st_uint(unsigned int i) { arr3[i + 3] = 30; }
+
+void __attribute__((noinline)) st_long(int i) { arr4[i + 3] = 30; }
+
+void __attribute__((noinline)) st_ulong(unsigned int i) { arr4[i + 3] = 30; }
+
+void __attribute__((noinline)) st_float(int i) { arr5[i + 3] = 30.0f; }
+
+void __attribute__((noinline)) st_double(int i) { arr6[i + 3] = 30.0; }
+
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr1\\+3\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr1\\+3\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr1\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr1\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr2\\+6\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr2\\+6\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr2\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr2\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr3\\+12\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr3\\+12\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr3\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr3\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr4\\+24\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr4\\+24\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr4\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr4\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr5\\+12\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr5\\+12\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr6\\+24\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr6\\+24\\)" 2 } } */
+/* { dg-final { scan-assembler-not "sh\[1-3\]add\t" } } */
+/* { dg-final { scan-assembler-not "sh\[1-3\].uw\t" } } */
+/* { dg-final { scan-assembler-not "add.uw\t" } } */
+/* { dg-final { scan-assembler-not "addi\t\[a-x0-9\]+,\[a-x0-9\]+,\[0-9\]+" } }
+ */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-5.c 
b/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-5.c
new file mode 100644
index 00000000000..db22705c3c4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-5.c
@@ -0,0 +1,72 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+/* { dg-options "-march=rv64gc_zbb_zba -mabi=lp64d -fno-pic -mcmodel=medlow" } 
*/
+
+extern char arr1[100];
+extern short arr2[100];
+extern int arr3[100];
+extern long long arr4[100];
+extern float arr5[100];
+extern double arr6[100];
+
+char __attribute__((noinline)) ld_char(int i) { return arr1[i + 3]; }
+
+char __attribute__((noinline)) ld_uchar(unsigned int i) { return arr1[i + 3]; }
+
+short __attribute__((noinline)) ld_short(int i) { return arr2[i + 3]; }
+
+short __attribute__((noinline)) ld_ushort(unsigned int i) {
+  return arr2[i + 3];
+}
+
+int __attribute__((noinline)) ld_int(int i) { return arr3[i + 3]; }
+
+int __attribute__((noinline)) ld_uint(unsigned int i) { return arr3[i + 3]; }
+
+long long __attribute__((noinline)) ld_long(int i) { return arr4[i + 3]; }
+
+long long __attribute__((noinline)) ld_ulong(unsigned int i) {
+  return arr4[i + 3];
+}
+
+float __attribute__((noinline)) ld_float(int i) { return arr5[i + 3]; }
+
+double __attribute__((noinline)) ld_double(int i) { return arr6[i + 3]; }
+
+void __attribute__((noinline)) st_char(int i) { arr1[i + 3] = 30; }
+
+void __attribute__((noinline)) st_uchar(unsigned int i) { arr1[i + 3] = 30; }
+
+void __attribute__((noinline)) st_short(int i) { arr2[i + 3] = 30; }
+
+void __attribute__((noinline)) st_ushort(unsigned int i) { arr2[i + 3] = 30; }
+
+void __attribute__((noinline)) st_int(int i) { arr3[i + 3] = 30; }
+
+void __attribute__((noinline)) st_uint(unsigned int i) { arr3[i + 3] = 30; }
+
+void __attribute__((noinline)) st_long(int i) { arr4[i + 3] = 30; }
+
+void __attribute__((noinline)) st_ulong(unsigned int i) { arr4[i + 3] = 30; }
+
+void __attribute__((noinline)) st_float(int i) { arr5[i + 3] = 30.0f; }
+
+void __attribute__((noinline)) st_double(int i) { arr6[i + 3] = 30.0; }
+
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr1\\+3\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr1\\+3\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr2\\+6\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr2\\+6\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr3\\+12\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr3\\+12\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr4\\+24\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr4\\+24\\)" 4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr5\\+12\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr5\\+12\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(arr6\\+24\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(arr6\\+24\\)" 2 } } */
+/* { dg-final { scan-assembler-times 
"add\\.uw\t\[^\n\]*\\%base_idx_add\\(arr1\\+3\\)" 2 } } */
+/* { dg-final { scan-assembler-times 
"sh1add\\.uw\t\[^\n\]*\\%base_idx_add\\(arr2\\+6\\)" 2 } } */
+/* { dg-final { scan-assembler-times 
"sh2add\\.uw\t\[^\n\]*\\%base_idx_add\\(arr3\\+12\\)" 2 } } */
+/* { dg-final { scan-assembler-times 
"sh3add\\.uw\t\[^\n\]*\\%base_idx_add\\(arr4\\+24\\)" 2 } } */
+/* { dg-final { scan-assembler-not "addi\t\[a-x0-9\]+,\[a-x0-9\]+,\[0-9\]+" } 
} */
diff --git a/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-6.c 
b/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-6.c
new file mode 100644
index 00000000000..4e7f41e363c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-6.c
@@ -0,0 +1,79 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -fno-pic -mcmodel=medlow" } */
+
+char arr1[100];
+short arr2[100];
+int arr3[100];
+long long arr4[100];
+float arr5[100];
+double arr6[100];
+
+char __attribute__((noinline)) ld_char(int i) { return arr1[i + 3]; }
+
+char __attribute__((noinline)) ld_uchar(unsigned int i) { return arr1[i + 3]; }
+
+short __attribute__((noinline)) ld_short(int i) { return arr2[i + 3]; }
+
+short __attribute__((noinline)) ld_ushort(unsigned int i) {
+  return arr2[i + 3];
+}
+
+int __attribute__((noinline)) ld_int(int i) { return arr3[i + 3]; }
+
+int __attribute__((noinline)) ld_uint(unsigned int i) { return arr3[i + 3]; }
+
+long long __attribute__((noinline)) ld_long(int i) { return arr4[i + 3]; }
+
+long long __attribute__((noinline)) ld_ulong(unsigned int i) {
+  return arr4[i + 3];
+}
+
+float __attribute__((noinline)) ld_float(int i) { return arr5[i + 3]; }
+
+double __attribute__((noinline)) ld_double(int i) { return arr6[i + 3]; }
+
+void __attribute__((noinline)) st_char(int i) { arr1[i + 3] = 30; }
+
+void __attribute__((noinline)) st_uchar(unsigned int i) { arr1[i + 3] = 30; }
+
+void __attribute__((noinline)) st_short(int i) { arr2[i + 3] = 30; }
+
+void __attribute__((noinline)) st_ushort(unsigned int i) { arr2[i + 3] = 30; }
+
+void __attribute__((noinline)) st_int(int i) { arr3[i + 3] = 30; }
+
+void __attribute__((noinline)) st_uint(unsigned int i) { arr3[i + 3] = 30; }
+
+void __attribute__((noinline)) st_long(int i) { arr4[i + 3] = 30; }
+
+void __attribute__((noinline)) st_ulong(unsigned int i) { arr4[i + 3] = 30; }
+
+void __attribute__((noinline)) st_float(int i) { arr5[i + 3] = 30.0f; }
+
+void __attribute__((noinline)) st_double(int i) { arr6[i + 3] = 30.0; }
+
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+3\\)" 2 
} } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+3\\)" 2 } 
} */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\)" 2 } } 
*/
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+110\\)" 
2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+110\\)" 2 
} } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+104\\)" 
2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+104\\)" 2 
} } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+316\\)" 
2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+316\\)" 2 
} } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+304\\)" 
2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+304\\)" 2 
} } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+728\\)" 
2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+728\\)" 2 
} } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+704\\)" 
2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+704\\)" 2 
} } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+1516\\)" 
2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+1516\\)" 
2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+1928\\)" 
2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+1928\\)" 
2 } } */
+/* { dg-final { scan-assembler-not "sh\[1-3\]add\t" } } */
+/* { dg-final { scan-assembler-not "sh\[1-3\].uw\t" } } */
+/* { dg-final { scan-assembler-not "add.uw\t" } } */
+/* { dg-final { scan-assembler-not "addi\t\[a-x0-9\]+,\[a-x0-9\]+,\[0-9\]+" } 
} */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-7.c 
b/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-7.c
new file mode 100644
index 00000000000..12eb575b61c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fold-base-idx-array-7.c
@@ -0,0 +1,73 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+/* { dg-options "-march=rv64gc_zba_zbb -mabi=lp64d -fno-pic -mcmodel=medlow" } 
*/
+
+char arr1[100];
+short arr2[100];
+int arr3[100];
+long long arr4[100];
+float arr5[100];
+double arr6[100];
+
+char __attribute__((noinline)) ld_char(int i) { return arr1[i + 3]; }
+
+char __attribute__((noinline)) ld_uchar(unsigned int i) { return arr1[i + 3]; }
+
+short __attribute__((noinline)) ld_short(int i) { return arr2[i + 3]; }
+
+short __attribute__((noinline)) ld_ushort(unsigned int i) {
+  return arr2[i + 3];
+}
+
+int __attribute__((noinline)) ld_int(int i) { return arr3[i + 3]; }
+
+int __attribute__((noinline)) ld_uint(unsigned int i) { return arr3[i + 3]; }
+
+long long __attribute__((noinline)) ld_long(int i) { return arr4[i + 3]; }
+
+long long __attribute__((noinline)) ld_ulong(unsigned int i) {
+  return arr4[i + 3];
+}
+
+float __attribute__((noinline)) ld_float(int i) { return arr5[i + 3]; }
+
+double __attribute__((noinline)) ld_double(int i) { return arr6[i + 3]; }
+
+void __attribute__((noinline)) st_char(int i) { arr1[i + 3] = 30; }
+
+void __attribute__((noinline)) st_uchar(unsigned int i) { arr1[i + 3] = 30; }
+
+void __attribute__((noinline)) st_short(int i) { arr2[i + 3] = 30; }
+
+void __attribute__((noinline)) st_ushort(unsigned int i) { arr2[i + 3] = 30; }
+
+void __attribute__((noinline)) st_int(int i) { arr3[i + 3] = 30; }
+
+void __attribute__((noinline)) st_uint(unsigned int i) { arr3[i + 3] = 30; }
+
+void __attribute__((noinline)) st_long(int i) { arr4[i + 3] = 30; }
+
+void __attribute__((noinline)) st_ulong(unsigned int i) { arr4[i + 3] = 30; }
+
+void __attribute__((noinline)) st_float(int i) { arr5[i + 3] = 30.0f; }
+
+void __attribute__((noinline)) st_double(int i) { arr6[i + 3] = 30.0; }
+
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+3\\)" 4 
} } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+3\\)" 4 } 
}
+ */
+/* { dg-final { scan-assembler-times 
"add\\.uw\t\[^\n\]*\\%base_idx_add\\(\\.LANCHOR0\\+3\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+110\\)" 
4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+110\\)" 4 
} } */
+/* { dg-final { scan-assembler-times 
"sh1add\\.uw\t\[^\n\]*\\%base_idx_add\\(\\.LANCHOR0\\+110\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+316\\)" 
4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+316\\)" 4 
} } */
+/* { dg-final { scan-assembler-times 
"sh2add\\.uw\t\[^\n\]*\\%base_idx_add\\(\\.LANCHOR0\\+316\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+728\\)" 
4 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+728\\)" 4 
} } */
+/* { dg-final { scan-assembler-times 
"sh3add\\.uw\t\[^\n\]*\\%base_idx_add\\(\\.LANCHOR0\\+728\\)" 2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+1516\\)" 
2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+1516\\)" 
2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(\\.LANCHOR0\\+1928\\)" 
2 } } */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(\\.LANCHOR0\\+1928\\)" 
2 } } */
+/* { dg-final { scan-assembler-not "addi\t\[a-x0-9\]+,\[a-x0-9\]+,\[0-9\]+" } 
} */
diff --git a/gcc/testsuite/gcc.target/riscv/fold-base-idx-strcut-1.c 
b/gcc/testsuite/gcc.target/riscv/fold-base-idx-strcut-1.c
new file mode 100644
index 00000000000..378f38cefed
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fold-base-idx-strcut-1.c
@@ -0,0 +1,86 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -fno-pic -mcmodel=medlow" } */
+
+// struct
+#include <stdint.h>
+
+struct bin_info_s {
+  int reg_size;
+  int slab_size;
+  uint32_t nregs[10];
+  uint32_t n_shards;
+};
+
+typedef struct bin_info_s bin_info_t;
+extern bin_info_t bin_infos[100];
+int __attribute__((noinline)) struct_ld(int i) {
+  return bin_infos[i].slab_size;
+}
+
+int __attribute__((noinline)) struct_ld_uindex(unsigned int i) {
+  return bin_infos[i].slab_size;
+}
+
+int __attribute__((noinline)) struct_array_const_ld(int i) {
+  return bin_infos[i].nregs[2];
+}
+
+int __attribute__((noinline)) struct_array_const_ld_uindex(unsigned int i) {
+  return bin_infos[i].nregs[2];
+}
+
+int __attribute__((noinline)) struct_array_index_ld(int i) {
+  return bin_infos[i].nregs[i];
+}
+
+int __attribute__((noinline)) struct_array_index_ld_uindex(unsigned int i) {
+  return bin_infos[i].nregs[i];
+}
+
+int __attribute__((noinline)) struct_array_index_off_ld(int i) {
+  return bin_infos[i].nregs[i + 3];
+}
+
+int __attribute__((noinline)) struct_array_index_off_ld_uindex(unsigned int i) 
{
+  return bin_infos[i].nregs[i + 3];
+}
+
+void __attribute__((noinline)) struct_st(int i) { bin_infos[i].slab_size = 10; 
}
+
+void __attribute__((noinline)) struct_st_uindex(unsigned int i) {
+  bin_infos[i].slab_size = 10;
+}
+
+void __attribute__((noinline)) struct_array_const_st(int i) {
+  bin_infos[i].nregs[2] = 10;
+}
+
+void __attribute__((noinline)) struct_array_const_st_uindex(unsigned int i) {
+  bin_infos[i].nregs[2] = 10;
+}
+
+void __attribute__((noinline)) struct_array_index_st(int i) {
+  bin_infos[i].nregs[i] = 10;
+}
+
+void __attribute__((noinline)) struct_array_index_st_uindex(unsigned int i) {
+  bin_infos[i].nregs[i] = 10;
+}
+
+void __attribute__((noinline)) struct_array_index_off_st(int i) {
+  bin_infos[i].nregs[i + 3] = 10;
+}
+
+void __attribute__((noinline))
+struct_array_index_off_st_uindex(unsigned int i) {
+  bin_infos[i].nregs[i + 3] = 10;
+}
+
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(bin_infos\\+4\\)" 4 } 
} */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(bin_infos\\+4\\)" 4 } } 
*/
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(bin_infos\\+8\\)" 8 } 
} */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(bin_infos\\+8\\)" 8 } } 
*/
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(bin_infos\\+16\\)" 4 } 
} */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(bin_infos\\+16\\)" 4 } 
} */
+/* { dg-final { scan-assembler-not "addi\t\[a-x0-9\]+,\[a-x0-9\]+,\[0-9\]+" } 
} */
diff --git a/gcc/testsuite/gcc.target/riscv/fold-base-idx-strcut-2.c 
b/gcc/testsuite/gcc.target/riscv/fold-base-idx-strcut-2.c
new file mode 100644
index 00000000000..5953847cdc6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/fold-base-idx-strcut-2.c
@@ -0,0 +1,86 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Os" } } */
+/* { dg-options "-march=rv64gc_zbb_zba -mabi=lp64d -fno-pic -mcmodel=medlow" { 
target { rv64 } } } */
+
+// struct
+#include <stdint.h>
+
+struct bin_info_s {
+  int reg_size;
+  int slab_size;
+  uint32_t nregs[10];
+  uint32_t n_shards;
+};
+
+typedef struct bin_info_s bin_info_t;
+extern bin_info_t bin_infos[100];
+int __attribute__((noinline)) struct_ld(int i) {
+  return bin_infos[i].slab_size;
+}
+
+int __attribute__((noinline)) struct_ld_uindex(unsigned int i) {
+  return bin_infos[i].slab_size;
+}
+
+int __attribute__((noinline)) struct_array_const_ld(int i) {
+  return bin_infos[i].nregs[2];
+}
+
+int __attribute__((noinline)) struct_array_const_ld_uindex(unsigned int i) {
+  return bin_infos[i].nregs[2];
+}
+
+int __attribute__((noinline)) struct_array_index_ld(int i) {
+  return bin_infos[i].nregs[i];
+}
+
+int __attribute__((noinline)) struct_array_index_ld_uindex(unsigned int i) {
+  return bin_infos[i].nregs[i];
+}
+
+int __attribute__((noinline)) struct_array_index_off_ld(int i) {
+  return bin_infos[i].nregs[i + 3];
+}
+
+int __attribute__((noinline)) struct_array_index_off_ld_uindex(unsigned int i) 
{
+  return bin_infos[i].nregs[i + 3];
+}
+
+void __attribute__((noinline)) struct_st(int i) { bin_infos[i].slab_size = 10; 
}
+
+void __attribute__((noinline)) struct_st_uindex(unsigned int i) {
+  bin_infos[i].slab_size = 10;
+}
+
+void __attribute__((noinline)) struct_array_const_st(int i) {
+  bin_infos[i].nregs[2] = 10;
+}
+
+void __attribute__((noinline)) struct_array_const_st_uindex(unsigned int i) {
+  bin_infos[i].nregs[2] = 10;
+}
+
+void __attribute__((noinline)) struct_array_index_st(int i) {
+  bin_infos[i].nregs[i] = 10;
+}
+
+void __attribute__((noinline)) struct_array_index_st_uindex(unsigned int i) {
+  bin_infos[i].nregs[i] = 10;
+}
+
+void __attribute__((noinline)) struct_array_index_off_st(int i) {
+  bin_infos[i].nregs[i + 3] = 10;
+}
+
+void __attribute__((noinline))
+struct_array_index_off_st_uindex(unsigned int i) {
+  bin_infos[i].nregs[i + 3] = 10;
+}
+
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(bin_infos\\+4\\)" 4 } 
} */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(bin_infos\\+4\\)" 4 } } 
*/
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(bin_infos\\+8\\)" 8 } 
} */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(bin_infos\\+8\\)" 8 } } 
*/
+/* { dg-final { scan-assembler-times "\\%base_idx_add\\(bin_infos\\+16\\)" 4 } 
} */
+/* { dg-final { scan-assembler-times "\\%base_idx_lo\\(bin_infos\\+16\\)" 4 } 
} */
+/* { dg-final { scan-assembler-not "addi\t\[a-x0-9\]+,\[a-x0-9\]+,\[0-9\]+" } 
} */
-- 
2.43.0

Reply via email to