On 7/7/2026 2:20 AM, wangjue wrote:
From: juewang <[email protected]>
This patch introduces a conservative loop unrolling heuristic for the
RISC-V backend, controlled by the new -munroll-only-small-loops option.
When -munroll-only-small-loops is active, only small loops (those whose
body does not exceed a per-tune instruction threshold) are unrolled, and
the unroll factor is capped by a per-tune parameter, so that tight loops
benefit from unrolling without exposing larger loops to its code-size and
instruction-cache costs.
Mirroring the i386 model, -funroll-loops and -munroll-only-small-loops are
enabled by default at -O2 and above (for speed). An explicit -funroll-loops
(or -funroll-all-loops) turns -munroll-only-small-loops off, so a user who
explicitly asks for unrolling still gets loops of any size unrolled. The
size threshold and the maximum unroll factor come from the -mtune tuning
parameters.
Since -funroll-loops is now enabled by default at -O2 and above, a number
of pre-existing RISC-V tests that scan for a specific code sequence change
their output once loops are unrolled. As those tests do not aim to exercise
unrolling, add -fno-unroll-loops to their options so they keep validating
their intended property regardless of the unrolling decision.
gcc/ChangeLog:
* common/config/riscv/riscv-common.cc (riscv_option_optimization_table):
Enable -funroll-loops and -munroll-only-small-loops at -O2 and above.
* config/riscv/riscv.cc (struct riscv_tune_param): Add fields
small_loop_unroll_ninsns and small_loop_unroll_factor.
(xt_c9501_tune_info): Set them.
(riscv_loop_unroll_adjust): New function.
(riscv_option_override): Turn off -munroll-only-small-loops when
-funroll-loops or -funroll-all-loops is explicitly given.
(TARGET_LOOP_UNROLL_ADJUST): Define.
* config/riscv/riscv.opt (munroll-only-small-loops): New option.
* config/riscv/riscv.opt.urls: Regenerate.
* doc/invoke.texi (RISC-V Options): Document -munroll-only-small-loops.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/unroll-explicit.c: New test.
* gcc.target/riscv/unroll-large-loop.c: New test.
* gcc.target/riscv/unroll-pragma.c: New test.
* gcc.target/riscv/unroll-small-loop-tune.c: New test.
* gcc.target/riscv/unroll-small-loop.c: New test.
* g++.dg/tree-prof/pr57451.C: Add -fno-unroll-loops.
* g++.target/riscv/pr97682.C: Likewise.
* gcc.dg/tree-ssa/pr117973-1.c: Likewise.
* gcc.dg/vect/vect-alias-check-4.c: Likewise.
* gcc.target/riscv/pr67731.c: Likewise.
* gcc.target/riscv/rvv/autovec/pr113206-1.c: Likewise.
* gcc.target/riscv/rvv/autovec/unop/math-nearbyint-0.c: Likewise.
* gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-1u.c: Likewise.
* gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-2u.c: Likewise.
* gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-3u.c: Likewise.
* gcc.target/riscv/rvv/autovec/vls-vlmax/vec_extract-4u.c: Likewise.
* gcc.target/riscv/rvv/autovec/vls/calling-convention-1.c: Likewise.
* gcc.target/riscv/rvv/autovec/vls/calling-convention-2.c: Likewise.
* gcc.target/riscv/rvv/autovec/vls/calling-convention-3.c: Likewise.
* gcc.target/riscv/rvv/autovec/vls/calling-convention-4.c: Likewise.
* gcc.target/riscv/rvv/autovec/vls/calling-convention-5.c: Likewise.
* gcc.target/riscv/rvv/autovec/vls/calling-convention-6.c: Likewise.
* gcc.target/riscv/rvv/autovec/vls/calling-convention-7.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-frm-insert-4.c: Likewise.
* gcc.target/riscv/rvv/base/float-point-frm-insert-5.c: Likewise.
* gcc.target/riscv/rvv/base/pr114352-3.c: Likewise.
* gcc.target/riscv/rvv/base/scalar_move-7.c: Likewise.
* gcc.target/riscv/rvv/base/spill-10.c: Likewise.
* gcc.target/riscv/rvv/base/spill-11.c: Likewise.
* gcc.target/riscv/rvv/base/spill-12.c: Likewise.
* gcc.target/riscv/rvv/base/spill-8.c: Likewise.
* gcc.target/riscv/rvv/base/spill-9.c: Likewise.
* gcc.target/riscv/rvv/base/vwaddsub-1.c: Likewise.
* gcc.target/riscv/rvv/base/zvbb_vandn_vx_constraint.c: Likewise.
* gcc.target/riscv/rvv/base/zvbc_vx_constraint-2.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/avl_multiple-3.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/avl_multiple-4.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/avl_single-4.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/avl_single-6.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/avl_single-66.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/imm_loop_invariant-1.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/imm_loop_invariant-2.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/imm_loop_invariant-3.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/imm_loop_invariant-4.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/imm_loop_invariant-5.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/imm_loop_invariant-6.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-1.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-10.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-14.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-15.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-16.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-17.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-18.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-19.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-20.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-21.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-22.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-23.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-25.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-27.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-28.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-29.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-3.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-30.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-31.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-35.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-37.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-7.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-8.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-9.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-17.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-18.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-19.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_bb_prop-20.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_conflict-11.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-14.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-15.c: Likewise.
* gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-16.c: Likewise.
* gcc.target/riscv/slt-1.c: Likewise.
* gcc.target/riscv/struct_vect_24.c: Likewise.
Note this is causing vrp91.c to regress on rv64.
It looks like we unroll that loop (which looks like a CRC at first
glance). With no loop we no longer have a loop induction variable which
is what we were checking the discovered range on.
What doesn't make sense to me is if x86, power and s390 have the same
basic code in place to unroll small loops, why are they not failing?
While we can add an rv64 optimization adjustment to this test, I'd like
to understand why risc-v is behaving differently first.
Jeff