On Sat, 15 Feb 2025 08:47:16 PST (-0800), jeffreya...@gmail.com wrote:
On 2/13/25 3:54 PM, Edwin Lu wrote:
The instruction scheduler appears to be speculatively hoisting vsetvl
insns outside of their basic block without checking for data
dependencies. This resulted in a situation where the following occurs
vsetvli a5,a1,e32,m1,tu,ma
vle32.v v2,0(a0)
sub a1,a1,a5 <-- a1 potentially set to 0
sh2add a0,a5,a0
vfmacc.vv v1,v2,v2
vsetvli a5,a1,e32,m1,tu,ma <-- incompatible vinfo. update vl to 0
beq a1,zero,.L12 <-- check if avl is 0
This patch would essentially delay the vsetvl update to after the branch
to prevent unnecessarily updating the vinfo at the end of a basic block.
Since this is purely a performance related patch, gate the target hook
with an opt flag to see the fallout.
PR 117974
gcc/ChangeLog:
* config/riscv/riscv.cc (riscv_sched_can_speculate_insn):
(TARGET_SCHED_CAN_SPECULATE_INSN): Implement.
* config/riscv/riscv.opt: Add temporary opt.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/rvv/vsetvl/pr117974.c: New test.
I was kind of thinking we'd have a flag in the tuning structure so that
each uarch could make a reasonable default selection rather than having
it controlled by a flag.
Ya, seems reasonable. We wanted the flag to make it easier to do some
expirements -- otherwise we'd need either two builds or an
expirement-specific tune struct, and our perf guys aren't so great with
SW so the flag is just easier.
I realize there may not be any designs upstream which would set this
right now, but it puts the right infrastructure in place. Very similar
to the divmod expansion stuff from a while back.
I'm fine either way. It's always kind of tough to tell what the right
answer is on these things: we're taking complexity without a strong
justification, but if it's an ISA corner case then it's not crazy to
assume some HW will trip over it at some point. This one is so small I
don't think it really matters which way we go, but if someone else is
interested in using it that'd probably tip things towards getting it
upstream on my end.
FWIW: This is just in the idea stage right now so it's no big deal if we
don't merge it, it's both pretty easy to keep locally and of unknown
utility (even internally). We've got to go look at the generated code
either way and we'll post what we can publicly.
Edwin and I were also talking in the office yesterday and I think we can
do a slightly better job here if we use the runqueue sorting hook. At
that point we can actually look at the instructions and see if the
branch will avoid a VL=0 case before preventing the hoisting, so we can
avoid introducing unnecessary latency.
I put together some code that did what's in here via that sorting hook,
but my attempts at matching more specific subtrees failed so I sent it
to Edwin to try and figure out what I screwed up. It's probably
something easy, I always screw that stuff up until I get it right.
So assuming that works we'll have another flavor of this to post.
Q. Does Rivos have a cpu defined in your internal tree? We do that for
ours as keep it as a local change for now. Assuming you do, then adding
the bits to the tuning structure should make it trivial to make this
behavior the default on your design internally.
We've got internal tune structs. They're super easy to keep around and
we'll likely always need them for internal stuff, so no big deal on that
end.