aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/trans.c
diff options
context:
space:
mode:
authorArnaud Charlet <charlet@gcc.gnu.org>2005-01-03 16:36:06 +0100
committerArnaud Charlet <charlet@gcc.gnu.org>2005-01-03 16:36:06 +0100
commit050d31e81515eeaaad6768904faf40fd0ce7f1dc (patch)
treed2fe6394d342c3b74749dc0e0c67f5ebc45351d6 /gcc/ada/trans.c
parentc5e12904bcca3866f419bb91365dbdfb052b8782 (diff)
downloadgcc-050d31e81515eeaaad6768904faf40fd0ce7f1dc.zip
gcc-050d31e81515eeaaad6768904faf40fd0ce7f1dc.tar.gz
gcc-050d31e81515eeaaad6768904faf40fd0ce7f1dc.tar.bz2
eval_fat.adb: (Eps_Model,Eps_Denorm): Remove, no longer used.
* eval_fat.adb: (Eps_Model,Eps_Denorm): Remove, no longer used. (Succ): Re-implement using Scaling, Exponent and Ceiling attributes. (Pred): Implement in terms of Succ. * trans.c (convert_with_check): Reimplement conversion of float to integer. From-SVN: r92834
Diffstat (limited to 'gcc/ada/trans.c')
-rw-r--r--gcc/ada/trans.c71
1 files changed, 54 insertions, 17 deletions
diff --git a/gcc/ada/trans.c b/gcc/ada/trans.c
index a005fed..94aa9dc 100644
--- a/gcc/ada/trans.c
+++ b/gcc/ada/trans.c
@@ -165,9 +165,6 @@ static tree maybe_implicit_deref (tree);
static tree gnat_stabilize_reference_1 (tree, bool);
static void annotate_with_node (tree, Node_Id);
-/* Constants for +0.5 and -0.5 for float-to-integer rounding. */
-static REAL_VALUE_TYPE dconstp5;
-static REAL_VALUE_TYPE dconstmp5;
/* This is the main program of the back-end. It sets up all the table
structures and then generates code. */
@@ -288,9 +285,6 @@ gnat_init_stmt_group ()
set_stack_check_libfunc (gen_rtx_SYMBOL_REF (Pmode, "_gnat_stack_check"));
gcc_assert (Exception_Mechanism != Front_End_ZCX);
-
- REAL_ARITHMETIC (dconstp5, RDIV_EXPR, dconst1, dconst2);
- REAL_ARITHMETIC (dconstmp5, RDIV_EXPR, dconstm1, dconst2);
}
/* Subroutine of gnat_to_gnu to translate gnat_node, an N_Identifier,
@@ -5195,17 +5189,60 @@ convert_with_check (Entity_Id gnat_type, tree gnu_expr, bool overflowp,
if (INTEGRAL_TYPE_P (gnu_ada_base_type) && FLOAT_TYPE_P (gnu_in_basetype)
&& !truncatep)
{
- tree gnu_point_5 = build_real (gnu_in_basetype, dconstp5);
- tree gnu_minus_point_5 = build_real (gnu_in_basetype, dconstmp5);
- tree gnu_zero = convert (gnu_in_basetype, integer_zero_node);
- tree gnu_saved_result = save_expr (gnu_result);
- tree gnu_comp = build2 (GE_EXPR, integer_type_node,
- gnu_saved_result, gnu_zero);
- tree gnu_adjust = build3 (COND_EXPR, gnu_in_basetype, gnu_comp,
- gnu_point_5, gnu_minus_point_5);
-
- gnu_result
- = build2 (PLUS_EXPR, gnu_in_basetype, gnu_saved_result, gnu_adjust);
+ REAL_VALUE_TYPE half_minus_pred_half, pred_half;
+ tree gnu_conv, gnu_zero, gnu_comp, gnu_saved_result, calc_type;
+ tree gnu_pred_half, gnu_add_pred_half, gnu_subtract_pred_half;
+ const struct real_format *fmt;
+
+ /* The following calculations depend on proper rounding to even
+ of each arithmetic operation. In order to prevent excess
+ precision from spoiling this property, use the widest hardware
+ floating-point type.
+
+ FIXME: For maximum efficiency, this should only be done for machines
+ and types where intermediates may have extra precision. */
+
+ calc_type = longest_float_type_node;
+ /* FIXME: Should not have padding in the first place */
+ if (TREE_CODE (calc_type) == RECORD_TYPE
+ && TYPE_IS_PADDING_P (calc_type))
+ calc_type = TREE_TYPE (TYPE_FIELDS (calc_type));
+
+ /* Compute the exact value calc_type'Pred (0.5) at compile time. */
+ fmt = REAL_MODE_FORMAT (TYPE_MODE (calc_type));
+ real_2expN (&half_minus_pred_half, -(fmt->p) - 1);
+ REAL_ARITHMETIC (pred_half, MINUS_EXPR, dconsthalf,
+ half_minus_pred_half);
+ gnu_pred_half = build_real (calc_type, pred_half);
+
+ /* If the input is strictly negative, subtract this value
+ and otherwise add it from the input. For 0.5, the result
+ is exactly between 1.0 and the machine number preceding 1.0
+ (for calc_type). Since the last bit of 1.0 is even, this 0.5
+ will round to 1.0, while all other number with an absolute
+ value less than 0.5 round to 0.0. For larger numbers exactly
+ halfway between integers, rounding will always be correct as
+ the true mathematical result will be closer to the higher
+ integer compared to the lower one. So, this constant works
+ for all floating-point numbers.
+
+ The reason to use the same constant with subtract/add instead
+ of a positive and negative constant is to allow the comparison
+ to be scheduled in parallel with retrieval of the constant and
+ conversion of the input to the calc_type (if necessary).
+ */
+
+ gnu_zero = convert (gnu_in_basetype, integer_zero_node);
+ gnu_saved_result = save_expr (gnu_result);
+ gnu_conv = convert (calc_type, gnu_saved_result);
+ gnu_comp = build2 (GE_EXPR, integer_type_node,
+ gnu_saved_result, gnu_zero);
+ gnu_add_pred_half
+ = build2 (PLUS_EXPR, calc_type, gnu_conv, gnu_pred_half);
+ gnu_subtract_pred_half
+ = build2 (MINUS_EXPR, calc_type, gnu_conv, gnu_pred_half);
+ gnu_result = build3 (COND_EXPR, calc_type, gnu_comp,
+ gnu_add_pred_half, gnu_subtract_pred_half);
}
if (TREE_CODE (gnu_ada_base_type) == INTEGER_TYPE