diff options
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r-- | gcc/c-common.c | 152 |
1 files changed, 90 insertions, 62 deletions
diff --git a/gcc/c-common.c b/gcc/c-common.c index ed67bb0..7fad4b3 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -2202,10 +2202,15 @@ truthvalue_conversion (expr) break; case MINUS_EXPR: - /* With IEEE arithmetic, x - x may not equal 0, so we can't optimize - this case. */ - if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT - && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE) + /* Perhaps reduce (x - y) != 0 to (x != y). The expressions + aren't guaranteed to the be same for modes that can represent + infinity, since if x and y are both +infinity, or both + -infinity, then x - y is not a number. + + Note that this transformation is safe when x or y is NaN. + (x - y) is then NaN, and both (x - y) != 0 and x != y will + be false. */ + if (HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (TREE_OPERAND (expr, 0))))) break; /* fall through... */ case BIT_XOR_EXPR: @@ -3051,6 +3056,81 @@ strip_array_types (type) return type; } +static tree expand_unordered_cmp PARAMS ((tree, tree, enum tree_code, + enum tree_code)); + +/* Expand a call to an unordered comparison function such as + __builtin_isgreater(). FUNCTION is the function's declaration and + PARAMS a list of the values passed. For __builtin_isunordered(), + UNORDERED_CODE is UNORDERED_EXPR and ORDERED_CODE is NOP_EXPR. In + other cases, UNORDERED_CODE and ORDERED_CODE are comparison codes + that give the opposite of the desired result. UNORDERED_CODE is + used for modes that can hold NaNs and ORDERED_CODE is used for the + rest. */ + +static tree +expand_unordered_cmp (function, params, unordered_code, ordered_code) + tree function, params; + enum tree_code unordered_code, ordered_code; +{ + tree arg0, arg1, type; + enum tree_code code0, code1; + + /* Check that we have exactly two arguments. */ + if (params == 0 || TREE_CHAIN (params) == 0) + { + error ("too few arguments to function `%s'", + IDENTIFIER_POINTER (DECL_NAME (function))); + return error_mark_node; + } + else if (TREE_CHAIN (TREE_CHAIN (params)) != 0) + { + error ("too many arguments to function `%s'", + IDENTIFIER_POINTER (DECL_NAME (function))); + return error_mark_node; + } + + arg0 = TREE_VALUE (params); + arg1 = TREE_VALUE (TREE_CHAIN (params)); + + code0 = TREE_CODE (TREE_TYPE (arg0)); + code1 = TREE_CODE (TREE_TYPE (arg1)); + + /* Make sure that the arguments have a common type of REAL. */ + type = 0; + if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE) + && (code1 == INTEGER_TYPE || code1 == REAL_TYPE)) + type = common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)); + + if (type == 0 || TREE_CODE (type) != REAL_TYPE) + { + error ("non-floating-point argument to function `%s'", + IDENTIFIER_POINTER (DECL_NAME (function))); + return error_mark_node; + } + + if (unordered_code == UNORDERED_EXPR) + { + if (MODE_HAS_NANS (TYPE_MODE (type))) + return build_binary_op (unordered_code, + convert (type, arg0), + convert (type, arg1), + 0); + else + return integer_zero_node; + } + + return build_unary_op (TRUTH_NOT_EXPR, + build_binary_op (MODE_HAS_NANS (TYPE_MODE (type)) + ? unordered_code + : ordered_code, + convert (type, arg0), + convert (type, arg1), + 0), + 0); +} + + /* Recognize certain built-in functions so we can make tree-codes other than CALL_EXPR. We do this when it enables fold-const.c to do something useful. */ @@ -3063,8 +3143,6 @@ tree expand_tree_builtin (function, params, coerced_params) tree function, params, coerced_params; { - enum tree_code code; - if (DECL_BUILT_IN_CLASS (function) != BUILT_IN_NORMAL) return NULL_TREE; @@ -3103,72 +3181,22 @@ expand_tree_builtin (function, params, coerced_params) return build_unary_op (IMAGPART_EXPR, TREE_VALUE (coerced_params), 0); case BUILT_IN_ISGREATER: - if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT) - code = UNLE_EXPR; - else - code = LE_EXPR; - goto unordered_cmp; + return expand_unordered_cmp (function, params, UNLE_EXPR, LE_EXPR); case BUILT_IN_ISGREATEREQUAL: - if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT) - code = UNLT_EXPR; - else - code = LT_EXPR; - goto unordered_cmp; + return expand_unordered_cmp (function, params, UNLT_EXPR, LT_EXPR); case BUILT_IN_ISLESS: - if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT) - code = UNGE_EXPR; - else - code = GE_EXPR; - goto unordered_cmp; + return expand_unordered_cmp (function, params, UNGE_EXPR, GE_EXPR); case BUILT_IN_ISLESSEQUAL: - if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT) - code = UNGT_EXPR; - else - code = GT_EXPR; - goto unordered_cmp; + return expand_unordered_cmp (function, params, UNGT_EXPR, GT_EXPR); case BUILT_IN_ISLESSGREATER: - if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT) - code = UNEQ_EXPR; - else - code = EQ_EXPR; - goto unordered_cmp; + return expand_unordered_cmp (function, params, UNEQ_EXPR, EQ_EXPR); case BUILT_IN_ISUNORDERED: - if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT) - return integer_zero_node; - code = UNORDERED_EXPR; - goto unordered_cmp; - - unordered_cmp: - { - tree arg0, arg1; - - if (params == 0 - || TREE_CHAIN (params) == 0) - { - error ("too few arguments to function `%s'", - IDENTIFIER_POINTER (DECL_NAME (function))); - return error_mark_node; - } - else if (TREE_CHAIN (TREE_CHAIN (params)) != 0) - { - error ("too many arguments to function `%s'", - IDENTIFIER_POINTER (DECL_NAME (function))); - return error_mark_node; - } - - arg0 = TREE_VALUE (params); - arg1 = TREE_VALUE (TREE_CHAIN (params)); - arg0 = build_binary_op (code, arg0, arg1, 0); - if (code != UNORDERED_EXPR) - arg0 = build_unary_op (TRUTH_NOT_EXPR, arg0, 0); - return arg0; - } - break; + return expand_unordered_cmp (function, params, UNORDERED_EXPR, NOP_EXPR); default: break; |