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);

Reply via email to