aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-math-opts.c
diff options
context:
space:
mode:
authorUros Bizjak <ubizjak@gmail.com>2007-06-16 11:52:48 +0200
committerUros Bizjak <uros@gcc.gnu.org>2007-06-16 11:52:48 +0200
commit6b889d891d24d2edbdb8554d0c1b0c3311799ae3 (patch)
tree332aeacd4c176a2297138e64e399861ff84a0b59 /gcc/tree-ssa-math-opts.c
parent5be014d5b728cf754020b8ab4df1cd029f69922e (diff)
downloadgcc-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.c125
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 */
+};