On Mon, 15 Sep 2025, Avinash Jayakar wrote:
> Hello Richard,
>
> Thank you for reviewing the patch! I have made changes based on your
> comments, but I have some doubts for a few comments as mentioned below.
>
> On Thu, 2025-09-11 at 13:08 +0200, Richard Biener wrote:
> > On Wed, 10 Sep 2025, Avinash Jayakar wrote:
> > > + bool unsignedp = TYPE_UNSIGNED (itype) && (tree_int_cst_sgn
> > > (oprnd1) > 0);
> > > +
> > > + if (unsignedp)
> > > + {
> > > + switch (rhs_code)
> > > + {
> > > + case FLOOR_DIV_EXPR:
> > > + rhs_code = TRUNC_DIV_EXPR;
> > > + break;
> > > + case FLOOR_MOD_EXPR:
> > > + rhs_code = TRUNC_MOD_EXPR;
> > > + break;
> >
> > I would have expected this to be already done on gimple, in
> > a more generic way by
> >
> > /* For unsigned integral types, FLOOR_DIV_EXPR is the same as
> > TRUNC_DIV_EXPR. Rewrite into the latter in this case. Similarly
> > for MOD instead of DIV. */
> > (for floor_divmod (floor_div floor_mod)
> > trunc_divmod (trunc_div trunc_mod)
> > (simplify
> > (floor_divmod @0 @1)
> > (if ((INTEGRAL_TYPE_P (type) || VECTOR_INTEGER_TYPE_P (type))
> > && TYPE_UNSIGNED (type))
> > (trunc_divmod @0 @1))))
> >
>
> I think this happens only if types for both operands is of integer
> type. But in this particular case operand #1 is a constant so I think
> this rule is not working for that case.
A constant also has a type and for binary ops the types of the
operands and the result agrees.
> bool unsignedp = TYPE_UNSIGNED (itype) && (tree_int_cst_sgn
> (oprnd1) > 0);
> This line however checks if operand #1 > 0, the previous checks in this
> function also makes sure that operand #1 must be a constant, else this
> pattern returns NULL.
That extra tree_int_cst_sgn (oprnd1) > 0 simply makes sure this isn't
division by zero. So as said, you shouldn't see an unsigned
floor_div/mod.
> > You are emitting code that might not be vectorizable and which needs
> > post-processing with bool vector patterns. So you should
> >
> > 1) use the appropriate precision scalar bools, anticipating the
> > vector
> > mask type used
> > 2) check at least whether the compares are supported, I think we can
> > rely on bit operations suppoort
>
> I have limited COND_EXPR stmt in the following code to just 1 stmt.
> Also added checks to see all used operations are supported for the
> target.
> I did not understand point 1), would it still be valid if I use only
> the result of LT_EXPR only as the input for COND_EXPR as in the below
> code?
> if (rhs_code == FLOOR_MOD_EXPR)
> {
> if (!target_has_vecop_for_code(NEGATE_EXPR, vectype)
> || !target_has_vecop_for_code(BIT_XOR_EXPR, vectype)
> || !target_has_vecop_for_code(LT_EXPR, vectype)
> || !target_has_vecop_for_code(BIT_IOR_EXPR, vectype)
> || !target_has_vecop_for_code(COND_EXPR, vectype)
this check isn't going to work and will always fail.
The same is true for LT_EXPR.
> || !target_has_vecop_for_code(PLUS_EXPR, vectype)
> )
> return NULL;
>
> append_pattern_def_seq (vinfo, stmt_vinfo, pattern_stmt);
> // r = x %[fl] y;
> // is
> // r = x % y; if (r && (x ^ y) < 0) r += y;
> // Produce following sequence
> // v0 = x^y
> // v1 = -r
> // v2 = r | -r
> // v3 = v0 & v2
> // v4 = v3 < 0 (equivalent to (r && (x ^ y) < 0))
> // v5 = v4 ? y : 0
> // v6 = r + v5 (final result)
> tree cond_reg = vect_recog_temp_ssa_var(itype, NULL);
> def_stmt = gimple_build_assign(cond_reg, BIT_XOR_EXPR, oprnd0,
> oprnd1);
> append_pattern_def_seq (vinfo, stmt_vinfo, def_stmt);
>
> // -r
> tree negate_r = vect_recog_temp_ssa_var(itype, NULL);
> def_stmt = gimple_build_assign(negate_r, NEGATE_EXPR, r);
> append_pattern_def_seq (vinfo, stmt_vinfo, def_stmt);
>
> // r | -r , sign bit is set if r!=0
> tree r_or_negr = vect_recog_temp_ssa_var(itype, NULL);
> def_stmt = gimple_build_assign(r_or_negr, BIT_IOR_EXPR, r,
> negate_r);
> append_pattern_def_seq (vinfo, stmt_vinfo, def_stmt);
>
> // (x^y) & (r|-r)
> tree r_or_negr_and_xor = vect_recog_temp_ssa_var(itype, NULL);
> def_stmt = gimple_build_assign(r_or_negr_and_xor, BIT_AND_EXPR,
> r_or_negr,
> cond_reg);
> append_pattern_def_seq (vinfo, stmt_vinfo, def_stmt);
>
> // (x^y) & (r|-r) < 0 which is equivalent to (x^y < 0 && r!=0)
> tree bool_cond = vect_recog_temp_ssa_var(boolean_type_node,
> NULL);
So what I meant with 1) is that here you should do sth like
tree mask_vectype = truth_type_for (vectype);
if (!mask_vectype)
return NULL;
and for compaes use the TREE_TYPE (mask_vectype) component
type for the scalar result of the LT_EXPR and as the first
operand of COND_EXPRs.
You need to verify expand_vec_cmp_expr_p (vectype, mask_vectype, LT_EXPR)
and expand_vec_cond_expr_p (vectype, mask_vectype) for the COND_EXPR.
> def_stmt = gimple_build_assign(bool_cond, LT_EXPR,
> r_or_negr_and_xor,
> build_int_cst(itype, 0));
> append_pattern_def_seq (vinfo, stmt_vinfo, def_stmt,
> truth_type_for(vectype), itype);
>
> // (x^y < 0 && r) ? y : 0
> tree extr_cond = vect_recog_temp_ssa_var(itype, NULL);
> def_stmt = gimple_build_assign(extr_cond, COND_EXPR, bool_cond,
> oprnd1,
> build_int_cst(itype, 0));
> append_pattern_def_seq (vinfo, stmt_vinfo, def_stmt);
>
> // r += (x ^ y < 0 && r) ? y : 0
> tree floor_mod_r = vect_recog_temp_ssa_var(itype, NULL);
> pattern_stmt = gimple_build_assign(floor_mod_r, PLUS_EXPR, r,
> extr_cond);
> }
>
> Thanks and regards,
> Avinash Jayakar
>
--
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)