From 976c37ad089d74465f1b173517138a0a047336ee Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 10 Nov 2010 13:46:01 -0800 Subject: [PATCH 2/3] Recognize -(a * b) + c -> fma(-a,b,c). --- gcc/tree-ssa-math-opts.c | 107 +++++++++++++++++++++++++++++++++------------ 1 files changed, 78 insertions(+), 29 deletions(-) diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c index 96140f0..2840150 100644 --- a/gcc/tree-ssa-math-opts.c +++ b/gcc/tree-ssa-math-opts.c @@ -1503,7 +1503,7 @@ convert_mult_to_fma (gimple mul_stmt) { tree mul_result = gimple_assign_lhs (mul_stmt); tree type = TREE_TYPE (mul_result); - gimple use_stmt, fma_stmt; + gimple use_stmt, neguse_stmt, fma_stmt; use_operand_p use_p; imm_use_iterator imm_iter; @@ -1529,17 +1529,12 @@ convert_mult_to_fma (gimple mul_stmt) FOR_EACH_IMM_USE_FAST (use_p, imm_iter, mul_result) { enum tree_code use_code; + tree result = mul_result; + bool negate_p = false; + optab opt; use_stmt = USE_STMT (use_p); - if (!is_gimple_assign (use_stmt)) - return false; - use_code = gimple_assign_rhs_code (use_stmt); - /* ??? We need to handle NEGATE_EXPR to eventually form fnms. */ - if (use_code != PLUS_EXPR - && use_code != MINUS_EXPR) - return false; - /* For now restrict this operations to single basic blocks. In theory we would want to support sinking the multiplication in m = a*b; @@ -1552,32 +1547,82 @@ convert_mult_to_fma (gimple mul_stmt) if (gimple_bb (use_stmt) != gimple_bb (mul_stmt)) return false; - /* We can't handle a * b + a * b. */ - if (gimple_assign_rhs1 (use_stmt) == gimple_assign_rhs2 (use_stmt)) + if (!is_gimple_assign (use_stmt)) return false; - /* If the target doesn't support a * b - c then drop the ball. */ - if (gimple_assign_rhs1 (use_stmt) == mul_result - && use_code == MINUS_EXPR - && optab_handler (fms_optab, TYPE_MODE (type)) == CODE_FOR_nothing) - return false; + use_code = gimple_assign_rhs_code (use_stmt); + + /* A negate on the multiplication leads to FNMA. */ + if (use_code == NEGATE_EXPR) + { + result = gimple_assign_lhs (use_stmt); + + /* Make sure the negate statement becomes dead with this + single transformation. */ + if (!single_imm_use (gimple_assign_lhs (use_stmt), + &use_p, &neguse_stmt)) + return false; + + /* Re-validate. */ + use_stmt = neguse_stmt; + if (gimple_bb (use_stmt) != gimple_bb (mul_stmt)) + return false; + if (!is_gimple_assign (use_stmt)) + return false; + + use_code = gimple_assign_rhs_code (use_stmt); + negate_p = true; + } - /* If the target doesn't support -a * b + c then drop the ball. */ - if (gimple_assign_rhs2 (use_stmt) == mul_result - && use_code == MINUS_EXPR - && optab_handler (fnma_optab, TYPE_MODE (type)) == CODE_FOR_nothing) + /* Determine if the target supports the exact form we found. */ + switch (use_code) + { + case MINUS_EXPR: + if (gimple_assign_rhs1 (use_stmt) == result) + { + opt = negate_p ? fnms_optab : fms_optab; + break; + } + negate_p = !negate_p; + /* FALLTHRU */ + + case PLUS_EXPR: + opt = negate_p ? fnma_optab : fma_optab; + break; + + default: + /* FMA can only be formed from PLUS and MINUS. */ + return false; + } + if (optab_handler (opt, TYPE_MODE (type)) == CODE_FOR_nothing) return false; - /* We don't yet generate -a * b - c below yet. */ + /* We can't handle a * b + a * b. */ + if (gimple_assign_rhs1 (use_stmt) == gimple_assign_rhs2 (use_stmt)) + return false; } FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, mul_result) { - tree addop, mulop1; gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt); + enum tree_code use_code = gimple_assign_rhs_code (use_stmt); + tree addop, mulop1, result = mul_result; + bool negate_p = false; - mulop1 = gimple_assign_rhs1 (mul_stmt); - if (gimple_assign_rhs1 (use_stmt) == mul_result) + if (use_code == NEGATE_EXPR) + { + result = gimple_assign_lhs (use_stmt); + single_imm_use (gimple_assign_lhs (use_stmt), &use_p, &neguse_stmt); + gsi_remove (&gsi, true); + release_defs (use_stmt); + + use_stmt = neguse_stmt; + gsi = gsi_for_stmt (use_stmt); + use_code = gimple_assign_rhs_code (use_stmt); + negate_p = true; + } + + if (gimple_assign_rhs1 (use_stmt) == result) { addop = gimple_assign_rhs2 (use_stmt); /* a * b - c -> a * b + (-c) */ @@ -1593,13 +1638,17 @@ convert_mult_to_fma (gimple mul_stmt) addop = gimple_assign_rhs1 (use_stmt); /* a - b * c -> (-b) * c + a */ if (gimple_assign_rhs_code (use_stmt) == MINUS_EXPR) - mulop1 = force_gimple_operand_gsi (&gsi, - build1 (NEGATE_EXPR, - type, mulop1), - true, NULL_TREE, true, - GSI_SAME_STMT); + negate_p = !negate_p; } + mulop1 = gimple_assign_rhs1 (mul_stmt); + if (negate_p) + mulop1 = force_gimple_operand_gsi (&gsi, + build1 (NEGATE_EXPR, + type, mulop1), + true, NULL_TREE, true, + GSI_SAME_STMT); + fma_stmt = gimple_build_assign_with_ops3 (FMA_EXPR, gimple_assign_lhs (use_stmt), mulop1, -- 1.7.3.2