https://gcc.gnu.org/g:c0b97b859d18b56faaa3d55a617fe784185aa3e1
commit r17-1445-gc0b97b859d18b56faaa3d55a617fe784185aa3e1 Author: Monk Chiang <[email protected]> Date: Tue Jun 9 06:51:43 2026 -0600 [PATCH v2] RISC-V: Add load-to-address bypass for SiFive-7 series The SiFive-7 series processors have a dual-pipeline architecture with load latency of 3 cycles. However, when a load instruction produces an address register that is used immediately by a subsequent load or store with zero offset, the address can be forwarded after 2 cycles instead of 3. This reduces pipeline stalls for common address calculation patterns like: ld a0, 0(a1) # Load pointer, 3-cycle latency ld a2, 0(a0) # Use as address with zero offset, bypass to 2 cycles Changes in v2: - Fix sifive-7-load-address-bypass test for rv32 targets. gcc/ * config/riscv/riscv-protos.h (riscv_zero_offset_address_bypass_p): New function. * config/riscv/riscv.cc (riscv_zero_offset_address_bypass_p): New function. * config/riscv/sifive-7.md: Add bypass definition. gcc/testsuite/ * gcc.target/riscv/sifive-7-load-address-bypass.c: New test. Co-authored-by: "Jim Wilson <[email protected]> Diff: --- gcc/config/riscv/riscv-protos.h | 1 + gcc/config/riscv/riscv.cc | 39 ++++++++++++++++++++++ gcc/config/riscv/sifive-7.md | 3 ++ .../riscv/sifive-7-load-address-bypass.c | 23 +++++++++++++ 4 files changed, 66 insertions(+) diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index b0d73f641e1a..39cef8617487 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -185,6 +185,7 @@ extern void riscv_split_sum_of_two_s12 (HOST_WIDE_INT, HOST_WIDE_INT *, extern bool riscv_vector_float_type_p (const_tree type); extern void expand_crc_using_clmul (scalar_mode, scalar_mode, rtx *); extern void expand_reversed_crc_using_clmul (scalar_mode, scalar_mode, rtx *); +extern bool riscv_zero_offset_address_bypass_p (rtx_insn *, rtx_insn *); /* Routines implemented in riscv-c.cc. */ void riscv_cpu_cpp_builtins (cpp_reader *); diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index e70df9530d94..ab50549d4e0b 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -11043,6 +11043,45 @@ arcv_mpy_10c_bypass_p (rtx_insn *out_insn ATTRIBUTE_UNUSED, return arcv_mpy_option == ARCV_MPY_OPTION_10C; } +/* Return true if OUT_INSN produces a register value that is used as an + address in IN_INSN, and the address has a zero immediate offset. */ + +bool +riscv_zero_offset_address_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn) +{ + rtx out_set, in_set; + rtx out_reg; + rtx in_mem, in_addr; + + out_set = single_set (out_insn); + if (!out_set) + return false; + out_reg = SET_DEST (out_set); + if (GET_CODE (out_reg) == SUBREG) + out_reg = SUBREG_REG (out_reg); + if (GET_CODE (out_reg) != REG) + return false; + + in_set = single_set (in_insn); + if (!in_set) + return false; + in_mem = SET_SRC (in_set); + if (GET_CODE (in_mem) != MEM) + { + in_mem = SET_DEST (in_set); + if (GET_CODE (in_mem) != MEM) + return false; + } + + in_addr = XEXP (in_mem, 0); + if (GET_CODE (in_addr) == SUBREG) + in_addr = SUBREG_REG (in_addr); + if (GET_CODE (in_addr) != REG) + return false; + + return REGNO (out_reg) == REGNO (in_addr); +} + /* Implement TARGET_SECONDARY_MEMORY_NEEDED. When floating-point registers are wider than integer ones, moves between diff --git a/gcc/config/riscv/sifive-7.md b/gcc/config/riscv/sifive-7.md index 8db388901a00..cca54c6708fd 100644 --- a/gcc/config/riscv/sifive-7.md +++ b/gcc/config/riscv/sifive-7.md @@ -162,6 +162,9 @@ (define_bypass 1 "sifive_7_load,sifive_7_alu,sifive_7_mul,sifive_7_f2i,sifive_7_sfb_alu" "sifive_7_store" "riscv_store_data_bypass_p") +(define_bypass 2 "sifive_7_load" + "sifive_7_load,sifive_7_store" "riscv_zero_offset_address_bypass_p") + (define_bypass 2 "sifive_7_i2f" "sifive_7_sfma,sifive_7_dfma,sifive_7_fp_other,sifive_7_fdiv_h,sifive_7_fdiv_s,sifive_7_fdiv_d,sifive_7_hfma") diff --git a/gcc/testsuite/gcc.target/riscv/sifive-7-load-address-bypass.c b/gcc/testsuite/gcc.target/riscv/sifive-7-load-address-bypass.c new file mode 100644 index 000000000000..416ac4d56832 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/sifive-7-load-address-bypass.c @@ -0,0 +1,23 @@ +/* Test SiFive-7 load-to-address bypass optimization. */ + +/* { dg-do compile } */ +/* { dg-options "-mtune=sifive-7-series" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Os" "-Oz" "-Og" "-flto" } } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +struct node { + int value; + struct node *next; +}; + +/* +**load_value: +** l[wd] [at][0-9],0\(a0\) +** lw a0,0\([at][0-9]\) +** ret +*/ +int load_value(struct node **ptr) +{ + struct node *p = *ptr; + return p->value; +}
