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)

Reply via email to