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:
parent
cea79118fa
commit
a1a8261107
13 changed files with 129 additions and 34 deletions
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
15
gcc/opts.c
15
gcc/opts.c
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 *);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
Loading…
Add table
Reference in a new issue