Patchwork Fix final_scan_insn to handle all comparisons in non-jump and cmove insn

login
register
mail settings
Submitter Andreas Schwab
Date Nov. 3, 2012, 1:16 p.m.
Message ID <m2obje968m.fsf@igel.home>
Download mbox | patch
Permalink /patch/196839/
State New
Headers show

Comments

Andreas Schwab - Nov. 3, 2012, 1:16 p.m.
final_scan_insn didn't handle the IEEE-aware compares in a
non-jump/cmove insn, causing wrong code if it was generated with swapped
operands (CC_REVERSED set).  Tested on m68k-linux.

Andreas.

	* final.c (final_scan_insn) [HAVE_cc0]: Handle all comparison
	codes in non-jump and cmove insn.

testsuite/
	* gcc.dg/torture/fp-compare.c: New testcase.
---
 gcc/final.c                               | 43 ++++++++++---------------------
 gcc/testsuite/gcc.dg/torture/fp-compare.c | 23 +++++++++++++++++
 2 files changed, 36 insertions(+), 30 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/fp-compare.c
Richard Sandiford - Nov. 5, 2012, 10:49 a.m.
Andreas Schwab <schwab@linux-m68k.org> writes:
> 	* final.c (final_scan_insn) [HAVE_cc0]: Handle all comparison
> 	codes in non-jump and cmove insn.

OK, thanks.

Richard

Patch

diff --git a/gcc/final.c b/gcc/final.c
index f414dd0..8aabddd 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -1,7 +1,7 @@ 
 /* Convert RTL to assembler code and output it, for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
    1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-   2010, 2011
+   2010, 2011, 2012
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -2700,36 +2700,19 @@  final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 		else_rtx = const0_rtx;
 	      }
 
-	    switch (GET_CODE (cond_rtx))
+	    if (COMPARISON_P (cond_rtx)
+		&& XEXP (cond_rtx, 0) == cc0_rtx)
 	      {
-	      case GTU:
-	      case GT:
-	      case LTU:
-	      case LT:
-	      case GEU:
-	      case GE:
-	      case LEU:
-	      case LE:
-	      case EQ:
-	      case NE:
-		{
-		  int result;
-		  if (XEXP (cond_rtx, 0) != cc0_rtx)
-		    break;
-		  result = alter_cond (cond_rtx);
-		  if (result == 1)
-		    validate_change (insn, &SET_SRC (set), then_rtx, 0);
-		  else if (result == -1)
-		    validate_change (insn, &SET_SRC (set), else_rtx, 0);
-		  else if (result == 2)
-		    INSN_CODE (insn) = -1;
-		  if (SET_DEST (set) == SET_SRC (set))
-		    delete_insn (insn);
-		}
-		break;
-
-	      default:
-		break;
+		int result;
+		result = alter_cond (cond_rtx);
+		if (result == 1)
+		  validate_change (insn, &SET_SRC (set), then_rtx, 0);
+		else if (result == -1)
+		  validate_change (insn, &SET_SRC (set), else_rtx, 0);
+		else if (result == 2)
+		  INSN_CODE (insn) = -1;
+		if (SET_DEST (set) == SET_SRC (set))
+		  delete_insn (insn);
 	      }
 	  }
 
diff --git a/gcc/testsuite/gcc.dg/torture/fp-compare.c b/gcc/testsuite/gcc.dg/torture/fp-compare.c
new file mode 100644
index 0000000..0d51dfd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/fp-compare.c
@@ -0,0 +1,23 @@ 
+/* { dg-do run } */
+/* Check that find_scan_insn properly handles swapped FP comparisons.  */
+static double x;
+static int exit_code;
+
+void __attribute__ ((noinline))
+check_int (int a, int b)
+{
+  exit_code += (a != b);
+}
+
+int
+main (void)
+{
+  x = 0.0;
+  asm ("" : "+m" (x));
+  check_int (__builtin_isgreater (x, 1.0), 0);
+  check_int (__builtin_isgreaterequal (x, 1.0), 0);
+  check_int (__builtin_isless (x, 1.0), 1);
+  check_int (__builtin_islessequal (x, 1.0), 1);
+  check_int (__builtin_islessgreater (x, 1.0), 1);
+  return exit_code;
+}