+
+ /* The result of {MIN,MAX}_EXPR is unspecified if either operand is
+ a NaN so we implement the semantics of C99 f{min,max} to make it
+ predictable in this case: if either operand is a NaN, the other
+ is returned; if both operands are NaN's, a NaN is returned. */
+ if (SCALAR_FLOAT_TYPE_P (gnu_result_type))
+ {
+ const bool lhs_side_effects_p = TREE_SIDE_EFFECTS (gnu_lhs);
+ const bool rhs_side_effects_p = TREE_SIDE_EFFECTS (gnu_rhs);
+ tree t = builtin_decl_explicit (BUILT_IN_ISNAN);
+ tree lhs_is_nan, rhs_is_nan;
+
+ /* If the operands have side-effects, they need to be evaluated
+ only once in spite of the multiple references in the result. */
+ if (lhs_side_effects_p)
+ gnu_lhs = gnat_protect_expr (gnu_lhs);
+ if (rhs_side_effects_p)
+ gnu_rhs = gnat_protect_expr (gnu_rhs);
+
+ lhs_is_nan = fold_build2 (NE_EXPR, boolean_type_node,
+ build_call_expr (t, 1, gnu_lhs),
+ integer_zero_node);
+
+ rhs_is_nan = fold_build2 (NE_EXPR, boolean_type_node,
+ build_call_expr (t, 1, gnu_rhs),
+ integer_zero_node);
+
+ gnu_result = build_binary_op (attribute == Attr_Min
+ ? MIN_EXPR : MAX_EXPR,
+ gnu_result_type, gnu_lhs, gnu_rhs);
+ gnu_result = fold_build3 (COND_EXPR, gnu_result_type,
+ rhs_is_nan, gnu_lhs, gnu_result);
+ gnu_result = fold_build3 (COND_EXPR, gnu_result_type,
+ lhs_is_nan, gnu_rhs, gnu_result);
+
+ /* If the operands have side-effects, they need to be evaluated
+ before doing the tests above since the place they otherwise
+ would end up being evaluated at run time could be wrong. */
+ if (lhs_side_effects_p)
+ gnu_result
+ = build2 (COMPOUND_EXPR, gnu_result_type, gnu_lhs, gnu_result);
+
+ if (rhs_side_effects_p)
+ gnu_result
+ = build2 (COMPOUND_EXPR, gnu_result_type, gnu_rhs, gnu_result);
+ }
+ else
+ gnu_result = build_binary_op (attribute == Attr_Min
+ ? MIN_EXPR : MAX_EXPR,
+ gnu_result_type, gnu_lhs, gnu_rhs);