diff mbox

[AArch64] Handle -|x| case using a single csneg

Message ID 55A38963.6080408@arm.com
State New
Headers show

Commit Message

Kyrylo Tkachov July 13, 2015, 9:48 a.m. UTC
Hi all,

For the testcase in the patch we were generating an extra neg instruction:
         cmp     w0, wzr
         csneg   w0, w0, w0, ge
         neg     w0, w0
         ret

instead of the optimal:
         cmp     w0, wzr
         csneg   w0, w0, w0, lt
         ret

The reason is that combine tries to merge the operation into a negation of an abs.
I considered teaching combine not to do that but it would require telling it that it shouldn't
do it if there is a conditional negate instruction. There's no optab for that though :(
Also, we already advertise that we have an abs optab, even though we expand to a compare and
a csneg anyway. This patch was the cleanest way I could do this. We just match the neg of an abs
and generate the same csneg sequence as for normal abs, just with the comparison condition inverted.

Bootstrapped and tested on aarch64.

Ok for trunk?
Thanks,
Kyrill

2015-07-13  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>

     * config/aarch64/aarch64.md (*absneg2<mode>_insn): New
     define_and_split.

2015-07-13  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>

     * gcc.target/aarch64/neg-abs_1.c: New test.

Comments

Segher Boessenkool July 14, 2015, 12:38 a.m. UTC | #1
On Mon, Jul 13, 2015 at 10:48:19AM +0100, Kyrill Tkachov wrote:
> For the testcase in the patch we were generating an extra neg instruction:
>         cmp     w0, wzr
>         csneg   w0, w0, w0, ge
>         neg     w0, w0
>         ret
> 
> instead of the optimal:
>         cmp     w0, wzr
>         csneg   w0, w0, w0, lt
>         ret
> 
> The reason is that combine tries to merge the operation into a negation of 
> an abs.

Before combine, you have two insns, a negation and an abs, so that is
not so very strange :-)

Some archs have actual nabs insns btw (for floating point, anyway).

Archs without abs or conditional assignment, and with cheap branches,
get a branch around a neg followed by another neg, at expand time.
This then isn't optimised away either.

So I'd say expand should be made a bit smarter for this.  Failing
that, your approach looks fine to me -- assuming you want to have a
fake "abs" insn at all.

On to the patch...


> +;; Combine will try merging (c > 0 ? -x : x) into (-|x|).  This isn't a good

"x > 0" here.


Segher
Kyrylo Tkachov July 14, 2015, 8:18 a.m. UTC | #2
Hi Segher,

On 14/07/15 01:38, Segher Boessenkool wrote:
> On Mon, Jul 13, 2015 at 10:48:19AM +0100, Kyrill Tkachov wrote:
>> For the testcase in the patch we were generating an extra neg instruction:
>>          cmp     w0, wzr
>>          csneg   w0, w0, w0, ge
>>          neg     w0, w0
>>          ret
>>
>> instead of the optimal:
>>          cmp     w0, wzr
>>          csneg   w0, w0, w0, lt
>>          ret
>>
>> The reason is that combine tries to merge the operation into a negation of
>> an abs.
> Before combine, you have two insns, a negation and an abs, so that is
> not so very strange :-)

Well, because the aarch64 integer abs expander expands to a compare
and a conditional negate, we have a compare followed by an if_then_else
with a neg in it. That's followed by a neg of that:
(insn 6 3 7 2 (set (reg:CC 66 cc)
         (compare:CC (reg/v:SI 76 [ x ])
             (const_int 0 [0]))) abs.c:1 374 {*cmpsi}
      (nil))
(insn 7 6 8 2 (set (reg:SI 78 [ D.2683 ])
         (if_then_else:SI (lt (reg:CC 66 cc)
                 (const_int 0 [0]))
             (neg:SI (reg/v:SI 76 [ x ]))
             (reg/v:SI 76 [ x ]))) abs.c:1 441 {csneg3si_insn}
      (expr_list:REG_DEAD (reg/v:SI 76 [ x ])
         (expr_list:REG_DEAD (reg:CC 66 cc)
             (expr_list:REG_EQUAL (abs:SI (reg/v:SI 76 [ x ]))
                 (nil)))))
(insn 8 7 13 2 (set (reg:SI 77 [ D.2683 ])
         (neg:SI (reg:SI 78 [ D.2683 ]))) abs.c:1 319 {negsi2}
      (expr_list:REG_DEAD (reg:SI 78 [ D.2683 ])
         (nil)))


combine tries to convert it into a neg-of-an-abs in simplify_if_then_else

>
> Some archs have actual nabs insns btw (for floating point, anyway).
>
> Archs without abs or conditional assignment, and with cheap branches,
> get a branch around a neg followed by another neg, at expand time.
> This then isn't optimised away either.
>
> So I'd say expand should be made a bit smarter for this.  Failing
> that, your approach looks fine to me -- assuming you want to have a
> fake "abs" insn at all.
>
> On to the patch...
>
>
>> +;; Combine will try merging (c > 0 ? -x : x) into (-|x|).  This isn't a good
> "x > 0" here.

Thanks, I'll fix that when committing if approved.

Kyrill

>
> Segher
>
Andrew Pinski July 14, 2015, 10:06 a.m. UTC | #3
On Tue, Jul 14, 2015 at 1:18 AM, Kyrill Tkachov <kyrylo.tkachov@arm.com> wrote:
> Hi Segher,
>
> On 14/07/15 01:38, Segher Boessenkool wrote:
>>
>> On Mon, Jul 13, 2015 at 10:48:19AM +0100, Kyrill Tkachov wrote:
>>>
>>> For the testcase in the patch we were generating an extra neg
>>> instruction:
>>>          cmp     w0, wzr
>>>          csneg   w0, w0, w0, ge
>>>          neg     w0, w0
>>>          ret
>>>
>>> instead of the optimal:
>>>          cmp     w0, wzr
>>>          csneg   w0, w0, w0, lt
>>>          ret
>>>
>>> The reason is that combine tries to merge the operation into a negation
>>> of
>>> an abs.
>>
>> Before combine, you have two insns, a negation and an abs, so that is
>> not so very strange :-)
>
>
> Well, because the aarch64 integer abs expander expands to a compare
> and a conditional negate, we have a compare followed by an if_then_else
> with a neg in it. That's followed by a neg of that:
> (insn 6 3 7 2 (set (reg:CC 66 cc)
>         (compare:CC (reg/v:SI 76 [ x ])
>             (const_int 0 [0]))) abs.c:1 374 {*cmpsi}
>      (nil))
> (insn 7 6 8 2 (set (reg:SI 78 [ D.2683 ])
>         (if_then_else:SI (lt (reg:CC 66 cc)
>                 (const_int 0 [0]))
>             (neg:SI (reg/v:SI 76 [ x ]))
>             (reg/v:SI 76 [ x ]))) abs.c:1 441 {csneg3si_insn}
>      (expr_list:REG_DEAD (reg/v:SI 76 [ x ])
>         (expr_list:REG_DEAD (reg:CC 66 cc)
>             (expr_list:REG_EQUAL (abs:SI (reg/v:SI 76 [ x ]))
>                 (nil)))))
> (insn 8 7 13 2 (set (reg:SI 77 [ D.2683 ])
>         (neg:SI (reg:SI 78 [ D.2683 ]))) abs.c:1 319 {negsi2}
>      (expr_list:REG_DEAD (reg:SI 78 [ D.2683 ])
>         (nil)))


What does combine do when it props 7 into 8?  I suspect you want to
optimize that instead of doing it any other way.
That is if prop the neg into the two sides of the conditional and if
one simplifies, produce a new rtl.

Thanks,
Andrew Pinski

>
>
> combine tries to convert it into a neg-of-an-abs in simplify_if_then_else
>
>>
>> Some archs have actual nabs insns btw (for floating point, anyway).
>>
>> Archs without abs or conditional assignment, and with cheap branches,
>> get a branch around a neg followed by another neg, at expand time.
>> This then isn't optimised away either.
>>
>> So I'd say expand should be made a bit smarter for this.  Failing
>> that, your approach looks fine to me -- assuming you want to have a
>> fake "abs" insn at all.
>>
>> On to the patch...
>>
>>
>>> +;; Combine will try merging (c > 0 ? -x : x) into (-|x|).  This isn't a
>>> good
>>
>> "x > 0" here.
>
>
> Thanks, I'll fix that when committing if approved.
>
> Kyrill
>
>>
>> Segher
>>
>
Andrew Pinski July 14, 2015, 10:10 a.m. UTC | #4
On Tue, Jul 14, 2015 at 3:06 AM, Andrew Pinski <pinskia@gmail.com> wrote:
> On Tue, Jul 14, 2015 at 1:18 AM, Kyrill Tkachov <kyrylo.tkachov@arm.com> wrote:
>> Hi Segher,
>>
>> On 14/07/15 01:38, Segher Boessenkool wrote:
>>>
>>> On Mon, Jul 13, 2015 at 10:48:19AM +0100, Kyrill Tkachov wrote:
>>>>
>>>> For the testcase in the patch we were generating an extra neg
>>>> instruction:
>>>>          cmp     w0, wzr
>>>>          csneg   w0, w0, w0, ge
>>>>          neg     w0, w0
>>>>          ret
>>>>
>>>> instead of the optimal:
>>>>          cmp     w0, wzr
>>>>          csneg   w0, w0, w0, lt
>>>>          ret
>>>>
>>>> The reason is that combine tries to merge the operation into a negation
>>>> of
>>>> an abs.
>>>
>>> Before combine, you have two insns, a negation and an abs, so that is
>>> not so very strange :-)
>>
>>
>> Well, because the aarch64 integer abs expander expands to a compare
>> and a conditional negate, we have a compare followed by an if_then_else
>> with a neg in it. That's followed by a neg of that:
>> (insn 6 3 7 2 (set (reg:CC 66 cc)
>>         (compare:CC (reg/v:SI 76 [ x ])
>>             (const_int 0 [0]))) abs.c:1 374 {*cmpsi}
>>      (nil))
>> (insn 7 6 8 2 (set (reg:SI 78 [ D.2683 ])
>>         (if_then_else:SI (lt (reg:CC 66 cc)
>>                 (const_int 0 [0]))
>>             (neg:SI (reg/v:SI 76 [ x ]))
>>             (reg/v:SI 76 [ x ]))) abs.c:1 441 {csneg3si_insn}
>>      (expr_list:REG_DEAD (reg/v:SI 76 [ x ])
>>         (expr_list:REG_DEAD (reg:CC 66 cc)
>>             (expr_list:REG_EQUAL (abs:SI (reg/v:SI 76 [ x ]))
>>                 (nil)))))
>> (insn 8 7 13 2 (set (reg:SI 77 [ D.2683 ])
>>         (neg:SI (reg:SI 78 [ D.2683 ]))) abs.c:1 319 {negsi2}
>>      (expr_list:REG_DEAD (reg:SI 78 [ D.2683 ])
>>         (nil)))
>
>
> What does combine do when it props 7 into 8?  I suspect you want to
> optimize that instead of doing it any other way.
> That is if prop the neg into the two sides of the conditional and if
> one simplifies, produce a new rtl.

This should help code even like:
static inline int f(int a, int b, int c)
{
  if (a) return b;
  else return -c;
}

int g(int a, int b, int c)
{
  return -f(a, b, c);
}

Note the above code might be optimized at the tree level already.

Thanks,
Andrew

>
> Thanks,
> Andrew Pinski
>
>>
>>
>> combine tries to convert it into a neg-of-an-abs in simplify_if_then_else
>>
>>>
>>> Some archs have actual nabs insns btw (for floating point, anyway).
>>>
>>> Archs without abs or conditional assignment, and with cheap branches,
>>> get a branch around a neg followed by another neg, at expand time.
>>> This then isn't optimised away either.
>>>
>>> So I'd say expand should be made a bit smarter for this.  Failing
>>> that, your approach looks fine to me -- assuming you want to have a
>>> fake "abs" insn at all.
>>>
>>> On to the patch...
>>>
>>>
>>>> +;; Combine will try merging (c > 0 ? -x : x) into (-|x|).  This isn't a
>>>> good
>>>
>>> "x > 0" here.
>>
>>
>> Thanks, I'll fix that when committing if approved.
>>
>> Kyrill
>>
>>>
>>> Segher
>>>
>>
Kyrylo Tkachov July 14, 2015, 10:13 a.m. UTC | #5
On 14/07/15 11:06, Andrew Pinski wrote:
> On Tue, Jul 14, 2015 at 1:18 AM, Kyrill Tkachov <kyrylo.tkachov@arm.com> wrote:
>> Hi Segher,
>>
>> On 14/07/15 01:38, Segher Boessenkool wrote:
>>> On Mon, Jul 13, 2015 at 10:48:19AM +0100, Kyrill Tkachov wrote:
>>>> For the testcase in the patch we were generating an extra neg
>>>> instruction:
>>>>           cmp     w0, wzr
>>>>           csneg   w0, w0, w0, ge
>>>>           neg     w0, w0
>>>>           ret
>>>>
>>>> instead of the optimal:
>>>>           cmp     w0, wzr
>>>>           csneg   w0, w0, w0, lt
>>>>           ret
>>>>
>>>> The reason is that combine tries to merge the operation into a negation
>>>> of
>>>> an abs.
>>> Before combine, you have two insns, a negation and an abs, so that is
>>> not so very strange :-)
>>
>> Well, because the aarch64 integer abs expander expands to a compare
>> and a conditional negate, we have a compare followed by an if_then_else
>> with a neg in it. That's followed by a neg of that:
>> (insn 6 3 7 2 (set (reg:CC 66 cc)
>>          (compare:CC (reg/v:SI 76 [ x ])
>>              (const_int 0 [0]))) abs.c:1 374 {*cmpsi}
>>       (nil))
>> (insn 7 6 8 2 (set (reg:SI 78 [ D.2683 ])
>>          (if_then_else:SI (lt (reg:CC 66 cc)
>>                  (const_int 0 [0]))
>>              (neg:SI (reg/v:SI 76 [ x ]))
>>              (reg/v:SI 76 [ x ]))) abs.c:1 441 {csneg3si_insn}
>>       (expr_list:REG_DEAD (reg/v:SI 76 [ x ])
>>          (expr_list:REG_DEAD (reg:CC 66 cc)
>>              (expr_list:REG_EQUAL (abs:SI (reg/v:SI 76 [ x ]))
>>                  (nil)))))
>> (insn 8 7 13 2 (set (reg:SI 77 [ D.2683 ])
>>          (neg:SI (reg:SI 78 [ D.2683 ]))) abs.c:1 319 {negsi2}
>>       (expr_list:REG_DEAD (reg:SI 78 [ D.2683 ])
>>          (nil)))
>
> What does combine do when it props 7 into 8?  I suspect you want to
> optimize that instead of doing it any other way.
> That is if prop the neg into the two sides of the conditional and if
> one simplifies, produce a new rtl.

Yeah, that's what combine tries in simplify_if_then_else, instead of
propagating the neg it tries a (neg (abs x)). I did consider telling it not
to do that, but how would it be gated?
Should we look if the one arm of the if_then_else is a neg of the other and
invert the comparison code instead of trying (neg (abs x)) when HAVE_conditional_move?

Kyrill
>
> Thanks,
> Andrew Pinski
>
>>
>> combine tries to convert it into a neg-of-an-abs in simplify_if_then_else
>>
>>> Some archs have actual nabs insns btw (for floating point, anyway).
>>>
>>> Archs without abs or conditional assignment, and with cheap branches,
>>> get a branch around a neg followed by another neg, at expand time.
>>> This then isn't optimised away either.
>>>
>>> So I'd say expand should be made a bit smarter for this.  Failing
>>> that, your approach looks fine to me -- assuming you want to have a
>>> fake "abs" insn at all.
>>>
>>> On to the patch...
>>>
>>>
>>>> +;; Combine will try merging (c > 0 ? -x : x) into (-|x|).  This isn't a
>>>> good
>>> "x > 0" here.
>>
>> Thanks, I'll fix that when committing if approved.
>>
>> Kyrill
>>
>>> Segher
>>>
Andrew Pinski July 14, 2015, 10:40 a.m. UTC | #6
On Tue, Jul 14, 2015 at 3:13 AM, Kyrill Tkachov <kyrylo.tkachov@arm.com> wrote:
>
> On 14/07/15 11:06, Andrew Pinski wrote:
>>
>> On Tue, Jul 14, 2015 at 1:18 AM, Kyrill Tkachov <kyrylo.tkachov@arm.com>
>> wrote:
>>>
>>> Hi Segher,
>>>
>>> On 14/07/15 01:38, Segher Boessenkool wrote:
>>>>
>>>> On Mon, Jul 13, 2015 at 10:48:19AM +0100, Kyrill Tkachov wrote:
>>>>>
>>>>> For the testcase in the patch we were generating an extra neg
>>>>> instruction:
>>>>>           cmp     w0, wzr
>>>>>           csneg   w0, w0, w0, ge
>>>>>           neg     w0, w0
>>>>>           ret
>>>>>
>>>>> instead of the optimal:
>>>>>           cmp     w0, wzr
>>>>>           csneg   w0, w0, w0, lt
>>>>>           ret
>>>>>
>>>>> The reason is that combine tries to merge the operation into a negation
>>>>> of
>>>>> an abs.
>>>>
>>>> Before combine, you have two insns, a negation and an abs, so that is
>>>> not so very strange :-)
>>>
>>>
>>> Well, because the aarch64 integer abs expander expands to a compare
>>> and a conditional negate, we have a compare followed by an if_then_else
>>> with a neg in it. That's followed by a neg of that:
>>> (insn 6 3 7 2 (set (reg:CC 66 cc)
>>>          (compare:CC (reg/v:SI 76 [ x ])
>>>              (const_int 0 [0]))) abs.c:1 374 {*cmpsi}
>>>       (nil))
>>> (insn 7 6 8 2 (set (reg:SI 78 [ D.2683 ])
>>>          (if_then_else:SI (lt (reg:CC 66 cc)
>>>                  (const_int 0 [0]))
>>>              (neg:SI (reg/v:SI 76 [ x ]))
>>>              (reg/v:SI 76 [ x ]))) abs.c:1 441 {csneg3si_insn}
>>>       (expr_list:REG_DEAD (reg/v:SI 76 [ x ])
>>>          (expr_list:REG_DEAD (reg:CC 66 cc)
>>>              (expr_list:REG_EQUAL (abs:SI (reg/v:SI 76 [ x ]))
>>>                  (nil)))))
>>> (insn 8 7 13 2 (set (reg:SI 77 [ D.2683 ])
>>>          (neg:SI (reg:SI 78 [ D.2683 ]))) abs.c:1 319 {negsi2}
>>>       (expr_list:REG_DEAD (reg:SI 78 [ D.2683 ])
>>>          (nil)))
>>
>>
>> What does combine do when it props 7 into 8?  I suspect you want to
>> optimize that instead of doing it any other way.
>> That is if prop the neg into the two sides of the conditional and if
>> one simplifies, produce a new rtl.
>
>
> Yeah, that's what combine tries in simplify_if_then_else, instead of
> propagating the neg it tries a (neg (abs x)). I did consider telling it not
> to do that, but how would it be gated?
> Should we look if the one arm of the if_then_else is a neg of the other and
> invert the comparison code instead of trying (neg (abs x)) when
> HAVE_conditional_move?

Does it do that even with insn 6 is not involved?
I doubt it.

Please look into that again.  I bet it is not creating the instruction
you want it to create and having the not in the last operand of the
if_then_else instead of the first one.

Thanks,
Andrew


>
> Kyrill
>
>>
>> Thanks,
>> Andrew Pinski
>>
>>>
>>> combine tries to convert it into a neg-of-an-abs in simplify_if_then_else
>>>
>>>> Some archs have actual nabs insns btw (for floating point, anyway).
>>>>
>>>> Archs without abs or conditional assignment, and with cheap branches,
>>>> get a branch around a neg followed by another neg, at expand time.
>>>> This then isn't optimised away either.
>>>>
>>>> So I'd say expand should be made a bit smarter for this.  Failing
>>>> that, your approach looks fine to me -- assuming you want to have a
>>>> fake "abs" insn at all.
>>>>
>>>> On to the patch...
>>>>
>>>>
>>>>> +;; Combine will try merging (c > 0 ? -x : x) into (-|x|).  This isn't
>>>>> a
>>>>> good
>>>>
>>>> "x > 0" here.
>>>
>>>
>>> Thanks, I'll fix that when committing if approved.
>>>
>>> Kyrill
>>>
>>>> Segher
>>>>
>
Andrew Pinski July 14, 2015, 11:04 a.m. UTC | #7
> On Jul 13, 2015, at 5:48 PM, Kyrill Tkachov <kyrylo.tkachov@arm.com> wrote:
> 
> Hi all,
> 
> For the testcase in the patch we were generating an extra neg instruction:
>        cmp     w0, wzr
>        csneg   w0, w0, w0, ge
>        neg     w0, w0
>        ret
> 
> instead of the optimal:
>        cmp     w0, wzr
>        csneg   w0, w0, w0, lt
>        ret
> 
> The reason is that combine tries to merge the operation into a negation of an abs.
> I considered teaching combine not to do that but it would require telling it that it shouldn't
> do it if there is a conditional negate instruction. There's no optab for that though :(
> Also, we already advertise that we have an abs optab, even though we expand to a compare and
> a csneg anyway. This patch was the cleanest way I could do this. We just match the neg of an abs
> and generate the same csneg sequence as for normal abs, just with the comparison condition inverted.
> 
> Bootstrapped and tested on aarch64.
> 
> Ok for trunk?
> Thanks,
> Kyrill
> 
> 2015-07-13  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
> 
>    * config/aarch64/aarch64.md (*absneg2<mode>_insn): New
>    define_and_split.

This pattern is incorrect as you need to say you are clobbering the flags register. Otherwise an optimization between combine and the splitter can move an instruction between it. Also it might be better to just have a define_split rather than a define_insn_and_split. Combine knows how to use define_split without being an insn. 

Thanks,
Andrew

> 
> 2015-07-13  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
> 
>    * gcc.target/aarch64/neg-abs_1.c: New test.
> <abs-neg.patch>
Kyrylo Tkachov July 14, 2015, 11:20 a.m. UTC | #8
On 14/07/15 11:40, Andrew Pinski wrote:
> On Tue, Jul 14, 2015 at 3:13 AM, Kyrill Tkachov <kyrylo.tkachov@arm.com> wrote:
>> On 14/07/15 11:06, Andrew Pinski wrote:
>>> On Tue, Jul 14, 2015 at 1:18 AM, Kyrill Tkachov <kyrylo.tkachov@arm.com>
>>> wrote:
>>>> Hi Segher,
>>>>
>>>> On 14/07/15 01:38, Segher Boessenkool wrote:
>>>>> On Mon, Jul 13, 2015 at 10:48:19AM +0100, Kyrill Tkachov wrote:
>>>>>> For the testcase in the patch we were generating an extra neg
>>>>>> instruction:
>>>>>>            cmp     w0, wzr
>>>>>>            csneg   w0, w0, w0, ge
>>>>>>            neg     w0, w0
>>>>>>            ret
>>>>>>
>>>>>> instead of the optimal:
>>>>>>            cmp     w0, wzr
>>>>>>            csneg   w0, w0, w0, lt
>>>>>>            ret
>>>>>>
>>>>>> The reason is that combine tries to merge the operation into a negation
>>>>>> of
>>>>>> an abs.
>>>>> Before combine, you have two insns, a negation and an abs, so that is
>>>>> not so very strange :-)
>>>>
>>>> Well, because the aarch64 integer abs expander expands to a compare
>>>> and a conditional negate, we have a compare followed by an if_then_else
>>>> with a neg in it. That's followed by a neg of that:
>>>> (insn 6 3 7 2 (set (reg:CC 66 cc)
>>>>           (compare:CC (reg/v:SI 76 [ x ])
>>>>               (const_int 0 [0]))) abs.c:1 374 {*cmpsi}
>>>>        (nil))
>>>> (insn 7 6 8 2 (set (reg:SI 78 [ D.2683 ])
>>>>           (if_then_else:SI (lt (reg:CC 66 cc)
>>>>                   (const_int 0 [0]))
>>>>               (neg:SI (reg/v:SI 76 [ x ]))
>>>>               (reg/v:SI 76 [ x ]))) abs.c:1 441 {csneg3si_insn}
>>>>        (expr_list:REG_DEAD (reg/v:SI 76 [ x ])
>>>>           (expr_list:REG_DEAD (reg:CC 66 cc)
>>>>               (expr_list:REG_EQUAL (abs:SI (reg/v:SI 76 [ x ]))
>>>>                   (nil)))))
>>>> (insn 8 7 13 2 (set (reg:SI 77 [ D.2683 ])
>>>>           (neg:SI (reg:SI 78 [ D.2683 ]))) abs.c:1 319 {negsi2}
>>>>        (expr_list:REG_DEAD (reg:SI 78 [ D.2683 ])
>>>>           (nil)))
>>>
>>> What does combine do when it props 7 into 8?  I suspect you want to
>>> optimize that instead of doing it any other way.
>>> That is if prop the neg into the two sides of the conditional and if
>>> one simplifies, produce a new rtl.
>>
>> Yeah, that's what combine tries in simplify_if_then_else, instead of
>> propagating the neg it tries a (neg (abs x)). I did consider telling it not
>> to do that, but how would it be gated?
>> Should we look if the one arm of the if_then_else is a neg of the other and
>> invert the comparison code instead of trying (neg (abs x)) when
>> HAVE_conditional_move?
> Does it do that even with insn 6 is not involved?
> I doubt it.
>
> Please look into that again.  I bet it is not creating the instruction
> you want it to create and having the not in the last operand of the
> if_then_else instead of the first one.

Ok, I dug a bit further. There's a couple of issues here:
* combine_simplify_rtx tries to simplify the comparison in the if_then_else
then has the lines:
        if (cond_code == NE && COMPARISON_P (cond))
          return x;

which quits early and doesn't try optimising the (neg (if_then_else)) further.

* If I bypass that condition it proceeds further into simplify_unary_operation from
simplify-rtx.c which doesn't have the simplifcation rule we want.
If I add a [- (x ? -y : y) -> !x ? -y : y] transformation there then it works.

I'll try to whip a patch into shape.

Thanks,
Kyrill

>
> Thanks,
> Andrew
>
>
>> Kyrill
>>
>>> Thanks,
>>> Andrew Pinski
>>>
>>>> combine tries to convert it into a neg-of-an-abs in simplify_if_then_else
>>>>
>>>>> Some archs have actual nabs insns btw (for floating point, anyway).
>>>>>
>>>>> Archs without abs or conditional assignment, and with cheap branches,
>>>>> get a branch around a neg followed by another neg, at expand time.
>>>>> This then isn't optimised away either.
>>>>>
>>>>> So I'd say expand should be made a bit smarter for this.  Failing
>>>>> that, your approach looks fine to me -- assuming you want to have a
>>>>> fake "abs" insn at all.
>>>>>
>>>>> On to the patch...
>>>>>
>>>>>
>>>>>> +;; Combine will try merging (c > 0 ? -x : x) into (-|x|).  This isn't
>>>>>> a
>>>>>> good
>>>>> "x > 0" here.
>>>>
>>>> Thanks, I'll fix that when committing if approved.
>>>>
>>>> Kyrill
>>>>
>>>>> Segher
>>>>>
Segher Boessenkool July 14, 2015, 12:39 p.m. UTC | #9
On Tue, Jul 14, 2015 at 07:04:13PM +0800, pinskia@gmail.com wrote:
> Combine knows how to use define_split without being an insn. 

Combine uses define_split in very different circumstances than it uses
define_insn.  In this case, define_split will only do anything if the
"nabs" is combined from three insns, while a define_insn handles it
being combined from two as well.

A define_split will be split during combine (and combine can then work
on its factors); a define_insn is only split _after_ combine.


Segher
Segher Boessenkool July 14, 2015, 12:55 p.m. UTC | #10
On Tue, Jul 14, 2015 at 09:18:06AM +0100, Kyrill Tkachov wrote:
> >Before combine, you have two insns, a negation and an abs, so that is
> >not so very strange :-)

Oh, hrm, my aarch64 cross was three months old, and this now changed.
Or I messed up.  Sorry for the noise.

It does look like the if_then_else stuff in combine (and simplify-rtx)
could use some improvement, probably more than just fixing this one
case.  Or look at the first huge case in combine_simplify_rtx, that
looks eerily similar.


Segher
Kyrylo Tkachov July 14, 2015, 1:16 p.m. UTC | #11
On 14/07/15 13:55, Segher Boessenkool wrote:
> On Tue, Jul 14, 2015 at 09:18:06AM +0100, Kyrill Tkachov wrote:
>>> Before combine, you have two insns, a negation and an abs, so that is
>>> not so very strange :-)
> Oh, hrm, my aarch64 cross was three months old, and this now changed.
> Or I messed up.  Sorry for the noise.
>
> It does look like the if_then_else stuff in combine (and simplify-rtx)
> could use some improvement, probably more than just fixing this one
> case.  Or look at the first huge case in combine_simplify_rtx, that
> looks eerily similar.

Yeah, removing an early return in combine_simplify_rtx and
adding the simplification to simplify_unary_operation did
the trick.

I'll see if it survives testing.

Thanks,
Kyrill

>
>
> Segher
>
diff mbox

Patch

commit 7527a76d25067ce4a5426e563e162487604ac6c1
Author: Kyrylo Tkachov <kyrylo.tkachov@arm.com>
Date:   Thu Jul 9 16:54:23 2015 +0100

    [AArch64] Handle -|x| case using a single csneg

diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index e6d0764..6664d1a 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -2333,6 +2333,29 @@  (define_expand "abs<mode>2"
   }
 )
 
+;; Combine will try merging (c > 0 ? -x : x) into (-|x|).  This isn't a good
+;; idea if the target has a conditional negate instruction and no integer
+;; abs instruction, but the midend doesn't have an optab for conditional neg
+;; and we advertise an optab for abs, so match that case here and emit the
+;; optimal CSNEG variant.
+(define_insn_and_split "*absneg2<mode>_insn"
+  [(set (match_operand:GPI 0 "register_operand" "=r")
+	(neg:GPI
+	  (abs:GPI (match_operand:GPI 1 "register_operand" "r"))))]
+  ""
+  "#"
+  ""
+  [(const_int 0)]
+  {
+    rtx ccreg = aarch64_gen_compare_reg (LT, operands[1], const0_rtx);
+    rtx x = gen_rtx_GE (VOIDmode, ccreg, const0_rtx);
+    emit_insn (gen_csneg3<mode>_insn (operands[0], x, operands[1],
+				       operands[1]));
+    DONE;
+  }
+  [(set_attr "type" "csel")]
+)
+
 (define_insn "neg<mode>2"
   [(set (match_operand:GPI 0 "register_operand" "=r,w")
 	(neg:GPI (match_operand:GPI 1 "register_operand" "r,w")))]
diff --git a/gcc/testsuite/gcc.target/aarch64/neg-abs_1.c b/gcc/testsuite/gcc.target/aarch64/neg-abs_1.c
new file mode 100644
index 0000000..cb2a387
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/neg-abs_1.c
@@ -0,0 +1,17 @@ 
+/* { dg-do compile } */
+/* { dg-options "-save-temps -O2" } */
+
+int
+f1 (int x)
+{
+  return x < 0 ? x : -x;
+}
+
+long long
+f2 (long long x)
+{
+  return x < 0 ? x : -x;
+}
+
+/* { dg-final { scan-assembler-not "\tneg\tw\[0-9\]*.*" } } */
+/* { dg-final { scan-assembler-not "\tneg\tx\[0-9\]*.*" } } */