diff options
author | Uros Bizjak <ubizjak@gmail.com> | 2007-06-16 11:52:48 +0200 |
---|---|---|
committer | Uros Bizjak <uros@gcc.gnu.org> | 2007-06-16 11:52:48 +0200 |
commit | 6b889d891d24d2edbdb8554d0c1b0c3311799ae3 (patch) | |
tree | 332aeacd4c176a2297138e64e399861ff84a0b59 /gcc/tree-ssa-math-opts.c | |
parent | 5be014d5b728cf754020b8ab4df1cd029f69922e (diff) | |
download | gcc-6b889d891d24d2edbdb8554d0c1b0c3311799ae3.zip gcc-6b889d891d24d2edbdb8554d0c1b0c3311799ae3.tar.gz gcc-6b889d891d24d2edbdb8554d0c1b0c3311799ae3.tar.bz2 |
re PR middle-end/31723 (Use reciprocal and reciprocal square root with -ffast-math)
PR middle-end/31723
* hooks.c (hook_tree_tree_bool_null): New hook.
* hooks.h (hook_tree_tree_bool_null): Add prototype.
* tree-pass.h (pass_convert_to_rsqrt): Declare.
* passes.c (init_optimization_passes): Add pass_convert_to_rsqrt.
* tree-ssa-math-opts.c (execute_cse_reciprocals): Scan for a/func(b)
and convert it to reciprocal a*rfunc(b).
(execute_convert_to_rsqrt): New function.
(gate_convert_to_rsqrt): New function.
(pass_convert_to_rsqrt): New pass definition.
* target.h (struct gcc_target): Add builtin_reciprocal.
* target-def.h (TARGET_BUILTIN_RECIPROCAL): New define.
(TARGET_INITIALIZER): Initialize builtin_reciprocal with
TARGET_BUILTIN_RECIPROCAL.
* doc/tm.texi (TARGET_BUILTIN_RECIPROCAL): Document.
* config/i386/i386.h (TARGET_RECIP): New define.
* config/i386/i386.md (divsf3): Expand by calling ix86_emit_swdivsf
for TARGET_SSE_MATH and TARGET_RECIP when
flag_unsafe_math_optimizations is set and not optimizing for size.
(*rcpsf2_sse): New insn pattern.
(*rsqrtsf2_sse): Ditto.
(rsqrtsf2): New expander. Expand by calling ix86_emit_swsqrtsf
for TARGET_SSE_MATH and TARGET_RECIP when
flag_unsafe_math_optimizations is set and not optimizing for size.
(sqrt<mode>2): Expand SFmode operands by calling ix86_emit_swsqrtsf
for TARGET_SSE_MATH and TARGET_RECIP when
flag_unsafe_math_optimizations is set and not optimizing for size.
* config/i386/sse.md (divv4sf): Expand by calling ix86_emit_swdivsf
for TARGET_SSE_MATH and TARGET_RECIP when
flag_unsafe_math_optimizations is set and not optimizing for size.
(*sse_rsqrtv4sf2): Do not export.
(sqrtv4sf2): Ditto.
(sse_rsqrtv4sf2): New expander. Expand by calling ix86_emit_swsqrtsf
for TARGET_SSE_MATH and TARGET_RECIP when
flag_unsafe_math_optimizations is set and not optimizing for size.
(sqrtv4sf2): Ditto.
* config/i386/i386.opt (mrecip): New option.
* config/i386/i386-protos.h (ix86_emit_swdivsf): Declare.
(ix86_emit_swsqrtsf): Ditto.
* config/i386/i386.c (IX86_BUILTIN_RSQRTF): New constant.
(ix86_init_mmx_sse_builtins): __builtin_ia32_rsqrtf: New
builtin definition.
(ix86_expand_builtin): Expand IX86_BUILTIN_RSQRTF using
ix86_expand_unop1_builtin.
(ix86_emit_swdivsf): New function.
(ix86_emit_swsqrtsf): Ditto.
(ix86_builtin_reciprocal): New function.
(TARGET_BUILTIN_RECIPROCAL): Use it.
(ix86_vectorize_builtin_conversion): Rename from
ix86_builtin_conversion.
(TARGET_VECTORIZE_BUILTIN_CONVERSION): Use renamed function.
* doc/invoke.texi (Machine Dependent Options): Add -mrecip to
"i386 and x86_64 Options" section.
(Intel 386 and AMD x86_64 Options): Document -mrecip.
testsuite/ChangeLog:
PR middle-end/31723
* gcc.target/i386/recip-divf.c: New test.
* gcc.target/i386/recip-sqrtf.c: Ditto.
* gcc.target/i386/recip-vec-divf.c: Ditto.
* gcc.target/i386/recip-vec-sqrtf.c: Ditto.
* gcc.target/i386/sse-recip.c: Ditto.
From-SVN: r125756
Diffstat (limited to 'gcc/tree-ssa-math-opts.c')
-rw-r--r-- | gcc/tree-ssa-math-opts.c | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c index fe67993..0534dcf 100644 --- a/gcc/tree-ssa-math-opts.c +++ b/gcc/tree-ssa-math-opts.c @@ -496,6 +496,46 @@ execute_cse_reciprocals (void) && TREE_CODE (def) == SSA_NAME) execute_cse_reciprocals_1 (&bsi, def); } + + /* Scan for a/func(b) and convert it to reciprocal a*rfunc(b). */ + for (bsi = bsi_after_labels (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + tree stmt = bsi_stmt (bsi); + tree fndecl; + + if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT + && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == RDIV_EXPR) + { + tree arg1 = TREE_OPERAND (GIMPLE_STMT_OPERAND (stmt, 1), 1); + tree stmt1 = SSA_NAME_DEF_STMT (arg1); + + if (TREE_CODE (stmt1) == GIMPLE_MODIFY_STMT + && TREE_CODE (GIMPLE_STMT_OPERAND (stmt1, 1)) == CALL_EXPR + && (fndecl + = get_callee_fndecl (GIMPLE_STMT_OPERAND (stmt1, 1))) + && (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL + || DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)) + { + enum built_in_function code; + tree arg10; + tree tmp; + + code = DECL_FUNCTION_CODE (fndecl); + fndecl = targetm.builtin_reciprocal (code, false); + if (!fndecl) + continue; + + arg10 = CALL_EXPR_ARG (GIMPLE_STMT_OPERAND (stmt1, 1), 0); + tmp = build_call_expr (fndecl, 1, arg10); + GIMPLE_STMT_OPERAND (stmt1, 1) = tmp; + update_stmt (stmt1); + + TREE_SET_CODE (GIMPLE_STMT_OPERAND (stmt, 1), MULT_EXPR); + fold_stmt_inplace (stmt); + update_stmt (stmt); + } + } + } } free_dominance_info (CDI_DOMINATORS); @@ -726,3 +766,88 @@ struct tree_opt_pass pass_cse_sincos = | TODO_verify_stmts, /* todo_flags_finish */ 0 /* letter */ }; + +/* Find all expressions in the form of sqrt(a/b) and + convert them to rsqrt(b/a). */ + +static unsigned int +execute_convert_to_rsqrt (void) +{ + basic_block bb; + + FOR_EACH_BB (bb) + { + block_stmt_iterator bsi; + + for (bsi = bsi_after_labels (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + tree stmt = bsi_stmt (bsi); + tree fndecl; + + if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT + && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == CALL_EXPR + && (fndecl = get_callee_fndecl (GIMPLE_STMT_OPERAND (stmt, 1))) + && (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL + || DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)) + { + enum built_in_function code; + tree arg1; + tree stmt1; + + code = DECL_FUNCTION_CODE (fndecl); + fndecl = targetm.builtin_reciprocal (code, true); + if (!fndecl) + continue; + + arg1 = CALL_EXPR_ARG (GIMPLE_STMT_OPERAND (stmt, 1), 0); + stmt1 = SSA_NAME_DEF_STMT (arg1); + + if (TREE_CODE (stmt1) == GIMPLE_MODIFY_STMT + && TREE_CODE (GIMPLE_STMT_OPERAND (stmt1, 1)) == RDIV_EXPR) + { + tree arg10, arg11; + tree tmp; + + arg10 = TREE_OPERAND (GIMPLE_STMT_OPERAND (stmt1, 1), 0); + arg11 = TREE_OPERAND (GIMPLE_STMT_OPERAND (stmt1, 1), 1); + + /* Swap operands of RDIV_EXPR. */ + TREE_OPERAND (GIMPLE_STMT_OPERAND (stmt1, 1), 0) = arg11; + TREE_OPERAND (GIMPLE_STMT_OPERAND (stmt1, 1), 1) = arg10; + fold_stmt_inplace (stmt1); + update_stmt (stmt1); + + tmp = build_call_expr (fndecl, 1, arg1); + GIMPLE_STMT_OPERAND (stmt, 1) = tmp; + update_stmt (stmt); + } + } + } + } + + return 0; +} + +static bool +gate_convert_to_rsqrt (void) +{ + return flag_unsafe_math_optimizations && optimize; +} + +struct tree_opt_pass pass_convert_to_rsqrt = +{ + "rsqrt", /* name */ + gate_convert_to_rsqrt, /* gate */ + execute_convert_to_rsqrt, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_update_ssa | TODO_verify_ssa + | TODO_verify_stmts, /* todo_flags_finish */ + 0 /* letter */ +}; |