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