On Mon, 20 Jul 2026, Richard Biener wrote:
> On Fri, 17 Jul 2026, Jeffrey Law wrote:
>
> >
> >
> > On 5/19/2026 6:14 AM, Robin Dapp wrote:
> > > Hi,
> > >
> > > I have been playing around with a vec_predicate RTX locally, moving parts
> > > of
> > > the RVV backend over to it. Its main purpose is to lay out common
> > > operands
> > > in
> > > a fixed order. This helps rtl passes to reason about the predicate as a
> > > whole,
> > > as well as backends which needed to carry index information if they wanted
> > > to
> > > access particular fields.
> > And just to be clear, the ability to find the predicate and interpret is a
> > huge part of the motivation here.
> >
> > >
> > > The staging I have in mind is roughly, each at least one patch:
> > >
> > > (1) Add basic vec_predicate plumbing for non-"move" insns.
> > > (2) Handle vec_predicate in simplify-rtx to allow canonicalization,
> > > merging,
> > > and elision.
> > > (3) Convert a self-contained subset of RVV instructions to the new
> > > format.
> > >
> > > A vec_predicate would look like this:
> > >
> > > (define_insn "pred_add"
> > > [(set (match_operand:V 0 "register_operand" "=vd")
> > > (vec_predicate:V plus
> > > [(match_operand:V 3 "register_operand" " v")
> > > (match_operand:V 4 "register_operand" " v")]
>
> So there's not actually the predicated RTL operation, but just
> the code and a vector of ... operands? I'd have expected either
>
> (vec_predicate
> (plus:<mode> (...) (...))
>
> or
>
> (cond_plus:<mode>
> (vec_predicate
> ...)
> (...) (...))
>
> where the latter is probably "safer" combine/split wise. The latter
> would mimic .COND_* ifns on GIMPLE, but of course we'd explode the
> RTX code somewhat unless we maybe stage it like
>
> (cond_op:<mode> PLUS
> (vec_predicate ...)
> (...) (...))
>
> and that's where you come from? Having (vec_predicate ..) as
> nested RTX would allow that to be compile-time shortened for
> targets that do not need all of the below ...
>
> > > (match_operand:V 2 "else_operand" " velse")
> > > (match_operand:<VM> 1 "mask_operand" " vm")
> > > (match_operand 5 "vector_length_operand" " vl")
> > > (const_int 0) # Bias
> > > (match_operand 6 "const_int_operand" " i") # Length else
> > > policy
> > > (match_operand 7 "const_int_operand" " i")))]) # Mask else
> > > policy
> > So at a high level this seems to broadly match what the RISC-V backend is
> > doing. That shouldn't be a big surprise to anyone.
>
> ... like x86 can do with mask_operand and else_operand.
Oh, and this might extend to loads and stores - at least the
(vec_predicate ..) part can be re-usable, even if
(cond_set:<mode>
(vec_predicate ...)
(mem:..) (<set-rhs>))
and
(cond_set:<mode>
(vec_predicate ...)
(<set-lhs>) (mem:...))
do not work out - we'd have to guard the (mem:..) part from being split
out based on the toplevel insn, but we already need to do this for
(cond_exec ..), so nothing new there?
> > >
> > > As AVX and SVE don't need operands 5-7, and most autovec patterns might
> > > not
> > > even need the else/mask, I added default-fill parsing in read-rtl: If a
> > > vec_predicate ends prematurely, the remaining operands are filled with
> > > "autovec" defaults like zero-fill policies, no bias, full length, etc.
> > > One issue with default filling is the mode of else and mask. I hope that
> > > can work if we use dedicated sentinels like VEC_UNDEF and VEC_ALL_TRUE
> > > (which target predicates would need to allow)?
> > I think as long as we can avoid the need for the other architectures to
> > worry
> > about this stuff with any kind of regularity, then we're going to be in good
> > shape. Obviously the RTL optimizers will need awareness, but the target
> > files
> > shouldn't. If that means we need a few well known sentinels, that's OK by
> > me.
> >
> > >
> > > What's not yet covered but should be in the future:
> > >
> > > - Predicated vector "copy" insns (register copy, load, store).
> > > During initial brainstorming we couldn't come up with a good way to
> > > represent predicated vector stores.
> > > What could perhaps work is something like
> > > [(set (reg:V) (vec_predicate:V vec_copy [reg:V] ...))]
> > > and
> > > [(set (reg:V) (vec_predicate:V vec_copy [mem:V] ...))]
> > > [(set (mem:V) (vec_predicate:V vec_copy [reg:V] ...))]
> > > where the mem attributes could still be stored in dest or src.
> > > This obviously would not inherit any regular "move" handling we have.
> > > I'm not sure this is a good thing :) But at least it would be a clear
> > > cut.
> > I can probably live with moves being special. Exposing the predicates on
> > the
> > operations seems like the big gain to me, even if we have a few stragglers
> > like moves.
> >
> > >
> > > Once we have predicated loads, the question of vectorizer interaction
> > > needs
> > > to
> > > come up, which brings us to another work or staging item:
> > >
> > > (4?) Add handling for the new shape to ifn and optabs. So far, I
> > > couldn't
> > > think of a nicer way of identifying "vec_predicate"-style
> > > optabs/insns
> > > than adding a field to idata and have it be populated by genoutput
> > > and
> > > friends. Then, we could do something like
> > > bool
> > > insn_has_vec_predicate (enum insn_code icode)
> > > {
> > > return insn_data[icode].vec_predicate_opno >= 0;
> > > }
> > Seems basically reasonable and it allows you to trivially gate all kinds of
> > behavior that most targets aren't going to need.
> >
> > >
> > > gcc/ChangeLog:
> > >
> > > * cse.cc (hash_rtx): Hash predicate code.
> > > (exp_equiv_p): Return false for unequal code.
> > > * cselib.cc (rtx_equal_for_cselib_1): Ditto.
> > > (cselib_hash_rtx): Add predicate code to hash.
> > > * doc/rtl.texi: Document vector predicate.
> > > * dwarf2out.cc (mem_loc_descriptor): Break for vec_predicate.
> > > * emit-rtl.cc (init_emit_once): Init vec_all_true and vec_undef.
> > > (rtx_expander::get_rtx): Set vec_predicate code.
> > > (gen_vec_predicate): New function to generate a default
> > > vector predicate.
> > > (verify_vec_predicate): Verify vector predicate.
> > > * genemit.cc (generator::add_exp): Encode vec_predicate code.
> > > * genrecog.cc (rtx_test::vec_pred_code_field): Add.
> > > (safe_to_hoist_p): Ditto.
> > > (transition_parameter_type): Ditto.
> > > (match_pattern_2): Ditto.
> > > (print_nonbool_test): Print vec_predicate.
> > > (print_test): Handle vec_predicate.
> > > * print-rtl.cc (rtx_writer::print_rtx): Ditto.
> > > * read-rtl.cc (apply_code_iterator): Ditto.
> > > (rtx_reader::read_rtx_code): Ditto.
> > > * rtl.cc (DEF_RTL_EXPR): Declare vec_all_true and vec_undef.
> > > (rtx_equal_p): Compare vec_predicate code.
> > > * rtl.def (VEC_ALL_TRUE): Declare.
> > > (VEC_UNDEF): Ditto.
> > > (VEC_PREDICATE): Declare.
> > > * rtl.h (struct GTY): Add vec_pred_code.
> > > (VEC_PRED_CODE): Add.
> > > (PUT_VEC_PRED_CODE): Add.
> > > (VEC_PRED_OPERANDS): Add.
> > > (VEC_PRED_NOPERANDS): Add.
> > > (VEC_PRED_OPERAND): Add.
> > > (VEC_PRED_ELSE): Add.
> > > (VEC_PRED_MASK): Add.
> > > (VEC_PRED_LENGTH): Add.
> > > (VEC_PRED_BIAS): Add.
> > > (VEC_PRED_TAIL_POLICY): Add.
> > > (VEC_PRED_MASK_POLICY): Add.
> > > (VEC_PRED_FIRST_OPTIONAL): Add.
> > > (VEC_PRED_UNDEF_ELSE_P): Add.
> > > (VEC_PRED_FULL_LEN): Add.
> > > (VEC_PRED_ALL_TRUE_P): Add.
> > > (enum vec_pred_policy): Add.
> > > (VEC_PRED_POLICY_MAX): Add.
> > > (VEC_PRED_POLICY_VALID_P): Add.
> > > (VEC_PRED_POLICY_PRESERVE_P): Add.
> > > (gen_vec_predicate): Declare.
> > > (verify_vec_predicate): Declare.
> > > (GTY): Declare vec_all_true and vec_undefined.
> > > ---
> > > gcc/cse.cc | 9 +++++
> > > gcc/cselib.cc | 9 +++++
> > > gcc/doc/rtl.texi | 91 ++++++++++++++++++++++++++++++++++++++++++++++++
> > > gcc/dwarf2out.cc | 1 +
> > > gcc/emit-rtl.cc | 69 ++++++++++++++++++++++++++++++++++++
> > > gcc/genemit.cc | 4 +++
> > > gcc/genrecog.cc | 25 +++++++++++++
> > > gcc/print-rtl.cc | 3 ++
> > > gcc/read-rtl.cc | 72 ++++++++++++++++++++++++++++++++++++--
> > > gcc/rtl.cc | 11 ++++++
> > > gcc/rtl.def | 18 ++++++++++
> > > gcc/rtl.h | 55 +++++++++++++++++++++++++++++
> > > 12 files changed, 365 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/gcc/cse.cc b/gcc/cse.cc
> > > index b4b39e3ebf8..ee4e8b86f1c 100644
> > > --- a/gcc/cse.cc
> > > +++ b/gcc/cse.cc
> > > @@ -2494,6 +2494,10 @@ hash_rtx (const_rtx x, machine_mode mode,
> > > }
> > > break;
> > > + case VEC_PREDICATE:
> > > + hash += (unsigned) VEC_PRED_CODE (x);
> > > + break;
> > > +
> > > default:
> > > break;
> > [ ... ]
> > I wouldn't be surprised if there's more plumbing of this nature needed. I
> > guess perhaps the question to ask is are you looking for this kind of thing
> > systematically or by throwing code into the compiler and seeing what trips?
> > I
> > would think you'd want to include the relevant fields in the hash? Of
> > course
> > if all this is handled via a recursive step, then it's a non-issue :-)
> >
> > > }
> > > @@ -2623,6 +2627,11 @@ exp_equiv_p (const_rtx x, const_rtx y, int
> > > validate,
> > > @@ bool for_gcse)
> > > return false;
> > > break;
> > > + case VEC_PREDICATE:
> > > + if (VEC_PRED_CODE (x) != VEC_PRED_CODE (y))
> > > + return false;
> > > + break;
> > Similar to the hashing question above, the only difference is this is
> > correctness rather than just potentially having a poor hash.
> >
> > >
> > >
> > > diff --git a/gcc/rtl.h b/gcc/rtl.h
> > > index d60587dc5ce..4adbc2cb59e 100644
> > > --- a/gcc/rtl.h
> > > +++ b/gcc/rtl.h
> > > @@ -438,6 +438,9 @@ struct GTY((desc("0"), tag("0"),
> > > /* For future expansion. */
> > > unsigned int unused : 8;
> > > } const_vector;
> > > +
> > > + /* The code of a VEC_PREDICATE. */
> > > + unsigned int vec_pred_code;
> > > } GTY ((skip)) u2;
> > It doesn't look like this is going to increase the size of an RTX as this is
> > just another variant in a union. Phew!
> >
> > Overall it's nowhere near as complex as I expected. Obviously I worry about
> > missed paths, but at some level we're going to be the guinea pig here, so if
> > we'll be the ones to stumble over this stuff and need to fix it. I would
> > probably not suggest other targets jump on the bandwagon until we've got
> > confidence that it's working well for RISC-V.
> >
> > I'd love to hear Richard S's thoughts on the gen* bits, but they generally
> > looked sensible to me.
> >
> > You mentioned that you've confirmed we can drop some of the vector patterns
> > for RISC-V with your changes. That's definitely a good sign. If autovec.md
> > turned into just moves, I'd jump for joy...
> >
> > jeff
> >
>
>
--
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Jochen Jaser, Andrew McDonald, Abhinav Puri; (HRB 36809, AG Nuernberg)