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
>
>
> --