On Mon, Sep 14, 2026 at 2:32 AM Tamar Christina <[email protected]> wrote:
>
> This patch forms conditional vector compare IFNs during gimple isel.
>
> The match.pd rules recognize integer vector compare idioms where a compare is
> guarded by another vector predicate.  gimple isel then lowers those idioms to
> IFN_COND_VEC_CMP or IFN_COND_LEN_VEC_CMP when the target reports support for
> the corresponding optab.  If the original compare was only used by the
> converted statement, the patch removes that now-dead definition.
>
> The tests for this lowering are kept with the later AArch64 SVE expander
> patch, since they require the SVE cond_vec_cmp target support added there.
>
> Bootstrapped Regtested on aarch64-none-linux-gnu,
> arm-none-linux-gnueabihf, x86_64-pc-linux-gnu
> -m32, -m64 and no issues.
>
> -O3, profiled, profiled -O3 and -O3 -LTO bootstrap tested and no issues.
>
>  Also SPECCPU 2017 and SPECCPU 2026 tested.
>
> OK for master?
>
> gcc/ChangeLog:
>         * gimple-isel.cc (gimple_convert_conditional_compare): Declare.
>         (gimple_convert_conditional_len_compare): Likewise.
>         (maybe_duplicate_comparison): Fix comment.
>         (gimple_expand_conditional_compare): New function.
>         (pass_gimple_isel::execute): Use it.
>         * match.pd (convert_conditional_compare): New match.
>         (convert_conditional_len_compare): Likewise.
>
> ---
> diff --git a/gcc/gimple-isel.cc b/gcc/gimple-isel.cc
> index 
> 1d346ee124ffdfdccf658ea79cc72cbf80240f81..9bd523cd81be541383ea9c962a9180565cea9f0d
>  100644
> --- a/gcc/gimple-isel.cc
> +++ b/gcc/gimple-isel.cc
> @@ -327,8 +327,8 @@ maybe_duplicate_comparison (gassign *stmt, basic_block bb)
>    tree lhs = gimple_assign_lhs (stmt);
>    unsigned cnt = 0;
>
> -  /* This is should not be used for -O0 nor it is not useful
> -     when ter is turned off. */
> +  /* This should not be used for -O0 and is not useful when TER is turned
> +     off.  */
>    if (!optimize || !flag_tree_ter)
>      return;
>
> @@ -376,6 +376,9 @@ maybe_duplicate_comparison (gassign *stmt, basic_block bb)
>  extern bool gimple_nop_atomic_bit_test_and_p (tree, tree *,
>                                               tree (*) (tree));
>  extern bool gimple_nop_convert (tree, tree*, tree (*) (tree));
> +extern bool gimple_convert_conditional_compare (tree, tree *, tree (*) 
> (tree));
> +extern bool gimple_convert_conditional_len_compare (tree, tree *,
> +                                                  tree (*) (tree));
>
>  namespace {
>
> @@ -488,6 +491,74 @@ convert_atomic_bit_not (enum internal_fn fn, gimple 
> *use_stmt,
>    return use_stmt;
>  }
>
> +/* Try to replace STMT with a conditional vector comparison internal 
> function.
> +   The generated matchers recognize the source patterns and capture the mask,
> +   operands and original comparison SSA name.  If the original comparison is
> +   used only by STMT, store its defining statement in *DEAD_CMP_DEF so that 
> the
> +   caller can remove it after replacing STMT.  */
> +
> +static gimple *
> +gimple_expand_conditional_compare (gimple_stmt_iterator *gsi,
> +                                  gassign **dead_cmp_def)
> +{
> +  gimple *stmt = gsi_stmt (*gsi);
> +  *dead_cmp_def = nullptr;
> +  tree lhs = gimple_get_lhs (stmt);
> +
> +  if (!lhs || TREE_CODE (lhs) != SSA_NAME)
> +    return nullptr;
> +
> +  tree ops[6] = {};
> +  location_t loc = gimple_location (stmt);
> +  bool len_p = false;
> +  if (!gimple_convert_conditional_compare (lhs, ops, nullptr)
> +      && !gimple_convert_conditional_len_compare (lhs, ops, nullptr))
> +    return nullptr;
> +  len_p = ops[4] != NULL_TREE;
> +
> +  unsigned int cmp_opno = len_p ? 5 : 3;
> +  tree cmp_name = ops[cmp_opno];
> +  if (TREE_CODE (cmp_name) != SSA_NAME)
> +    return nullptr;
> +
> +  gassign *cmp_def = dyn_cast<gassign *> (SSA_NAME_DEF_STMT (cmp_name));
> +  if (!cmp_def)
> +    return nullptr;
> +
> +  tree_code code = gimple_assign_rhs_code (cmp_def);
> +  if (TREE_CODE_CLASS (code) != tcc_comparison)
> +    return nullptr;
> +
> +  internal_fn ifn = len_p ? IFN_COND_LEN_VEC_CMP : IFN_COND_VEC_CMP;
> +  bool supported_p
> +    = (len_p
> +       ? expand_cond_len_vec_cmp_p (code, ops[0], ops[1], ops[2],
> +                                   ops[3], ops[4])
> +       : expand_cond_vec_cmp_p (code, ops[0], ops[1], ops[2]));
> +  if (!supported_p)
> +    return nullptr;
> +
> +  auto_vec<tree, 6> args;
> +  args.quick_push (build_int_cst (integer_type_node, code));
> +  args.quick_push (ops[0]);
> +  args.quick_push (ops[1]);
> +  args.quick_push (ops[2]);
> +  if (len_p)
> +    {
> +      args.quick_push (ops[3]);
> +      args.quick_push (ops[4]);
> +    }
> +
> +  gcall *call = gimple_build_call_internal_vec (ifn, args);
> +  gimple_call_set_lhs (call, lhs);
> +  gimple_set_location (call, loc);
> +  use_operand_p use_p;
> +  gimple *use_stmt;
> +  if (single_imm_use (cmp_name, &use_p, &use_stmt) && use_stmt == stmt)
> +    *dead_cmp_def = cmp_def;
> +  return call;
> +}
> +
>  /* Optimize
>       mask_2 = 1 << cnt_1;
>       _4 = __atomic_fetch_or_* (ptr_6, mask_2, _3);
> @@ -1369,6 +1440,20 @@ pass_gimple_isel::execute (struct function *fun)
>           /* Give the target first try at replacing the instruction.  */
>           cfg_changed |= targetm.instruction_selection (fun, &gsi);
>
> +         gimple *isel_stmt = NULL;
> +         gassign *dead_cmp_def = NULL;
> +         if (!gsi_end_p (gsi))
> +           isel_stmt = gimple_expand_conditional_compare (&gsi, 
> &dead_cmp_def);
> +         if (isel_stmt)
> +           {
> +             gsi_replace (&gsi, isel_stmt, true);
> +             if (dead_cmp_def)
> +               {
> +                 gimple_stmt_iterator cmp_gsi = gsi_for_stmt (dead_cmp_def);
> +                 gsi_remove (&cmp_gsi, true);
> +               }
> +           }
> +
>           /* Pre-expand VEC_COND_EXPRs to .VCOND* internal function
>              calls mapping to supported optabs.  */
>           gimple *g = gimple_expand_vec_cond_expr (&gsi);
> @@ -1411,4 +1496,3 @@ make_pass_gimple_isel (gcc::context *ctxt)
>  {
>    return new pass_gimple_isel (ctxt);
>  }
> -
> diff --git a/gcc/match.pd b/gcc/match.pd
> index 
> c1aba410b66e38c947a4d52064fda1594934f297..db5038b7dccd030a09b67d5070a2ce2b74651184
>  100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -13364,3 +13364,20 @@ and,
>   (if (INTEGRAL_TYPE_P (type))
>     (with { tree itype = TREE_TYPE (@2); }
>      (convert (minus @2 (convert:itype @1))))))
> +
> +#if GIMPLE
> +
> +(for cmp (tcc_comparison)
> + (match (convert_conditional_compare @0 @1 @2 @3)
> +  (bit_and:c @0 (cmp@3 @1 @2))
> +  (if (VECTOR_BOOLEAN_TYPE_P (type)
> +       && !FLOAT_TYPE_P (TREE_TYPE (@1)))))

Just a minor thing here.  You don't need to use a for loop, you can
use tcc_comparison directly.
So this becomes:
(match (convert_conditional_compare @0 @1 @2 @3)
  (bit_and:c @0 (tcc_comparison@3 @1 @2))
   (if (VECTOR_BOOLEAN_TYPE_P (type)
        && !FLOAT_TYPE_P (TREE_TYPE (@1)))))

> +
> +/* Transform .VCOND_MASK_LEN (a `cmp` b, {-1, ...}, {0, ...}, len, bias)
> +   into cond_len_vec_cmp (cmp, mask, a, b, len, bias).  */
> + (match (convert_conditional_len_compare @0 @1 @2 @3 @4 @5)
> +  (IFN_VCOND_MASK_LEN @0 (cmp@5 @1 @2) integer_minus_onep integer_zerop @3 
> @4)
> +  (if (VECTOR_BOOLEAN_TYPE_P (type)
> +       && !FLOAT_TYPE_P (TREE_TYPE (@1))))))

Likewise.

Thanks,
Andrea

> +
> +#endif
>
>
> --

Reply via email to