Patchwork ARM: Fix miscompilation in arm.md:*minmax_arithsi. (PR target/51408)

login
register
mail settings
Submitter Kazu_Hirata@mentor.com
Date Dec. 4, 2011, 1:32 p.m.
Message ID <yxj5hb1gzcli.fsf@build3-lucid-cs.sje.mentorg.com>
Download mbox | patch
Permalink /patch/129153/
State New
Headers show

Comments

Kazu_Hirata@mentor.com - Dec. 4, 2011, 1:32 p.m.
Hi,

Attached is a patch to fix miscompilation in
arm.md:*minmax_arithsi.

The following testcase, reduced from efgcvt_r.c:fcvt_r in glibc, gets
miscompiled:

extern void abort (void);

int __attribute__((noinline))
foo (int a, int b)
{
  int max = (b > 0) ? b : 0;
  return max - a;
}

int
main (void)
{
  if (foo (3, -1) != -3)
    abort ();
  return 0;
}

arm-none-eabi-gcc -O1 generates:

foo:
	@ Function supports interworking.
	@ args = 0, pretend = 0, frame = 0
	@ frame_needed = 0, uses_anonymous_args = 0
	@ link register save eliminated.
	cmp	r1, #0
	rsbge	r0, r0, r1
	bx	lr

This would be equivalent to:

  return b >= 0 ? b - a : a;

which is different from:

  return b >= 0 ? b - a : -a;

That is, in assembly code, we should have an "else" clause like so:

	cmp	r1, #0
	rsbge	r0, r0, r1  <- then clause
	rsblt	r0, r0, #0  <- else clause
	bx	lr

The problem comes from the fact that arm.md:*minmax_arithsi does not
add the "else" clause even though MINUS is not commutative.

The patch fixes the problem by always requiring the "else" clause in
the MINUS case.

Tested by running gcc testsuite on various ARM subarchitectures.  OK
to apply?

Kazu Hirata

gcc/
2011-12-04  Kazu Hirata  <kazu@codesourcery.com>

	PR target/51408
	* config/arm/arm.md (*minmax_arithsi): Always require the else
	clause in the MINUS case.

gcc/testsuite/
2011-12-04  Kazu Hirata  <kazu@codesourcery.com>

	PR target/51408
	* gcc.dg/pr51408.c: New.
Richard Earnshaw - Dec. 5, 2011, 10:42 a.m.
On 04/12/11 13:32, Kazu_Hirata@mentor.com wrote:
> Hi,
> 
> Attached is a patch to fix miscompilation in
> arm.md:*minmax_arithsi.
> 
> The following testcase, reduced from efgcvt_r.c:fcvt_r in glibc, gets
> miscompiled:
> 
> extern void abort (void);
> 
> int __attribute__((noinline))
> foo (int a, int b)
> {
>   int max = (b > 0) ? b : 0;
>   return max - a;
> }
> 
> int
> main (void)
> {
>   if (foo (3, -1) != -3)
>     abort ();
>   return 0;
> }
> 
> arm-none-eabi-gcc -O1 generates:
> 
> foo:
> 	@ Function supports interworking.
> 	@ args = 0, pretend = 0, frame = 0
> 	@ frame_needed = 0, uses_anonymous_args = 0
> 	@ link register save eliminated.
> 	cmp	r1, #0
> 	rsbge	r0, r0, r1
> 	bx	lr
> 
> This would be equivalent to:
> 
>   return b >= 0 ? b - a : a;
> 
> which is different from:
> 
>   return b >= 0 ? b - a : -a;
> 
> That is, in assembly code, we should have an "else" clause like so:
> 
> 	cmp	r1, #0
> 	rsbge	r0, r0, r1  <- then clause
> 	rsblt	r0, r0, #0  <- else clause
> 	bx	lr
> 
> The problem comes from the fact that arm.md:*minmax_arithsi does not
> add the "else" clause even though MINUS is not commutative.
> 
> The patch fixes the problem by always requiring the "else" clause in
> the MINUS case.
> 
> Tested by running gcc testsuite on various ARM subarchitectures.  OK
> to apply?
> 
> Kazu Hirata
> 
> gcc/
> 2011-12-04  Kazu Hirata  <kazu@codesourcery.com>
> 
> 	PR target/51408
> 	* config/arm/arm.md (*minmax_arithsi): Always require the else
> 	clause in the MINUS case.
> 
> gcc/testsuite/
> 2011-12-04  Kazu Hirata  <kazu@codesourcery.com>
> 
> 	PR target/51408
> 	* gcc.dg/pr51408.c: New.
> 

OK.

R.
Richard Earnshaw - Dec. 7, 2011, 4:43 p.m.
On 05/12/11 10:42, Richard Earnshaw wrote:
> On 04/12/11 13:32, Kazu_Hirata@mentor.com wrote:
>> Hi,
>>
>> Attached is a patch to fix miscompilation in
>> arm.md:*minmax_arithsi.
>>
>> The following testcase, reduced from efgcvt_r.c:fcvt_r in glibc, gets
>> miscompiled:
>>
>> extern void abort (void);
>>
>> int __attribute__((noinline))
>> foo (int a, int b)
>> {
>>   int max = (b > 0) ? b : 0;
>>   return max - a;
>> }
>>
>> int
>> main (void)
>> {
>>   if (foo (3, -1) != -3)
>>     abort ();
>>   return 0;
>> }
>>
>> arm-none-eabi-gcc -O1 generates:
>>
>> foo:
>> 	@ Function supports interworking.
>> 	@ args = 0, pretend = 0, frame = 0
>> 	@ frame_needed = 0, uses_anonymous_args = 0
>> 	@ link register save eliminated.
>> 	cmp	r1, #0
>> 	rsbge	r0, r0, r1
>> 	bx	lr
>>
>> This would be equivalent to:
>>
>>   return b >= 0 ? b - a : a;
>>
>> which is different from:
>>
>>   return b >= 0 ? b - a : -a;
>>
>> That is, in assembly code, we should have an "else" clause like so:
>>
>> 	cmp	r1, #0
>> 	rsbge	r0, r0, r1  <- then clause
>> 	rsblt	r0, r0, #0  <- else clause
>> 	bx	lr
>>
>> The problem comes from the fact that arm.md:*minmax_arithsi does not
>> add the "else" clause even though MINUS is not commutative.
>>
>> The patch fixes the problem by always requiring the "else" clause in
>> the MINUS case.
>>
>> Tested by running gcc testsuite on various ARM subarchitectures.  OK
>> to apply?
>>
>> Kazu Hirata
>>
>> gcc/
>> 2011-12-04  Kazu Hirata  <kazu@codesourcery.com>
>>
>> 	PR target/51408
>> 	* config/arm/arm.md (*minmax_arithsi): Always require the else
>> 	clause in the MINUS case.
>>
>> gcc/testsuite/
>> 2011-12-04  Kazu Hirata  <kazu@codesourcery.com>
>>
>> 	PR target/51408
>> 	* gcc.dg/pr51408.c: New.
>>
> 
> OK.
> 
> R.

BTW, I would expect this to also exist in all the release branches.  Could you back-port it where
needed please.

TIA,

R.
Kazu_Hirata@mentor.com - Dec. 9, 2011, 5:03 a.m.
Hi Richard,

> BTW, I would expect this to also exist in all the release branches.  Could you back-port it where
> needed please.

I just backported to 4.4, 4.5, and 4.6 branches.

Kazu Hirata

Patch

Index: gcc/config/arm/arm.md
===================================================================
--- gcc/config/arm/arm.md	(revision 181985)
+++ gcc/config/arm/arm.md	(working copy)
@@ -3413,7 +3413,7 @@ 
     bool need_else;
 
     if (which_alternative != 0 || operands[3] != const0_rtx
-        || (code != PLUS && code != MINUS && code != IOR && code != XOR))
+        || (code != PLUS && code != IOR && code != XOR))
       need_else = true;
     else
       need_else = false;
Index: gcc/testsuite/gcc.dg/pr51408.c
===================================================================
--- gcc/testsuite/gcc.dg/pr51408.c	(revision 0)
+++ gcc/testsuite/gcc.dg/pr51408.c	(revision 0)
@@ -0,0 +1,22 @@ 
+/* This testcase used to fail because of a bug in 
+   arm.md:*minmax_arithsi.  */
+
+/* { dg-do run } */
+/* { dg-options "-O1" } */
+
+extern void abort (void);
+
+int __attribute__((noinline))
+foo (int a, int b)
+{
+  int max = (b > 0) ? b : 0;
+  return max - a;
+}
+
+int
+main (void)
+{
+  if (foo (3, -1) != -3)
+    abort ();
+  return 0;
+}