On Thu, Jun 25, 2026 at 5:52 PM Christopher Bazley <[email protected]> wrote:
>
> Hi Richard,
>
> On 24/06/2026 14:39, Richard Biener wrote:
> > On Wed, Jun 24, 2026 at 2:11 PM Richard Sandiford
> > <[email protected]> wrote:
> >>
> >> Richard Biener <[email protected]> writes:
> >>>> Not sure whether this is how you understood it, but when I said:
> >>>>
> >>>> The only valid situations seem to be:
> >>>>
> >>>> (1) a duplicate of a single zero, where:
> >>>>
> >>>> npatterns == nelts_per_pattern == encoded_nelts == 1
> >>>>
> >>>> and the only encoded value is zero
> >>>>
> >>>> (2) the combination of:
> >>>>
> >>>> - nelts_per_pattern == 2
> >>>> - multiple_p (TYPE_VECTOR_SUBPARTS (type), npatterns)
> >>>> - the second half of the encoded elements are all zeros
> >>>>
> >>>> I meant that those conditions seemed to be the ones that your code would
> >>>> need to follow in order to fill VLA vectors with zeros. Those conditions
> >>>> certainly don't apply to all gimple_build_vector callers.
> >>>>
> >>>> So to be correct, the original patch would need to add an assert to
> >>>> gimple_build_vector that checks the above conditions before using
> >>>> constant_lower_bound. Like you say above, without the assert:
> >>>>
> >>>> { 1, x } nelts_per_pattern == 1, npatterns == 2
> >>>>
> >>>> would incorrectly give:
> >>>>
> >>>> { 1, x, 0, 0, 0, 0, ... }
> >>>>
> >>>> whereas it should instead be:
> >>>>
> >>>> { 1, x, 1, x, 1, x, ... }
> >>>>
> >>>> The current VLS CONSTRUCTOR path is supposedly correct because it
> >>>> explicitly initialises every element of the vector (i.e. it does not
> >>>> rely on zero padding of the constructor).
> >>>>
> >>>> My argument was that (1) or (2) above would not come about by chance.
> >>>> The caller would have to do something explicit to ensure that (2) is
> >>>> true.
> >>>> And if (1) or (2) is true, there is no need to for the
> >>>> tree_vector_builder.
> >>>> An array of the leading nonzero elements would be good enough, and would
> >>>> be simpler to build.
> >>>>
> >>>> That's why I thought that a different interface from the
> >>>> tree_vector_builder
> >>>> version would be better than adding a complicated assert to the existing
> >>>> function.
> >>>
> >>> My argument is that the current API can cover the new use just fine and
> >>> we should avoid introducing new APIs for a single use which could then
> >>> well just build a properly constrained CTOR directly. As we've
> >>> legitimized
> >>> the zero-padded VLA typed CTOR variant it is IMHO sensible to have
> >>> gimple_build_vector support that case.
> >>>
> >>> Did I say we have too many APIs already?
> >>
> >> Many APIs start out as single use though.
> >>
> >> The reason for having two APIs in this case is that ctors and vector
> >> constants have different representations. The current API matches
> >> the vector constant representation and the new one would match the
> >> ctor representation.
> >>
> >> But maybe the two representations are the real issue, and that ctors
> >> should have the same representation as constants and be built in the
> >> same way as constants (although that might be significantly more awkward
> >> for users).
>
> I think the real issue is that tree_vector_builder isn't the most
> suitable representation for every interface. It is more expressive than
> most callers need. Expressivity is not always a good thing.
>
> Just because any infinite-length sequence of elements (including one
> ending in an infinite number of zeros) can be encoded as a
> tree_vector_builder, it does not follow that tree_vector_builder is
> always the appropriate choice. For example, consider the fact that
> duplicate_and_interleave is always called with a tree_vector_builder,
> but that tree_vector_builder is in fact treated as a const vec<tree>
> because of subtype polymorphism (thereby quietly losing its shape).
>
> I don't see why duplicate_and_interleave should be permitted to consume
> a vec<tree> but equivalent functions on alternative paths should not.
> From the point of view of clarity and simplicity, it seems better to me
> that data never has a shape in the first place, instead of having a
> shape that is either discarded or not properly honoured.
>
> There seem to be only two call sites at which representing the input to
> gimple_build_vector as a tree_vector_builder is actually necessary (in
> get_initial_defs_for_reduction and vect_create_constant_vectors); in
> every other case, a repeating sequence is not needed. Such a sequence
> would be accidental if it ever occurred, and permitting it
> introduces tricky and irrelevant failure modes
> (three-element-per-pattern encodings not supported at all,
> two-element-per-pattern encodings only supported for VLA types if every
> second element is zero).
>
> To me, the choice to deny the majority of callers a simpler interface
> that is better aligned with their needs seems to me to impose
> unnecessary complexity.
>
> >>>> It's also why...
> >>>>
> >>>>> The only practical thing that my gimple_build_vector_from_elems function
> >>>>> does differently from gimple_build_vector for non-constant vectors is
> >>>>> that it does not rely on the vector type having a fixed length: instead,
> >>>>> it relies on implicit zero-filling of not-mentioned elements of a
> >>>>> CONSTRUCTOR node. Is that behaviour you would be willing to adopt in
> >>>>> gimple_build_vector?
> >>>>
> >>>> ...I don't think that this question really applies (assuming that
> >>>> you're asking about the current gimple_build_vector). By design,
> >>>> tree_vector_builder implicitly specifies a full vector's worth of
> >>>> elements based on a possibly shorter sequence of explicitly elements.
> >>>> There are no ambiguities to be resolved. There is nothing that is left
> >>>> to gimple_build_vector's interpretation.
> >>>>
> >>>> If we don't want tree_vector_builder semantics then we should provide
> >>>> an interface that doesn't use tree_vector_builder, which is essentially
> >>>> my argument above.
> >>>
> >>> But we have that. Build a CTOR and then an assignment.
> >>
> >> But I thought the idea of the gimple_build_* interfaces was to avoid
> >> unnecessary assignments. I.e. the purpose of the new API would be to
> >> fold a ctor to a constant without ever creating a temporary SSA name.
> >
> > True, but then this is valid for the VLA "head" case as well. I've
> > asked for how he handles constants there (should just zero-pad).
> >
> >> Anyway, I suppose I should bow out of this. I'll have wasted a lot of
> >> Chris's time by suggesting the path that I did.
>
> I don't have any ill feelings about it.
>
> >> I do think though that the ctor path in gimple_build_vector should
> >> check for the case that it handles (i.e. zero padding), rather than
> >> just ignoring the second half of the tree_vector_builder and hoping
> >> for the best.
> >
> > Yes, of course - that's what I was asking for.
> I will try to create a patch that does what you want, but in the
> meantime I have been experimenting with addressing one of your points
> against my gimple_build_vector_from_elems function: that "we should
> avoid introducing new APIs for a single use which could then well just
> build a properly constrained CTOR directly".
>
> The CTOR is not built directly by callers of gimple_build_vector, so
> from my point of view, the only question is how far building of that
> CTOR should be delegated down the call stack. I think the answer should
> depend on the needs of the calling code.
>
> I don't think a function resembling gimple_build_vector_from_elems does
> need to have only a single use. As I observed above, there are many
> existing callers of gimple_build_vector for which repetition is not
> required, including calls where logic that makes my brain hurt is needed
> to ensure that gimple_build_vector is not called inappropriately, and
> that it has the expected behaviour if it is called.
>
> Despite that guarding logic, the caller still has to rely on assumptions
> that are unchecked at the call site and cannot easily be statically
> verified, such as "number of elements per pattern is not three" and "if
> number of elements per pattern is two then the second of each pattern is
> constant zero... unless the builder has a fixed-length vector type".
>
> Here's an example of how I believe I have simplified one of the more
> complex existing uses of gimple_build_vector:
Hmm, but diffstat doesn't say this is simpler than before. What
gimple_build_vector wants to abstract is constant vs. CTOR and
then optimize getting a gimple_val for it which requires an assignment
for a CTOR and nothing for the constant. We lack the latter thing
when not wanting to use the gimplification interface so we could split
the API to add a gimple_build_single accepting single-RHSs or vals
(don't like the name much). Much of the vectorizer already explicitly
distinguishes between constants and non-constants, possibly
since forever.
Note I didn't introduce tree_vector_builder and friends, that was
Richard S., I don't know much about when that's overkill and when
not, I assume it's always required to verify we can create a vector
when it has VLA type, and in this case we have to specify the
zero-padding of the minimum initial sequence.
I'm not against simplifying code, even when that requires new
APIs. But I don't really want to do this as part of this series
(predicated tails or making zero-padded CTORs of VLA vector
types well-defined).
> @@ -4986,57 +4985,63 @@ get_initial_defs_for_reduction (loop_vec_info
> loop_vinfo,
> initial_values[i]);
> }
> op = initial_values[i];
> }
>
> /* Create 'vect_ = {op0,op1,...,opn}'. */
> number_of_places_left_in_vector--;
> elts[nunits - number_of_places_left_in_vector - 1] = op;
> - if (!CONSTANT_CLASS_P (op))
> - constant_p = false;
>
> if (number_of_places_left_in_vector == 0)
> {
> - tree init;
> - if (constant_p && !neutral_op
> - ? multiple_p (TYPE_VECTOR_SUBPARTS (vector_type), nunits)
> - : known_eq (TYPE_VECTOR_SUBPARTS (vector_type), nunits))
> - /* Build the vector directly from ELTS. */
> - init = gimple_build_vector (&ctor_seq, &elts);
> + tree init = NULL_TREE;
> + if (known_eq (TYPE_VECTOR_SUBPARTS (vector_type), nunits))
> + {
> + /* No repetition or neutral value is needed. */
> + init = gimple_build_simple_vector (&ctor_seq, vector_type,
> elts);
> + gcc_checking_assert (init);
> + }
> else if (neutral_op)
> {
> /* Build a vector of the neutral value and shift the
> other elements into place. */
> init = gimple_build_vector_from_val (&ctor_seq, vector_type,
> neutral_op);
> int k = nunits;
> while (k > 0 && operand_equal_p (elts[k - 1], neutral_op))
> k -= 1;
> while (k > 0)
> {
> k -= 1;
> init = gimple_build (&ctor_seq, CFN_VEC_SHL_INSERT,
> vector_type, init, elts[k]);
> }
> + gcc_checking_assert (init);
> }
> - else
> + else if (multiple_p (TYPE_VECTOR_SUBPARTS (vector_type), nunits))
> + {
> + /* Repeat ELTS to fill the vector. This can fail to build
> + a CONSTRUCTOR node if there are non-constant elements
> + and VECTOR_TYPE is variable-length. */
> + init = gimple_try_build_repeating_vector (&ctor_seq,
> vector_type,
> + elts);
> + }
> +
> + if (!init)
> {
> /* First time round, duplicate ELTS to fill the
> required number of vectors. */
> duplicate_and_interleave (loop_vinfo, &ctor_seq,
> vector_type, elts,
> number_of_vectors, *vec_oprnds);
> break;
> }
> vec_oprnds->quick_push (init);
>
> number_of_places_left_in_vector = nunits;
> - elts.new_vector (vector_type, nunits, 1);
> - elts.quick_grow (nunits);
> - constant_p = true;
> }
> }
> if (ctor_seq != NULL)
> vect_emit_reduction_init_stmts (loop_vinfo, reduc_info, ctor_seq);
> }
>
> vect_reduc_info
> info_for_reduction (loop_vec_info loop_vinfo, slp_tree node)
>
>
> I'm not trying to maintain the terseness of the original code; I'm
> trying to make it easy to understand and maintain. I hope you will
> reconsider the possible merits of this approach when I email the next
> version of my patch.
>
> Another reason for providing separate gimple_build_simple_vector and
> gimple_try_build_repeating_vector functions is that it would potentially
> allow the upper lanes of a vector created by gimple_build_simple_vector
> to be treated as "don't care" in future, without requiring all call
> sites to be updated.
>
> Like I wrote, I'll also work on trying to implement your suggested approach.
>
> Thanks,
> --
> Christopher Bazley
> Staff Software Engineer, GNU Tools Team.
> Arm Ltd, 110 Fulbourn Road, Cambridge, CB1 9NJ, UK.
> http://www.arm.com/