On Mon, 22 Sep 2025, Tamar Christina wrote:
> > -----Original Message-----
> > From: Richard Biener <[email protected]>
> > Sent: Monday, September 22, 2025 2:45 PM
> > To: Tamar Christina <[email protected]>
> > Cc: Pengfei Li <[email protected]>; [email protected]
> > Subject: RE: [PATCH] vect: Support early break with gswitch statements
> >
> > On Mon, 22 Sep 2025, Tamar Christina wrote:
> >
> > > > -----Original Message-----
> > > > From: Richard Biener <[email protected]>
> > > > Sent: 22 September 2025 12:34
> > > > To: Pengfei Li <[email protected]>
> > > > Cc: [email protected]; [email protected]; Tamar Christina
> > > > <[email protected]>
> > > > Subject: Re: [PATCH] vect: Support early break with gswitch statements
> > > >
> > > > On Thu, Sep 18, 2025 at 2:34 PM Pengfei Li <[email protected]> wrote:
> > > > >
> > > > > This patch adds vectorization support to early-break loops with
> > > > > gswitch
> > > > > statements. Such gswitches may come from original switch-case
> > > > > constructs
> > > > > in the source or the iftoswitch pass which rewrites if conditions
> > > > > with a
> > > > > chain of comparisons, like below, to gswitch statements.
> > > > >
> > > > > if (a[i] == c1 || a[i] == c2 || a[i] == c3)
> > > > >
> > > > > In this patch, the loop exit condition type is generalized from gcond
> > > > > to
> > > > > gimple, so that gswitch statements can be treated as valid loop
> > > > > exits. A
> > > > > new vectorizer pattern recognization function is introduced to check
> > > > > if
> > > > > all non-default labels of the gswitch have the same destination.
> > > >
> > > > So the labels should have the same label and the default label should
> > > > be the fallthru? Like the only handled case is
> > > >
> > > > for (;;)
> > > > {
> > > > ...
> > > > switch (x)
> > > > {
> > > > case A:
> > > > case B:
> > > > case C:
> > > > /* any code here? single BB? */
> > > > goto exit;
> > > > default:;
> > > > }
> > > > ...
> > > > }
> > > > exit:
> > > >
> > > > ?
> > > >
> > > > > If yes,
> > > > > it lowers the gswitch to an equivalent gcond.
> > > >
> > > > If so I think it might be simpler to implement this in if-conversion?
> > > > In fact I think
> > > > that already does this?
> > >
> > > Switch lowering in icvt is really limited. In fact, so limited it's not
> > > worth extending
> > I think.
> > > There's a couple of reason this approach was taken:
> > >
> > > 1. Today switch lowering if icvt can only handle cases where the return is
> > invariant. i.e. it can
> > > only handle simple data dependencies:
> > >
> > > int find (int *a, int n)
> > > {
> > > for (int i = 0; i < n; i++)
> > > {
> > > if (a[i] == 1 || a[i] == 3 || a[i] == 4 || a[i] == 5)
> > > return 1;
> > > }
> > > return -1;
> > > }
> > >
> > > As soon as you want to know the index of the element you found it doesn't
> > > work
> > >
> > > int find (int *a, int n)
> > > {
> > > for (int i = 0; i < n; i++)
> > > {
> > > if (a[i] == 1 || a[i] == 3 || a[i] == 4 || a[i] == 5)
> > > return i;
> > > }
> > > return -1;
> > > }
> > >
> > > Because this loop now has multiple exits where the value of I requires a
> > reduction,
> > > and ifcvt does not handle this:
> > >
> > > "Can not ifcvt due to multiple exits"
> >
> > Yeah, but that's another thing that needs fixing anyway - IIRC we
> > currently do not handle regular if-conversion in multi-exit loops
> > because of this.
>
> That seems to be logically inconsistent with
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121383#c2 though.
I'm sorry about that ;)
> Because
> if ifcvt could handle multiple exits the above would also be handled.
>
> But I agree with you that the way to handle this isn't in ifcvt because ifcvt
> forces a data dependency.
The issue is that as long as if-conversion doesn't handle multi-exit
loops at all, then we don't ever get .MASK_LOAD/STORE, etc. handled
for non exit conditions in such loops. I was suggesting to see to
do that. And then figure if/why the existing switch support isn't
enough.
> For instance since SVE supports short circuiting compares we don't want to
> have your typical conversion
> where both branches are executed and you VEC_COND_EXPR select the lanes at
> the end. For SVE we
> would want to conditionally execute the basic block, and masking will combine
> the results for us.
Yes. Though for the scalar
if (cond)
A;
else
B;
you then end up with
if (any (vec_cond))
{
A-with-mask;
B-with-mask;
}
else
B;
or even tri-state, also checking for all (vec_cond). The jumps are
profitable when all ones/zeros masks are common.
> Ifcvt removes this choice where-as in the vectorizer we can pick based on the
> mode being costed.
>
> The same applies here. We don't want ifcvt for instance to collapse nested
> switches.
But we have to, no?
> >
> > > While perhaps this could be extended this would require ifcvt to select a
> > > main
> > exit.
> > > This would also limit us in future expansion.
> >
> > Why does ifcvt need to select a main edge?
>
> I've not looked too deep into it, but ifcvt seems to want to know which edge
> to
> use conditionalize the statement.
>
> So for
>
> d + c
> if (a > b)
> foo
>
> the mask for d+c needs to come from the main exit. I admit I haven't though
> about
> what would happen in the PEELED case. but I have a feeling it would need
> something
> different.
Basically ifcvt relies on empty latches, it doesn't predicate stmts in it
(with the negated exit condition). With multiple exits you'd generally
have to predicate the following in-loop part with the negated exit
condition.
>
> >
> > > For instance in this case
> > >
> > > int find2 (int * restrict a, int *b, int n)
> > > {
> > > for (int i = 0; i < n; i++)
> > > {
> > > switch (a[i])
> > > {
> > > case 1:
> > > case 2:
> > > case 5:
> > > switch (b[i])
> > > {
> > > case 1:
> > > case 2:
> > > case 5:
> > > return 1;
> > > default:
> > > break;
> > > }
> > > default:
> > > break;
> > > }
> > > }
> > > return -1;
> > > }
> > >
> > > Is vectorizable, but ifcvt doesn't handle it. But once support for &&
> > > blocks are
> > > added to the vectorizer, we should be able to handle it fine.
> >
> > Sure.
> >
> > > The reason we support only one destination today is that as you say, the
> > > switch
> > is
> > > equivalent to a gcond. This limitation is there because we can't
> > > introduce new
> > > control flow to the vectorizer yet. But this is something we should be
> > > able to do
> > in
> > > the future.
> >
> > Sure.
> >
> > > I suggested doing this in the vectorizer for two other reason:
> > >
> > > 1. You've been adamant in the past about not introducing control
> > > dependencies
> > into icvt.
> > > Which will limit the usefulness of ifcvt going forward for control
> > > flow.
> > > 2. I believe the plan is still to move ifcvt into the vectorizer? If so
> > > it didn't seem
> > worth while
> > > Extending the very limited switch lowering in ifcvt. It just makes
> > > more work to
> > more.
> >
> > I think it belongs in the vectorizer, yes. But I don't see this as a
> > reason to stop improving it - in fact I think being able to drop it in
> > full requires to first code generate vector code without prior copying
> > of the scalar (if-converted) loop.
> >
>
> I have a patch stack to do just this. Hence the email sent a week ago about
> the optabs.
> It's one of the big topics at my AArch64 Performance BoF and my goal is to
> start sending
> them out in pieces as soon as cauldron is over and I've freed up more time.
>
> But as I'll show at cauldron I'm quite far along with simple to follow
> incremental patches (I hope).
> and one reason It took me long is I wanted to make sure the changes would
> work together.
>
> For instance the loops in this patch series won't require a scalar epilogue
> at all.
>
> > > Lastly, in cases as the above where we do an NxM compare, AArch64 has
> > instructions for this.
> > > Historically ifcvt has only done conditionalization of expression, but not
> > instruction selection.
> > >
> > > Ifcvt would also have a hard time handling cases such as:
> > >
> > > int find2 (int * restrict a, int *b, int n)
> > > {
> > > for (int i = 0; i < n; i++)
> > > {
> > > switch (a[i])
> > > {
> > > case 1:
> > > case 2:
> > > case 5:
> > > a[i] = i * b[i];
> > > return i;
> > > default:
> > > break;
> > > }
> > > }
> > > return -1;
> > > }
> > >
> > > Which we should be handle in the future.
> >
> > I think give we have a switch lowering pass (aka switch-to-if), it
> > should be reasonably "easy" to perform switch-to-if during ifcvt
> > (on the loop copy for the vectorizer).
> >
> > But then first handling multi-exit loops in ifcvt at all would be nice
> > (before trying to handle exit-from-switch).
> >
>
> It really does seem like this would be doing work double though.
> The improvement to support ifcvt handling of multiple exits with
> an invariant return was done in GCC 15, and even then it was immediately
> clear the approach was limited. Given that it never actually solved the
> issue filed.
>
> In fact, with this code, I think we can pretty much drop the code added in
> Icvt and still handle more cases in less code.
>
> Teaching ifcvt about multiple exit is teaching it about control flow the
> vectorizer
> can in principle handle on its own, but whereas the vectorizer can choose how
> to
> handle it, ifcvt must pick one way early.
That's true. It's the reason I think we want to drop ifcvt long term.
Richard.
> If none of this is entirely convincing, maybe lets come back to it after the
> presentations
> where I can show what codegen we can/will/should be able to do soon which
> would
> make it somewhat clearer (hopefully) that the vectorizer's masking support is
> more
> capable than ifcvt :)
>
> Thanks,
> Tamar
>
> > > I agree that it's slightly not nice needing the change in
> > > vectorizable_early_exit and
> > we can
> > > Hopefully get rid of it in the future. But I believe having this inside
> > > the vectorizer
> > will allow
> > > us to handle more cases and have a more general solution.
> >
> > Note I didn't look into the patch details but tried to understand
> > what exactly the proposed limitation is and compare that to the
> > existing switch handling in ifcvt.
> >
> > Richard.
> >
> > >
> > > Thanks,
> > > Tamar
> > >
> > > >
> > > > Richard.
> > > >
> > > > > To avoid excessive compile
> > > > > time, a new parameter vect-max-compare-in-switch-lowering is
> > > > > introduced
> > > > > to limit the maximum number of comparisons in the gswitch lowering. In
> > > > > addition, the CRC loop optimization is adjusted a bit to make sure CRC
> > > > > loops still have gcond exits.
> > > > >
> > > > > This patch is bootstrapped and regression-tested on x86_64-linux-gnu,
> > > > > arm-linux-gnueabihf and aarch64-linux-gnu.
> > > > >
> > > > > gcc/ChangeLog:
> > > > >
> > > > > * doc/invoke.texi: Document
> > > > > vect-max-compare-in-switch-lowering.
> > > > > * gimple-crc-optimization.cc
> > > > (crc_optimization::loop_may_calculate_crc):
> > > > > Ensure CRC loop exits are still gconds.
> > > > > (crc_optimization::optimize_crc_loop): Cast CRC loop exits.
> > > > > * params.opt: Add option vect-max-compare-in-switch-lowering.
> > > > > * tree-scalar-evolution.cc (scev_dfs::follow_ssa_edge_expr):
> > > > > Generalize loop exit conditions type from gcond to gimple.
> > > > > (get_loop_exit_condition): Likewise.
> > > > > * tree-scalar-evolution.h (get_loop_exit_condition): Likewise.
> > > > > * tree-vect-loop-manip.cc (vect_set_loop_condition_normal):
> > > > > Likewise.
> > > > > (vect_set_loop_condition): Likewise.
> > > > > (slpeel_can_duplicate_loop_p): Likewise.
> > > > > * tree-vect-loop.cc (vect_get_loop_niters): Likewise.
> > > > > (vect_analyze_loop_form): Likewise.
> > > > > (vect_create_loop_vinfo): Likewise.
> > > > > * tree-vect-patterns.cc (vect_recog_gswitch_pattern): New
> > > > > pattern recognition function for gswitch early exits.
> > > > > * tree-vect-slp.cc (vect_analyze_slp): Bail out if a gswitch
> > > > > is
> > > > > not lowered into a gcond.
> > > > > * tree-vect-stmts.cc (vect_mark_stmts_to_be_vectorized): Allow
> > > > > gswitch statements as loop exits.
> > > > > (vectorizable_early_exit): Transform gswitch early exits.
> > > > > * tree-vectorizer.h (struct vect_loop_form_info): Allow
> > > > > gswitch
> > > > > statements as loop exits.
> > > > >
> > > > > gcc/testsuite/ChangeLog:
> > > > >
> > > > > * gcc.dg/vect/vect-switch-search-line-fast.c: Update the test
> > > > > as
> > > > > the loop is now vectorizable on multiple targets.
> > > > > * gcc.dg/vect/vect-early-break_139-switch1.c: New test.
> > > > > * gcc.dg/vect/vect-early-break_139-switch2.c: New test.
> > > > > * gcc.dg/vect/vect-early-break_139-switch3.c: New test.
> > > > > * gcc.dg/vect/vect-early-break_139-switch4.c: New test.
> > > > > ---
> > > > > gcc/doc/invoke.texi | 4 +
> > > > > gcc/gimple-crc-optimization.cc | 9 +-
> > > > > gcc/params.opt | 4 +
> > > > > .../vect/vect-early-break_139-switch1.c | 19 +++
> > > > > .../vect/vect-early-break_139-switch2.c | 21 ++++
> > > > > .../vect/vect-early-break_139-switch3.c | 24 ++++
> > > > > .../vect/vect-early-break_139-switch4.c | 26 ++++
> > > > > .../vect/vect-switch-search-line-fast.c | 3 +-
> > > > > gcc/tree-scalar-evolution.cc | 12 +-
> > > > > gcc/tree-scalar-evolution.h | 4 +-
> > > > > gcc/tree-vect-loop-manip.cc | 6 +-
> > > > > gcc/tree-vect-loop.cc | 10 +-
> > > > > gcc/tree-vect-patterns.cc | 111
> > > > > ++++++++++++++++++
> > > > > gcc/tree-vect-slp.cc | 11 +-
> > > > > gcc/tree-vect-stmts.cc | 74 ++++++++----
> > > > > gcc/tree-vectorizer.h | 8 +-
> > > > > 16 files changed, 295 insertions(+), 51 deletions(-)
> > > > > create mode 100644 gcc/testsuite/gcc.dg/vect/vect-early-break_139-
> > > > switch1.c
> > > > > create mode 100644 gcc/testsuite/gcc.dg/vect/vect-early-break_139-
> > > > switch2.c
> > > > > create mode 100644 gcc/testsuite/gcc.dg/vect/vect-early-break_139-
> > > > switch3.c
> > > > > create mode 100644 gcc/testsuite/gcc.dg/vect/vect-early-break_139-
> > > > switch4.c
> > > > >
> > > > > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> > > > > index 3cf326cc22c..def84a6675a 100644
> > > > > --- a/gcc/doc/invoke.texi
> > > > > +++ b/gcc/doc/invoke.texi
> > > > > @@ -16652,6 +16652,10 @@ Complex expressions slow the analyzer.
> > > > > Maximum number of arguments in a PHI supported by TREE if conversion
> > > > > unless the loop is marked with simd pragma.
> > > > >
> > > > > +@item vect-max-compare-in-switch-lowering
> > > > > +The maximum number of comparisons that can be performed when
> > > > lowering switch
> > > > > +statements in the vectorizer.
> > > > > +
> > > > > @item vect-max-layout-candidates
> > > > > The maximum number of possible vector layouts (such as permutations)
> > > > > to consider when optimizing to-be-vectorized code.
> > > > > diff --git a/gcc/gimple-crc-optimization.cc
> > > > > b/gcc/gimple-crc-optimization.cc
> > > > > index 1751be9bc97..986aa193893 100644
> > > > > --- a/gcc/gimple-crc-optimization.cc
> > > > > +++ b/gcc/gimple-crc-optimization.cc
> > > > > @@ -937,6 +937,12 @@ crc_optimization::loop_may_calculate_crc (class
> > > > loop *loop)
> > > > > return false;
> > > > >
> > > > > m_crc_loop = loop;
> > > > > +
> > > > > + /* Filter out the loops, which don't have a gcond as single exit.
> > > > > */
> > > > > + gimple *loop_exit_cond = get_loop_exit_condition (m_crc_loop);
> > > > > + if (loop_exit_cond == NULL || !is_a <gcond *> (loop_exit_cond))
> > > > > + return false;
> > > > > +
> > > > > basic_block *loop_bbs = get_loop_body_in_dom_order (m_crc_loop);
> > > > >
> > > > > /* Filter out the cases, which don't have exactly two conditions
> > > > > in the loop.
> > > > > @@ -1274,7 +1280,8 @@ crc_optimization::optimize_crc_loop (gphi
> > > > *output_crc)
> > > > > remove_phi_node (&tmp_gsi, false);
> > > > >
> > > > > /* Alter the exit condition of the loop to always exit. */
> > > > > - gcond* loop_exit_cond = get_loop_exit_condition (m_crc_loop);
> > > > > + gcond *loop_exit_cond
> > > > > + = safe_dyn_cast <gcond *> (get_loop_exit_condition (m_crc_loop));
> > > > > gimple_cond_make_false (loop_exit_cond);
> > > > > update_stmt (loop_exit_cond);
> > > > > return true;
> > > > > diff --git a/gcc/params.opt b/gcc/params.opt
> > > > > index dd53d830895..115400ee8d2 100644
> > > > > --- a/gcc/params.opt
> > > > > +++ b/gcc/params.opt
> > > > > @@ -1229,6 +1229,10 @@ Whether to use canonical types.
> > > > > Common Joined UInteger Var(param_vect_epilogues_nomask) Init(1)
> > > > IntegerRange(0, 1) Param Optimization NoOffload
> > > > > Enable loop epilogue vectorization using smaller vector size.
> > > > >
> > > > > +-param=vect-max-compare-in-switch-lowering=
> > > > > +Common Joined UInteger
> > > > Var(param_vect_max_compare_in_switch_lowering) Init(16) Param
> > > > Optimization
> > > > > +Maximum number of comparisons that can be performed when lowering
> > > > switch statements in the vectorizer.
> > > > > +
> > > > > -param=vect-max-layout-candidates=
> > > > > Common Joined UInteger Var(param_vect_max_layout_candidates) Init(32)
> > > > Param Optimization
> > > > > Maximum number of possible vector layouts (such as permutations) to
> > > > consider when optimizing to-be-vectorized code.
> > > > > diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_139-switch1.c
> > > > b/gcc/testsuite/gcc.dg/vect/vect-early-break_139-switch1.c
> > > > > new file mode 100644
> > > > > index 00000000000..bbe75d20116
> > > > > --- /dev/null
> > > > > +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_139-switch1.c
> > > > > @@ -0,0 +1,19 @@
> > > > > +/* { dg-add-options vect_early_break } */
> > > > > +/* { dg-do compile } */
> > > > > +/* { dg-require-effective-target vect_early_break } */
> > > > > +/* { dg-require-effective-target vect_int } */
> > > > > +
> > > > > +/* { dg-additional-options "-Ofast" } */
> > > > > +
> > > > > +int find (int *a, int n)
> > > > > +{
> > > > > + for (int i = 0; i < n; i++)
> > > > > + {
> > > > > + /* This is converted to a switch statement in the iftoswitch
> > > > > pass. */
> > > > > + if (a[i] == 1 || a[i] == 2 || a[i] == 5 || a[i] == 7)
> > > > > + return i;
> > > > > + }
> > > > > + return -1;
> > > > > +}
> > > > > +
> > > > > +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */
> > > > > diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_139-switch2.c
> > > > b/gcc/testsuite/gcc.dg/vect/vect-early-break_139-switch2.c
> > > > > new file mode 100644
> > > > > index 00000000000..d200bea4594
> > > > > --- /dev/null
> > > > > +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_139-switch2.c
> > > > > @@ -0,0 +1,21 @@
> > > > > +/* { dg-add-options vect_early_break } */
> > > > > +/* { dg-do compile } */
> > > > > +/* { dg-require-effective-target vect_early_break } */
> > > > > +/* { dg-require-effective-target vect_int } */
> > > > > +
> > > > > +/* { dg-additional-options "-Ofast" } */
> > > > > +
> > > > > +int find (int *a, int n)
> > > > > +{
> > > > > + for (int i = 0; i < n; i++)
> > > > > + {
> > > > > + /* This is converted to a switch statement in the iftoswitch
> > > > > pass. */
> > > > > + if (a[i] == 1 || a[i] == 3 || a[i] == 4 || a[i] == 5)
> > > > > + continue;
> > > > > + else
> > > > > + return i;
> > > > > + }
> > > > > + return -1;
> > > > > +}
> > > > > +
> > > > > +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */
> > > > > diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_139-switch3.c
> > > > b/gcc/testsuite/gcc.dg/vect/vect-early-break_139-switch3.c
> > > > > new file mode 100644
> > > > > index 00000000000..f696267a855
> > > > > --- /dev/null
> > > > > +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_139-switch3.c
> > > > > @@ -0,0 +1,24 @@
> > > > > +/* { dg-add-options vect_early_break } */
> > > > > +/* { dg-do compile } */
> > > > > +/* { dg-require-effective-target vect_early_break } */
> > > > > +/* { dg-require-effective-target vect_int } */
> > > > > +
> > > > > +/* { dg-additional-options "-Ofast" } */
> > > > > +
> > > > > +int find (int *a, int n)
> > > > > +{
> > > > > + for (int i = 0; i < n; i++)
> > > > > + {
> > > > > + /* An early break in case labels of a switch statement. */
> > > > > + switch (a[i])
> > > > > + {
> > > > > + case -1 ... 1:
> > > > > + case 10:
> > > > > + case 20:
> > > > > + return i;
> > > > > + }
> > > > > + }
> > > > > + return -1;
> > > > > +}
> > > > > +
> > > > > +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */
> > > > > diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_139-switch4.c
> > > > b/gcc/testsuite/gcc.dg/vect/vect-early-break_139-switch4.c
> > > > > new file mode 100644
> > > > > index 00000000000..f8e3187843d
> > > > > --- /dev/null
> > > > > +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_139-switch4.c
> > > > > @@ -0,0 +1,26 @@
> > > > > +/* { dg-add-options vect_early_break } */
> > > > > +/* { dg-do compile } */
> > > > > +/* { dg-require-effective-target vect_early_break } */
> > > > > +/* { dg-require-effective-target vect_int } */
> > > > > +
> > > > > +/* { dg-additional-options "-Ofast" } */
> > > > > +
> > > > > +int find (int *a, int n)
> > > > > +{
> > > > > + for (int i = 0; i < n; i++)
> > > > > + {
> > > > > + /* An early break in the default label of a switch statement. */
> > > > > + switch (a[i])
> > > > > + {
> > > > > + case 1 ... 3:
> > > > > + case 5:
> > > > > + case 10:
> > > > > + continue;
> > > > > + default:
> > > > > + return i;
> > > > > + }
> > > > > + }
> > > > > + return -1;
> > > > > +}
> > > > > +
> > > > > +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */
> > > > > diff --git a/gcc/testsuite/gcc.dg/vect/vect-switch-search-line-fast.c
> > > > b/gcc/testsuite/gcc.dg/vect/vect-switch-search-line-fast.c
> > > > > index 678512db319..17e80330daa 100644
> > > > > --- a/gcc/testsuite/gcc.dg/vect/vect-switch-search-line-fast.c
> > > > > +++ b/gcc/testsuite/gcc.dg/vect/vect-switch-search-line-fast.c
> > > > > @@ -16,5 +16,4 @@ const unsigned char *search_line_fast2 (const
> > > > unsigned char *s,
> > > > > return s;
> > > > > }
> > > > >
> > > > > -/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" {
> > > > > target {
> > > > ilp32 || { amdgcn*-*-* } } } } } */
> > > > > -/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 0 "vect" {
> > > > > target { !
> > > > { ilp32 || { amdgcn*-*-* } } } } } } */
> > > > > +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" }
> > > > > } */
> > > > > diff --git a/gcc/tree-scalar-evolution.cc
> > > > > b/gcc/tree-scalar-evolution.cc
> > > > > index ecdef7529a6..0a5172c3be4 100644
> > > > > --- a/gcc/tree-scalar-evolution.cc
> > > > > +++ b/gcc/tree-scalar-evolution.cc
> > > > > @@ -1302,7 +1302,7 @@ scev_dfs::follow_ssa_edge_expr (gimple
> > > > *at_stmt, tree expr,
> > > > > guards the exit edge. If the expression is too difficult to
> > > > > analyze, then give up. */
> > > > >
> > > > > -gcond *
> > > > > +gimple *
> > > > > get_loop_exit_condition (const class loop *loop)
> > > > > {
> > > > > return get_loop_exit_condition (single_exit (loop));
> > > > > @@ -1311,16 +1311,20 @@ get_loop_exit_condition (const class loop
> > > > *loop)
> > > > > /* If the statement just before the EXIT_EDGE contains a condition
> > > > > then
> > > > > return the condition, otherwise NULL. */
> > > > >
> > > > > -gcond *
> > > > > +gimple *
> > > > > get_loop_exit_condition (const_edge exit_edge)
> > > > > {
> > > > > - gcond *res = NULL;
> > > > > + gimple *res = NULL;
> > > > >
> > > > > if (dump_file && (dump_flags & TDF_SCEV))
> > > > > fprintf (dump_file, "(get_loop_exit_condition \n ");
> > > > >
> > > > > if (exit_edge)
> > > > > - res = safe_dyn_cast <gcond *> (*gsi_last_bb (exit_edge->src));
> > > > > + {
> > > > > + gimple *g = *gsi_last_bb (exit_edge->src);
> > > > > + if (is_a <gcond *> (g) || is_a <gswitch *> (g))
> > > > > + res = g;
> > > > > + }
> > > > >
> > > > > if (dump_file && (dump_flags & TDF_SCEV))
> > > > > {
> > > > > diff --git a/gcc/tree-scalar-evolution.h b/gcc/tree-scalar-evolution.h
> > > > > index c7feeacf1db..54f0bf82c7b 100644
> > > > > --- a/gcc/tree-scalar-evolution.h
> > > > > +++ b/gcc/tree-scalar-evolution.h
> > > > > @@ -22,8 +22,8 @@ along with GCC; see the file COPYING3. If not see
> > > > > #define GCC_TREE_SCALAR_EVOLUTION_H
> > > > >
> > > > > extern tree number_of_latch_executions (class loop *);
> > > > > -extern gcond *get_loop_exit_condition (const class loop *);
> > > > > -extern gcond *get_loop_exit_condition (const_edge);
> > > > > +extern gimple *get_loop_exit_condition (const class loop *);
> > > > > +extern gimple *get_loop_exit_condition (const_edge);
> > > > >
> > > > > extern void scev_initialize (void);
> > > > > extern bool scev_initialized_p (void);
> > > > > diff --git a/gcc/tree-vect-loop-manip.cc b/gcc/tree-vect-loop-manip.cc
> > > > > index 20141dbc2e5..bd04252da2d 100644
> > > > > --- a/gcc/tree-vect-loop-manip.cc
> > > > > +++ b/gcc/tree-vect-loop-manip.cc
> > > > > @@ -1233,7 +1233,7 @@ vect_set_loop_condition_normal (loop_vec_info
> > > > /* loop_vinfo */, edge exit_edge,
> > > > > {
> > > > > tree indx_before_incr, indx_after_incr;
> > > > > gcond *cond_stmt;
> > > > > - gcond *orig_cond;
> > > > > + gimple *orig_cond;
> > > > > edge pe = loop_preheader_edge (loop);
> > > > > gimple_stmt_iterator incr_gsi;
> > > > > bool insert_after;
> > > > > @@ -1395,7 +1395,7 @@ vect_set_loop_condition (class loop *loop, edge
> > > > loop_e, loop_vec_info loop_vinfo
> > > > > bool niters_maybe_zero)
> > > > > {
> > > > > gcond *cond_stmt;
> > > > > - gcond *orig_cond = get_loop_exit_condition (loop_e);
> > > > > + gimple *orig_cond = get_loop_exit_condition (loop_e);
> > > > > gimple_stmt_iterator loop_cond_gsi = gsi_for_stmt (orig_cond);
> > > > >
> > > > > if (loop_vinfo && LOOP_VINFO_USING_PARTIAL_VECTORS_P (loop_vinfo))
> > > > > @@ -2039,7 +2039,7 @@ slpeel_can_duplicate_loop_p (const class loop
> > > > *loop, const_edge exit_e,
> > > > > const_edge e)
> > > > > {
> > > > > edge entry_e = loop_preheader_edge (loop);
> > > > > - gcond *orig_cond = get_loop_exit_condition (exit_e);
> > > > > + gimple *orig_cond = get_loop_exit_condition (exit_e);
> > > > > gimple_stmt_iterator loop_exit_gsi = gsi_last_bb (exit_e->src);
> > > > >
> > > > > /* All loops have an outer scope; the only case loop->outer is
> > > > > NULL is for
> > > > > diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc
> > > > > index b58e4355e58..02db9f5a2eb 100644
> > > > > --- a/gcc/tree-vect-loop.cc
> > > > > +++ b/gcc/tree-vect-loop.cc
> > > > > @@ -627,12 +627,12 @@ vect_fixup_scalar_cycles_with_patterns
> > > > (loop_vec_info loop_vinfo)
> > > > > Return the loop exit conditions. */
> > > > >
> > > > >
> > > > > -static vec<gcond *>
> > > > > +static vec<gimple *>
> > > > > vect_get_loop_niters (class loop *loop, const_edge main_exit, tree
> > > > *assumptions,
> > > > > tree *number_of_iterations, tree
> > > > > *number_of_iterationsm1)
> > > > > {
> > > > > auto_vec<edge> exits = get_loop_exit_edges (loop);
> > > > > - vec<gcond *> conds;
> > > > > + vec<gimple *> conds;
> > > > > conds.create (exits.length ());
> > > > > class tree_niter_desc niter_desc;
> > > > > tree niter_assumptions, niter, may_be_zero;
> > > > > @@ -654,7 +654,7 @@ vect_get_loop_niters (class loop *loop, const_edge
> > > > main_exit, tree *assumptions,
> > > > > unsigned int i;
> > > > > FOR_EACH_VEC_ELT (exits, i, exit)
> > > > > {
> > > > > - gcond *cond = get_loop_exit_condition (exit);
> > > > > + gimple *cond = get_loop_exit_condition (exit);
> > > > > if (cond)
> > > > > conds.safe_push (cond);
> > > > >
> > > > > @@ -1680,7 +1680,7 @@ vect_analyze_loop_form (class loop *loop,
> > > > gimple *loop_vectorized_call,
> > > > > /* Determine what the primary and alternate exit conds are. */
> > > > > for (unsigned i = 0; i < info->conds.length (); i++)
> > > > > {
> > > > > - gcond *cond = info->conds[i];
> > > > > + gimple *cond = info->conds[i];
> > > > > if (exit_e->src == gimple_bb (cond))
> > > > > std::swap (info->conds[0], info->conds[i]);
> > > > > }
> > > > > @@ -1745,7 +1745,7 @@ vect_create_loop_vinfo (class loop *loop,
> > > > vec_info_shared *shared,
> > > > > if (!integer_onep (info->assumptions) && !orig_loop_info)
> > > > > LOOP_VINFO_NITERS_ASSUMPTIONS (loop_vinfo) = info->assumptions;
> > > > >
> > > > > - for (gcond *cond : info->conds)
> > > > > + for (gimple *cond : info->conds)
> > > > > {
> > > > > stmt_vec_info loop_cond_info = loop_vinfo->lookup_stmt (cond);
> > > > > /* Mark the statement as a condition. */
> > > > > diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc
> > > > > index 70bf768d339..cd39bdfbd0d 100644
> > > > > --- a/gcc/tree-vect-patterns.cc
> > > > > +++ b/gcc/tree-vect-patterns.cc
> > > > > @@ -5529,6 +5529,116 @@ vect_recog_gcond_pattern (vec_info *vinfo,
> > > > > return pattern_stmt;
> > > > > }
> > > > >
> > > > > +/* Function vect_recog_gswitch_pattern
> > > > > +
> > > > > + Try to find pattern like following:
> > > > > +
> > > > > + switch (x) <default: <La>, case b1: <Lb>, ... case bN: <Lb>>
> > > > > +
> > > > > + where all labels except the default one have the same destination
> > > > > and
> > > > > + convert it to a boolean pattern
> > > > > +
> > > > > + mask = (x == b1) || (x == b2) || ... || (x == bN)
> > > > > + if (mask != 0)
> > > > > +
> > > > > + The type of output TYPE_OUT is set in this function.
> > > > > +
> > > > > + Input:
> > > > > +
> > > > > + * STMT_VINFO: The stmt at the end from which the pattern
> > > > > + search begins, i.e., cast of a bool to
> > > > > + an integer type.
> > > > > +
> > > > > + Output:
> > > > > +
> > > > > + * TYPE_OUT: The type of the output of this pattern.
> > > > > +
> > > > > + * Return value: A new stmt that will be used to replace the
> > > > > pattern. */
> > > > > +
> > > > > +static gimple *
> > > > > +vect_recog_gswitch_pattern (vec_info *vinfo,
> > > > > + stmt_vec_info stmt_vinfo, tree *type_out)
> > > > > +{
> > > > > + /* Currently we only support this for loop vectorization and when
> > > > > multiple
> > > > > + exits. */
> > > > > + loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
> > > > > + if (!loop_vinfo || !LOOP_VINFO_EARLY_BREAKS (loop_vinfo))
> > > > > + return NULL;
> > > > > +
> > > > > + gimple *last_stmt = STMT_VINFO_STMT (stmt_vinfo);
> > > > > + gswitch *gs = NULL;
> > > > > + if (!(gs = dyn_cast <gswitch *> (last_stmt)))
> > > > > + return NULL;
> > > > > +
> > > > > + tree index = gimple_switch_index (gs);
> > > > > + tree stype = TREE_TYPE (index);
> > > > > +
> > > > > + /* For now, there should be no gswitch with boolean type index. */
> > > > > + gcc_assert (!VECT_SCALAR_BOOLEAN_TYPE_P (stype));
> > > > > + tree vectype = get_mask_type_for_scalar_type (vinfo, stype);
> > > > > + if (vectype == NULL_TREE)
> > > > > + return NULL;
> > > > > +
> > > > > + tree case_label_dest = NULL_TREE;
> > > > > + tree cond = NULL_TREE;
> > > > > + unsigned int num_cmps = 0;
> > > > > + for (unsigned li = 1; li < gimple_switch_num_labels (gs); li++)
> > > > > + {
> > > > > + tree label = gimple_switch_label (gs, li);
> > > > > +
> > > > > + /* Check if all case labels have the same destination. */
> > > > > + tree dest = CASE_LABEL (label);
> > > > > + if (case_label_dest == NULL)
> > > > > + case_label_dest = dest;
> > > > > + else if (dest != case_label_dest)
> > > > > + return NULL;
> > > > > +
> > > > > + tree low = CASE_LOW (label);
> > > > > + gcc_assert (low != NULL_TREE);
> > > > > + tree high = CASE_HIGH (label);
> > > > > + gcc_assert (high == NULL_TREE || tree_int_cst_lt (low, high));
> > > > > +
> > > > > + wide_int val = wi::to_wide (low);
> > > > > + wide_int one = wi::one (TYPE_PRECISION (stype));
> > > > > + while (true)
> > > > > + {
> > > > > + /* A large number of comparisons lead to long compile time
> > > > > and make
> > > > > + vectorization non-profitable (most cost models will
> > > > > reject the
> > > > > + vectorized code). So bail out in this case. */
> > > > > + if (++num_cmps > (unsigned)
> > > > param_vect_max_compare_in_switch_lowering)
> > > > > + return NULL;
> > > > > +
> > > > > + tree eq_cond = vect_recog_temp_ssa_var (boolean_type_node,
> > > > > NULL);
> > > > > + gimple *eq_stmt = gimple_build_assign (eq_cond, EQ_EXPR,
> > > > > index,
> > > > > + wide_int_to_tree
> > > > > (stype, val));
> > > > > + append_pattern_def_seq (vinfo, stmt_vinfo, eq_stmt,
> > > > > vectype, stype);
> > > > > + if (cond == NULL_TREE)
> > > > > + cond = eq_cond;
> > > > > + else
> > > > > + {
> > > > > + tree new_cond = vect_recog_temp_ssa_var
> > > > > (boolean_type_node,
> > > > NULL);
> > > > > + gimple *or_stmt = gimple_build_assign (new_cond,
> > > > > BIT_IOR_EXPR,
> > > > > + cond, eq_cond);
> > > > > + append_pattern_def_seq (vinfo, stmt_vinfo, or_stmt,
> > > > > + vectype, stype);
> > > > > + cond = new_cond;
> > > > > + }
> > > > > +
> > > > > + /* Break if the case label has a single value or we've
> > > > > reached the
> > > > > + high value. */
> > > > > + if (high == NULL_TREE || wi::eq_p (val, wi::to_wide (high)))
> > > > > + break;
> > > > > +
> > > > > + val = wi::add (val, one);
> > > > > + }
> > > > > + }
> > > > > +
> > > > > + vect_pattern_detected ("vect_recog_gswitch_pattern", last_stmt);
> > > > > + *type_out = vectype;
> > > > > + return gimple_build_cond (NE_EXPR, cond, build_zero_cst (TREE_TYPE
> > > > (cond)),
> > > > > + NULL_TREE, NULL_TREE);
> > > > > +}
> > > > > +
> > > > > /* Function vect_recog_bool_pattern
> > > > >
> > > > > Try to find pattern like following:
> > > > > @@ -6987,6 +7097,7 @@ static vect_recog_func
> > > > vect_vect_recog_func_ptrs[] = {
> > > > > { vect_recog_sat_sub_pattern, "sat_sub" },
> > > > > { vect_recog_sat_trunc_pattern, "sat_trunc" },
> > > > > { vect_recog_gcond_pattern, "gcond" },
> > > > > + { vect_recog_gswitch_pattern, "gswitch" },
> > > > > { vect_recog_bool_pattern, "bool" },
> > > > > /* This must come before mask conversion, and includes the parts
> > > > > of mask conversion that are needed for gather and scatter
> > > > > diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc
> > > > > index 895fb88ab7f..217d1299656 100644
> > > > > --- a/gcc/tree-vect-slp.cc
> > > > > +++ b/gcc/tree-vect-slp.cc
> > > > > @@ -5409,14 +5409,13 @@ vect_analyze_slp (vec_info *vinfo, unsigned
> > > > max_tree_size,
> > > > > vec<stmt_vec_info> roots = vNULL;
> > > > > roots.safe_push (cond_info);
> > > > > gimple *stmt = STMT_VINFO_STMT (cond_info);
> > > > > - tree args0 = gimple_cond_lhs (stmt);
> > > > > - tree args1 = gimple_cond_rhs (stmt);
> > > > >
> > > > > /* These should be enforced by cond lowering, but if it
> > > > > failed
> > > > > bail. */
> > > > > - if (gimple_cond_code (stmt) != NE_EXPR
> > > > > - || TREE_TYPE (args0) != boolean_type_node
> > > > > - || !integer_zerop (args1))
> > > > > + if (!is_a <gcond *> (stmt)
> > > > > + || gimple_cond_code (stmt) != NE_EXPR
> > > > > + || TREE_TYPE (gimple_cond_lhs (stmt)) !=
> > > > > boolean_type_node
> > > > > + || !integer_zerop (gimple_cond_rhs (stmt)))
> > > > > {
> > > > > roots.release ();
> > > > > return opt_result::failure_at (vect_location,
> > > > > @@ -5428,7 +5427,7 @@ vect_analyze_slp (vec_info *vinfo, unsigned
> > > > max_tree_size,
> > > > > from them. It's highly likely that the resulting SLP
> > > > > tree here if both
> > > > > arguments have a def will be incompatible, but we rely
> > > > > on it being split
> > > > > later on. */
> > > > > - auto varg = loop_vinfo->lookup_def (args0);
> > > > > + auto varg = loop_vinfo->lookup_def (gimple_cond_lhs (stmt));
> > > > > vec<stmt_vec_info> stmts;
> > > > > vec<tree> remain = vNULL;
> > > > > stmts.create (1);
> > > > > diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc
> > > > > index 6274956e2a5..436a4f4fc44 100644
> > > > > --- a/gcc/tree-vect-stmts.cc
> > > > > +++ b/gcc/tree-vect-stmts.cc
> > > > > @@ -743,6 +743,7 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info
> > > > loop_vinfo, bool *fatal)
> > > > >
> > > > > if (gimple_get_lhs (stmt) == NULL_TREE
> > > > > && !is_a <gcond *> (stmt)
> > > > > + && !is_a <gswitch *> (stmt)
> > > > > && !is_a <gcall *> (stmt))
> > > > > return opt_result::failure_at
> > > > > (stmt, "not vectorized: irregular stmt: %G", stmt);
> > > > > @@ -12339,28 +12340,6 @@ vectorizable_early_exit (loop_vec_info
> > > > loop_vinfo, stmt_vec_info stmt_info,
> > > > > bool masked_loop_p = LOOP_VINFO_FULLY_MASKED_P (loop_vinfo);
> > > > > bool len_loop_p = LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo);
> > > > >
> > > > > - /* Now build the new conditional. Pattern gimple_conds get dropped
> > > > during
> > > > > - codegen so we must replace the original insn. */
> > > > > - gimple *orig_stmt = STMT_VINFO_STMT (vect_orig_stmt (stmt_info));
> > > > > - gcond *cond_stmt = as_a <gcond *>(orig_stmt);
> > > > > -
> > > > > - tree vectype_out = vectype;
> > > > > - auto bb = gimple_bb (cond_stmt);
> > > > > - edge exit_true_edge = EDGE_SUCC (bb, 0);
> > > > > - if (exit_true_edge->flags & EDGE_FALSE_VALUE)
> > > > > - exit_true_edge = EDGE_SUCC (bb, 1);
> > > > > - gcc_assert (exit_true_edge->flags & EDGE_TRUE_VALUE);
> > > > > -
> > > > > - /* When vectorizing we assume that if the branch edge is taken
> > > > > that we're
> > > > > - exiting the loop. This is not however always the case as the
> > > > > compiler will
> > > > > - rewrite conditions to always be a comparison against 0. To do
> > > > > this it
> > > > > - sometimes flips the edges. This is fine for scalar, but for
> > > > > vector we
> > > > > - then have to negate the result of the test, as we're still
> > > > > assuming that if
> > > > > - you take the branch edge that we found the exit condition.
> > > > > i.e. we need
> > > > to
> > > > > - know whether we are generating a `forall` or an `exist`
> > > > > condition. */
> > > > > - bool flipped = flow_bb_inside_loop_p (LOOP_VINFO_LOOP (loop_vinfo),
> > > > > - exit_true_edge->dest);
> > > > > -
> > > > > /* See if we support ADDHN and use that for the reduction. */
> > > > > internal_fn ifn = IFN_VEC_TRUNC_ADD_HIGH;
> > > > > bool addhn_supported_p
> > > > > @@ -12439,6 +12418,53 @@ vectorizable_early_exit (loop_vec_info
> > > > loop_vinfo, stmt_vec_info stmt_info,
> > > > > auto_vec<tree> stmts;
> > > > > stmts.safe_splice (SLP_TREE_VEC_DEFS (slp_node));
> > > > >
> > > > > + /* Now build the new conditional. Pattern gimple_conds get dropped
> > > > during
> > > > > + codegen so we must replace the original insn. */
> > > > > + gimple *orig_stmt = STMT_VINFO_STMT (vect_orig_stmt (stmt_info));
> > > > > + tree vectype_out = vectype;
> > > > > + auto bb = gimple_bb (orig_stmt);
> > > > > +
> > > > > + /* Find the edge which indicates the branch is taken. If original
> > > > > statement
> > > > > + is a gcond, we find the edge with flag EDGE_TRUE_VALUE. For
> > > > > gswitch,
> > > > we
> > > > > + find the edge from the non-default label, and set flags
> > > > EDGE_TRUE_VALUE,
> > > > > + EDGE_FALSE_VALUE for the two edges. */
> > > > > + edge exit_true_edge = EDGE_SUCC (bb, 0);
> > > > > + if (is_a <gcond *> (orig_stmt))
> > > > > + {
> > > > > + if (exit_true_edge->flags & EDGE_FALSE_VALUE)
> > > > > + exit_true_edge = EDGE_SUCC (bb, 1);
> > > > > + gcc_assert (exit_true_edge->flags & EDGE_TRUE_VALUE);
> > > > > + }
> > > > > + else
> > > > > + {
> > > > > + gcc_assert (is_a <gswitch *> (orig_stmt));
> > > > > + gcc_assert (bb->succs->length () == 2);
> > > > > + tree dft_lab = gimple_switch_default_label (as_a <gswitch *>
> > > > (orig_stmt));
> > > > > + basic_block dft_bb = label_to_block (cfun, CASE_LABEL
> > > > > (dft_lab));
> > > > > + if (exit_true_edge->dest != dft_bb)
> > > > > + {
> > > > > + EDGE_SUCC (bb, 0)->flags |= EDGE_TRUE_VALUE;
> > > > > + EDGE_SUCC (bb, 1)->flags |= EDGE_FALSE_VALUE;
> > > > > + }
> > > > > + else
> > > > > + {
> > > > > + exit_true_edge = EDGE_SUCC (bb, 1);
> > > > > + EDGE_SUCC (bb, 0)->flags |= EDGE_FALSE_VALUE;
> > > > > + EDGE_SUCC (bb, 1)->flags |= EDGE_TRUE_VALUE;
> > > > > + }
> > > > > + gcc_assert (exit_true_edge->dest != dft_bb);
> > > > > + }
> > > > > +
> > > > > + /* When vectorizing we assume that if the branch edge is taken
> > > > > that we're
> > > > > + exiting the loop. This is not however always the case as the
> > > > > compiler will
> > > > > + rewrite conditions to always be a comparison against 0. To do
> > > > > this it
> > > > > + sometimes flips the edges. This is fine for scalar, but for
> > > > > vector we
> > > > > + then have to negate the result of the test, as we're still
> > > > > assuming that if
> > > > > + you take the branch edge that we found the exit condition.
> > > > > i.e., we need
> > > > > + to know whether we are generating a `forall` or an `exist`
> > > > > condition. */
> > > > > + bool flipped = flow_bb_inside_loop_p (LOOP_VINFO_LOOP (loop_vinfo),
> > > > > + exit_true_edge->dest);
> > > > > +
> > > > > /* If we're comparing against a previous forall we need to negate
> > > > > the
> > > > resullts
> > > > > before we do the final comparison or reduction. */
> > > > > if (flipped)
> > > > > @@ -12536,8 +12562,8 @@ vectorizable_early_exit (loop_vec_info
> > > > loop_vinfo, stmt_vec_info stmt_info,
> > > > > gcc_assert (new_temp);
> > > > >
> > > > > tree cst = build_zero_cst (vectype_out);
> > > > > - gimple_cond_set_condition (cond_stmt, NE_EXPR, new_temp, cst);
> > > > > - update_stmt (orig_stmt);
> > > > > + new_stmt = gimple_build_cond (NE_EXPR, new_temp, cst, NULL_TREE,
> > > > NULL_TREE);
> > > > > + gsi_replace (&cond_gsi, new_stmt, true);
> > > > >
> > > > > /* ??? */
> > > > > SLP_TREE_VEC_DEFS (slp_node).truncate (0);
> > > > > diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
> > > > > index b7c2188ab3d..cb715459c00 100644
> > > > > --- a/gcc/tree-vectorizer.h
> > > > > +++ b/gcc/tree-vectorizer.h
> > > > > @@ -1155,10 +1155,10 @@ public:
> > > > > bool early_breaks;
> > > > >
> > > > > /* List of loop additional IV conditionals found in the loop. */
> > > > > - auto_vec<gcond *> conds;
> > > > > + auto_vec<gimple *> conds;
> > > > >
> > > > > /* Main loop IV cond. */
> > > > > - gcond* loop_iv_cond;
> > > > > + gimple *loop_iv_cond;
> > > > >
> > > > > /* True if we have an unroll factor requested by the user through
> > > > > pragma
> > > > GCC
> > > > > unroll. */
> > > > > @@ -2702,8 +2702,8 @@ struct vect_loop_form_info
> > > > > tree number_of_iterations;
> > > > > tree number_of_iterationsm1;
> > > > > tree assumptions;
> > > > > - auto_vec<gcond *> conds;
> > > > > - gcond *inner_loop_cond;
> > > > > + auto_vec<gimple *> conds;
> > > > > + gimple *inner_loop_cond;
> > > > > edge loop_exit;
> > > > > };
> > > > > extern opt_result vect_analyze_loop_form (class loop *, gimple *,
> > > > > --
> > > > > 2.43.0
> > > > >
> > >
> >
> > --
> > Richard Biener <[email protected]>
> > SUSE Software Solutions Germany GmbH,
> > Frankenstrasse 146, 90461 Nuernberg, Germany;
> > GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)
>
--
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)