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 <ebotca...@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
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;