On Tue, Nov 18, 2025 at 7:14 AM Tamar Christina <[email protected]> wrote:
>
> This patch introduces six new vector cbranch optabs
>
> 1. vec_cbranch_any and vec_cbranch_all.
> 2. cond_vec_cbranch_any and cond_vec_cbranch_all.
> 3. cond_len_vec_cbranch_any and cond_len_vec_cbranch_all.
>
> Today cbranch can be used for both vector and scalar modes.  In both these
> cases it's intended to compare boolean values, either scalar or vector.
>
> The optab documentation does not however state that it can only handle
> comparisons against 0.  So many targets have added code for the vector variant
> that tries to deal with the case where we branch based on two non-zero
> registers.
>
> However this code can't ever be reached because the cbranch expansion only 
> deals
> with comparisons against 0 for vectors.  This is because for vectors the rest 
> of
> the compiler has no way to generate a non-zero comparison. e.g. the vectorizer
> will always generate a zero comparison, and the C/C++ front-ends won't allow
> vectors to be used in a cbranch as it expects a boolean value.  ISAs like SVE
> work around this by requiring you to use an SVE PTEST intrinsics which results
> in a single scalar boolean value that represents the flag values.
>
> e.g. if (svptest_any (..))
>
> The natural question is why do we not at expand time then rewrite the 
> comparison
> to a non-zero comparison if the target supports it.
>
> The reason is we can't safely do so.  For an ANY comparison (e.g. != b) this 
> is
> trivial, but for an ALL comparison (e.g. == b) we would have to flip both 
> branch
> and invert the value being compared.  i.e. we have to make it a != b 
> comparison.
>
> But in emit_cmp_and_jump_insns we can't flip the branches anymore because they
> have already been lowered into a fall through branch (PC) and a label, ready 
> for
> use in an if_then_else RTL expression.
>
> Now why does any of this matter?  Well there are three optimizations we want 
> to be
> able to do.
>
> 1. Adv. SIMD does not support a vector !=, as in there's no instruction for 
> it.
>    For both Integer and FP vectors we perform the comparisons as EQ and then
>    invert the resulting mask.  Ideally we'd like to replace this with just a 
> XOR
>    and the appropriate branch.
>
> 2. When on an SVE enabled system we would like to use an SVE compare + branch
>    for the Adv. SIMD sequence which could happen due to cost modelling.  
> However
>    we can only do so based on if we know that the values being compared 
> against
>    are the boolean masks.  This means we can't really use combine to do this
>    because combine would have to match the entire sequence including the
>    vector comparisons because at RTL we've lost the information that
>    VECTOR_BOOLEAN_P would have given us.  This sequence would be too long for
>    combine to match due to it having to match the compare + branch sequence
>    being generated as well.  It also becomes a bit messy to match ANY and ALL
>    sequences.
>
> 3. For SVE systems we would like to avoid generating the PTEST operation
>    whenever possible.  Because SVE vector integer comparisons already set 
> flags
>    we don't need the PTEST on an any or all check.  Eliminating this in RTL is
>    difficult, so the best approach is to not generate the PTEST at all when 
> not
>    needed.
>
> To handle these three cases the new optabs are added and the current cbranch 
> is
> no longer required if the target does not need help in distinguishing between
> boolean vector vs data vector operands.
>
> This difference is not important for correctness, but it is for optimization.
> So I've chosen not to deprecate the cbranch_optab but make it completely 
> optional.
>
> I'll try to explain why:
>
> An example is when unrolling is done on Adv. SIMD early break loops.
>
> We generate
>
>   vect__1.8_29 = MEM <vector(4) int> [(int *)_25];
>   vect__1.9_31 = MEM <vector(4) int> [(int *)_25 + 16B];
>   mask_patt_10.10_32 = vect__1.8_29 == { 124, 124, 124, 124 };
>   mask_patt_10.10_33 = vect__1.9_31 == { 124, 124, 124, 124 };
>   vexit_reduc_34 = .VEC_TRUNC_ADD_HIGH (mask_patt_10.10_33, 
> mask_patt_10.10_32);
>   if (vexit_reduc_34 != { 0, 0, 0, 0 })
>     goto <bb 4>; [5.50%]
>   else
>     goto <bb 18>; [94.50%]
>
> And so the new optabs aren't immediately useful because the comparisons can't
> be done by the optab itself.
>
> As such vec_cbranch_any would be called with vexit_reduc_34 and { 0, 0, 0, 0 }
> however since this expects to perform the comparison itself we end up with
>
>         ldp     q30, q31, [x0], 32
>         cmeq    v30.4s, v30.4s, v27.4s
>         cmeq    v31.4s, v31.4s, v27.4s
>         addhn   v31.4h, v31.4s, v30.4s
>         cmtst   v31.4h, v31.4h, v31.4h
>         fmov    x3, d31
>         cbz     x3, .L2
>
> instead of
>
>         ldp     q30, q31, [x0], 32
>         cmeq    v30.4s, v30.4s, v27.4s
>         cmeq    v31.4s, v31.4s, v27.4s
>         addhn   v31.4h, v31.4s, v30.4s
>         fmov    x3, d31
>         cbz     x3, .L2
>
> because we don't know that the value is already a boolean -1/0 value.  Without
> this we can't safely not perform the compare.
>
> The conversion is needed because e.g. it's not valid to drop the compare with
> zero when the vector just contains data:
>
> v30.8h = [ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008 ]
> cmeq   v31.8h, v30.8h, #0        // -> v31.8h = [0,0,0,0,0,0,0,0]
> umaxp  v31.4s, v31.4s, v31.4s    // pairwise-OR over 0/FFFF masks -> still 
> [0,0,0,0]
> fmov   x7, d31                   // x7 = 0
> cbnz   x7, .L6                   // NOT taken (correct: there were no zeros)
>
> vs
>
> umaxp v31.4s, v31.4s, v31.4s     // pairwise unsigned max:
>                                  //   [ max(0x00020001,0x00040003)=0x00040003,
>                                  //     
> max(0x00060005,0x00080007)=0x00080007, ... ]
> fmov  x7, d31                    // x7 = 0x0008000700040003  (non-zero)
> cbnz  x7, .L66                   // TAKEN
>
> As such, to avoid the extra compare on boolean vectors, we still need the
> cbranch_optab or the new vec_cbranch_* optabs need an extre operand to 
> indicate
> what kind of data they hold.  Note that this isn't an issue for SVE because
> SVE has BImode for booleans.
>
> With these two optabs it's trivial to implement all the optimizations I
> described above.
>
> I.e. with them we can now generate
>
> .L2:
>         ldr     q31, [x1, x2]
>         add     v29.4s, v29.4s, v25.4s
>         add     v28.4s, v28.4s, v26.4s
>         add     v31.4s, v31.4s, v30.4s
>         str     q31, [x1, x2]
>         add     x1, x1, 16
>         cmp     x1, 2560
>         beq     .L1
> .L6:
>         ldr     q30, [x3, x1]
>         cmpeq   p15.s, p7/z, z30.s, z27.s
>         b.none  .L2
>
> and easily prove it correct.
>
> Bootstrapped Regtested on aarch64-none-linux-gnu,
> arm-none-linux-gnueabihf, x86_64-pc-linux-gnu
> -m32, -m64 and no issues.
> Ok for master?
>
> Thanks,
> Tamar
>
> gcc/ChangeLog:
>
>         PR target/118974
>         * optabs.def (vec_cbranch_any_optab, vec_cbranch_all_optab,
>         cond_vec_cbranch_any_optab, cond_vec_cbranch_all_optab,
>         cond_len_vec_cbranch_any_optab, cond_len_vec_cbranch_all_optab): New.
>         * doc/md.texi: Document them.
>         * optabs.cc (prepare_cmp_insn): Refactor to take optab to check for
>         instead of hardcoded cbranch and support mask and len.
>         (emit_cmp_and_jump_insn_1, emit_cmp_and_jump_insns): Implement them.
>         (emit_conditional_move, emit_conditional_add, gen_cond_trap): Update
>         after changing function signatures to support new optabs.
>
> ---
> diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
> index 
> ae5d709bd47945272e6f45f83840e21c68bb6534..e668048a387e146b072d414168c5ed6db3707609
>  100644
> --- a/gcc/doc/md.texi
> +++ b/gcc/doc/md.texi
> @@ -7664,8 +7664,65 @@ position of Operand 1 to test.  Operand 3 is the 
> @code{code_label} to jump to.
>  Conditional branch instruction combined with a compare instruction.
>  Operand 0 is a comparison operator.  Operand 1 and operand 2 are the
>  first and second operands of the comparison, respectively.  Operand 3
> +is the @code{code_label} to jump to.  This optab is only used for 
> comparisons of
> +VECTOR_BOOLEAN_TYPE_P values and it never called for data-registers.  Data
> +vector operands should use one of the patterns below instead.
> +
> +@cindex @code{vec_cbranch_any@var{mode}} instruction pattern
> +@item @samp{vec_cbranch_any@var{mode}}
> +Conditional branch instruction based on a vector compare that branches
> +when at least one of the elementwise comparisons of the two input
> +vectors is true.
> +Operand 0 is a comparison operator.  Operand 1 and operand 2 are the
> +first and second operands of the comparison, respectively.  Operand 3
>  is the @code{code_label} to jump to.
>
> +@cindex @code{vec_cbranch_all@var{mode}} instruction pattern
> +@item @samp{vec_cbranch_all@var{mode}}
> +Conditional branch instruction based on a vector compare that branches
> +when all of the elementwise comparisons of the two input vectors is true.
> +Operand 0 is a comparison operator.  Operand 1 and operand 2 are the
> +first and second operands of the comparison, respectively.  Operand 3
> +is the @code{code_label} to jump to.
> +
> +@cindex @code{cond_vec_cbranch_any@var{mode}} instruction pattern
> +@item @samp{cond_vec_cbranch_any@var{mode}}
> +Masked conditional branch instruction based on a vector compare that branches
> +when at least one of the elementwise comparisons of the two input
> +vectors is true.
> +Operand 0 is a comparison operator.  Operand 1 is the mask operand.
> +Operand 2 and operand 3 are the first and second operands of the comparison,
> +respectively.  Operand 4 is the else value for the masked operation.
> +Operand 5 is the @code{code_label} to jump to.

Hello, I'd like to confirm that operand[4] is also a mask with the
same mode as operands[1], and each corresponding bit represents its
else value?
I notice the aarch64 backend patch defines operands[4] as
aarch64_simd_imm_zero, but it can be any mask, right?

> +
> +@cindex @code{cond_vec_cbranch_all@var{mode}} instruction pattern
> +@item @samp{cond_vec_cbranch_all@var{mode}}
> +Masked conditional branch instruction based on a vector compare that branches
> +when all of the elementwise comparisons of the two input vectors is true.
> +Operand 0 is a comparison operator.  Operand 1 is the mask operand.
> +Operand 2 and operand 3 are the first and second operands of the comparison,
> +respectively.  Operand 4 is the else value for the masked operation.
> +Operand 5 is the @code{code_label} to jump to.
> +
> +@cindex @code{cond_len_vec_cbranch_any@var{mode}} instruction pattern
> +@item @samp{cond_len_vec_cbranch_any@var{mode}}
> +Len based conditional branch instruction based on a vector compare that 
> branches
> +when at least one of the elementwise comparisons of the two input
> +vectors is true.
> +Operand 0 is a comparison operator.  Operand 1 and operand 2 are the first 
> and
> +second operands of the comparison, respectively.  Operand 3 is the len 
> operand.
> +Operand 4 is the else value for the masked operation.  Operand 5 is the
> +@code{code_label} to jump to.
> +
> +@cindex @code{cond_len_vec_cbranch_all@var{mode}} instruction pattern
> +@item @samp{cond_len_vec_cbranch_all@var{mode}}
> +Len based conditional branch instruction based on a vector compare that 
> branches
> +when all of the elementwise comparisons of the two input vectors is true.
> +Operand 0 is a comparison operator.  Operand 1 and operand 2 are the first 
> and
> +second operands of the comparison, respectively.  Operand 3 is the len 
> operand.
> +Operand 4 is the else value for the masked operation.  Operand 5 is the
> +@code{code_label} to jump to.
> +
>  @cindex @code{jump} instruction pattern
>  @item @samp{jump}
>  A jump inside a function; an unconditional branch.  Operand 0 is the
> diff --git a/gcc/optabs.cc b/gcc/optabs.cc
> index 
> 0865fc2e19aeb2b3056c8634334d6c1644a3cc96..1072239fef086e4ed959e472f299ed048fd507ad
>  100644
> --- a/gcc/optabs.cc
> +++ b/gcc/optabs.cc
> @@ -48,6 +48,8 @@ along with GCC; see the file COPYING3.  If not see
>  #include "langhooks.h"
>  #include "gimple.h"
>  #include "ssa.h"
> +#include "tree-ssa-live.h"
> +#include "tree-outof-ssa.h"
>
>  static void prepare_float_lib_cmp (rtx, rtx, enum rtx_code, rtx *,
>                                    machine_mode *);
> @@ -4405,6 +4407,9 @@ can_vec_extract_var_idx_p (machine_mode vec_mode, 
> machine_mode extr_mode)
>
>     *PMODE is the mode of the inputs (in case they are const_int).
>
> +   *OPTAB is the optab to check for OPTAB_DIRECT support.  Defaults to
> +   cbranch_optab.
> +
>     This function performs all the setup necessary so that the caller only has
>     to emit a single comparison insn.  This setup can involve doing a BLKmode
>     comparison or emitting a library call to perform the comparison if no insn
> @@ -4414,9 +4419,9 @@ can_vec_extract_var_idx_p (machine_mode vec_mode, 
> machine_mode extr_mode)
>     comparisons must have already been folded.  */
>
>  static void
> -prepare_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size,
> +prepare_cmp_insn (rtx x, rtx y, rtx *mask, enum rtx_code comparison, rtx 
> size,
>                   int unsignedp, enum optab_methods methods,
> -                 rtx *ptest, machine_mode *pmode)
> +                 rtx *ptest, machine_mode *pmode, optab optab)
>  {
>    machine_mode mode = *pmode;
>    rtx libfunc, test;
> @@ -4534,7 +4539,7 @@ prepare_cmp_insn (rtx x, rtx y, enum rtx_code 
> comparison, rtx size,
>    FOR_EACH_WIDER_MODE_FROM (cmp_mode, mode)
>      {
>        enum insn_code icode;
> -      icode = optab_handler (cbranch_optab, cmp_mode);
> +      icode = optab_handler (optab, cmp_mode);
>        if (icode != CODE_FOR_nothing
>           && insn_operand_matches (icode, 0, test))
>         {
> @@ -4566,8 +4571,8 @@ prepare_cmp_insn (rtx x, rtx y, enum rtx_code 
> comparison, rtx size,
>        /* Small trick if UNORDERED isn't implemented by the hardware.  */
>        if (comparison == UNORDERED && rtx_equal_p (x, y))
>         {
> -         prepare_cmp_insn (x, y, UNLT, NULL_RTX, unsignedp, OPTAB_WIDEN,
> -                           ptest, pmode);
> +         prepare_cmp_insn (x, y, mask, UNLT, NULL_RTX, unsignedp, 
> OPTAB_WIDEN,
> +                           ptest, pmode, optab);
>           if (*ptest)
>             return;
>         }
> @@ -4618,8 +4623,8 @@ prepare_cmp_insn (rtx x, rtx y, enum rtx_code 
> comparison, rtx size,
>         }
>
>        *pmode = ret_mode;
> -      prepare_cmp_insn (x, y, comparison, NULL_RTX, unsignedp, methods,
> -                       ptest, pmode);
> +      prepare_cmp_insn (x, y, mask, comparison, NULL_RTX, unsignedp, methods,
> +                       ptest, pmode, optab);
>      }
>
>    return;
> @@ -4657,9 +4662,10 @@ prepare_operand (enum insn_code icode, rtx x, int 
> opnum, machine_mode mode,
>     we can do the branch.  */
>
>  static void
> -emit_cmp_and_jump_insn_1 (rtx test, machine_mode mode, rtx label,
> -                         direct_optab cmp_optab, profile_probability prob,
> -                         bool test_branch)
> +emit_cmp_and_jump_insn_1 (rtx test, rtx cond, rtx inactive, machine_mode 
> mode,
> +                         rtx label, direct_optab cmp_optab,
> +                         profile_probability prob, bool test_branch,
> +                         bool len_op)
>  {
>    machine_mode optab_mode;
>    enum mode_class mclass;
> @@ -4672,12 +4678,20 @@ emit_cmp_and_jump_insn_1 (rtx test, machine_mode 
> mode, rtx label,
>
>    gcc_assert (icode != CODE_FOR_nothing);
>    gcc_assert (test_branch || insn_operand_matches (icode, 0, test));
> +  gcc_assert (cond == NULL_RTX || (cond != NULL_RTX && !test_branch));
>    if (test_branch)
>      insn = emit_jump_insn (GEN_FCN (icode) (XEXP (test, 0),
>                                             XEXP (test, 1), label));
> -  else
> +  else if (cond == NULL_RTX)
>      insn = emit_jump_insn (GEN_FCN (icode) (test, XEXP (test, 0),
>                                             XEXP (test, 1), label));
> +  else if (len_op)
> +    insn = emit_jump_insn (GEN_FCN (icode) (test, XEXP (test, 0),
> +                                           XEXP (test, 1), cond, inactive,
> +                                           label));
> +  else
> +    insn = emit_jump_insn (GEN_FCN (icode) (test, cond, XEXP (test, 0),
> +                                           XEXP (test, 1), inactive, label));
>
>    if (prob.initialized_p ()
>        && profile_status_for_fn (cfun) != PROFILE_ABSENT
> @@ -4796,22 +4810,202 @@ emit_cmp_and_jump_insns (rtx x, rtx y, enum rtx_code 
> comparison, rtx size,
>    if (unsignedp)
>      comparison = unsigned_condition (comparison);
>
> -  prepare_cmp_insn (op0, op1, comparison, size, unsignedp, OPTAB_LIB_WIDEN,
> -                   &test, &mode);
> +  /* cbranch is no longer allowed for vectors, so when using a vector mode
> +     check vec_cbranch variants instead.  */
> +  if (!VECTOR_MODE_P (GET_MODE (op0)))
> +    prepare_cmp_insn (op0, op1, NULL, comparison, size, unsignedp,
> +                     OPTAB_LIB_WIDEN, &test, &mode, cbranch_optab);
>
>    /* Check if we're comparing a truth type with 0, and if so check if
>       the target supports tbranch.  */
>    machine_mode tmode = mode;
>    direct_optab optab;
> -  if (op1 == CONST0_RTX (GET_MODE (op1))
> -      && validate_test_and_branch (val, &test, &tmode,
> -                                  &optab) != CODE_FOR_nothing)
> +  if (op1 == CONST0_RTX (GET_MODE (op1)))
>      {
> -      emit_cmp_and_jump_insn_1 (test, tmode, label, optab, prob, true);
> -      return;
> +      if (!VECTOR_MODE_P (GET_MODE (op1))
> +         && validate_test_and_branch (val, &test, &tmode,
> +                                      &optab) != CODE_FOR_nothing)
> +       {
> +         emit_cmp_and_jump_insn_1 (test, NULL_RTX, NULL_RTX, tmode, label,
> +                                   optab, prob, true, false);
> +         return;
> +       }
> +
> +      /* If we are comparing equality with 0, check if VAL is another 
> equality
> +        comparison and if the target supports it directly.  */
> +      gimple *def_stmt = NULL;
> +      if (val && TREE_CODE (val) == SSA_NAME
> +         && VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (val))
> +         && (comparison == NE || comparison == EQ)
> +         && (def_stmt = get_gimple_for_ssa_name (val)))
> +       {
> +         tree masked_op = NULL_TREE;
> +         tree len_op = NULL_TREE;
> +         tree len_else_op = NULL_TREE;
> +         /* First determine if the operation should be masked or unmasked.  
> */
> +         if (is_gimple_assign (def_stmt)
> +             && gimple_assign_rhs_code (def_stmt) == BIT_AND_EXPR)
> +           {
> +             /* See if one side if a comparison, if so use the other side as
> +                the mask.  */
> +             gimple *mask_def = NULL;
> +             tree rhs1 = gimple_assign_rhs1 (def_stmt);
> +             tree rhs2 = gimple_assign_rhs2 (def_stmt);
> +             if ((mask_def = get_gimple_for_ssa_name (rhs1))
> +                 && is_gimple_assign (mask_def)
> +                 && TREE_CODE_CLASS (gimple_assign_rhs_code (mask_def)))
> +               masked_op = rhs2;
> +             else if ((mask_def = get_gimple_for_ssa_name (rhs2))
> +                 && is_gimple_assign (mask_def)
> +                 && TREE_CODE_CLASS (gimple_assign_rhs_code (mask_def)))
> +               masked_op = rhs1;
> +
> +             if (masked_op)
> +               def_stmt = mask_def;
> +           }
> +           /* Else check to see if we're a LEN target.  */
> +         else if (is_gimple_call (def_stmt)
> +                  && gimple_call_internal_p (def_stmt)
> +                  && gimple_call_internal_fn (def_stmt) == 
> IFN_VCOND_MASK_LEN)
> +           {
> +             /* Example to consume:
> +
> +                  a = _59 != vect__4.17_75;
> +                  vcmp = .VCOND_MASK_LEN (a, { -1, ... }, { 0, ... }, _90, 
> 0);
> +                  if (vcmp != { 0, ... })
> +
> +               and transform into
> +
> +                  if (cond_len_vec_cbranch_any (a, _90, 0)).  */
> +             gcall *call = dyn_cast <gcall *> (def_stmt);
> +             tree true_branch = gimple_call_arg (call, 1);
> +             tree false_branch = gimple_call_arg (call, 2);
> +             if (integer_minus_onep (true_branch)
> +                 && integer_zerop (false_branch))
> +               {
> +                 len_op = gimple_call_arg (call, 3);
> +                 len_else_op = gimple_call_arg (call, 4);
> +
> +                 def_stmt = SSA_NAME_DEF_STMT (gimple_call_arg (call, 0));
> +               }
> +           }
> +
> +         bool cond_op = masked_op || len_op;
> +         enum insn_code icode;
> +         if (is_gimple_assign (def_stmt)
> +             && TREE_CODE_CLASS (gimple_assign_rhs_code (def_stmt))
> +                  == tcc_comparison)
> +           {
> +             class expand_operand ops[4];
> +             rtx_insn *tmp = NULL;
> +             start_sequence ();
> +             rtx op0c = expand_normal (gimple_assign_rhs1 (def_stmt));
> +             rtx op1c = expand_normal (gimple_assign_rhs2 (def_stmt));
> +             machine_mode mode2 = GET_MODE (op0c);
> +
> +             int nops = cond_op ? 4 : 2;
> +             int offset = masked_op ? 1 : 0;
> +             create_input_operand (&ops[offset + 0], op0c, mode2);
> +             create_input_operand (&ops[offset + 1], op1c, mode2);
> +             if (masked_op)
> +               {
> +                 rtx mask_op = expand_normal (masked_op);
> +                 auto mask_mode = GET_MODE (mask_op);
> +                 create_input_operand (&ops[0], mask_op, mask_mode);
> +                 create_input_operand (&ops[3], CONST0_RTX (mask_mode),
> +                                       mask_mode);
> +               }
> +             else if (len_op)
> +               {
> +                 rtx len_op2 = expand_normal (len_op);
> +                 rtx len_else_op2 = expand_normal (len_else_op);
> +                 create_input_operand (&ops[2], len_op2, GET_MODE (len_op2));
> +                 create_input_operand (&ops[3], len_else_op2,
> +                                       GET_MODE (len_else_op2));
> +               }
> +
> +             int unsignedp2 = TYPE_UNSIGNED (TREE_TYPE (val));
> +             auto inner_code = gimple_assign_rhs_code (def_stmt);
> +             rtx test2 = NULL_RTX;
> +
> +             enum rtx_code comparison2 = get_rtx_code (inner_code, 
> unsignedp2);
> +             if (unsignedp2)
> +               comparison2 = unsigned_condition (comparison2);
> +             if (comparison == NE)
> +               optab = masked_op ? cond_vec_cbranch_any_optab
> +                                 : len_op ? cond_len_vec_cbranch_any_optab
> +                                          : vec_cbranch_any_optab;
> +             else
> +               optab = masked_op ? cond_vec_cbranch_all_optab
> +                                 : len_op ? cond_len_vec_cbranch_all_optab
> +                                          : vec_cbranch_all_optab;
> +
> +             if ((icode = optab_handler (optab, mode2))
> +                 != CODE_FOR_nothing
> +                 && maybe_legitimize_operands (icode, 1, nops, ops))
> +               {
> +                 rtx cond = masked_op ? ops[0].value
> +                                      : len_op ? ops[2].value : NULL_RTX;
> +                 rtx inactive
> +                   = masked_op || len_op ? ops[3].value : NULL_RTX;
> +                 test2 = gen_rtx_fmt_ee (comparison2, VOIDmode,
> +                                         ops[offset + 0].value,
> +                                         ops[offset + 1].value);
> +                 if (insn_operand_matches (icode, 0, test2))
> +                   {
> +                     emit_cmp_and_jump_insn_1 (test2, cond, inactive, mode2,
> +                                               label, optab, prob, false,
> +                                               len_op);
> +                     tmp = get_insns ();
> +                   }
> +               }
> +
> +             end_sequence ();
> +             if (tmp)
> +               {
> +                 emit_insn (tmp);
> +                 return;
> +               }
> +           }
> +       }
> +    }
> +
> +  /*  cbranch should only be used for VECTOR_BOOLEAN_TYPE_P values.   */
> +  direct_optab base_optab = cbranch_optab;
> +  if (VECTOR_MODE_P (GET_MODE (op0)))
> +    {
> +      /* If cbranch is provided, use it.  If we get here it means we have an
> +        instruction in between what created the boolean value and the gcond
> +        that is not a masking operation.  This can happen for instance during
> +        unrolling of early-break where we have an OR-reduction to reduce the
> +        masks.  In this case knowing we have a mask can let us generate 
> better
> +        code.  If it's not there there then check the vector specific
> +        optabs.  */
> +      if (optab_handler (cbranch_optab, mode) == CODE_FOR_nothing)
> +       {
> +         if (comparison == NE)
> +           base_optab = vec_cbranch_any_optab;
> +         else
> +           base_optab = vec_cbranch_all_optab;
> +
> +         prepare_cmp_insn (op0, op1, NULL, comparison, size, unsignedp,
> +                           OPTAB_DIRECT, &test, &mode, base_optab);
> +
> +         enum insn_code icode = optab_handler (base_optab, mode);
> +
> +         /* If the new cbranch isn't supported, degrade back to old one.  */
> +         if (icode == CODE_FOR_nothing
> +             || !test
> +             || !insn_operand_matches (icode, 0, test))
> +           base_optab = cbranch_optab;
> +       }
> +
> +      prepare_cmp_insn (op0, op1, NULL, comparison, size, unsignedp,
> +                       OPTAB_LIB_WIDEN, &test, &mode, base_optab);
>      }
>
> -  emit_cmp_and_jump_insn_1 (test, mode, label, cbranch_optab, prob, false);
> +  emit_cmp_and_jump_insn_1 (test, NULL_RTX, NULL_RTX, mode, label, 
> base_optab,
> +                           prob, false, false);
>  }
>
>  /* Overloaded version of emit_cmp_and_jump_insns in which VAL is unknown.  */
> @@ -5099,9 +5293,9 @@ emit_conditional_move (rtx target, struct 
> rtx_comparison comp,
>               else if (rtx_equal_p (orig_op1, op3))
>                 op3p = XEXP (comparison, 1) = force_reg (cmpmode, orig_op1);
>             }
> -         prepare_cmp_insn (XEXP (comparison, 0), XEXP (comparison, 1),
> +         prepare_cmp_insn (XEXP (comparison, 0), XEXP (comparison, 1), NULL,
>                             GET_CODE (comparison), NULL_RTX, unsignedp,
> -                           OPTAB_WIDEN, &comparison, &cmpmode);
> +                           OPTAB_WIDEN, &comparison, &cmpmode, 
> cbranch_optab);
>           if (comparison)
>             {
>                rtx res = emit_conditional_move_1 (target, comparison,
> @@ -5316,9 +5510,9 @@ emit_conditional_add (rtx target, enum rtx_code code, 
> rtx op0, rtx op1,
>
>    do_pending_stack_adjust ();
>    last = get_last_insn ();
> -  prepare_cmp_insn (XEXP (comparison, 0), XEXP (comparison, 1),
> -                    GET_CODE (comparison), NULL_RTX, unsignedp, OPTAB_WIDEN,
> -                    &comparison, &cmode);
> +  prepare_cmp_insn (XEXP (comparison, 0), XEXP (comparison, 1), NULL,
> +                   GET_CODE (comparison), NULL_RTX, unsignedp, OPTAB_WIDEN,
> +                   &comparison, &cmode, cbranch_optab);
>    if (comparison)
>      {
>        class expand_operand ops[4];
> @@ -6132,8 +6326,8 @@ gen_cond_trap (enum rtx_code code, rtx op1, rtx op2, 
> rtx tcode)
>
>    do_pending_stack_adjust ();
>    start_sequence ();
> -  prepare_cmp_insn (op1, op2, code, NULL_RTX, false, OPTAB_DIRECT,
> -                   &trap_rtx, &mode);
> +  prepare_cmp_insn (op1, op2, NULL, code, NULL_RTX, false, OPTAB_DIRECT,
> +                   &trap_rtx, &mode, cbranch_optab);
>    if (!trap_rtx)
>      insn = NULL;
>    else
> diff --git a/gcc/optabs.def b/gcc/optabs.def
> index 
> b6f290a95130cd53e94af2249c02a53f01ca3890..371514f3dbe41f1336475f99d1b837c24fa3b818
>  100644
> --- a/gcc/optabs.def
> +++ b/gcc/optabs.def
> @@ -268,6 +268,8 @@ OPTAB_D (cond_fms_optab, "cond_fms$a")
>  OPTAB_D (cond_fnma_optab, "cond_fnma$a")
>  OPTAB_D (cond_fnms_optab, "cond_fnms$a")
>  OPTAB_D (cond_neg_optab, "cond_neg$a")
> +OPTAB_D (cond_vec_cbranch_any_optab, "cond_vec_cbranch_any$a")
> +OPTAB_D (cond_vec_cbranch_all_optab, "cond_vec_cbranch_all$a")
>  OPTAB_D (cond_one_cmpl_optab, "cond_one_cmpl$a")
>  OPTAB_D (cond_len_add_optab, "cond_len_add$a")
>  OPTAB_D (cond_len_sub_optab, "cond_len_sub$a")
> @@ -295,6 +297,8 @@ OPTAB_D (cond_len_fnma_optab, "cond_len_fnma$a")
>  OPTAB_D (cond_len_fnms_optab, "cond_len_fnms$a")
>  OPTAB_D (cond_len_neg_optab, "cond_len_neg$a")
>  OPTAB_D (cond_len_one_cmpl_optab, "cond_len_one_cmpl$a")
> +OPTAB_D (cond_len_vec_cbranch_any_optab, "cond_len_vec_cbranch_any$a")
> +OPTAB_D (cond_len_vec_cbranch_all_optab, "cond_len_vec_cbranch_all$a")
>  OPTAB_D (vcond_mask_len_optab, "vcond_mask_len_$a")
>  OPTAB_D (cstore_optab, "cstore$a4")
>  OPTAB_D (ctrap_optab, "ctrap$a4")
> @@ -427,6 +431,8 @@ OPTAB_D (smulhrs_optab, "smulhrs$a3")
>  OPTAB_D (umulhs_optab, "umulhs$a3")
>  OPTAB_D (umulhrs_optab, "umulhrs$a3")
>  OPTAB_D (sdiv_pow2_optab, "sdiv_pow2$a3")
> +OPTAB_D (vec_cbranch_any_optab, "vec_cbranch_any$a")
> +OPTAB_D (vec_cbranch_all_optab, "vec_cbranch_all$a")
>  OPTAB_D (vec_pack_sfix_trunc_optab, "vec_pack_sfix_trunc_$a")
>  OPTAB_D (vec_pack_ssat_optab, "vec_pack_ssat_$a")
>  OPTAB_D (vec_pack_trunc_optab, "vec_pack_trunc_$a")
>
>
> --



-- 
BR,
Hongtao

Reply via email to