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  <k...@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  <k...@codesourcery.com>

        PR target/51408
        * gcc.dg/pr51408.c: New.

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;
+}

Reply via email to