diff options
author | Tamar Christina <tnfchris@gcc.gnu.org> | 2017-06-09 08:10:51 +0000 |
---|---|---|
committer | Tamar Christina <tnfchris@gcc.gnu.org> | 2017-06-09 08:10:51 +0000 |
commit | 903c723b9d931abb6de044135c3bd4f44559fca7 (patch) | |
tree | 501cfa4a6ed13c934e7150ad55732b9b2c606305 /gcc/gimple-low.c | |
parent | 48e692477f5e3e1e99755b1e964ddd8a51fb5775 (diff) | |
download | gcc-903c723b9d931abb6de044135c3bd4f44559fca7.zip gcc-903c723b9d931abb6de044135c3bd4f44559fca7.tar.gz gcc-903c723b9d931abb6de044135c3bd4f44559fca7.tar.bz2 |
Reverted r249005 until PowerPC and AIX issues sorted.
From-SVN: r249050
Diffstat (limited to 'gcc/gimple-low.c')
-rw-r--r-- | gcc/gimple-low.c | 910 |
1 files changed, 7 insertions, 903 deletions
diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index 1cc4a4d..619b9d7 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -30,9 +30,6 @@ along with GCC; see the file COPYING3. If not see #include "calls.h" #include "gimple-iterator.h" #include "gimple-low.h" -#include "stor-layout.h" -#include "target.h" -#include "gimplify.h" /* The differences between High GIMPLE and Low GIMPLE are the following: @@ -75,13 +72,6 @@ static void lower_gimple_bind (gimple_stmt_iterator *, struct lower_data *); static void lower_try_catch (gimple_stmt_iterator *, struct lower_data *); static void lower_gimple_return (gimple_stmt_iterator *, struct lower_data *); static void lower_builtin_setjmp (gimple_stmt_iterator *); -static void lower_builtin_fpclassify (gimple_stmt_iterator *); -static void lower_builtin_isnan (gimple_stmt_iterator *); -static void lower_builtin_isinfinite (gimple_stmt_iterator *); -static void lower_builtin_isnormal (gimple_stmt_iterator *); -static void lower_builtin_iszero (gimple_stmt_iterator *); -static void lower_builtin_issubnormal (gimple_stmt_iterator *); -static void lower_builtin_isfinite (gimple_stmt_iterator *); static void lower_builtin_posix_memalign (gimple_stmt_iterator *); @@ -340,69 +330,18 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL) { - switch (DECL_FUNCTION_CODE (decl)) + if (DECL_FUNCTION_CODE (decl) == BUILT_IN_SETJMP) { - case BUILT_IN_SETJMP: lower_builtin_setjmp (gsi); data->cannot_fallthru = false; return; - - case BUILT_IN_POSIX_MEMALIGN: - if (flag_tree_bit_ccp - && gimple_builtin_call_types_compatible_p (stmt, decl)) - { - lower_builtin_posix_memalign (gsi); - return; - } - break; - - case BUILT_IN_FPCLASSIFY: - lower_builtin_fpclassify (gsi); - data->cannot_fallthru = false; - return; - - CASE_FLT_FN (BUILT_IN_ISINF): - case BUILT_IN_ISINFD32: - case BUILT_IN_ISINFD64: - case BUILT_IN_ISINFD128: - lower_builtin_isinfinite (gsi); - data->cannot_fallthru = false; - return; - - case BUILT_IN_ISNAND32: - case BUILT_IN_ISNAND64: - case BUILT_IN_ISNAND128: - CASE_FLT_FN (BUILT_IN_ISNAN): - lower_builtin_isnan (gsi); - data->cannot_fallthru = false; - return; - - case BUILT_IN_ISNORMAL: - lower_builtin_isnormal (gsi); - data->cannot_fallthru = false; - return; - - case BUILT_IN_ISZERO: - lower_builtin_iszero (gsi); - data->cannot_fallthru = false; - return; - - case BUILT_IN_ISSUBNORMAL: - lower_builtin_issubnormal (gsi); - data->cannot_fallthru = false; - return; - - CASE_FLT_FN (BUILT_IN_FINITE): - case BUILT_IN_FINITED32: - case BUILT_IN_FINITED64: - case BUILT_IN_FINITED128: - case BUILT_IN_ISFINITE: - lower_builtin_isfinite (gsi); - data->cannot_fallthru = false; + } + else if (DECL_FUNCTION_CODE (decl) == BUILT_IN_POSIX_MEMALIGN + && flag_tree_bit_ccp + && gimple_builtin_call_types_compatible_p (stmt, decl)) + { + lower_builtin_posix_memalign (gsi); return; - - default: - break; } } @@ -883,841 +822,6 @@ lower_builtin_setjmp (gimple_stmt_iterator *gsi) gsi_remove (gsi, false); } -/* This function will if ARG is not already a variable or SSA_NAME, - create a new temporary TMP and bind ARG to TMP. This new binding is then - emitted into SEQ and TMP is returned. */ -static tree -emit_tree_and_return_var (gimple_seq *seq, tree arg) -{ - if (TREE_CODE (arg) == SSA_NAME || VAR_P (arg)) - return arg; - - tree tmp = create_tmp_reg (TREE_TYPE (arg)); - gassign *stm = gimple_build_assign (tmp, arg); - gimple_seq_add_stmt (seq, stm); - return tmp; -} - -/* This function builds an if statement that ends up using explicit branches - instead of becoming a ternary conditional select. This function assumes you - will fall through to the next statements after the condition for the false - branch. The code emitted looks like: - - if (COND) - RESULT_VARIABLE = TRUE_BRANCH - GOTO EXIT_LABEL - else - ... - - SEQ is the gimple sequence/buffer to emit any new bindings to. - RESULT_VARIABLE is the value to set if COND. - EXIT_LABEL is the label to jump to in case COND. - COND is condition to use in the conditional statement of the if. - TRUE_BRANCH is the value to set RESULT_VARIABLE to if COND. */ -static void -emit_tree_cond (gimple_seq *seq, tree result_variable, tree exit_label, - tree cond, tree true_branch) -{ - /* Create labels for fall through. */ - tree true_label = create_artificial_label (UNKNOWN_LOCATION); - tree false_label = create_artificial_label (UNKNOWN_LOCATION); - gcond *stmt = gimple_build_cond_from_tree (cond, true_label, false_label); - gimple_seq_add_stmt (seq, stmt); - - /* Build the true case. */ - gimple_seq_add_stmt (seq, gimple_build_label (true_label)); - tree value = TREE_CONSTANT (true_branch) - ? true_branch - : emit_tree_and_return_var (seq, true_branch); - gimple_seq_add_stmt (seq, gimple_build_assign (result_variable, value)); - gimple_seq_add_stmt (seq, gimple_build_goto (exit_label)); - - /* Build the false case. */ - gimple_seq_add_stmt (seq, gimple_build_label (false_label)); -} - -/* This function returns a variable containing an reinterpreted ARG as an - integer. - - SEQ is the gimple sequence/buffer to write any new bindings to. - ARG is the floating point number to reinterpret as an integer. - LOC is the location to use when doing folding operations. */ -static tree -get_num_as_int (gimple_seq *seq, tree arg, location_t loc) -{ - tree type = TREE_TYPE (arg); - - const HOST_WIDE_INT type_width = TYPE_PRECISION (type); - - /* Re-interpret the float as an unsigned integer type - with equal precision. */ - tree int_arg_type = build_nonstandard_integer_type (type_width, true); - tree conv_arg = fold_build1_loc (loc, VIEW_CONVERT_EXPR, int_arg_type, arg); - return emit_tree_and_return_var (seq, conv_arg); -} - -/* Check if ARG which is the floating point number being classified is close - enough to IEEE 754 format to be able to go in the early exit code. */ -static bool -use_ieee_int_mode (tree arg) -{ - tree type = TREE_TYPE (arg); - machine_mode mode = TYPE_MODE (type); - - const real_format *format = REAL_MODE_FORMAT (mode); - machine_mode imode = int_mode_for_mode (mode); - bool is_ibm_extended = MODE_COMPOSITE_P (mode); - - return (format->is_binary_ieee_compatible - && FLOAT_WORDS_BIG_ENDIAN == WORDS_BIG_ENDIAN - /* Check if there's a usable integer mode. */ - && imode != BLKmode - && targetm.scalar_mode_supported_p (imode) - && !is_ibm_extended); -} - -/* Perform some IBM extended format fixups on ARG for use by FP functions. - This is done by ignoring the lower 64 bits of the number. - - MODE is the machine mode of ARG. - TYPE is the type of ARG. - LOC is the location to be used in fold functions. Usually is the location - of the definition of ARG. */ -static bool -perform_ibm_extended_fixups (tree *arg, machine_mode *mode, - tree *type, location_t loc) -{ - bool is_ibm_extended = MODE_COMPOSITE_P (*mode); - if (is_ibm_extended) - { - /* NaN and Inf are encoded in the high-order double value - only. The low-order value is not significant. */ - *type = double_type_node; - *mode = DFmode; - *arg = fold_build1_loc (loc, NOP_EXPR, *type, *arg); - } - - return is_ibm_extended; -} - -/* Generates code to check if ARG is a normal number. For the FP case we check - MIN_VALUE(ARG) <= ABS(ARG) > INF and for the INT value we check the exp and - mantissa bits. Returns a variable containing a boolean which has the result - of the check. - - SEQ is the buffer to use to emit the gimple instructions into. - LOC is the location to use during fold calls. */ -static tree -is_normal (gimple_seq *seq, tree arg, location_t loc) -{ - tree type = TREE_TYPE (arg); - - machine_mode mode = TYPE_MODE (type); - const real_format *format = REAL_MODE_FORMAT (mode); - const tree bool_type = boolean_type_node; - - - /* If not using optimized route then exit early. */ - if (!use_ieee_int_mode (arg)) - { - tree orig_arg = arg; - machine_mode orig_mode = mode; - if (TREE_CODE (arg) != SSA_NAME - && (TREE_ADDRESSABLE (arg) != 0 - || (TREE_CODE (arg) != PARM_DECL - && (!VAR_P (arg) || TREE_STATIC (arg))))) - orig_arg = save_expr (arg); - - /* Perform IBM extended format fixups if required. */ - bool is_ibm_extended = perform_ibm_extended_fixups (&arg, &mode, - &type, loc); - - REAL_VALUE_TYPE rinf, rmin; - tree arg_p = fold_build1_loc (loc, ABS_EXPR, type, arg); - - tree const islt_fn = builtin_decl_explicit (BUILT_IN_ISLESS); - tree const isgt_fn = builtin_decl_explicit (BUILT_IN_ISGREATER); - tree const isge_fn = builtin_decl_explicit (BUILT_IN_ISGREATEREQUAL); - - char buf[128]; - real_inf (&rinf); - get_min_float (REAL_MODE_FORMAT (orig_mode), buf, sizeof (buf)); - real_from_string (&rmin, buf); - - tree inf_exp = build_call_expr (islt_fn, 2, arg_p, - build_real (type, rinf)); - tree min_exp = build_real (type, rmin); - if (is_ibm_extended) - { - /* Testing the high end of the range is done just using - the high double, using the same test as isfinite(). - For the subnormal end of the range we first test the - high double, then if its magnitude is equal to the - limit of 0x1p-969, we test whether the low double is - non-zero and opposite sign to the high double. */ - tree gt_min = build_call_expr (isgt_fn, 2, arg_p, min_exp); - tree eq_min = fold_build2 (EQ_EXPR, integer_type_node, - arg_p, min_exp); - tree as_complex = build1 (VIEW_CONVERT_EXPR, - complex_double_type_node, orig_arg); - tree hi_dbl = build1 (REALPART_EXPR, type, as_complex); - tree lo_dbl = build1 (IMAGPART_EXPR, type, as_complex); - tree zero = build_real (type, dconst0); - tree hilt = build_call_expr (islt_fn, 2, hi_dbl, zero); - tree lolt = build_call_expr (islt_fn, 2, lo_dbl, zero); - tree logt = build_call_expr (isgt_fn, 2, lo_dbl, zero); - tree ok_lo = fold_build1 (TRUTH_NOT_EXPR, integer_type_node, - fold_build3 (COND_EXPR, - integer_type_node, - hilt, logt, lolt)); - eq_min = fold_build2 (TRUTH_ANDIF_EXPR, integer_type_node, - eq_min, ok_lo); - min_exp = fold_build2 (TRUTH_ORIF_EXPR, integer_type_node, - gt_min, eq_min); - } - else - { - min_exp = build_call_expr (isge_fn, 2, arg_p, min_exp); - } - - push_gimplify_context (); - gimplify_expr (&min_exp, seq, NULL, is_gimple_val, fb_either); - gimplify_expr (&inf_exp, seq, NULL, is_gimple_val, fb_either); - - tree res - = fold_build2_loc (loc, BIT_AND_EXPR, bool_type, - emit_tree_and_return_var (seq, - gimple_boolify (min_exp)), - emit_tree_and_return_var (seq, - gimple_boolify (inf_exp))); - pop_gimplify_context (NULL); - - return emit_tree_and_return_var (seq, res); - } - - const tree int_type = unsigned_type_node; - const int exp_bits = (GET_MODE_SIZE (mode) * BITS_PER_UNIT) - format->p; - const int exp_mask = (1 << exp_bits) - 1; - - /* Get the number reinterpreted as an integer. */ - tree int_arg = get_num_as_int (seq, arg, loc); - - /* Extract exp bits from the float, where we expect the exponent to be. - We create a new type because BIT_FIELD_REF does not allow you to - extract less bits than the precision of the storage variable. */ - tree exp_tmp - = fold_build3_loc (loc, BIT_FIELD_REF, - build_nonstandard_integer_type (exp_bits, true), - int_arg, - build_int_cstu (int_type, exp_bits), - build_int_cstu (int_type, format->p - 1)); - tree exp_bitfield = emit_tree_and_return_var (seq, exp_tmp); - - /* Re-interpret the extracted exponent bits as a 32 bit int. - This allows us to continue doing operations as int_type. */ - tree exp - = emit_tree_and_return_var (seq, fold_build1_loc (loc, NOP_EXPR, int_type, - exp_bitfield)); - - /* exp_mask & ~1. */ - tree mask_check - = fold_build2_loc (loc, BIT_AND_EXPR, int_type, - build_int_cstu (int_type, exp_mask), - fold_build1_loc (loc, BIT_NOT_EXPR, int_type, - build_int_cstu (int_type, 1))); - - /* (exp + 1) & mask_check. - Check to see if exp is not all 0 or all 1. */ - tree exp_check - = fold_build2_loc (loc, BIT_AND_EXPR, int_type, - emit_tree_and_return_var (seq, - fold_build2_loc (loc, PLUS_EXPR, int_type, exp, - build_int_cstu (int_type, 1))), - mask_check); - - tree res = fold_build2_loc (loc, NE_EXPR, boolean_type_node, - build_int_cstu (int_type, 0), - emit_tree_and_return_var (seq, exp_check)); - - return emit_tree_and_return_var (seq, res); -} - -/* Generates code to check if ARG is a zero. For both the FP and INT case we - check if ARG == 0 (modulo sign bit). Returns a variable containing a boolean - which has the result of the check. - - SEQ is the buffer to use to emit the gimple instructions into. - LOC is the location to use during fold calls. */ -static tree -is_zero (gimple_seq *seq, tree arg, location_t loc) -{ - tree type = TREE_TYPE (arg); - - /* If not using optimized route then exit early. */ - if (!use_ieee_int_mode (arg)) - { - machine_mode mode = TYPE_MODE (type); - /* Perform IBM extended format fixups if required. */ - perform_ibm_extended_fixups (&arg, &mode, &type, loc); - - tree res = fold_build2_loc (loc, EQ_EXPR, boolean_type_node, arg, - build_real (type, dconst0)); - return emit_tree_and_return_var (seq, res); - } - - const HOST_WIDE_INT type_width = TYPE_PRECISION (type); - - tree int_arg_type = build_nonstandard_integer_type (type_width, true); - - /* Get the number reinterpreted as an integer. - Shift left to remove the sign. */ - tree int_arg - = fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type, - get_num_as_int (seq, arg, loc), - build_int_cstu (int_arg_type, 1)); - - /* num << 1 == 0. - This checks to see if the number is zero. */ - tree zero_check - = fold_build2_loc (loc, EQ_EXPR, boolean_type_node, - build_int_cstu (int_arg_type, 0), - emit_tree_and_return_var (seq, int_arg)); - - return emit_tree_and_return_var (seq, zero_check); -} - -/* Generates code to check if ARG is a subnormal number. In the FP case we test - fabs (ARG) != 0 && fabs (ARG) < MIN_VALUE (ARG) and in the INT case we check - the exp and mantissa bits on ARG. Returns a variable containing a boolean - which has the result of the check. - - SEQ is the buffer to use to emit the gimple instructions into. - LOC is the location to use during fold calls. */ -static tree -is_subnormal (gimple_seq *seq, tree arg, location_t loc) -{ - const tree bool_type = boolean_type_node; - - tree type = TREE_TYPE (arg); - - machine_mode mode = TYPE_MODE (type); - const real_format *format = REAL_MODE_FORMAT (mode); - const HOST_WIDE_INT type_width = TYPE_PRECISION (type); - - tree int_arg_type = build_nonstandard_integer_type (type_width, true); - - /* If not using optimized route then exit early. */ - if (!use_ieee_int_mode (arg)) - { - tree const islt_fn = builtin_decl_explicit (BUILT_IN_ISLESS); - tree const isgt_fn = builtin_decl_explicit (BUILT_IN_ISGREATER); - - tree arg_p - = emit_tree_and_return_var (seq, fold_build1_loc (loc, ABS_EXPR, type, - arg)); - REAL_VALUE_TYPE r; - char buf[128]; - get_min_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf)); - real_from_string (&r, buf); - tree subnorm = build_call_expr (islt_fn, 2, arg_p, build_real (type, r)); - - tree zero = build_call_expr (isgt_fn, 2, arg_p, - build_real (type, dconst0)); - - push_gimplify_context (); - gimplify_expr (&subnorm, seq, NULL, is_gimple_val, fb_either); - gimplify_expr (&zero, seq, NULL, is_gimple_val, fb_either); - - tree res - = fold_build2_loc (loc, BIT_AND_EXPR, bool_type, - emit_tree_and_return_var (seq, - gimple_boolify (subnorm)), - emit_tree_and_return_var (seq, - gimple_boolify (zero))); - pop_gimplify_context (NULL); - - return emit_tree_and_return_var (seq, res); - } - - /* Get the number reinterpreted as an integer. - Shift left to remove the sign. */ - tree int_arg - = fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type, - get_num_as_int (seq, arg, loc), - build_int_cstu (int_arg_type, 1)); - - /* Check for a zero exponent and non-zero mantissa. - This can be done with two comparisons by first apply a - removing the sign bit and checking if the value is larger - than the mantissa mask. */ - - /* This creates a mask to be used to check the mantissa value in the shifted - integer representation of the fpnum. */ - tree significant_bit = build_int_cstu (int_arg_type, format->p - 1); - tree mantissa_mask - = fold_build2_loc (loc, MINUS_EXPR, int_arg_type, - fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type, - build_int_cstu (int_arg_type, 2), - significant_bit), - build_int_cstu (int_arg_type, 1)); - - /* Check if exponent is zero and mantissa is not. */ - tree subnorm_cond_tmp - = fold_build2_loc (loc, LE_EXPR, bool_type, - emit_tree_and_return_var (seq, int_arg), - mantissa_mask); - - tree subnorm_cond = emit_tree_and_return_var (seq, subnorm_cond_tmp); - - tree zero_cond - = fold_build2_loc (loc, GT_EXPR, boolean_type_node, - emit_tree_and_return_var (seq, int_arg), - build_int_cstu (int_arg_type, 0)); - - tree subnorm_check - = fold_build2_loc (loc, BIT_AND_EXPR, boolean_type_node, - emit_tree_and_return_var (seq, subnorm_cond), - emit_tree_and_return_var (seq, zero_cond)); - - return emit_tree_and_return_var (seq, subnorm_check); -} - -/* Generates code to check if ARG is an infinity. In the FP case we test - FABS(ARG) == INF and in the INT case we check the bits on the exp and - mantissa. Returns a variable containing a boolean which has the result - of the check. - - SEQ is the buffer to use to emit the gimple instructions into. - LOC is the location to use during fold calls. */ -static tree -is_infinity (gimple_seq *seq, tree arg, location_t loc) -{ - tree type = TREE_TYPE (arg); - - machine_mode mode = TYPE_MODE (type); - const tree bool_type = boolean_type_node; - - if (!HONOR_INFINITIES (mode)) - { - return build_int_cst (bool_type, false); - } - - /* If not using optimized route then exit early. */ - if (!use_ieee_int_mode (arg)) - { - /* Perform IBM extended format fixups if required. */ - perform_ibm_extended_fixups (&arg, &mode, &type, loc); - - tree arg_p - = emit_tree_and_return_var (seq, fold_build1_loc (loc, ABS_EXPR, type, - arg)); - REAL_VALUE_TYPE r; - real_inf (&r); - tree res = fold_build2_loc (loc, EQ_EXPR, bool_type, arg_p, - build_real (type, r)); - - return emit_tree_and_return_var (seq, res); - } - - const real_format *format = REAL_MODE_FORMAT (mode); - const HOST_WIDE_INT type_width = TYPE_PRECISION (type); - - tree int_arg_type = build_nonstandard_integer_type (type_width, true); - - /* This creates a mask to be used to check the exp value in the shifted - integer representation of the fpnum. */ - const int exp_bits = (GET_MODE_SIZE (mode) * BITS_PER_UNIT) - format->p; - gcc_assert (format->p > 0); - - tree significant_bit = build_int_cstu (int_arg_type, format->p); - tree exp_mask - = fold_build2_loc (loc, MINUS_EXPR, int_arg_type, - fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type, - build_int_cstu (int_arg_type, 2), - build_int_cstu (int_arg_type, - exp_bits - 1)), - build_int_cstu (int_arg_type, 1)); - - /* Get the number reinterpreted as an integer. - Shift left to remove the sign. */ - tree int_arg - = fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type, - get_num_as_int (seq, arg, loc), - build_int_cstu (int_arg_type, 1)); - - /* This mask checks to see if the exp has all bits set and mantissa no - bits set. */ - tree inf_mask - = fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type, - exp_mask, significant_bit); - - /* Check if exponent has all bits set and mantissa is 0. */ - tree inf_check - = emit_tree_and_return_var(seq, - fold_build2_loc (loc, EQ_EXPR, bool_type, - emit_tree_and_return_var(seq, int_arg), - inf_mask)); - - return emit_tree_and_return_var (seq, inf_check); -} - -/* Generates code to check if ARG is a finite number. In the FP case we check - if FABS(ARG) <= MAX_VALUE(ARG) and in the INT case we check the exp and - mantissa bits. Returns a variable containing a boolean which has the result - of the check. - - SEQ is the buffer to use to emit the gimple instructions into. - LOC is the location to use during fold calls. */ -static tree -is_finite (gimple_seq *seq, tree arg, location_t loc) -{ - tree type = TREE_TYPE (arg); - - machine_mode mode = TYPE_MODE (type); - const tree bool_type = boolean_type_node; - - if (!HONOR_NANS (arg) && !HONOR_INFINITIES (arg)) - { - return build_int_cst (bool_type, true); - } - - /* If not using optimized route then exit early. */ - if (!use_ieee_int_mode (arg)) - { - - /* Perform IBM extended format fixups if required. */ - perform_ibm_extended_fixups (&arg, &mode, &type, loc); - - tree const isle_fn = builtin_decl_explicit (BUILT_IN_ISLESSEQUAL); - - tree arg_p - = emit_tree_and_return_var (seq, fold_build1_loc (loc, ABS_EXPR, type, - arg)); - REAL_VALUE_TYPE rmax; - char buf[128]; - get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf)); - real_from_string (&rmax, buf); - - tree res = build_call_expr (isle_fn, 2, arg_p, build_real (type, rmax)); - - push_gimplify_context (); - gimplify_expr (&res, seq, NULL, is_gimple_val, fb_either); - pop_gimplify_context (NULL); - - return emit_tree_and_return_var (seq, gimple_boolify(res)); - } - - const real_format *format = REAL_MODE_FORMAT (mode); - const HOST_WIDE_INT type_width = TYPE_PRECISION (type); - - tree int_arg_type = build_nonstandard_integer_type (type_width, true); - - /* This creates a mask to be used to check the exp value in the shifted - integer representation of the fpnum. */ - const int exp_bits = (GET_MODE_SIZE (mode) * BITS_PER_UNIT) - format->p; - gcc_assert (format->p > 0); - - tree significant_bit = build_int_cstu (int_arg_type, format->p); - tree exp_mask - = fold_build2_loc (loc, MINUS_EXPR, int_arg_type, - fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type, - build_int_cstu (int_arg_type, 2), - build_int_cstu (int_arg_type, - exp_bits - 1)), - build_int_cstu (int_arg_type, 1)); - - /* Get the number reinterpreted as an integer. - Shift left to remove the sign. */ - tree int_arg - = fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type, - get_num_as_int (seq, arg, loc), - build_int_cstu (int_arg_type, 1)); - - /* This mask checks to see if the exp has all bits set and mantissa no - bits set. */ - tree inf_mask - = fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type, - exp_mask, significant_bit); - - /* Check if exponent has all bits set and mantissa is 0. */ - tree inf_check_tmp - = fold_build2_loc (loc, LT_EXPR, bool_type, - emit_tree_and_return_var (seq, int_arg), - inf_mask); - - tree inf_check = emit_tree_and_return_var (seq, inf_check_tmp); - - return emit_tree_and_return_var (seq, inf_check); -} - -/* Generates code to check if ARG is a NaN. In the FP case we simply check if - ARG != ARG and in the INT case we check the bits in the exp and mantissa. - Returns a variable containing a boolean which has the result of the check. - - SEQ is the buffer to use to emit the gimple instructions into. - LOC is the location to use during fold calls. */ -static tree -is_nan (gimple_seq *seq, tree arg, location_t loc) -{ - tree type = TREE_TYPE (arg); - - machine_mode mode = TYPE_MODE (type); - const tree bool_type = boolean_type_node; - - if (!HONOR_NANS (mode)) - { - return build_int_cst (bool_type, false); - } - - const real_format *format = REAL_MODE_FORMAT (mode); - - /* If not using optimized route then exit early. */ - if (!use_ieee_int_mode (arg)) - { - /* Perform IBM extended format fixups if required. */ - perform_ibm_extended_fixups (&arg, &mode, &type, loc); - - tree arg_p - = emit_tree_and_return_var (seq, fold_build1_loc (loc, ABS_EXPR, type, - arg)); - tree res - = fold_build2_loc (loc, UNORDERED_EXPR, bool_type,arg_p, arg_p); - - return emit_tree_and_return_var (seq, res); - } - - const HOST_WIDE_INT type_width = TYPE_PRECISION (type); - tree int_arg_type = build_nonstandard_integer_type (type_width, true); - - /* This creates a mask to be used to check the exp value in the shifted - integer representation of the fpnum. */ - const int exp_bits = (GET_MODE_SIZE (mode) * BITS_PER_UNIT) - format->p; - tree significant_bit = build_int_cstu (int_arg_type, format->p); - tree exp_mask - = fold_build2_loc (loc, MINUS_EXPR, int_arg_type, - fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type, - build_int_cstu (int_arg_type, 2), - build_int_cstu (int_arg_type, - exp_bits - 1)), - build_int_cstu (int_arg_type, 1)); - - /* Get the number reinterpreted as an integer. - Shift left to remove the sign. */ - tree int_arg - = fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type, - get_num_as_int (seq, arg, loc), - build_int_cstu (int_arg_type, 1)); - - /* This mask checks to see if the exp has all bits set and mantissa no - bits set. */ - tree inf_mask - = fold_build2_loc (loc, LSHIFT_EXPR, int_arg_type, - exp_mask, significant_bit); - - /* Check if exponent has all bits set and mantissa is not 0. */ - tree nan_check - = emit_tree_and_return_var(seq, - fold_build2_loc (loc, GT_EXPR, bool_type, - emit_tree_and_return_var(seq, int_arg), - inf_mask)); - - return emit_tree_and_return_var (seq, nan_check); -} - -/* Validates a single argument from the arguments list CALL at position INDEX. - The extracted parameter is compared against the expected type CODE. - - A boolean is returned indicating if the parameter exist and if of the - expected type. */ -static bool -gimple_validate_arg (gimple* call, int index, enum tree_code code) -{ - const tree arg = gimple_call_arg (call, index); - if (!arg) - return false; - else if (code == POINTER_TYPE) - return POINTER_TYPE_P (TREE_TYPE (arg)); - else if (code == INTEGER_TYPE) - return INTEGRAL_TYPE_P (TREE_TYPE (arg)); - return code == TREE_CODE (TREE_TYPE (arg)); -} - -/* Lowers calls to __builtin_fpclassify to - fpclassify (x) -> - isnormal(x) ? FP_NORMAL : - iszero (x) ? FP_ZERO : - isnan (x) ? FP_NAN : - isinfinite (x) ? FP_INFINITE : - FP_SUBNORMAL. - - The code may use integer arithmentic if it decides - that the produced assembly would be faster. This can only be done - for numbers that are similar to IEEE-754 in format. - - This builtin will generate code to return the appropriate floating - point classification depending on the value of the floating point - number passed in. The possible return values must be supplied as - int arguments to the call in the following order: FP_NAN, FP_INFINITE, - FP_NORMAL, FP_SUBNORMAL and FP_ZERO. The ellipses is for exactly - one floating point argument which is "type generic". - - GSI is the gimple iterator containing the fpclassify call to lower. - The call will be expanded and replaced inline in the given GSI. */ -static void -lower_builtin_fpclassify (gimple_stmt_iterator *gsi) -{ - gimple *call = gsi_stmt (*gsi); - location_t loc = gimple_location (call); - - /* Verify the required arguments in the original call. */ - if (gimple_call_num_args (call) != 6 - || !gimple_validate_arg (call, 0, INTEGER_TYPE) - || !gimple_validate_arg (call, 1, INTEGER_TYPE) - || !gimple_validate_arg (call, 2, INTEGER_TYPE) - || !gimple_validate_arg (call, 3, INTEGER_TYPE) - || !gimple_validate_arg (call, 4, INTEGER_TYPE) - || !gimple_validate_arg (call, 5, REAL_TYPE)) - return; - - /* Collect the arguments from the call. */ - tree fp_nan = gimple_call_arg (call, 0); - tree fp_infinite = gimple_call_arg (call, 1); - tree fp_normal = gimple_call_arg (call, 2); - tree fp_subnormal = gimple_call_arg (call, 3); - tree fp_zero = gimple_call_arg (call, 4); - tree arg = gimple_call_arg (call, 5); - - gimple_seq body = NULL; - - /* Create label to jump to to exit. */ - tree done_label = create_artificial_label (UNKNOWN_LOCATION); - tree dest; - tree orig_dest = dest = gimple_call_lhs (call); - if (orig_dest && TREE_CODE (orig_dest) == SSA_NAME) - dest = create_tmp_reg (TREE_TYPE (orig_dest)); - - emit_tree_cond (&body, dest, done_label, - is_normal (&body, arg, loc), fp_normal); - emit_tree_cond (&body, dest, done_label, - is_zero (&body, arg, loc), fp_zero); - emit_tree_cond (&body, dest, done_label, - is_nan (&body, arg, loc), fp_nan); - emit_tree_cond (&body, dest, done_label, - is_infinity (&body, arg, loc), fp_infinite); - - /* And finally, emit the default case if nothing else matches. - This replaces the call to is_subnormal. */ - gimple_seq_add_stmt (&body, gimple_build_assign (dest, fp_subnormal)); - gimple_seq_add_stmt (&body, gimple_build_label (done_label)); - - /* Build orig_dest = dest if necessary. */ - if (dest != orig_dest) - { - gimple_seq_add_stmt (&body, gimple_build_assign (orig_dest, dest)); - } - - gsi_insert_seq_before (gsi, body, GSI_SAME_STMT); - - - /* Remove the call to __builtin_fpclassify. */ - gsi_remove (gsi, false); -} - -/* Generic wrapper for the is_nan, is_normal, is_subnormal, is_zero, etc. - All these functions have the same setup. The wrapper validates the parameter - and also creates the branches and labels required to properly invoke. - This has been generalize and the function to call is passed as argument FNDECL. - - GSI is the gimple iterator containing the fpclassify call to lower. - The call will be expanded and replaced inline in the given GSI. */ -static void -gen_call_fp_builtin (gimple_stmt_iterator *gsi, - tree (*fndecl)(gimple_seq *, tree, location_t)) -{ - gimple *call = gsi_stmt (*gsi); - location_t loc = gimple_location (call); - - /* Verify the required arguments in the original call. */ - if (gimple_call_num_args (call) != 1 - || !gimple_validate_arg (call, 0, REAL_TYPE)) - return; - - tree arg = gimple_call_arg (call, 0); - gimple_seq body = NULL; - - /* Create label to jump to to exit. */ - tree done_label = create_artificial_label (UNKNOWN_LOCATION); - tree dest; - tree orig_dest = dest = gimple_call_lhs (call); - tree type = TREE_TYPE (orig_dest); - if (orig_dest && TREE_CODE (orig_dest) == SSA_NAME) - dest = create_tmp_reg (type); - - tree t_true = build_int_cst (type, true); - tree t_false = build_int_cst (type, false); - - emit_tree_cond (&body, dest, done_label, - fndecl (&body, arg, loc), t_true); - - /* And finally, emit the default case if nothing else matches. - This replaces the call to false. */ - gimple_seq_add_stmt (&body, gimple_build_assign (dest, t_false)); - gimple_seq_add_stmt (&body, gimple_build_label (done_label)); - - /* Build orig_dest = dest if necessary. */ - if (dest != orig_dest) - { - gimple_seq_add_stmt (&body, gimple_build_assign (orig_dest, dest)); - } - - gsi_insert_seq_before (gsi, body, GSI_SAME_STMT); - - /* Remove the call to the builtin. */ - gsi_remove (gsi, false); -} - -/* Lower and expand calls to __builtin_isnan in GSI. */ -static void -lower_builtin_isnan (gimple_stmt_iterator *gsi) -{ - gen_call_fp_builtin (gsi, &is_nan); -} - -/* Lower and expand calls to __builtin_isinfinite in GSI. */ -static void -lower_builtin_isinfinite (gimple_stmt_iterator *gsi) -{ - gen_call_fp_builtin (gsi, &is_infinity); -} - -/* Lower and expand calls to __builtin_isnormal in GSI. */ -static void -lower_builtin_isnormal (gimple_stmt_iterator *gsi) -{ - gen_call_fp_builtin (gsi, &is_normal); -} - -/* Lower and expand calls to __builtin_iszero in GSI. */ -static void -lower_builtin_iszero (gimple_stmt_iterator *gsi) -{ - gen_call_fp_builtin (gsi, &is_zero); -} - -/* Lower and expand calls to __builtin_issubnormal in GSI. */ -static void -lower_builtin_issubnormal (gimple_stmt_iterator *gsi) -{ - gen_call_fp_builtin (gsi, &is_subnormal); -} - -/* Lower and expand calls to __builtin_isfinite in GSI. */ -static void -lower_builtin_isfinite (gimple_stmt_iterator *gsi) -{ - gen_call_fp_builtin (gsi, &is_finite); -} - /* Lower calls to posix_memalign to res = posix_memalign (ptr, align, size); if (res == 0) |