Commit 531e5376 by Richard Henderson Committed by Richard Henderson

loop-unroll.c (analyze_insn_to_expand_var): Accept

	* loop-unroll.c (analyze_insn_to_expand_var): Accept
	* accumulation
	via FMA if unsafe math.
	(insert_var_expansion_initialization): Handle FMA.
	(combine_var_copies_in_loop_exit): Likewise.

From-SVN: r166781
parent f19f1e5e
2010-11-15 Richard Henderson <rth@redhat.com> 2010-11-15 Richard Henderson <rth@redhat.com>
* loop-unroll.c (analyze_insn_to_expand_var): Accept accumulation
via FMA if unsafe math.
(insert_var_expansion_initialization): Handle FMA.
(combine_var_copies_in_loop_exit): Likewise.
2010-11-15 Richard Henderson <rth@redhat.com>
* config.gcc [ia64-*] (extra_options): Add fused-madd.opt. * config.gcc [ia64-*] (extra_options): Add fused-madd.opt.
* config/ia64/ia64.opt: Remove mfused-madd. * config/ia64/ia64.opt: Remove mfused-madd.
* config/ia64/ia64.c (ia64_rtx_costs): Handle FP MULT, PLUS, FMA. * config/ia64/ia64.c (ia64_rtx_costs): Handle FP MULT, PLUS, FMA.
...@@ -1616,10 +1616,10 @@ reset_debug_uses_in_loop (struct loop *loop, rtx reg, int debug_uses) ...@@ -1616,10 +1616,10 @@ reset_debug_uses_in_loop (struct loop *loop, rtx reg, int debug_uses)
static struct var_to_expand * static struct var_to_expand *
analyze_insn_to_expand_var (struct loop *loop, rtx insn) analyze_insn_to_expand_var (struct loop *loop, rtx insn)
{ {
rtx set, dest, src, op1, op2, something; rtx set, dest, src;
struct var_to_expand *ves; struct var_to_expand *ves;
enum machine_mode mode1, mode2;
unsigned accum_pos; unsigned accum_pos;
enum rtx_code code;
int debug_uses = 0; int debug_uses = 0;
set = single_set (insn); set = single_set (insn);
...@@ -1628,12 +1628,20 @@ analyze_insn_to_expand_var (struct loop *loop, rtx insn) ...@@ -1628,12 +1628,20 @@ analyze_insn_to_expand_var (struct loop *loop, rtx insn)
dest = SET_DEST (set); dest = SET_DEST (set);
src = SET_SRC (set); src = SET_SRC (set);
code = GET_CODE (src);
if (GET_CODE (src) != PLUS if (code != PLUS && code != MINUS && code != MULT && code != FMA)
&& GET_CODE (src) != MINUS
&& GET_CODE (src) != MULT)
return NULL; return NULL;
if (FLOAT_MODE_P (GET_MODE (dest)))
{
if (!flag_associative_math)
return NULL;
/* In the case of FMA, we're also changing the rounding. */
if (code == FMA && !flag_unsafe_math_optimizations)
return NULL;
}
/* Hmm, this is a bit paradoxical. We know that INSN is a valid insn /* Hmm, this is a bit paradoxical. We know that INSN is a valid insn
in MD. But if there is no optab to generate the insn, we can not in MD. But if there is no optab to generate the insn, we can not
perform the variable expansion. This can happen if an MD provides perform the variable expansion. This can happen if an MD provides
...@@ -1643,54 +1651,57 @@ analyze_insn_to_expand_var (struct loop *loop, rtx insn) ...@@ -1643,54 +1651,57 @@ analyze_insn_to_expand_var (struct loop *loop, rtx insn)
So we check have_insn_for which looks for an optab for the operation So we check have_insn_for which looks for an optab for the operation
in SRC. If it doesn't exist, we can't perform the expansion even in SRC. If it doesn't exist, we can't perform the expansion even
though INSN is valid. */ though INSN is valid. */
if (!have_insn_for (GET_CODE (src), GET_MODE (src))) if (!have_insn_for (code, GET_MODE (src)))
return NULL; return NULL;
op1 = XEXP (src, 0);
op2 = XEXP (src, 1);
if (!REG_P (dest) if (!REG_P (dest)
&& !(GET_CODE (dest) == SUBREG && !(GET_CODE (dest) == SUBREG
&& REG_P (SUBREG_REG (dest)))) && REG_P (SUBREG_REG (dest))))
return NULL; return NULL;
if (rtx_equal_p (dest, op1)) /* Find the accumulator use within the operation. */
if (code == FMA)
{
/* We only support accumulation via FMA in the ADD position. */
if (!rtx_equal_p (dest, XEXP (src, 2)))
return NULL;
accum_pos = 2;
}
else if (rtx_equal_p (dest, XEXP (src, 0)))
accum_pos = 0; accum_pos = 0;
else if (rtx_equal_p (dest, op2)) else if (rtx_equal_p (dest, XEXP (src, 1)))
accum_pos = 1; {
/* The method of expansion that we are using; which includes the
initialization of the expansions with zero and the summation of
the expansions at the end of the computation will yield wrong
results for (x = something - x) thus avoid using it in that case. */
if (code == MINUS)
return NULL;
accum_pos = 1;
}
else else
return NULL; return NULL;
/* The method of expansion that we are using; which includes /* It must not otherwise be used. */
the initialization of the expansions with zero and the summation of if (code == FMA)
the expansions at the end of the computation will yield wrong results {
for (x = something - x) thus avoid using it in that case. */ if (rtx_referenced_p (dest, XEXP (src, 0))
if (accum_pos == 1 || rtx_referenced_p (dest, XEXP (src, 1)))
&& GET_CODE (src) == MINUS) return NULL;
return NULL; }
else if (rtx_referenced_p (dest, XEXP (src, 1 - accum_pos)))
something = (accum_pos == 0) ? op2 : op1;
if (rtx_referenced_p (dest, something))
return NULL; return NULL;
/* It must be used in exactly one insn. */
if (!referenced_in_one_insn_in_loop_p (loop, dest, &debug_uses)) if (!referenced_in_one_insn_in_loop_p (loop, dest, &debug_uses))
return NULL; return NULL;
mode1 = GET_MODE (dest);
mode2 = GET_MODE (something);
if ((FLOAT_MODE_P (mode1)
|| FLOAT_MODE_P (mode2))
&& !flag_associative_math)
return NULL;
if (dump_file) if (dump_file)
{ {
fprintf (dump_file, fprintf (dump_file, "\n;; Expanding Accumulator ");
"\n;; Expanding Accumulator "); print_rtl (dump_file, dest);
print_rtl (dump_file, dest); fprintf (dump_file, "\n");
fprintf (dump_file, "\n"); }
}
if (debug_uses) if (debug_uses)
/* Instead of resetting the debug insns, we could replace each /* Instead of resetting the debug insns, we could replace each
...@@ -2123,22 +2134,33 @@ insert_var_expansion_initialization (struct var_to_expand *ve, ...@@ -2123,22 +2134,33 @@ insert_var_expansion_initialization (struct var_to_expand *ve,
return; return;
start_sequence (); start_sequence ();
if (ve->op == PLUS || ve->op == MINUS) switch (ve->op)
FOR_EACH_VEC_ELT (rtx, ve->var_expansions, i, var) {
{ case FMA:
if (honor_signed_zero_p) /* Note that we only accumulate FMA via the ADD operand. */
zero_init = simplify_gen_unary (NEG, mode, CONST0_RTX (mode), mode); case PLUS:
else case MINUS:
zero_init = CONST0_RTX (mode); FOR_EACH_VEC_ELT (rtx, ve->var_expansions, i, var)
{
if (honor_signed_zero_p)
zero_init = simplify_gen_unary (NEG, mode, CONST0_RTX (mode), mode);
else
zero_init = CONST0_RTX (mode);
emit_move_insn (var, zero_init);
}
break;
emit_move_insn (var, zero_init); case MULT:
} FOR_EACH_VEC_ELT (rtx, ve->var_expansions, i, var)
else if (ve->op == MULT) {
FOR_EACH_VEC_ELT (rtx, ve->var_expansions, i, var) zero_init = CONST1_RTX (GET_MODE (var));
{ emit_move_insn (var, zero_init);
zero_init = CONST1_RTX (GET_MODE (var)); }
emit_move_insn (var, zero_init); break;
}
default:
gcc_unreachable ();
}
seq = get_insns (); seq = get_insns ();
end_sequence (); end_sequence ();
...@@ -2165,18 +2187,24 @@ combine_var_copies_in_loop_exit (struct var_to_expand *ve, basic_block place) ...@@ -2165,18 +2187,24 @@ combine_var_copies_in_loop_exit (struct var_to_expand *ve, basic_block place)
return; return;
start_sequence (); start_sequence ();
if (ve->op == PLUS || ve->op == MINUS) switch (ve->op)
FOR_EACH_VEC_ELT (rtx, ve->var_expansions, i, var) {
{ case FMA:
sum = simplify_gen_binary (PLUS, GET_MODE (ve->reg), /* Note that we only accumulate FMA via the ADD operand. */
var, sum); case PLUS:
} case MINUS:
else if (ve->op == MULT) FOR_EACH_VEC_ELT (rtx, ve->var_expansions, i, var)
FOR_EACH_VEC_ELT (rtx, ve->var_expansions, i, var) sum = simplify_gen_binary (PLUS, GET_MODE (ve->reg), var, sum);
{ break;
sum = simplify_gen_binary (MULT, GET_MODE (ve->reg),
var, sum); case MULT:
} FOR_EACH_VEC_ELT (rtx, ve->var_expansions, i, var)
sum = simplify_gen_binary (MULT, GET_MODE (ve->reg), var, sum);
break;
default:
gcc_unreachable ();
}
expr = force_operand (sum, ve->reg); expr = force_operand (sum, ve->reg);
if (expr != ve->reg) if (expr != ve->reg)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment