Hi Richard, Thanks for the review.
On 1 June 2018 at 22:20, Richard Biener <richard.guent...@gmail.com> wrote: > On Fri, Jun 1, 2018 at 4:12 AM Kugan Vivekanandarajah > <kugan.vivekanandara...@linaro.org> wrote: >> >> Hi Richard, >> >> This is the revised patch based on the review and the discussion in >> https://gcc.gnu.org/ml/gcc/2018-05/msg00179.html. >> >> In summary: >> - I skipped (element_precision (type) < element_precision (TREE_TYPE >> (@0))) in the match.pd pattern as this would prevent transformation >> for the case in PR. >> that is, I am interested in is something like: >> char t = (char) ABS_EXPR <(int) x> >> and I want to generate >> char t = (char) ABSU_EXPR <x> >> >> - I also haven't added all the necessary match.pd changes for >> ABSU_EXPR. I have a patch for that but will submit separately based on >> this reveiw. >> >> - I also tried to add ABSU_EXPRsupport in the places as necessary by >> grepping for ABS_EXPR. >> >> - I also had to add special casing in vectorizer for ABSU_EXP as its >> result is unsigned type. >> >> Is this OK. Patch bootstraps and the regression test is ongoing. > > The c/c-typeck.c:build_unary_op change looks unnecessary - the > C FE should never generate this directly (the c-common one might > be triggered by early folding I guess). The Gimple FE testcase is running into this. > > @@ -1761,6 +1762,9 @@ const_unop (enum tree_code code, tree type, tree arg0) > if (TREE_CODE (arg0) == INTEGER_CST || TREE_CODE (arg0) == REAL_CST) > return fold_abs_const (arg0, type); > break; > + case ABSU_EXPR: > + return fold_convert (type, fold_abs_const (arg0, > + signed_type_for (type))); > > case CONJ_EXPR: > > I think this will get you bogus TREE_OVERFLOW flags set on ABSU (-INT_MIN). > > I think you want to change fold_abs_const to properly deal with arg0 being > signed and type unsigned. That is, sth like > > diff --git a/gcc/fold-const.c b/gcc/fold-const.c > index 6f80f1b1d69..f60f9c77e91 100644 > --- a/gcc/fold-const.c > +++ b/gcc/fold-const.c > @@ -13843,18 +13843,19 @@ fold_abs_const (tree arg0, tree type) > { > /* If the value is unsigned or non-negative, then the absolute value > is the same as the ordinary value. */ > - if (!wi::neg_p (wi::to_wide (arg0), TYPE_SIGN (type))) > - t = arg0; > + wide_int val = wi::to_wide (arg0); > + bool overflow = false; > + if (!wi::neg_p (val, TYPE_SIGN (TREE_TYPE (arg0)))) > + ; > > /* If the value is negative, then the absolute value is > its negation. */ > else > - { > - bool overflow; > - wide_int val = wi::neg (wi::to_wide (arg0), &overflow); > - t = force_fit_type (type, val, -1, > - overflow | TREE_OVERFLOW (arg0)); > - } > + wide_int val = wi::neg (val, &overflow); > + > + /* Force to the destination type, set TREE_OVERFLOW for signed > + TYPE only. */ > + t = force_fit_type (type, val, 1, overflow | TREE_OVERFLOW (arg0)); > } > break; > > and then simply share the const_unop code with ABS_EXPR. Done. > diff --git a/gcc/match.pd b/gcc/match.pd > index 14386da..7d7c132 100644 > --- a/gcc/match.pd > +++ b/gcc/match.pd > @@ -102,6 +102,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > (match (nop_convert @0) > @0) > > +(simplify (abs (convert @0)) > + (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0)) > + && !TYPE_UNSIGNED (TREE_TYPE (@0)) > + && !TYPE_UNSIGNED (type)) > + (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); } > + (convert (absu:utype @0))))) > + > + > > please put a comment before the pattern. I believe there's no > need to check for !TYPE_UNSIGNED (type). Note this > also converts abs ((char)int-var) to (char)absu(int-var) which > doesn't make sense. The original issue you want to address > here is the case where TYPE_PRECISION of @0 is less than > the precision of type. That is, you want to remove language > introduced integer promotion of @0 which only is possible > with ABSU. So please do add such precision check > (I simply suggested the bogus direction of the test). Done. > > diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c > index 68f4fd3..9b62583 100644 > --- a/gcc/tree-cfg.c > +++ b/gcc/tree-cfg.c > @@ -3685,6 +3685,12 @@ verify_gimple_assign_unary (gassign *stmt) > case PAREN_EXPR: > case CONJ_EXPR: > break; > + case ABSU_EXPR: > + if (!TYPE_UNSIGNED (lhs_type) > + || !ANY_INTEGRAL_TYPE_P (rhs1_type)) > > if (!ANY_INTEGRAL_TYPE_P (lhs_type) > || !TYPE_UNSIGNED (lhs_type) > || !ANY_INTEGRAL_TYPE_P (rhs1_type) > || TYPE_UNSIGNED (rhs1_type) > || element_precision (lhs_type) != element_precision (rhs1_type)) > { > error ("invalid types for ABSU_EXPR"); > debug_generic_expr (lhs_type); > debug_generic_expr (rhs1_type); > return true; > } > > + return true; > + return false; > + break; > > diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c > index 30c6d9e..44b1399 100644 > --- a/gcc/tree-eh.c > +++ b/gcc/tree-eh.c > @@ -2465,6 +2465,7 @@ operation_could_trap_helper_p (enum tree_code op, > > case NEGATE_EXPR: > case ABS_EXPR: > + case ABSU_EXPR: > case CONJ_EXPR: > /* These operations don't trap with floating point. */ > if (honor_trapv) > > ABSU never traps. Please instead unconditionally return false. Done. > > diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c > index 66c78de..b52d714 100644 > --- a/gcc/tree-vect-stmts.c > +++ b/gcc/tree-vect-stmts.c > @@ -5995,7 +5995,11 @@ vectorizable_operation (gimple *stmt, > gimple_stmt_iterator *gsi, > "transform binary/unary operation.\n"); > > /* Handle def. */ > - vec_dest = vect_create_destination_var (scalar_dest, vectype); > + if (code == ABSU_EXPR) > + vec_dest = vect_create_destination_var (scalar_dest, > + unsigned_type_for (vectype)); > + else > + vec_dest = vect_create_destination_var (scalar_dest, vectype); > > /* POINTER_DIFF_EXPR has pointer arguments which are vectorized as > vectors with unsigned elements, but the result is signed. So, we > > simply use vectype_out for creation of vec_dest. Done. > > diff --git a/gcc/tree.def b/gcc/tree.def > index c660b2c..5fec781 100644 > --- a/gcc/tree.def > +++ b/gcc/tree.def > @@ -760,6 +760,7 @@ DEFTREECODE (MAX_EXPR, "max_expr", tcc_binary, 2) > An ABS_EXPR must have either an INTEGER_TYPE or a REAL_TYPE. The > operand of the ABS_EXPR must have the same type. */ > DEFTREECODE (ABS_EXPR, "abs_expr", tcc_unary, 1) > +DEFTREECODE (ABSU_EXPR, "absu_expr", tcc_unary, 1) > > /* Shift operations for shift and rotate. > Shift means logical shift if done on an > > You can clearly see that the comment before ABS_EXPR doesn't apply to > ABSU_EXPR > so please add an appropriate one. I suggest > > /* Represents the unsigned absolute value of the operand. > An ABSU_EXPR must have unsigned INTEGER_TYPE. The operand of the > ABSU_EXPR > must have the corresponding signed type. */ Done. Here is the reviesed patch. Is this OK? Thanks, Kugan > > Otherwise looks OK. (I didn't explicitely check for missing ABSU_EXPR > handling this time) > > Thanks, > Richard. > > >> Thanks, >> Kugan >> >> >> On 18 May 2018 at 12:36, Kugan Vivekanandarajah >> <kugan.vivekanandara...@linaro.org> wrote: >> > Hi Richard, >> > >> > Thanks for the review. I am revising the patch based on Andrew's comments >> > too. >> > >> > On 17 May 2018 at 20:36, Richard Biener <richard.guent...@gmail.com> wrote: >> >> On Thu, May 17, 2018 at 4:56 AM Andrew Pinski <pins...@gmail.com> wrote: >> >> >> >>> On Wed, May 16, 2018 at 7:14 PM, Kugan Vivekanandarajah >> >>> <kugan.vivekanandara...@linaro.org> wrote: >> >>> > As mentioned in the PR, I am trying to add ABSU_EXPR to fix this >> >>> > issue. In the attached patch, in fold_cond_expr_with_comparison I am >> >>> > generating ABSU_EXPR for these cases. As I understand, absu_expr is >> >>> > well defined in RTL. So, the issue is generating absu_expr and >> >>> > transferring to RTL in the correct way. I am not sure I am not doing >> >>> > all that is needed. I will clean up and add more test-cases based on >> >>> > the feedback. >> >> >> >> >> >>> diff --git a/gcc/optabs-tree.c b/gcc/optabs-tree.c >> >>> index 71e172c..2b812e5 100644 >> >>> --- a/gcc/optabs-tree.c >> >>> +++ b/gcc/optabs-tree.c >> >>> @@ -235,6 +235,7 @@ optab_for_tree_code (enum tree_code code, const_tree >> >> type, >> >>> return trapv ? negv_optab : neg_optab; >> >> >> >>> case ABS_EXPR: >> >>> + case ABSU_EXPR: >> >>> return trapv ? absv_optab : abs_optab; >> >> >> >> >> >>> This part is not correct, it should something like this: >> >> >> >>> case ABS_EXPR: >> >>> return trapv ? absv_optab : abs_optab; >> >>> + case ABSU_EXPR: >> >>> + return abs_optab ; >> >> >> >>> Because ABSU is not undefined at the TYPE_MAX. >> >> >> >> Also >> >> >> >> /* Unsigned abs is simply the operand. Testing here means we >> >> don't >> >> risk generating incorrect code below. */ >> >> - if (TYPE_UNSIGNED (type)) >> >> + if (TYPE_UNSIGNED (type) >> >> + && (code != ABSU_EXPR)) >> >> return op0; >> >> >> >> is wrong. ABSU of an unsigned number is still just that number. >> >> >> >> The change to fold_cond_expr_with_comparison looks odd to me >> >> (premature optimization). It should be done separately - it seems >> >> you are doing >> > >> > FE seems to be using this to generate ABS_EXPR from >> > c_fully_fold_internal to fold_build3_loc and so on. I changed this to >> > generate ABSU_EXPR for the case in the testcase. So the question >> > should be, in what cases do we need ABS_EXPR and in what cases do we >> > need ABSU_EXPR. It is not very clear to me. >> > >> > >> >> >> >> (simplify (abs (convert @0)) (convert (absu @0))) >> >> >> >> here. >> >> >> >> You touch one other place in fold-const.c but there seem to be many >> >> more that need ABSU_EXPR handling (you touched the one needed >> >> for correctness) - esp. you should at least handle constant folding >> >> in const_unop and the nonnegative predicate. >> > >> > OK. >> >> >> >> @@ -3167,6 +3167,9 @@ verify_expr (tree *tp, int *walk_subtrees, void >> >> *data >> >> ATTRIBUTE_UNUSED) >> >> CHECK_OP (0, "invalid operand to unary operator"); >> >> break; >> >> >> >> + case ABSU_EXPR: >> >> + break; >> >> + >> >> case REALPART_EXPR: >> >> case IMAGPART_EXPR: >> >> >> >> verify_expr is no more. Did you test this recently against trunk? >> > >> > This patch is against slightly older trunk. I will rebase it. >> > >> >> >> >> @@ -3937,6 +3940,9 @@ verify_gimple_assign_unary (gassign *stmt) >> >> case PAREN_EXPR: >> >> case CONJ_EXPR: >> >> break; >> >> + case ABSU_EXPR: >> >> + /* FIXME. */ >> >> + return false; >> >> >> >> no - please not! Please add verification here - ABSU should be only >> >> called on INTEGRAL, vector or complex INTEGRAL types and the >> >> type of the LHS should be always the unsigned variant of the >> >> argument type. >> > >> > OK. >> >> >> >> if (is_gimple_val (cond_expr)) >> >> return cond_expr; >> >> >> >> - if (TREE_CODE (cond_expr) == ABS_EXPR) >> >> + if (TREE_CODE (cond_expr) == ABS_EXPR >> >> + || TREE_CODE (cond_expr) == ABSU_EXPR) >> >> { >> >> rhs1 = TREE_OPERAND (cond_expr, 1); >> >> STRIP_USELESS_TYPE_CONVERSION (rhs1); >> >> >> >> err, but the next line just builds a ABS_EXPR ... >> >> >> >> How did you identify spots that need adjustment? I would expect that >> >> once folding generates ABSU_EXPR that you need to adjust frontends >> >> (C++ constexpr handling for example). Also I miss adjustments >> >> to gimple-pretty-print.c and the GIMPLE FE parser. >> > >> > I will add this. >> >> >> >> recursively grepping throughout the whole gcc/ tree doesn't reveal too >> >> many >> >> cases of ABS_EXPR so I think it's reasonable to audit all of them. >> >> >> >> I also miss some trivial absu simplifications in match.pd. There are not >> >> a lot of abs cases but similar ones would be good to have initially. >> > >> > I will add them in the next version. >> > >> > Thanks, >> > Kugan >> > >> >> >> >> Thanks for tackling this! >> >> Richard. >> >> >> >>> Thanks, >> >>> Andrew >> >> >> >>> > >> >>> > Thanks, >> >>> > Kugan >> >>> > >> >>> > >> >>> > gcc/ChangeLog: >> >>> > >> >>> > 2018-05-13 Kugan Vivekanandarajah <kugan.vivekanandara...@linaro.org> >> >>> > >> >>> > * expr.c (expand_expr_real_2): Handle ABSU_EXPR. >> >>> > * fold-const.c (fold_cond_expr_with_comparison): Generate ABSU_EXPR >> >>> > (fold_unary_loc): Handle ABSU_EXPR. >> >>> > * optabs-tree.c (optab_for_tree_code): Likewise. >> >>> > * tree-cfg.c (verify_expr): Likewise. >> >>> > (verify_gimple_assign_unary): Likewise. >> >>> > * tree-if-conv.c (fold_build_cond_expr): Likewise. >> >>> > * tree-inline.c (estimate_operator_cost): Likewise. >> >>> > * tree-pretty-print.c (dump_generic_node): Likewise. >> >>> > * tree.def (ABSU_EXPR): New. >> >>> > >> >>> > gcc/testsuite/ChangeLog: >> >>> > >> >>> > 2018-05-13 Kugan Vivekanandarajah <kugan.vivekanandara...@linaro.org> >> >>> > >> >>> > * gcc.dg/absu.c: New test.
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 859eeb4..0e8efb5 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -3312,6 +3312,7 @@ c_common_truthvalue_conversion (location_t location, tree expr) case NEGATE_EXPR: case ABS_EXPR: + case ABSU_EXPR: case FLOAT_EXPR: case EXCESS_PRECISION_EXPR: /* These don't change whether an object is nonzero or zero. */ diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 45a4529..5bb6804 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -4314,6 +4314,16 @@ build_unary_op (location_t location, enum tree_code code, tree xarg, arg = default_conversion (arg); break; + case ABSU_EXPR: + if (!(typecode == INTEGER_TYPE)) + { + error_at (location, "wrong type argument to absu"); + return error_mark_node; + } + else if (!noconvert) + arg = default_conversion (arg); + break; + case CONJ_EXPR: /* Conjugating a real value is a no-op, but allow it anyway. */ if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE diff --git a/gcc/c/gimple-parser.c b/gcc/c/gimple-parser.c index c9abe24..11e76ff 100644 --- a/gcc/c/gimple-parser.c +++ b/gcc/c/gimple-parser.c @@ -328,7 +328,8 @@ c_parser_gimple_statement (c_parser *parser, gimple_seq *seq) case CPP_NAME: { tree id = c_parser_peek_token (parser)->value; - if (strcmp (IDENTIFIER_POINTER (id), "__ABS") == 0) + if (strcmp (IDENTIFIER_POINTER (id), "__ABS") == 0 + || strcmp (IDENTIFIER_POINTER (id), "__ABSU") == 0) goto build_unary_expr; break; } @@ -638,6 +639,12 @@ c_parser_gimple_unary_expression (c_parser *parser) op = c_parser_gimple_postfix_expression (parser); return parser_build_unary_op (op_loc, ABS_EXPR, op); } + else if (strcmp (IDENTIFIER_POINTER (id), "__ABSU") == 0) + { + c_parser_consume_token (parser); + op = c_parser_gimple_postfix_expression (parser); + return parser_build_unary_op (op_loc, ABSU_EXPR, op); + } else return c_parser_gimple_postfix_expression (parser); } diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index ef143a3..ba4543c 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -4621,6 +4621,7 @@ expand_debug_expr (tree exp) } case ABS_EXPR: + case ABSU_EXPR: return simplify_gen_unary (ABS, mode, op0, mode); case NEGATE_EXPR: diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index e19864d..487127c 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -51228,6 +51228,7 @@ ix86_add_stmt_cost (void *data, int count, enum vect_cost_for_stmt kind, case BIT_IOR_EXPR: case ABS_EXPR: + case ABSU_EXPR: case MIN_EXPR: case MAX_EXPR: case BIT_XOR_EXPR: diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 8c6ec55..bea9147 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -5760,6 +5760,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case FLOAT_EXPR: case NEGATE_EXPR: case ABS_EXPR: + case ABSU_EXPR: case TRUTH_NOT_EXPR: case FIXED_CONVERT_EXPR: case UNARY_PLUS_EXPR: diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index eda5f05..bca0c59 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -2271,6 +2271,7 @@ cp_fold (tree x) case FLOAT_EXPR: case NEGATE_EXPR: case ABS_EXPR: + case ABSU_EXPR: case BIT_NOT_EXPR: case TRUTH_NOT_EXPR: case FIXED_CONVERT_EXPR: diff --git a/gcc/dojump.c b/gcc/dojump.c index 9da8a0e..88cc96a 100644 --- a/gcc/dojump.c +++ b/gcc/dojump.c @@ -467,6 +467,7 @@ do_jump (tree exp, rtx_code_label *if_false_label, /* FALLTHRU */ case NON_LVALUE_EXPR: case ABS_EXPR: + case ABSU_EXPR: case NEGATE_EXPR: case LROTATE_EXPR: case RROTATE_EXPR: diff --git a/gcc/expr.c b/gcc/expr.c index 00a802c..9efa535 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -9074,6 +9074,7 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, return REDUCE_BIT_FIELD (temp); case ABS_EXPR: + case ABSU_EXPR: op0 = expand_expr (treeop0, subtarget, VOIDmode, EXPAND_NORMAL); if (modifier == EXPAND_STACK_PARM) @@ -9085,7 +9086,7 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, /* Unsigned abs is simply the operand. Testing here means we don't risk generating incorrect code below. */ - if (TYPE_UNSIGNED (type)) + if (TYPE_UNSIGNED (TREE_TYPE (treeop0))) return op0; return expand_abs (mode, op0, target, unsignedp, diff --git a/gcc/fold-const.c b/gcc/fold-const.c index faa184a..c19614e 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -1723,7 +1723,8 @@ const_unop (enum tree_code code, tree type, tree arg0) && HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0))) && REAL_VALUE_ISSIGNALING_NAN (TREE_REAL_CST (arg0)) && code != NEGATE_EXPR - && code != ABS_EXPR) + && code != ABS_EXPR + && code != ABSU_EXPR) return NULL_TREE; switch (code) @@ -1758,6 +1759,7 @@ const_unop (enum tree_code code, tree type, tree arg0) } case ABS_EXPR: + case ABSU_EXPR: if (TREE_CODE (arg0) == INTEGER_CST || TREE_CODE (arg0) == REAL_CST) return fold_abs_const (arg0, type); break; @@ -13846,20 +13848,21 @@ fold_abs_const (tree arg0, tree type) { /* If the value is unsigned or non-negative, then the absolute value is the same as the ordinary value. */ - if (!wi::neg_p (wi::to_wide (arg0), TYPE_SIGN (type))) - t = arg0; + wide_int val = wi::to_wide (arg0); + bool overflow = false; + if (!wi::neg_p (val, TYPE_SIGN (TREE_TYPE (arg0)))) + ; /* If the value is negative, then the absolute value is its negation. */ else - { - bool overflow; - wide_int val = wi::neg (wi::to_wide (arg0), &overflow); - t = force_fit_type (type, val, -1, - overflow | TREE_OVERFLOW (arg0)); - } + val = wi::neg (val, &overflow); + + /* Force to the destination type, set TREE_OVERFLOW for signed + TYPE only. */ + t = force_fit_type (type, val, 1, overflow | TREE_OVERFLOW (arg0)); } - break; + break; case REAL_CST: if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg0))) diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index afe0147..4fa992d 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -358,14 +358,17 @@ dump_unary_rhs (pretty_printer *buffer, gassign *gs, int spc, break; case ABS_EXPR: + case ABSU_EXPR: if (flags & TDF_GIMPLE) { - pp_string (buffer, "__ABS "); + pp_string (buffer, + rhs_code == ABS_EXPR ? "__ABS " : "__ABSU "); dump_generic_node (buffer, rhs, spc, flags, false); } else { - pp_string (buffer, "ABS_EXPR <"); + pp_string (buffer, + rhs_code == ABS_EXPR ? "ABS_EXPR <" : "ABSU_EXPR <"); dump_generic_node (buffer, rhs, spc, flags, false); pp_greater (buffer); } diff --git a/gcc/gimple-ssa-backprop.c b/gcc/gimple-ssa-backprop.c index 27aa575..a38b5eb 100644 --- a/gcc/gimple-ssa-backprop.c +++ b/gcc/gimple-ssa-backprop.c @@ -405,6 +405,7 @@ backprop::process_assign_use (gassign *assign, tree rhs, usage_info *info) switch (gimple_assign_rhs_code (assign)) { case ABS_EXPR: + case ABSU_EXPR: /* The sign of the input doesn't matter. */ info->flags.ignore_sign = true; break; @@ -681,6 +682,7 @@ strip_sign_op_1 (tree rhs) switch (gimple_assign_rhs_code (assign)) { case ABS_EXPR: + case ABSU_EXPR: case NEGATE_EXPR: return gimple_assign_rhs1 (assign); diff --git a/gcc/match.pd b/gcc/match.pd index 7033730..ba52bb0 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -90,6 +90,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (match (nop_convert @0) @0) +/* Transform likes of (char) ABS_EXPR <(int) x> into (char) ABSU_EXPR <x> + ABSU_EXPR returns unsigned absolute value of the operand and the operand + of the ABSU_EXPR will have the corresponding signed type. */ +(simplify (abs (convert @0)) + (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0)) + && !TYPE_UNSIGNED (TREE_TYPE (@0)) + && element_precision (type) > element_precision (TREE_TYPE (@0))) + (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); } + (convert (absu:utype @0))))) + + /* Simplifications of operations with one constant operand and simplifications to constants or single values. */ diff --git a/gcc/optabs-tree.c b/gcc/optabs-tree.c index 71e172c..aa119ec 100644 --- a/gcc/optabs-tree.c +++ b/gcc/optabs-tree.c @@ -237,6 +237,8 @@ optab_for_tree_code (enum tree_code code, const_tree type, case ABS_EXPR: return trapv ? absv_optab : abs_optab; + case ABSU_EXPR: + return abs_optab; default: return unknown_optab; } diff --git a/gcc/testsuite/gcc.dg/absu.c b/gcc/testsuite/gcc.dg/absu.c index e69de29..063da28 100644 --- a/gcc/testsuite/gcc.dg/absu.c +++ b/gcc/testsuite/gcc.dg/absu.c @@ -0,0 +1,85 @@ + +/* { dg-do run } */ +/* { dg-options "-O0" } */ + +#include <limits.h> +#define ABS(x) (((x) >= 0) ? (x) : -(x)) + +#define DEF_TEST(TYPE) \ +void foo_##TYPE (signed TYPE x, unsigned TYPE y){ \ + TYPE t = ABS (x); \ + if (t != y) \ + __builtin_abort (); \ +} \ + +DEF_TEST (char); +DEF_TEST (short); +DEF_TEST (int); +DEF_TEST (long); + +int main () +{ + foo_char (SCHAR_MIN + 1, SCHAR_MAX); + foo_char (0, 0); + foo_char (-1, 1); + foo_char (1, 1); + foo_char (SCHAR_MAX, SCHAR_MAX); + + foo_int (-1, 1); + foo_int (0, 0); + foo_int (INT_MAX, INT_MAX); + foo_int (INT_MIN + 1, INT_MAX); + + foo_short (-1, 1); + foo_short (0, 0); + foo_short (SHRT_MAX, SHRT_MAX); + foo_short (SHRT_MIN + 1, SHRT_MAX); + + foo_long (-1, 1); + foo_long (0, 0); + foo_long (LONG_MAX, LONG_MAX); + foo_long (LONG_MIN + 1, LONG_MAX); + + return 0; +} + +/* { dg-do run } */ +/* { dg-options "-O0" } */ + +#include <limits.h> +#define ABS(x) (((x) >= 0) ? (x) : -(x)) + +#define DEF_TEST(TYPE) \ +void foo_##TYPE (signed TYPE x, unsigned TYPE y){ \ + TYPE t = ABS (x); \ + if (t != y) \ + __builtin_abort (); \ +} \ + +DEF_TEST (char); +DEF_TEST (short); +DEF_TEST (int); +DEF_TEST (long); +void main () +{ + foo_char (SCHAR_MIN + 1, SCHAR_MAX); + foo_char (0, 0); + foo_char (-1, 1); + foo_char (1, 1); + foo_char (SCHAR_MAX, SCHAR_MAX); + + foo_int (-1, 1); + foo_int (0, 0); + foo_int (INT_MAX, INT_MAX); + foo_int (INT_MIN + 1, INT_MAX); + + foo_short (-1, 1); + foo_short (0, 0); + foo_short (SHRT_MAX, SHRT_MAX); + foo_short (SHRT_MIN + 1, SHRT_MAX); + + foo_long (-1, 1); + foo_long (0, 0); + foo_long (LONG_MAX, LONG_MAX); + foo_long (LONG_MIN + 1, LONG_MAX); +} diff --git a/gcc/testsuite/gcc.dg/gimplefe-29.c b/gcc/testsuite/gcc.dg/gimplefe-29.c index e69de29..54b86ef 100644 --- a/gcc/testsuite/gcc.dg/gimplefe-29.c +++ b/gcc/testsuite/gcc.dg/gimplefe-29.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fgimple -fdump-tree-ssa-gimple" } */ + +unsigned int __GIMPLE() f(int a) +{ + unsigned int t0; + t0_1 = __ABSU a; + return t0_1; +} + +/* { dg-final { scan-tree-dump "__ABSU a" "ssa" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/pr64946.c b/gcc/testsuite/gcc.target/aarch64/pr64946.c index e69de29..736656f 100644 --- a/gcc/testsuite/gcc.target/aarch64/pr64946.c +++ b/gcc/testsuite/gcc.target/aarch64/pr64946.c @@ -0,0 +1,13 @@ + +/* { dg-do compile } */ +/* { dg-options "-O3" } */ + +signed char a[100],b[100]; +void absolute_s8 (void) +{ + int i; + for (i=0; i<16; i++) + a[i] = (b[i] > 0 ? b[i] : -b[i]); +}; + +/* { dg-final { scan-assembler-times "abs\tv\[0-9\]+.16b, v\[0-9\]+.16b" 1 } } */ diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 7f48d2d..6df42cc 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -3685,6 +3685,12 @@ verify_gimple_assign_unary (gassign *stmt) case PAREN_EXPR: case CONJ_EXPR: break; + case ABSU_EXPR: + if (!TYPE_UNSIGNED (lhs_type) + || !ANY_INTEGRAL_TYPE_P (rhs1_type)) + return true; + return false; + break; case VEC_DUPLICATE_EXPR: if (TREE_CODE (lhs_type) != VECTOR_TYPE diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index 3609bca..da87466 100644 --- a/gcc/tree-eh.c +++ b/gcc/tree-eh.c @@ -2471,6 +2471,10 @@ operation_could_trap_helper_p (enum tree_code op, return true; return false; + case ABSU_EXPR: + /* ABSU_EXPR never traps. */ + return false; + case PLUS_EXPR: case MINUS_EXPR: case MULT_EXPR: diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 5a0a252..d272974 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -3866,6 +3866,7 @@ estimate_operator_cost (enum tree_code code, eni_weights *weights, case MIN_EXPR: case MAX_EXPR: case ABS_EXPR: + case ABSU_EXPR: case LSHIFT_EXPR: case RSHIFT_EXPR: diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index bc36c28..612a18f 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -2463,6 +2463,12 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags, pp_greater (pp); break; + case ABSU_EXPR: + pp_string (pp, "ABSU_EXPR <"); + dump_generic_node (pp, TREE_OPERAND (node, 0), spc, flags, false); + pp_greater (pp); + break; + case RANGE_EXPR: NIY; break; diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c index 5c2578f..e4df6c8 100644 --- a/gcc/tree-vect-patterns.c +++ b/gcc/tree-vect-patterns.c @@ -614,7 +614,8 @@ vect_recog_sad_pattern (vec<gimple *> *stmts, tree *type_in, gcc_assert (abs_stmt_vinfo); if (STMT_VINFO_DEF_TYPE (abs_stmt_vinfo) != vect_internal_def) return NULL; - if (gimple_assign_rhs_code (abs_stmt) != ABS_EXPR) + if (gimple_assign_rhs_code (abs_stmt) != ABS_EXPR + && gimple_assign_rhs_code (abs_stmt) != ABSU_EXPR) return NULL; tree abs_oprnd = gimple_assign_rhs1 (abs_stmt); diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 4539f6a..c71b688 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -5995,7 +5995,10 @@ vectorizable_operation (gimple *stmt, gimple_stmt_iterator *gsi, "transform binary/unary operation.\n"); /* Handle def. */ - vec_dest = vect_create_destination_var (scalar_dest, vectype); + if (code == ABSU_EXPR) + vec_dest = vect_create_destination_var (scalar_dest, vectype_out); + else + vec_dest = vect_create_destination_var (scalar_dest, vectype); /* POINTER_DIFF_EXPR has pointer arguments which are vectorized as vectors with unsigned elements, but the result is signed. So, we diff --git a/gcc/tree.def b/gcc/tree.def index 31de6c0..a1766e4 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -761,6 +761,11 @@ DEFTREECODE (MAX_EXPR, "max_expr", tcc_binary, 2) operand of the ABS_EXPR must have the same type. */ DEFTREECODE (ABS_EXPR, "abs_expr", tcc_unary, 1) +/* Represents the unsigned absolute value of the operand. + An ABSU_EXPR must have unsigned INTEGER_TYPE. The operand of the ABSU_EXPR + must have the corresponding signed type. */ +DEFTREECODE (ABSU_EXPR, "absu_expr", tcc_unary, 1) + /* Shift operations for shift and rotate. Shift means logical shift if done on an unsigned type, arithmetic shift if done on a signed type.