[RFC,PR64946] "abs" vectorization fails for char/short types

Message ID CAELXzTPFP5QkdDRscDGTaEPwTLe_ZzrGkuSimhm+DZDfK6dw_w@mail.gmail.com
State New
Headers show
Series
  • [RFC,PR64946] "abs" vectorization fails for char/short types
Related show

Commit Message

Kugan Vivekanandarajah May 17, 2018, 2:14 a.m.
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.

Thanks,
Kugan


gcc/ChangeLog:

2018-05-13  Kugan Vivekanandarajah  <kugan.vivekanandarajah@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.vivekanandarajah@linaro.org>

    * gcc.dg/absu.c: New test.

Comments

Andrew Pinski May 17, 2018, 2:56 a.m. | #1
On Wed, May 16, 2018 at 7:14 PM, Kugan Vivekanandarajah
<kugan.vivekanandarajah@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.

Thanks,
Andrew

>

> Thanks,

> Kugan

>

>

> gcc/ChangeLog:

>

> 2018-05-13  Kugan Vivekanandarajah  <kugan.vivekanandarajah@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.vivekanandarajah@linaro.org>

>

>     * gcc.dg/absu.c: New test.
Richard Biener May 17, 2018, 10:36 a.m. | #2
On Thu, May 17, 2018 at 4:56 AM Andrew Pinski <pinskia@gmail.com> wrote:

> On Wed, May 16, 2018 at 7:14 PM, Kugan Vivekanandarajah

> <kugan.vivekanandarajah@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

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

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

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

    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.

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.

Thanks for tackling this!
Richard.

> Thanks,

> Andrew


> >

> > Thanks,

> > Kugan

> >

> >

> > gcc/ChangeLog:

> >

> > 2018-05-13  Kugan Vivekanandarajah  <kugan.vivekanandarajah@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.vivekanandarajah@linaro.org>

> >

> >     * gcc.dg/absu.c: New test.
Kugan Vivekanandarajah May 18, 2018, 2:36 a.m. | #3
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.guenther@gmail.com> wrote:
> On Thu, May 17, 2018 at 4:56 AM Andrew Pinski <pinskia@gmail.com> wrote:

>

>> On Wed, May 16, 2018 at 7:14 PM, Kugan Vivekanandarajah

>> <kugan.vivekanandarajah@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.vivekanandarajah@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.vivekanandarajah@linaro.org>

>> >

>> >     * gcc.dg/absu.c: New test.
Richard Biener May 18, 2018, 7:58 a.m. | #4
On Fri, May 18, 2018 at 4:37 AM Kugan Vivekanandarajah <
kugan.vivekanandarajah@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.guenther@gmail.com>

wrote:
> > On Thu, May 17, 2018 at 4:56 AM Andrew Pinski <pinskia@gmail.com> wrote:

> >

> >> On Wed, May 16, 2018 at 7:14 PM, Kugan Vivekanandarajah

> >> <kugan.vivekanandarajah@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.


Well, all existing ABS_EXPR generations are obviously fine.  Then there
are transforms that are not possible w/o ABSU_EXPR like the narrowing
you performed here.  This is becasue for ABS_EXPR you can't simply avoid
the undefined
behavior by performing the operation on unsigned integers... (that's similar
to signed integer division of -INT_MIN / -1 -- the result is representable
in
unsigned but not in signed).


> >

> > (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.vivekanandarajah@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.vivekanandarajah@linaro.org>
> >> >

> >> >     * gcc.dg/absu.c: New test.

Patch

diff --git a/gcc/expr.c b/gcc/expr.c
index 5e3d9a5..67f8dd1 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -9063,6 +9063,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)
@@ -9074,7 +9075,8 @@  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 (type)
+	  && (code != ABSU_EXPR))
 	return op0;
 
       return expand_abs (mode, op0, target, unsignedp,
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 3a99b66..6e80178 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -5324,8 +5324,17 @@  fold_cond_expr_with_comparison (location_t loc, tree type,
       case GT_EXPR:
 	if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
 	  break;
-	tem = fold_build1_loc (loc, ABS_EXPR, TREE_TYPE (arg1), arg1);
-	return fold_convert_loc (loc, type, tem);
+	if (TREE_CODE (arg1) == NOP_EXPR)
+	  {
+	    arg1 = TREE_OPERAND (arg1, 0);
+	    tem = fold_build1_loc (loc, ABSU_EXPR, unsigned_type_for (arg1_type), arg1);
+	    return fold_convert_loc (loc, type, tem);
+	  }
+	else
+	  {
+	    tem = fold_build1_loc (loc, ABS_EXPR, TREE_TYPE (arg1), arg1);
+	    return fold_convert_loc (loc, type, tem);
+	  }
       case UNLE_EXPR:
       case UNLT_EXPR:
 	if (flag_trapping_math)
@@ -7698,7 +7707,8 @@  fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
   if (arg0)
     {
       if (CONVERT_EXPR_CODE_P (code)
-	  || code == FLOAT_EXPR || code == ABS_EXPR || code == NEGATE_EXPR)
+	  || code == FLOAT_EXPR || code == ABS_EXPR
+	  || code == ABSU_EXPR || code == NEGATE_EXPR)
 	{
 	  /* Don't use STRIP_NOPS, because signedness of argument type
 	     matters.  */
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;
 
     default:
diff --git a/gcc/testsuite/gcc.dg/absu.c b/gcc/testsuite/gcc.dg/absu.c
index e69de29..43e651b 100644
--- a/gcc/testsuite/gcc.dg/absu.c
+++ b/gcc/testsuite/gcc.dg/absu.c
@@ -0,0 +1,39 @@ 
+
+/* { 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 (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/tree-cfg.c b/gcc/tree-cfg.c
index 9485f73..59a115c 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -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:
     case BIT_FIELD_REF:
@@ -3937,6 +3940,9 @@  verify_gimple_assign_unary (gassign *stmt)
     case PAREN_EXPR:
     case CONJ_EXPR:
       break;
+    case ABSU_EXPR:
+      /* FIXME.  */
+      return false;
 
     case VEC_DUPLICATE_EXPR:
       if (TREE_CODE (lhs_type) != VECTOR_TYPE
diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c
index 71dac4f..13d4c25 100644
--- a/gcc/tree-if-conv.c
+++ b/gcc/tree-if-conv.c
@@ -466,7 +466,8 @@  fold_build_cond_expr (tree type, tree cond, tree rhs, tree lhs)
   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);
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 276ad00..b74d8c9 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -2460,6 +2460,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.def b/gcc/tree.def
index 31de6c0..768167b 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