Add new fp flags: -fassociative-math and -freciprocal-math

Co-Authored-By: R. Clint Whaley <whaley@cs.utsa.edu>
Co-Authored-By: Richard Guenther <rguenther@suse.de>

From-SVN: r128075
This commit is contained in:
Revital Eres 2007-09-04 12:11:11 +00:00 committed by Revital Eres
parent cea79118fa
commit a1a8261107
13 changed files with 129 additions and 34 deletions

View file

@ -1,3 +1,35 @@
2007-09-04 Revital Eres <eres@il.ibm.com>
Richard Guenther <rguenther@suse.de>
R. Clint Whaley <whaley@cs.utsa.edu>
* doc/invoke.texi (-fassociative-math, -freciprocal-math):
Document new flags.
* tree-tailcall.c (process_assignment): Use -fassociative-math
when reodering operands of floating-point type.
* fold-const.c (fold_comparison, fold_binary): Use
-fassociative-math and -freciprocal-math instead of
-funsafe-math-optimization flag.
* toplev.h (set_unsafe_math_optimizations_flags): Declare function.
* tree-ssa-math-opts.c (gate_cse_reciprocals): Use
-freciprocal-math instead of -funsafe-math-optimizations.
* opts.c (set_fast_math_flags): Set -freciprocal-math and
-fassociative-math when -ffast-math is set.
(set_unsafe_math_optimizations_flags): New Function
to set -freciprocal-math and -fassociative-math when
-funsafe-math-optimizations is set.
(common_handle_option): Call it.
* tree-vectorizer.c (vect_is_simple_reduction): Use
-fassociative-math when doing reduction on floats.
* loop-unroll.c (analyze_insn_to_expand_var): Use
-fassociative-math when expanding an accumulator of type float.
* simplify-rtx.c (simplify_binary_operation_1): Use
-fassociative-math and -freciprocal-math when reordeing operands
of floating-point type.
* combine.c (combine_simplify_rtx): Likewise.
* tree-ssa-reassoc.c (break_up_subtract_bb, reassociate_bb):
Likewise.
* common.opt (-fassociative-math, -freciprocal-math): New flags.
2007-09-04 Paolo Carlini <pcarlini@suse.de>
PR c++/18608

View file

@ -4699,7 +4699,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
|| code == AND || code == IOR || code == XOR
|| code == SMAX || code == SMIN || code == UMAX || code == UMIN)
&& ((INTEGRAL_MODE_P (mode) && code != DIV)
|| (flag_unsafe_math_optimizations && FLOAT_MODE_P (mode))))
|| (flag_associative_math && FLOAT_MODE_P (mode))))
{
if (GET_CODE (XEXP (x, 0)) == code)
{
@ -4972,7 +4972,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
}
/* Try simplify a*(b/c) as (a*b)/c. */
if (FLOAT_MODE_P (mode) && flag_unsafe_math_optimizations
if (FLOAT_MODE_P (mode) && flag_associative_math
&& GET_CODE (XEXP (x, 0)) == DIV)
{
rtx tem = simplify_binary_operation (MULT, mode,

View file

@ -1125,6 +1125,15 @@ funsafe-loop-optimizations
Common Report Var(flag_unsafe_loop_optimizations) Optimization
Allow loop optimizations to assume that the loops behave in normal way
fassociative-math
Common Report Var(flag_associative_math)
Allow optimization for floating-point arithmetic which may change the
result of the operation due to rounding.
freciprocal-math
Common Report Var(flag_reciprocal_math)
Same as -fassociative-math for expressions which include division.
; Nonzero means that unsafe floating-point math optimizations are allowed
; for the sake of speed. IEEE compliance is not guaranteed, and operations
; are allowed to assume that their arguments and results are "normal"

View file

@ -6173,6 +6173,7 @@ it might, and @option{-fno-math-errno} is the default.
@item -funsafe-math-optimizations
@opindex funsafe-math-optimizations
Allow optimizations for floating-point arithmetic that (a) assume
that arguments and results are valid and (b) may violate IEEE or
ANSI standards. When used at link-time, it may include libraries
@ -6184,9 +6185,36 @@ it can result in incorrect output for programs which depend on
an exact implementation of IEEE or ISO rules/specifications for
math functions. It may, however, yield faster code for programs
that do not require the guarantees of these specifications.
Enables @option{-freciprocal-math} and @option{-fassociative-math}.
The default is @option{-fno-unsafe-math-optimizations}.
@item -fassociative-math
@opindex -fassociative-math
Allow re-association of operands in series of floating-point operations.
This violates the ISO C and C++ language standard by possibly changing
computation result. NOTE: re-ordering may change the sign of zero as
well as ignore NaNs and inhibit or create underflow or overflow (and
thus cannot be used on a code which relies on rounding behavior like
@code{(x + 2**52) - 2**52)}. May also reorder floating-point comparisons
and thus may not be used when ordered comparisons are required.
This flag doesn't make much sense without @option{-fno-signed-zeros}
or @option{-fno-trapping-math} or with @option{-frounding-math}.
The default is @option{-fno-associative-math}.
@item -freciprocal-math
@opindex -freciprocal-math
Allow the reciprocal of a value to be used instead of dividing by
the value if this enables optimizations. For example @code{x / y}
can be replaced with @code{x * (1/y)} which is useful if @code{(1/y)}
is subject to common subexpression elimination. Note that this loses
precision and increases the number of flops operating on the value.
The default is @option{-fno-reciprocal-math}.
@item -ffinite-math-only
@opindex ffinite-math-only
Allow optimizations for floating-point arithmetic that assume

View file

@ -9096,8 +9096,9 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
/* Likewise, we can simplify a comparison of a real constant with
a MINUS_EXPR whose first operand is also a real constant, i.e.
(c1 - x) < c2 becomes x > c1-c2. */
if (flag_unsafe_math_optimizations
(c1 - x) < c2 becomes x > c1-c2. Reordering is allowed on
floating-point types only if -fassociative-math is set. */
if (flag_associative_math
&& TREE_CODE (arg1) == REAL_CST
&& TREE_CODE (arg0) == MINUS_EXPR
&& TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST
@ -9651,11 +9652,12 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
}
/* Handle (A1 * C1) + (A2 * C2) with A1, A2 or C1, C2 being the
same or one. Make sure type is not saturating. */
same or one. Make sure type is not saturating.
fold_plusminus_mult_expr will re-associate. */
if ((TREE_CODE (arg0) == MULT_EXPR
|| TREE_CODE (arg1) == MULT_EXPR)
&& !TYPE_SATURATING (type)
&& (!FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
&& (!FLOAT_TYPE_P (type) || flag_associative_math))
{
tree tem = fold_plusminus_mult_expr (code, type, arg0, arg1);
if (tem)
@ -9791,8 +9793,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
return fold_build2 (MULT_EXPR, type, arg0,
build_real (type, dconst2));
/* Convert a + (b*c + d*e) into (a + b*c) + d*e. */
if (flag_unsafe_math_optimizations
/* Convert a + (b*c + d*e) into (a + b*c) + d*e.
We associate floats only if the user has specified
-fassociative-math. */
if (flag_associative_math
&& TREE_CODE (arg1) == PLUS_EXPR
&& TREE_CODE (arg0) != MULT_EXPR)
{
@ -9806,8 +9810,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
return fold_build2 (PLUS_EXPR, type, tree0, tree11);
}
}
/* Convert (b*c + d*e) + a into b*c + (d*e +a). */
if (flag_unsafe_math_optimizations
/* Convert (b*c + d*e) + a into b*c + (d*e +a).
We associate floats only if the user has specified
-fassociative-math. */
if (flag_associative_math
&& TREE_CODE (arg0) == PLUS_EXPR
&& TREE_CODE (arg1) != MULT_EXPR)
{
@ -9898,10 +9904,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
/* In most languages, can't associate operations on floats through
parentheses. Rather than remember where the parentheses were, we
don't associate floats at all, unless the user has specified
-funsafe-math-optimizations.
-fassociative-math.
And, we need to make sure type is not saturating. */
if ((! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
if ((! FLOAT_TYPE_P (type) || flag_associative_math)
&& !TYPE_SATURATING (type))
{
tree var0, con0, lit0, minus_lit0;
@ -10202,11 +10208,12 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
return tem;
/* Handle (A1 * C1) - (A2 * C2) with A1, A2 or C1, C2 being the
same or one. Make sure type is not saturating. */
same or one. Make sure type is not saturating.
fold_plusminus_mult_expr will re-associate. */
if ((TREE_CODE (arg0) == MULT_EXPR
|| TREE_CODE (arg1) == MULT_EXPR)
&& !TYPE_SATURATING (type)
&& (!FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
&& (!FLOAT_TYPE_P (type) || flag_associative_math))
{
tree tem = fold_plusminus_mult_expr (code, type, arg0, arg1);
if (tem)
@ -10297,8 +10304,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
&& real_minus_onep (arg1))
return fold_convert (type, negate_expr (arg0));
/* Convert (C1/X)*C2 into (C1*C2)/X. */
if (flag_unsafe_math_optimizations
/* Convert (C1/X)*C2 into (C1*C2)/X. This transformation may change
the result for floating point types due to rounding so it is applied
only if -fassociative-math was specify. */
if (flag_associative_math
&& TREE_CODE (arg0) == RDIV_EXPR
&& TREE_CODE (arg1) == REAL_CST
&& TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST)
@ -10962,12 +10971,12 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
/* If ARG1 is a constant, we can convert this to a multiply by the
reciprocal. This does not have the same rounding properties,
so only do this if -funsafe-math-optimizations. We can actually
so only do this if -freciprocal-math. We can actually
always safely do it if ARG1 is a power of two, but it's hard to
tell if it is or not in a portable manner. */
if (TREE_CODE (arg1) == REAL_CST)
{
if (flag_unsafe_math_optimizations
if (flag_reciprocal_math
&& 0 != (tem = const_binop (code, build_real (type, dconst1),
arg1, 0)))
return fold_build2 (MULT_EXPR, type, arg0, tem);
@ -10984,15 +10993,15 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
}
}
}
/* Convert A/B/C to A/(B*C). */
if (flag_unsafe_math_optimizations
/* Convert A/B/C to A/(B*C). */
if (flag_reciprocal_math
&& TREE_CODE (arg0) == RDIV_EXPR)
return fold_build2 (RDIV_EXPR, type, TREE_OPERAND (arg0, 0),
fold_build2 (MULT_EXPR, type,
TREE_OPERAND (arg0, 1), arg1));
/* Convert A/(B/C) to (A/B)*C. */
if (flag_unsafe_math_optimizations
if (flag_reciprocal_math
&& TREE_CODE (arg1) == RDIV_EXPR)
return fold_build2 (MULT_EXPR, type,
fold_build2 (RDIV_EXPR, type, arg0,
@ -11000,7 +11009,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
TREE_OPERAND (arg1, 1));
/* Convert C1/(X*C2) into (C1/C2)/X. */
if (flag_unsafe_math_optimizations
if (flag_reciprocal_math
&& TREE_CODE (arg1) == MULT_EXPR
&& TREE_CODE (arg0) == REAL_CST
&& TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST)

View file

@ -1631,7 +1631,7 @@ analyze_insn_to_expand_var (struct loop *loop, rtx insn)
mode2 = GET_MODE (something);
if ((FLOAT_MODE_P (mode1)
|| FLOAT_MODE_P (mode2))
&& !flag_unsafe_math_optimizations)
&& !flag_associative_math)
return NULL;
if (dump_file)

View file

@ -1559,6 +1559,10 @@ common_handle_option (size_t scode, const char *arg, int value,
set_fast_math_flags (value);
break;
case OPT_funsafe_math_optimizations:
set_unsafe_math_optimizations_flags (value);
break;
case OPT_ffixed_:
fix_register (arg, 1, 1);
break;
@ -1857,6 +1861,8 @@ set_fast_math_flags (int set)
{
flag_trapping_math = !set;
flag_unsafe_math_optimizations = set;
flag_associative_math = set;
flag_reciprocal_math = set;
flag_finite_math_only = set;
flag_signed_zeros = !set;
flag_errno_math = !set;
@ -1868,6 +1874,15 @@ set_fast_math_flags (int set)
}
}
/* When -funsafe-math-optimizations is set the following
flags are set as well. */
void
set_unsafe_math_optimizations_flags (int set)
{
flag_reciprocal_math = set;
flag_associative_math = set;
}
/* Return true iff flags are set as if -ffast-math. */
bool
fast_math_flags_set_p (void)

View file

@ -1723,9 +1723,9 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
return tem;
/* Reassociate floating point addition only when the user
specifies unsafe math optimizations. */
specifies associative math operations. */
if (FLOAT_MODE_P (mode)
&& flag_unsafe_math_optimizations)
&& flag_associative_math)
{
tem = simplify_associative_operation (code, mode, op0, op1);
if (tem)
@ -2480,8 +2480,8 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
return simplify_gen_unary (NEG, mode, op0, mode);
/* Change FP division by a constant into multiplication.
Only do this with -funsafe-math-optimizations. */
if (flag_unsafe_math_optimizations
Only do this with -freciprocal-math. */
if (flag_reciprocal_math
&& !REAL_VALUES_EQUAL (d, dconst0))
{
REAL_ARITHMETIC (d, RDIV_EXPR, dconst1, d);

View file

@ -148,6 +148,8 @@ extern struct ht *ident_hash;
extern void set_fast_math_flags (int);
extern void set_unsafe_math_optimizations_flags (int);
/* Handle -d switch. */
extern void decode_d_option (const char *);

View file

@ -443,7 +443,7 @@ execute_cse_reciprocals_1 (block_stmt_iterator *def_bsi, tree def)
static bool
gate_cse_reciprocals (void)
{
return optimize && !optimize_size && flag_unsafe_math_optimizations;
return optimize && !optimize_size && flag_reciprocal_math;
}
/* Go through all the floating-point SSA_NAMEs, and call

View file

@ -1244,14 +1244,14 @@ break_up_subtract_bb (basic_block bb)
tree rhs = GIMPLE_STMT_OPERAND (stmt, 1);
TREE_VISITED (stmt) = 0;
/* If unsafe math optimizations we can do reassociation for
/* If associative-math we can do reassociation for
non-integral types. Or, we can do reassociation for
non-saturating fixed-point types. */
if ((!INTEGRAL_TYPE_P (TREE_TYPE (lhs))
|| !INTEGRAL_TYPE_P (TREE_TYPE (rhs)))
&& (!SCALAR_FLOAT_TYPE_P (TREE_TYPE (rhs))
|| !SCALAR_FLOAT_TYPE_P (TREE_TYPE(lhs))
|| !flag_unsafe_math_optimizations)
|| !flag_associative_math)
&& (!NON_SAT_FIXED_POINT_TYPE_P (TREE_TYPE (rhs))
|| !NON_SAT_FIXED_POINT_TYPE_P (TREE_TYPE(lhs))))
continue;
@ -1294,14 +1294,14 @@ reassociate_bb (basic_block bb)
if (TREE_VISITED (stmt))
continue;
/* If unsafe math optimizations we can do reassociation for
/* If associative-math we can do reassociation for
non-integral types. Or, we can do reassociation for
non-saturating fixed-point types. */
if ((!INTEGRAL_TYPE_P (TREE_TYPE (lhs))
|| !INTEGRAL_TYPE_P (TREE_TYPE (rhs)))
&& (!SCALAR_FLOAT_TYPE_P (TREE_TYPE (rhs))
|| !SCALAR_FLOAT_TYPE_P (TREE_TYPE(lhs))
|| !flag_unsafe_math_optimizations)
|| !flag_associative_math)
&& (!NON_SAT_FIXED_POINT_TYPE_P (TREE_TYPE (rhs))
|| !NON_SAT_FIXED_POINT_TYPE_P (TREE_TYPE(lhs))))
continue;

View file

@ -297,7 +297,7 @@ process_assignment (tree ass, tree stmt, block_stmt_iterator call, tree *m,
/* Accumulator optimizations will reverse the order of operations.
We can only do that for floating-point types if we're assuming
that addition and multiplication are associative. */
if (!flag_unsafe_math_optimizations)
if (!flag_associative_math)
if (FLOAT_TYPE_P (TREE_TYPE (DECL_RESULT (current_function_decl))))
return false;

View file

@ -2304,7 +2304,7 @@ vect_is_simple_reduction (loop_vec_info loop_info, tree phi)
outer-loop vectorization is safe. */
/* CHECKME: check for !flag_finite_math_only too? */
if (SCALAR_FLOAT_TYPE_P (type) && !flag_unsafe_math_optimizations
if (SCALAR_FLOAT_TYPE_P (type) && !flag_associative_math
&& !nested_in_vect_loop_p (vect_loop, def_stmt))
{
/* Changing the order of operations changes the semantics. */