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 second (less surprising) example is the e500 architecture which features
FP instructions operating on GP registers. It has neither ORDERED/UNORDERED
nor the UNLT/UNLE/UNGT/UNGE operators so, in this case, you get a new call to
the libgcc routine implementing UNORDERED in addition to the comparison. The
fix is to make it possible to use the (negated form of the) ordered comparison
instructions, which are signaling, for the quiet unordered operators when the
flag -fno-trapping-math is in effect. As a matter of fact, a partial support
was already there (e.g. in rs6000_generate_compare) but it was disabled.
Tested on e500v2/Linux and PowerPC/Linux, OK for the mainline?
2013-05-29 Eric Botcazou <ebotca...@adacore.com>
* config/rs6000/predicates.md (rs6000_cbranch_operator): Accept some
unordered comparison operators when -fno-trapping-math is in effect
on the e500.
* config/rs6000/rs6000.c (rs6000_generate_compare): Remove dead code
and implement unordered comparison operators properly on the e500.
--
Eric Botcazou
Index: config/rs6000/predicates.md
===================================================================
--- config/rs6000/predicates.md (revision 199343)
+++ config/rs6000/predicates.md (working copy)
@@ -1121,9 +1121,16 @@ (define_predicate "branch_comparison_ope
GET_MODE (XEXP (op, 0))),
1"))))
+;; 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 on e500 we can use the ordered-signaling instructions to implement
+;; the unordered-quiet FP comparison predicates modulo a reversal.
(define_predicate "rs6000_cbranch_operator"
(if_then_else (match_test "TARGET_HARD_FLOAT && !TARGET_FPRS")
- (match_operand 0 "ordered_comparison_operator")
+ (if_then_else (match_test "flag_trapping_math")
+ (match_operand 0 "ordered_comparison_operator")
+ (ior (match_operand 0 "ordered_comparison_operator")
+ (match_code ("unlt,unle,ungt,unge"))))
(match_operand 0 "comparison_operator")))
;; Return 1 if OP is a comparison operation that is valid for an SCC insn --
Index: config/rs6000/rs6000.c
===================================================================
--- config/rs6000/rs6000.c (revision 199343)
+++ config/rs6000/rs6000.c (working copy)
@@ -16086,16 +16086,41 @@ rs6000_generate_compare (rtx cmp, enum m
{
rtx cmp, or_result, compare_result2;
enum machine_mode op_mode = GET_MODE (op0);
+ bool reverse_p;
if (op_mode == VOIDmode)
op_mode = GET_MODE (op1);
+ /* First reverse the condition codes that aren't directly supported. */
+ switch (code)
+ {
+ case NE:
+ case UNLT:
+ case UNLE:
+ case UNGT:
+ case UNGE:
+ code = reverse_condition_maybe_unordered (code);
+ reverse_p = true;
+ break;
+
+ case EQ:
+ case LT:
+ case LE:
+ case GT:
+ case GE:
+ reverse_p = false;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
/* The E500 FP compare instructions toggle the GT bit (CR bit 1) only.
This explains the following mess. */
switch (code)
{
- case EQ: case UNEQ: case NE: case LTGT:
+ case EQ:
switch (op_mode)
{
case SFmode:
@@ -16121,7 +16146,8 @@ rs6000_generate_compare (rtx cmp, enum m
}
break;
- case GT: case GTU: case UNGT: case UNGE: case GE: case GEU:
+ case GT:
+ case GE:
switch (op_mode)
{
case SFmode:
@@ -16147,7 +16173,8 @@ rs6000_generate_compare (rtx cmp, enum m
}
break;
- case LT: case LTU: case UNLT: case UNLE: case LE: case LEU:
+ case LT:
+ case LE:
switch (op_mode)
{
case SFmode:
@@ -16172,24 +16199,16 @@ rs6000_generate_compare (rtx cmp, enum m
gcc_unreachable ();
}
break;
+
default:
gcc_unreachable ();
}
/* Synthesize LE and GE from LT/GT || EQ. */
- if (code == LE || code == GE || code == LEU || code == GEU)
+ if (code == LE || code == GE)
{
emit_insn (cmp);
- switch (code)
- {
- case LE: code = LT; break;
- case GE: code = GT; break;
- case LEU: code = LT; break;
- case GEU: code = GT; break;
- default: gcc_unreachable ();
- }
-
compare_result2 = gen_reg_rtx (CCFPmode);
/* Do the EQ. */
@@ -16216,23 +16235,18 @@ rs6000_generate_compare (rtx cmp, enum m
default:
gcc_unreachable ();
}
+
emit_insn (cmp);
/* OR them together. */
or_result = gen_reg_rtx (CCFPmode);
cmp = gen_e500_cr_ior_compare (or_result, compare_result,
- compare_result2);
+ compare_result2);
compare_result = or_result;
- code = EQ;
- }
- else
- {
- if (code == NE || code == LTGT)
- code = NE;
- else
- code = EQ;
}
+ code = reverse_p ? NE : EQ;
+
emit_insn (cmp);
}
else