Patchwork [IA-64] Improve FP comparisons with -fno-trapping-math

login
register
mail settings
Submitter Eric Botcazou
Date May 29, 2013, 8:33 a.m.
Message ID <6466472.8JuR9QNRED@polaris>
Download mbox | patch
Permalink /patch/247172/
State New
Headers show

Comments

Eric Botcazou - May 29, 2013, 8:33 a.m.
Hi,

on most platforms the Ada compiler doesn't enable trap-on-FP-exceptions, so 
it's appropriate to set -fno-trapping-math there, which has been done in
  http://gcc.gnu.org/ml/gcc-patches/2013-05/msg01461.html

However doing so can have an adverse effect if the architecture doesn't have a 
sufficiently rich set of FP comparison instructions because -fno-trapping-math 
allows the middle-end and the optimizers to turn the negation of signaling FP 
comparison operators into quiet FP unordered operators, e.g. not(<) into !>= 
and the quiet unordered operators aren't supported universally.  The effect is 
that you need 2 comparisons instead of just 1 to achieve the desired result.

The first (surprising) example is the IA-64, which has ORDERED and UNORDERED 
but not UNLT/UNLE/UNGT/UNGE because the unordered comparison instructions are 
signaling (since they are the negation of the signaling ordered comparisons).
Therefore the fix is to make it possible to use these unordered comparison 
instructions, which are signaling, for the quiet unordered operators when the 
flag -fno-trapping-math is in effect.  As a matter of fact, the support was 
already there (e.g. in ia64_print_operand) but it was rightfully disabled.

Tested on IA-64/Linux and IA-64/HP-UX, OK for the mainline?


2013-05-29  Eric Botcazou  <ebotcazou@adacore.com>

	* config/ia64/predicates.md (ia64_cbranch_operator): Accept unordered
	comparison operators when -fno-trapping-math is in effect.
	* config/ia64/ia64.c (ia64_expand_compare): Add support for unordered
	comparison operators in TFmode and assert that unsupported operators
	cannot reach here.
	(ia64_print_operand): Likewise.
Richard Guenther - May 29, 2013, 9:02 a.m.
On Wed, May 29, 2013 at 10:33 AM, Eric Botcazou <ebotcazou@adacore.com> wrote:
> Hi,
>
> on most platforms the Ada compiler doesn't enable trap-on-FP-exceptions, so
> it's appropriate to set -fno-trapping-math there, which has been done in
>   http://gcc.gnu.org/ml/gcc-patches/2013-05/msg01461.html
>
> However doing so can have an adverse effect if the architecture doesn't have a
> sufficiently rich set of FP comparison instructions because -fno-trapping-math
> allows the middle-end and the optimizers to turn the negation of signaling FP
> comparison operators into quiet FP unordered operators, e.g. not(<) into !>=
> and the quiet unordered operators aren't supported universally.  The effect is
> that you need 2 comparisons instead of just 1 to achieve the desired result.
>
> The first (surprising) example is the IA-64, which has ORDERED and UNORDERED
> but not UNLT/UNLE/UNGT/UNGE because the unordered comparison instructions are
> signaling (since they are the negation of the signaling ordered comparisons).
> Therefore the fix is to make it possible to use these unordered comparison
> instructions, which are signaling, for the quiet unordered operators when the
> flag -fno-trapping-math is in effect.  As a matter of fact, the support was
> already there (e.g. in ia64_print_operand) but it was rightfully disabled.
>
> Tested on IA-64/Linux and IA-64/HP-UX, OK for the mainline?

Did you check that this doesn't cause traps on SPEC CPU 2000 / 2006
when compiled with -ffast-math (something we generally want to support,
even if it is on the border of validity)?

Thanks,
Richard.

> 2013-05-29  Eric Botcazou  <ebotcazou@adacore.com>
>
>         * config/ia64/predicates.md (ia64_cbranch_operator): Accept unordered
>         comparison operators when -fno-trapping-math is in effect.
>         * config/ia64/ia64.c (ia64_expand_compare): Add support for unordered
>         comparison operators in TFmode and assert that unsupported operators
>         cannot reach here.
>         (ia64_print_operand): Likewise.
>
>
> --
> Eric Botcazou
Eric Botcazou - May 29, 2013, 9:19 a.m.
> Did you check that this doesn't cause traps on SPEC CPU 2000 / 2006
> when compiled with -ffast-math (something we generally want to support,
> even if it is on the border of validity)?

Do you mean SPECfp because some benchmarks might enable trap-on-FP-exceptions 
and you nevertheless compile them with -ffast-math?
Richard Guenther - May 29, 2013, 9:28 a.m.
On Wed, May 29, 2013 at 11:19 AM, Eric Botcazou <ebotcazou@adacore.com> wrote:
>> Did you check that this doesn't cause traps on SPEC CPU 2000 / 2006
>> when compiled with -ffast-math (something we generally want to support,
>> even if it is on the border of validity)?
>
> Do you mean SPECfp because some benchmarks might enable trap-on-FP-exceptions
> and you nevertheless compile them with -ffast-math?

Yes, SPECfp.  And no, I don't think they enable trap-on-FP-exceptions but they
may cause exceptional behavior even if -fno-trapping-math is specified (not sure
if IA64 masks exceptions on the comparisons?)

Richard.

> --
> Eric Botcazou
Eric Botcazou - May 29, 2013, 10:11 a.m.
> Yes, SPECfp.  And no, I don't think they enable trap-on-FP-exceptions but
> they may cause exceptional behavior even if -fno-trapping-math is specified
> (not sure if IA64 masks exceptions on the comparisons?)

The manual says that QNaNs signal Invalid for the signaling FP comparison 
operators and that you need to enable the Invalid Operation trap to get a 
fault from Invalid.  The IEEE standard also says that comparisons by way of 
unordered signaling predicates raise the "invalid operation exception", just 
like the regular operations.  That being said, I can double-check.

Patch

Index: config/ia64/predicates.md
===================================================================
--- config/ia64/predicates.md	(revision 199343)
+++ config/ia64/predicates.md	(working copy)
@@ -568,9 +568,15 @@  (define_predicate "fr_reg_or_0_operand"
 	    (match_test "op == CONST0_RTX (GET_MODE (op))"))))
 
 ;; Return 1 if OP is a valid comparison operator for "cbranch" instructions.
+;; If we're assuming that FP operations cannot generate user-visible traps,
+;; then we can use the FP unordered-signaling instructions to implement the
+;; FP unordered-quiet comparison predicates.
 (define_predicate "ia64_cbranch_operator"
-  (ior (match_operand 0 "ordered_comparison_operator")
-       (match_code "ordered,unordered")))
+  (if_then_else (match_test "flag_trapping_math")
+		(ior (match_operand 0 "ordered_comparison_operator")
+		      (match_code "ordered,unordered"))
+		(and (match_operand 0 "comparison_operator")
+		      (not (match_code "uneq,ltgt")))))
 
 ;; True if this is a comparison operator, which accepts a normal 8-bit
 ;; signed immediate operand.
Index: config/ia64/ia64.c
===================================================================
--- config/ia64/ia64.c	(revision 199343)
+++ config/ia64/ia64.c	(working copy)
@@ -1756,7 +1756,7 @@  ia64_expand_compare (rtx *expr, rtx *op0
   else if (TARGET_HPUX && GET_MODE (*op0) == TFmode)
     {
       enum qfcmp_magic {
-	QCMP_INV = 1,	/* Raise FP_INVALID on SNaN as a side effect.  */
+	QCMP_INV = 1,	/* Raise FP_INVALID on NaNs as a side effect.  */
 	QCMP_UNORD = 2,
 	QCMP_EQ = 4,
 	QCMP_LT = 8,
@@ -1770,21 +1770,27 @@  ia64_expand_compare (rtx *expr, rtx *op0
       switch (code)
 	{
 	  /* 1 = equal, 0 = not equal.  Equality operators do
-	     not raise FP_INVALID when given an SNaN operand.  */
+	     not raise FP_INVALID when given a NaN operand.  */
 	case EQ:        magic = QCMP_EQ;                  ncode = NE; break;
 	case NE:        magic = QCMP_EQ;                  ncode = EQ; break;
 	  /* isunordered() from C99.  */
 	case UNORDERED: magic = QCMP_UNORD;               ncode = NE; break;
 	case ORDERED:   magic = QCMP_UNORD;               ncode = EQ; break;
 	  /* Relational operators raise FP_INVALID when given
-	     an SNaN operand.  */
+	     a NaN operand.  */
 	case LT:        magic = QCMP_LT        |QCMP_INV; ncode = NE; break;
 	case LE:        magic = QCMP_LT|QCMP_EQ|QCMP_INV; ncode = NE; break;
 	case GT:        magic = QCMP_GT        |QCMP_INV; ncode = NE; break;
 	case GE:        magic = QCMP_GT|QCMP_EQ|QCMP_INV; ncode = NE; break;
-	  /* FUTURE: Implement UNEQ, UNLT, UNLE, UNGT, UNGE, LTGT.
-	     Expanders for buneq etc. weuld have to be added to ia64.md
-	     for this to be useful.  */
+          /* Unordered relational operators do not raise FP_INVALID
+	     when given a NaN operand.  */
+	case UNLT:    magic = QCMP_LT        |QCMP_UNORD; ncode = NE; break;
+	case UNLE:    magic = QCMP_LT|QCMP_EQ|QCMP_UNORD; ncode = NE; break;
+	case UNGT:    magic = QCMP_GT        |QCMP_UNORD; ncode = NE; break;
+	case UNGE:    magic = QCMP_GT|QCMP_EQ|QCMP_UNORD; ncode = NE; break;
+	  /* Not supported.  */
+	case UNEQ:
+	case LTGT:
 	default: gcc_unreachable ();
 	}
 
@@ -5279,6 +5285,9 @@  ia64_print_operand (FILE * file, rtx x,
 	case UNGE:
 	  str = "nlt";
 	  break;
+	case UNEQ:
+	case LTGT:
+	  gcc_unreachable ();
 	default:
 	  str = GET_RTX_NAME (GET_CODE (x));
 	  break;