Hi LiQin:
Thanks for the patch, few comments from my first scan attached :)
> diff --git a/gcc/ChangeLog b/gcc/ChangeLog
> index 326943d7efa..0853e4323ea 100644
> --- a/gcc/ChangeLog
> +++ b/gcc/ChangeLog
For GCC project, you just need put changelog into git commit message, and then
this file will be auto update later.
> diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
> index 0d16d79df3a..ca337563620 100644
> --- a/gcc/config/riscv/bitmanip.md
> +++ b/gcc/config/riscv/bitmanip.md
> @@ -39,6 +39,19 @@
> [(set_attr "type" "bitmanip")
> (set_attr "mode" "<X:MODE>")])
>
> +(define_insn "base_idx_shxadd<X:MODE>"
Add @ to the pattern name (@base_idx_shxadd<X:MODE>) and then GCC will generate
`gen_base_idx_shxadd(<MODE>, op0, op1, op2, op3, op4)` function
Then you can drop riscv_base_idx_shxadd.
> 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..92149e82772
> --- /dev/null
> +++ b/gcc/config/riscv/riscv-fold-base-idx.cc
> @@ -0,0 +1,583 @@
> +/* fold-base-idx pass for RISC-V.
> + Copyright (C) 2018-2024 Free Software Foundation, Inc.
2026 instead of 2018-2024
> +/*
> +This optimization is mainly to explain the low address of ADDI to the memory
> +offset of ld/st, reducing the low address calculation instructions.
> +1. Without GP relaxation:
> + lui + addi + add/add.uw/shxadd/shxadd.uw + ld/st
> + ----------------Transform---------------------
> + lui + add/add.uw/shxadd/shxadd.uw + ld/st (iff addend == 0)
> +
> + lui + addi + addi + add/add.uw/shxadd/shxadd.uw + ld/st
> + ----------------Transform---------------------
> + 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
> + ----------------Transform---------------------
> + add/add.uw/shxadd/shxadd.uw + ld/st
> +*/
> +
> +namespace {
> +
> +const pass_data pass_data_fold_base_idx = {
> + RTL_PASS, /* type */
> + "fold_gp", /* 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 detectFoldable(rtx_insn *high_insn, rtx_insn *&lo_insn);
> + rtx getMemAddrAndOffset(rtx_insn *mem);
> + // 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 foldGPIntoMemoryOps(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 hasOneUse(rtx_insn *insn, rtx dest, rtx_insn *&use_insn) {
has_one_use
> + 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 137)
> + (high:DI (symbol_ref:DI ("sym"))))
> +(set (reg/f:DI 138)
> + (lo_sum:DI (reg/f:DI 137) (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::detectFoldable(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 (!hasOneUse(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;
> +}
> +
> +rtx pass_fold_base_idx::getMemAddrAndOffset(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;
> +}
> +
> +// we have two cases to update the symbol with new offset:
> +// 1. mem access with offset, we can directly 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 old_sym = XEXP(SET_SRC(PATTERN(hi)), 0);
> + rtx new_sym = NULL_RTX;
> +
> + // if the old symbol is already a plus of symbol with offset, we can
> directly
> + // update the offset of the plus.
> + if (GET_CODE(old_sym) != SYMBOL_REF && GET_CODE(old_sym) == CONST &&
> + GET_CODE(XEXP(old_sym, 0)) == PLUS) {
> + HOST_WIDE_INT old_off = INTVAL(XEXP(XEXP(old_sym, 0), 1));
> + XEXP(XEXP(old_sym, 0), 1) = GEN_INT(old_off + offset);
> + new_sym = old_sym;
> + } else {
> + machine_mode mode = GET_MODE(old_sym);
> + rtx plus = gen_rtx_PLUS(mode, old_sym, GEN_INT(offset));
> + new_sym = gen_rtx_CONST(mode, plus);
> + }
> +
> + // update hi and lo symbol
> + XEXP(SET_SRC(PATTERN(hi)), 0) = new_sym;
> + XEXP(SET_SRC(PATTERN(lo)), 1) = new_sym;
> +}
> +
> +/*
> +mainly deal with access the struct member varival which not the first.
> +Update the sym with mem's addr offset.
> +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 140)))
> +(set (reg/i:DI 10 a0)
> + (zero_extend:DI (mem:QI (plus:DI (reg/f:DI plus_dst) (const_int mem_off
> [0x4])))))
> +
> +------- 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)))))
This example little bit confuse me, where is (reg:DI 140) and (reg/f:DI lo_dst)
after transform? is (reg:DI plus_src1) = (reg:DI 140)?
> +*/
> +void pass_fold_base_idx::merge_mem_offset_into_symbol(rtx_insn *&hi,
> + rtx_insn *&lo,
> + rtx_insn *mem) {
> + rtx mem_addr = getMemAddrAndOffset(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)))
What is remove_addi_src? it's `i`?
> +void pass_fold_base_idx::analyze_and_transform(rtx_insn *hi, rtx_insn *lo,
> + rtx_insn *add, rtx_insn *mem)
> {
> + if (!detectFoldable(hi, lo))
> + return;
> +
> + if (foldGPIntoMemoryOps(lo, add, mem)) {
> + merge_mem_offset_into_symbol(hi, lo, mem);
> + remove_addi_and_merge_addioff(hi, lo, add);
> + targetm.base_idx_sym_emit(hi, lo, add, mem);
we don't need define that in target hook because it's RISC-V specific pass.
> + }
> +}
> +
> +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..9e85e0743c1 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..cd685700e28 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;
> }
>
> @@ -2954,6 +2959,168 @@ static rtx riscv_tls_add_tp_le (rtx dest, rtx base,
> rtx sym)
> return gen_tls_add_tp_lesi (dest, base, tp, sym);
> }
>
> +// Add %base_idx_add reloc for global array non-const addressing optimization
> +
> +// To ensure consistent output across all assembly code,
> +// swap the positions of the two operands of plus.
> +// (plus:DI (reg/f:DI lo_dst) (reg:DI plus_src1)))
> +// ----------- Transform to -----------
> +// (unspec:DI (reg/f:DI plus_src1) (reg:DI hi_dst)))
> +
> +static rtx riscv_base_idx_add(rtx dest, rtx plus_src1, rtx update_addr,
> + rtx sym) {
> + if (Pmode == DImode)
> + return gen_base_idx_adddi(dest, plus_src1, update_addr, sym);
> + else
> + return gen_base_idx_addsi(dest, plus_src1, update_addr, sym);
> +}
> +
> +// (plus:DI (zero_extend:DI (subreg:SI (reg:DI zextend_src) 0)) (reg/f:DI
> +// lo_dst)))
> +// ----------- Transform to -----------
> +// (unspec:DI (zero_extend:DI (zextend_src))) (reg/f:DI hi_dst)))
> +
> +static rtx riscv_base_idx_adduw(rtx dest, rtx zextend_src, rtx update_addr,
> + rtx sym) {
> + return gen_base_idx_adduwDI(dest, zextend_src, update_addr, sym);
> +}
> +
> +// (plus:DI (ashift:DI (reg:DI ashift_src0) (const_int sshift_src1))
> (reg/f:DI
> +// lo_dst))
> +// ----------- Transform to -----------
> +// (unspec:DI (ashift:DI (reg:DI ashift_src0) (const_int sshift_src1))
> (reg/f:DI
> +// hi_dst))
> +
> +static rtx riscv_base_idx_shxadd(rtx dest, rtx ashift, rtx update_addr,
> + rtx sym) {
> + if (Xmode == DImode)
> + return gen_base_idx_shxaddDI(dest, XEXP(ashift, 0), XEXP(ashift, 1),
> + update_addr, sym);
> + else
> + return gen_base_idx_shxaddSI(dest, XEXP(ashift, 0), XEXP(ashift, 1),
> + update_addr, sym);
> +}
> +
> +// (plus:DI (and:DI (ashift:DI (reg:DI ashift_src0) (const_int sshift_src1))
> +// (const_int and_mask))
> +// (reg/f:DI lo_dst))
> +// ----------- Transform to ----------->
> +// (unspec:DI (and:DI (ashift:DI (reg:DI ashift_src0) (const_int
> sshift_src1))
> +// (const_int and_mask))
> +// (reg/f:DI hi_dst))
> +
> +static rtx riscv_base_idx_shxadduw(rtx dest, rtx ashift, rtx and_mask,
> + rtx update_addr, rtx sym) {
> + return gen_base_idx_shxadduwDI(dest, XEXP(ashift, 0), XEXP(ashift, 1),
> + and_mask, update_addr, sym);
> +}
> +
> +// 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) {
> + rtx pattern = PATTERN(mem);
> + if (GET_CODE(pattern) != SET)
> + return;
> +
> + rtx mem_dst = SET_DEST(PATTERN(mem));
> + rtx mem_src = SET_SRC(PATTERN(mem));
> +
> + if (MEM_P(mem_src))
> + XEXP(mem_src, 0) = addr;
> + else if (MEM_P(mem_dst))
> + XEXP(mem_dst, 0) = addr;
> + else if ((GET_CODE(mem_src) == ZERO_EXTEND ||
> + GET_CODE(mem_src) == SIGN_EXTEND) &&
> + MEM_P(XEXP(mem_src, 0)))
> + XEXP(XEXP(mem_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 regrel
> +// relocation type.
> +static void riscv_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 = riscv_base_idx_shxadd(add_dst, add_op0, 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
> + add_with_rel = riscv_base_idx_add(add_dst, add_op1, hi_dst, lo_op1);
> + } else if (TARGET_64BIT && TARGET_ZBA && GET_CODE(add_op0) == AND) {
> + // Replace shxadd.uw dst, src0, hi_dst, %shxadd_regrel to shxadd dst,
> src0,
> + // lo_dst
> + rtx ashift = XEXP(
> + add_op0, 0); // Get ashift from (and:DI (ashift:DI src0 shift) mask)
> + rtx and_mask =
> + XEXP(add_op0, 1); // Get mask from (and:DI (ashift:DI ...) mask)
> + add_with_rel =
> + riscv_base_idx_shxadduw(add_dst, ashift, 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 = riscv_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();
> +}
> +
> /* If MODE is MAX_MACHINE_MODE, ADDR appears as a move operand, otherwise
> it appears in a MEM of that mode. Return true if ADDR is a legitimate
> constant in that context and can be split into high and low parts.
> @@ -7780,6 +7947,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;
> @@ -16611,6 +16782,9 @@ riscv_prefetch_offset_address_p (rtx x, machine_mode
> mode)
> #undef TARGET_NOCE_CONVERSION_PROFITABLE_P
> #define TARGET_NOCE_CONVERSION_PROFITABLE_P
> riscv_noce_conversion_profitable_p
>
> +#undef TARGET_BASE_IDX_SYM_EMIT
> +#define TARGET_BASE_IDX_SYM_EMIT riscv_base_idx_sym_emit
> +
Drop TARGET_BASE_IDX_SYM_EMIT define and move riscv_base_idx_sym_emit
to that pass.
> #undef TARGET_ASM_FILE_START
> #define TARGET_ASM_FILE_START riscv_file_start
> #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index 3fe0ad0ccdf..922f6cdd550 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -49,6 +49,8 @@
> 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 @@
> [(set_attr "type" "arith")
> (set_attr "mode" "HI")])
>
> +(define_insn "base_idx_add<mode>"
Add @ to the name, same trick as base_idx_shxadd can be used here.
> diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
> index 5edddd7f36e..3c1cdf799b7 100644
> --- a/gcc/doc/tm.texi
> +++ b/gcc/doc/tm.texi
> @@ -7471,6 +7471,10 @@ scheduler from undoing address optimizations. The
> instruction containing the
> memref is @var{insn}. The default implementation returns @code{true}.
> @end deftypefn
>
> +@deftypefn {Target Hook} void TARGET_BASE_IDX_SYM_EMIT (rtx_insn *@var{hi},
> rtx_insn *@var{lo}, rtx_insn *@var{add}, rtx_insn *@var{mem})
> +This hook will add new Relocs for global array non-const addressing
> optimization
> +@end deftypefn
> +
Drop this.
> --- a/gcc/doc/tm.texi.in
> +++ b/gcc/doc/tm.texi.in
> @@ -4794,6 +4794,8 @@ Define this macro if a non-short-circuit operation
> produced by
>
> @hook TARGET_NEW_ADDRESS_PROFITABLE_P
>
> +@hook TARGET_BASE_IDX_SYM_EMIT
> +
Drop this.
> @hook TARGET_NO_SPECULATION_IN_DELAY_SLOTS_P
>
> @hook TARGET_ESTIMATED_POLY_VALUE
> diff --git a/gcc/target.def b/gcc/target.def
> index a9fcce7850f..f867504c900 100644
> --- a/gcc/target.def
> +++ b/gcc/target.def
> @@ -4195,6 +4195,12 @@ candidate as a replacement for the if-convertible
> sequence described in\n\
> bool, (rtx_insn *seq, struct noce_if_info *if_info),
> default_noce_conversion_profitable_p)
>
> +DEFHOOK
> +(base_idx_sym_emit,
> + "This hook will add new Relocs for global array non-const addressing
> optimization",
> +void, (rtx_insn *hi, rtx_insn *lo, rtx_insn *add, rtx_insn *mem),
> +default_base_idx_sym_emit)
> +
Drop this.
> /* Return true if new_addr should be preferred over the existing address
> used by
> memref in insn. */
> DEFHOOK
> diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
> index 5f1eac75122..99625ad0f91 100644
> --- a/gcc/targhooks.cc
> +++ b/gcc/targhooks.cc
> @@ -1856,6 +1856,9 @@ default_new_address_profitable_p (rtx memref
> ATTRIBUTE_UNUSED,
> return true;
> }
>
> +void default_base_idx_sym_emit(rtx_insn *, rtx_insn *, rtx_insn *, rtx_insn
> *) {
> +}
> +
Drop this.
> bool
> default_target_option_valid_attribute_p (tree ARG_UNUSED (fndecl),
> tree ARG_UNUSED (name),
> diff --git a/gcc/targhooks.h b/gcc/targhooks.h
> index 9582233e69f..309575caa31 100644
> --- a/gcc/targhooks.h
> +++ b/gcc/targhooks.h
> @@ -196,6 +196,8 @@ extern unsigned int default_hard_regno_nregs (unsigned
> int, machine_mode);
> extern bool default_hard_regno_scratch_ok (unsigned int);
> extern bool default_mode_dependent_address_p (const_rtx, addr_space_t);
> extern bool default_new_address_profitable_p (rtx, rtx_insn *, rtx);
> +extern void default_base_idx_sym_emit(rtx_insn *, rtx_insn *, rtx_insn *,
> + rtx_insn *);
Drop this.
> extern bool default_target_option_valid_attribute_p (tree, tree, tree, int);
> extern bool default_target_option_valid_version_attribute_p (tree, tree,
> tree, int);
> extern bool default_target_option_pragma_parse (tree, tree);