https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115795
Bug ID: 115795 Summary: RISC-V: vsetvl step causes wrong codegen after fusing info Product: gcc Version: 15.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: target Assignee: unassigned at gcc dot gnu.org Reporter: jordi.sala at semidynamics dot com Target Milestone: --- godbolt: https://godbolt.org/z/9Mf5caEzW compile option: -march=rv64gv -O1 testcase: #include <riscv_vector.h> void foo(int * from, int * to, size_t size) { size_t vl = __riscv_vsetvl_e32m8(size); vint32m8_t val = __riscv_vle32_v_i32m8(from, vl); __riscv_vse32_v_i32m8(to, val, vl); } resulting assembly: foo: vsetvli a2,a2,e8,m2,ta,ma vle32.v v8,0(a0) vse32.v v8,0(a1) ret LMUL and SEW of vset vli are not matching the one specified by the intrinsic __riscv_vle32_v_i32m8. This issue started happening after gcc 14.1.0 After some investigation I've seen that the vsetvl rtl step is fusing a vsetvl e8,m2 with a vsetvl e32,m8 Logs from vsetvl step ... Try fuse basic block 2 Ignore curr info since prev info available with it: prev_info: VALID (insn 29, bb 2) Demand fields: demand_ratio_only demand_avl SEW=8, VLMUL=m2, RATIO=4, MAX_SEW=64 TAIL_POLICY=agnostic, MASK_POLICY=agnostic AVL=(reg:DI 12 a2 [141]) VL=(reg/v:DI 12 a2 [orig:134 vlD.129141 ] [134]) curr_info: VALID (insn 12, bb 2) Demand fields: demand_ratio_only demand_avl SEW=32, VLMUL=m8, RATIO=4, MAX_SEW=64 TAIL_POLICY=agnostic, MASK_POLICY=agnostic AVL=(reg/v:DI 12 a2 [orig:134 vlD.129141 ] [134]) VL=(nil) ... Fused global info result (lift 0): Forbidden lift up vsetvl info into bb 0 since there is no vsetvl info that reaching in is compatible with it:VALID (insn 29, bb 2) Demand fields: demand_ratio_only demand_avl SEW=8, VLMUL=m2, RATIO=4, MAX_SEW=64 TAIL_POLICY=agnostic, MASK_POLICY=agnostic AVL=(reg:DI 12 a2 [141]) VL=(reg/v:DI 12 a2 [orig:134 vlD.129141 ] [134]) curr_info only demands avl and ratio which is shared with prev_info thus it only uses prev_info for that bb, losing the SEW and LMUL information of the __riscv_vle32_v_i32m8 intrinsic. with this bb info it generates the wrong vsetvli. after applying the following patch --- a/gcc/config/riscv/riscv-vsetvl.cc +++ b/gcc/config/riscv/riscv-vsetvl.cc @@ -1089,23 +1089,17 @@ public: dflags |= demand_flags::DEMAND_AVL_P; } - if (get_attr_ratio (insn->rtl ()) != INVALID_ATTRIBUTE) - dflags |= demand_flags::DEMAND_RATIO_P; - else - { - if (scalar_move_insn_p (insn->rtl ()) && m_ta) - { - dflags |= demand_flags::DEMAND_GE_SEW_P; - m_max_sew = get_attr_type (insn->rtl ()) == TYPE_VFMOVFV + if (scalar_move_insn_p (insn->rtl ()) && m_ta) + { + dflags |= demand_flags::DEMAND_GE_SEW_P; + m_max_sew = get_attr_type (insn->rtl ()) == TYPE_VFMOVFV ? get_max_float_sew () : get_max_int_sew (); - } - else - dflags |= demand_flags::DEMAND_SEW_P; - - if (!ignore_vlmul_insn_p (insn->rtl ())) - dflags |= demand_flags::DEMAND_LMUL_P; - } + } + else + dflags |= demand_flags::DEMAND_SEW_P; it removes the demand_ratio from non config vector instructions and instead demands on LMUL and/or SEW, I get the following resulting assembly: foo: vsetvli zero,a2,e32,m8,ta,ma # now using right SEW & LMUL vle32.v v8,0(a0) vse32.v v8,0(a1) ret Logs from vsetvl step ... Try fuse basic block 2 Fuse curr info since prev info compatible with it: prev_info: VALID (insn 27, bb 2) Demand fields: demand_ratio_only demand_avl SEW=8, VLMUL=m2, RATIO=4, MAX_SEW=64 TAIL_POLICY=agnostic, MASK_POLICY=agnostic AVL=(reg:DI 12 a2 [141]) VL=(reg/v:DI 12 a2 [orig:134 vlD.129134 ] [134]) curr_info: VALID (insn 9, bb 2) Demand fields: demand_sew_lmul demand_avl SEW=32, VLMUL=m8, RATIO=4, MAX_SEW=64 TAIL_POLICY=agnostic, MASK_POLICY=agnostic AVL=(reg/v:DI 12 a2 [orig:134 vlD.129134 ] [134]) VL=(nil) prev_info after fused: VALID (insn 27, bb 2) Demand fields: demand_sew_lmul demand_avl SEW=32, VLMUL=m8, RATIO=4, MAX_SEW=64 TAIL_POLICY=agnostic, MASK_POLICY=agnostic AVL=(reg:DI 12 a2 [141]) VL=(reg/v:DI 12 a2 [orig:134 vlD.129134 ] [134]) ... Fused global info result (lift 0): Forbidden lift up vsetvl info into bb 0 since there is no vsetvl info that reaching in is compatible with it:VALID (insn 27, bb 2) Demand fields: demand_sew_lmul demand_avl SEW=32, VLMUL=m8, RATIO=4, MAX_SEW=64 TAIL_POLICY=agnostic, MASK_POLICY=agnostic AVL=(reg:DI 12 a2 [141]) VL=(reg/v:DI 12 a2 [orig:134 vlD.129134 ] [134]) Now the bb information seems to be all right Problem is that after this change and doing contrib/compare_tests I get the following: Tests that now fail, but worked before (1043 tests): gcc: gcc.dg/vect/costmodel/riscv/rvv/pr111317.c scan-assembler-times vsetvli 1 gcc: gcc.dg/vect/costmodel/riscv/rvv/pr111317.c scan-assembler-times vsetvli\\s+[a-x0-9]+,\\s*[a-x0-9]+,\\s*e16,\\s*m1,\\s*t[au],\\s*m[au] 1 gcc: gcc.target/riscv/rvv/autovec/partial/slp-1.c scan-assembler \\tvand gcc: gcc.target/riscv/rvv/autovec/partial/slp-1.c scan-assembler \\tvand ... I'm assuming more things need to be changed but let me know if you guys think this is a vsetvl pass bug or not