diff options
author | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-11-04 10:56:22 +0000 |
---|---|---|
committer | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-11-04 10:56:22 +0000 |
commit | b9be572eda05cd23bbabd6409387d2c7ac782715 (patch) | |
tree | 5b089e25b51a9c3914b5055c84f8d83414072dab /gcc/tree-ssa-math-opts.c | |
parent | 2fee2038f99cb244aa1250f8ad42cae7fe2702ec (diff) | |
download | gcc-b9be572eda05cd23bbabd6409387d2c7ac782715.tar.gz |
2010-11-04 Richard Guenther <rguenther@suse.de>
Richard Henderson <rth@redhat.com>
* tree.def (FMA_EXPR): New tree code.
* expr.c (expand_expr_real_2): Add FMA_EXPR expansion code.
* gimple.c (gimple_rhs_class_table): FMA_EXPR is a GIMPLE_TERNARY_RHS.
* tree-cfg.c (verify_gimple_assign_ternary): Verify FMA_EXPR types.
* tree-inline.c (estimate_operator_cost): Handle FMA_EXPR.
* gimple-pretty-print.c (dump_ternary_rhs): Likewise.
* tree-ssa-math-opts.c (convert_mult_to_fma): New function.
(execute_optimize_widening_mul): Call it. Reorganize to allow
dead stmt removal. Move TODO flags ...
(pass_optimize_widening_mul): ... here.
* flag-types.h (enum fp_contract_mode): New enum.
* common.opt (flag_fp_contract_mode): New variable.
(-ffp-contract): New option.
* opts.c (common_handle_option): Handle it.
* doc/invoke.texi (-ffp-contract): Document.
* tree.h (fold_fma): Declare.
* builtins.c (fold_fma): New function.
(fold_builtin_fma): Likewise.
(fold_builtin_3): Call it for fma.
* fold-const.c (fold_ternary_loc): Fold FMA_EXPR.
* optabs.c (optab_for_tree_code): Handle FMA_EXPR.
* config/i386/sse.md (fms<mode>4, fnma<mode>, fnms<mode>4):
New expanders.
* doc/md.texi (fms<mode>4, fnma<mode>, fnms<mode>4): Document new
named patterns.
* genopinit.c (optabs): Initialize fms_optab, fnma_optab and fnms_optab.
* optabs.h (enum optab_index): Add OTI_fms, OTI_fnma and OTI_fnms.
(fms_optab, fnma_optab, fnms_optab): New defines.
* gimplify.c (gimplify_expr): Handle binary truth expressions
explicitly. Handle FMA_EXPR.
* tree-vect-stmts.c (vectorizable_operation): Handle ternary
operations.
* gcc.target/i386/fma4-vector-2.c: New testcase.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@166304 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-ssa-math-opts.c')
-rw-r--r-- | gcc/tree-ssa-math-opts.c | 158 |
1 files changed, 146 insertions, 12 deletions
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c index a814f6f0288..96140f06f63 100644 --- a/gcc/tree-ssa-math-opts.c +++ b/gcc/tree-ssa-math-opts.c @@ -1494,6 +1494,123 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt, return true; } +/* Combine the multiplication at MUL_STMT with uses in additions and + subtractions to form fused multiply-add operations. Returns true + if successful and MUL_STMT should be removed. */ + +static bool +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; + use_operand_p use_p; + imm_use_iterator imm_iter; + + if (FLOAT_TYPE_P (type) + && flag_fp_contract_mode == FP_CONTRACT_OFF) + return false; + + /* We don't want to do bitfield reduction ops. */ + if (INTEGRAL_TYPE_P (type) + && (TYPE_PRECISION (type) + != GET_MODE_PRECISION (TYPE_MODE (type)))) + return false; + + /* If the target doesn't support it, don't generate it. We assume that + if fma isn't available then fms, fnma or fnms are not either. */ + if (optab_handler (fma_optab, TYPE_MODE (type)) == CODE_FOR_nothing) + return false; + + /* Make sure that the multiplication statement becomes dead after + the transformation, thus that all uses are transformed to FMAs. + This means we assume that an FMA operation has the same cost + as an addition. */ + FOR_EACH_IMM_USE_FAST (use_p, imm_iter, mul_result) + { + enum tree_code use_code; + + 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; + if () + ma = m + c; + else + d = m; + to form a fma in the then block and sink the multiplication to the + else block. */ + 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)) + 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; + + /* 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) + return false; + + /* We don't yet generate -a * b - c below yet. */ + } + + FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, mul_result) + { + tree addop, mulop1; + gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt); + + mulop1 = gimple_assign_rhs1 (mul_stmt); + if (gimple_assign_rhs1 (use_stmt) == mul_result) + { + addop = gimple_assign_rhs2 (use_stmt); + /* a * b - c -> a * b + (-c) */ + if (gimple_assign_rhs_code (use_stmt) == MINUS_EXPR) + addop = force_gimple_operand_gsi (&gsi, + build1 (NEGATE_EXPR, + type, addop), + true, NULL_TREE, true, + GSI_SAME_STMT); + } + else + { + 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); + } + + fma_stmt = gimple_build_assign_with_ops3 (FMA_EXPR, + gimple_assign_lhs (use_stmt), + mulop1, + gimple_assign_rhs2 (mul_stmt), + addop); + gsi_replace (&gsi, fma_stmt, true); + } + + return true; +} + /* Find integer multiplications where the operands are extended from smaller types, and replace the MULT_EXPR with a WIDEN_MULT_EXPR where appropriate. */ @@ -1501,31 +1618,45 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt, static unsigned int execute_optimize_widening_mul (void) { - bool changed = false; basic_block bb; FOR_EACH_BB (bb) { gimple_stmt_iterator gsi; - for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi);) { gimple stmt = gsi_stmt (gsi); enum tree_code code; - if (!is_gimple_assign (stmt)) - continue; + if (is_gimple_assign (stmt)) + { + code = gimple_assign_rhs_code (stmt); + switch (code) + { + case MULT_EXPR: + if (!convert_mult_to_widen (stmt) + && convert_mult_to_fma (stmt)) + { + gsi_remove (&gsi, true); + release_defs (stmt); + continue; + } + break; + + case PLUS_EXPR: + case MINUS_EXPR: + convert_plusminus_to_widen (&gsi, stmt, code); + break; - code = gimple_assign_rhs_code (stmt); - if (code == MULT_EXPR) - changed |= convert_mult_to_widen (stmt); - else if (code == PLUS_EXPR || code == MINUS_EXPR) - changed |= convert_plusminus_to_widen (&gsi, stmt, code); + default:; + } + } + gsi_next (&gsi); } } - return (changed ? TODO_dump_func | TODO_update_ssa | TODO_verify_ssa - | TODO_verify_stmts : 0); + return 0; } static bool @@ -1549,6 +1680,9 @@ struct gimple_opt_pass pass_optimize_widening_mul = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - 0 /* todo_flags_finish */ + TODO_verify_ssa + | TODO_verify_stmts + | TODO_dump_func + | TODO_update_ssa /* todo_flags_finish */ } }; |