On Mon, Oct 20, 2025 at 3:10 PM <[email protected]> wrote:
>
> From: Pan Li <[email protected]>
>
> This patch would like to try to match the the unsigned
> SAT_MUL form 7, aka below:
>
> #define DEF_SAT_U_MUL_FMT_7(NT, WT) \
> NT __attribute__((noinline)) \
> sat_u_mul_##NT##_from_##WT##_fmt_7 (NT a, NT b) \
> { \
> WT x = (WT)a * (WT)b; \
> NT max = -1; \
> bool overflow_p = x > (WT)(max); \
> return -(NT)(overflow_p) | (NT)x; \
> }
>
> while WT is uint128_t, uint64_t, uint32_t and uint16_t, and
> NT is uint64_t, uint32_t, uint16_t or uint8_t.
>
> gcc/ChangeLog:
>
> * match.pd: Add pattern for SAT_MUL form 5 include
> mul and widen_mul.
>
> Signed-off-by: Pan Li <[email protected]>
> ---
> gcc/match.pd | 35 +++++++++++++++++++++++++++++++++++
> 1 file changed, 35 insertions(+)
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index bfc51e6579a..0f55a82d989 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -3749,6 +3749,41 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> bool widen_mult_p = prec * 2 == widen_prec;
> }
> (if (c2_is_type_precision_p && widen_mult_p)))))
> + (for mult_op (mult widen_mult)
I'm a bit confused as to this for and the explicit widen_mult case in the 2nd
pattern below. In fact, the patterns look similar enough to me and I wonder
whether the consumer can handle the outer conversion and the conversion
of the leafs of the multiplication? The conversion of the leafs doesn't have
any constraints, nor is it obvious why there's an outer conversion around the
IOR.
> + (match (unsigned_integer_sat_mul @0 @1)
> + (convert?
> + (bit_ior (negate (convert (gt @3 INTEGER_CST@2)))
> + (convert (mult_op:c@3 (convert@4 @0) (convert@5 @1)))))
> + (if (types_match (type, @0, @1))
> + (with
> + {
> + unsigned prec = TYPE_PRECISION (type);
> + unsigned widen_prec = TYPE_PRECISION (TREE_TYPE (@3));
> + unsigned cvt4_prec = TYPE_PRECISION (TREE_TYPE (@4));
> + unsigned cvt5_prec = TYPE_PRECISION (TREE_TYPE (@5));
> +
> + wide_int max = wi::mask (prec, false, widen_prec);
> + bool c2_is_max_p = wi::eq_p (wi::to_wide (@2), max);
> + bool widen_mult_p = mult_op == WIDEN_MULT_EXPR && cvt4_prec ==
> cvt5_prec
> + && widen_prec == cvt5_prec * 2;
> + bool mult_p = mult_op == MULT_EXPR && cvt4_prec == cvt5_prec
> + && cvt4_prec == widen_prec && widen_prec > prec;
> + }
> + (if (c2_is_max_p && (mult_p || widen_mult_p)))))))
> + (match (unsigned_integer_sat_mul @0 @1)
> + (bit_ior (negate (convert (gt @3 INTEGER_CST@2)))
> + (convert (widen_mult:c@3 @0 @1)))
> + (if (types_match (type, @0, @1))
> + (with
> + {
> + unsigned prec = TYPE_PRECISION (type);
> + unsigned widen_prec = TYPE_PRECISION (TREE_TYPE (@3));
> +
> + wide_int max = wi::mask (prec, false, widen_prec);
> + bool c2_is_max_p = wi::eq_p (wi::to_wide (@2), max);
> + bool widen_mult_p = prec * 2 == widen_prec;
> + }
> + (if (c2_is_max_p && widen_mult_p)))))
> )
>
> /* The boundary condition for case 10: IMM = 1:
> --
> 2.43.0
>