OSDN Git Service

2007-10-15 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-math-opts.c
index bb51c31..543169a 100644 (file)
@@ -1,11 +1,11 @@
 /* Global, SSA-based optimizations using mathematical identities.
-   Copyright (C) 2005 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
    
 This file is part of GCC.
    
 GCC is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
+Free Software Foundation; either version 3, or (at your option) any
 later version.
    
 GCC is distributed in the hope that it will be useful, but WITHOUT
@@ -14,9 +14,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
    
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* Currently, the only mini-pass in this file tries to CSE reciprocal
    operations.  These are common in sequences such as this one:
@@ -151,7 +150,7 @@ occ_new (basic_block bb, struct occurrence *children)
 {
   struct occurrence *occ;
 
-  occ = bb->aux = pool_alloc (occ_pool);
+  bb->aux = occ = (struct occurrence *) pool_alloc (occ_pool);
   memset (occ, 0, sizeof (struct occurrence));
 
   occ->bb = bb;
@@ -303,9 +302,10 @@ insert_reciprocals (block_stmt_iterator *def_bsi, struct occurrence *occ,
       /* Make a variable with the replacement and substitute it.  */
       type = TREE_TYPE (def);
       recip_def = make_rename_temp (type, "reciptmp");
-      new_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, recip_def,
-                        fold_build2 (RDIV_EXPR, type, build_one_cst (type),
-                                     def));
+      new_stmt = build_gimple_modify_stmt (recip_def,
+                                          fold_build2 (RDIV_EXPR, type,
+                                                       build_one_cst (type),
+                                                       def));
   
   
       if (occ->bb_has_division)
@@ -443,7 +443,7 @@ execute_cse_reciprocals_1 (block_stmt_iterator *def_bsi, tree def)
 static bool
 gate_cse_reciprocals (void)
 {
-  return optimize && !optimize_size && flag_unsafe_math_optimizations;
+  return optimize && !optimize_size && flag_reciprocal_math;
 }
 
 /* Go through all the floating-point SSA_NAMEs, and call
@@ -495,6 +495,54 @@ 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;
+
+             if (TREE_CODE (arg1) != SSA_NAME)
+               continue;
+
+             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;
+                 bool md_code;
+                 tree arg10;
+                 tree tmp;
+
+                 code = DECL_FUNCTION_CODE (fndecl);
+                 md_code = DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD;
+
+                 fndecl = targetm.builtin_reciprocal (code, md_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);
@@ -606,8 +654,8 @@ execute_cse_sincos_1 (tree name)
   if (!fndecl)
     return;
   res = make_rename_temp (TREE_TYPE (TREE_TYPE (fndecl)), "sincostmp");
-  call = build_function_call_expr (fndecl, build_tree_list (NULL_TREE, name));
-  stmt = build2 (GIMPLE_MODIFY_STMT, NULL_TREE, res, call);
+  call = build_call_expr (fndecl, 1, name);
+  stmt = build_gimple_modify_stmt (res, call);
   def_stmt = SSA_NAME_DEF_STMT (name);
   if (bb_for_stmt (def_stmt) == top_bb
       && TREE_CODE (def_stmt) == GIMPLE_MODIFY_STMT)
@@ -684,7 +732,7 @@ execute_cse_sincos (void)
                CASE_FLT_FN (BUILT_IN_SIN):
                CASE_FLT_FN (BUILT_IN_CEXPI):
                  arg = GIMPLE_STMT_OPERAND (stmt, 1);
-                 arg = TREE_VALUE (TREE_OPERAND (arg, 1));
+                 arg = CALL_EXPR_ARG (arg, 0);
                  if (TREE_CODE (arg) == SSA_NAME)
                    execute_cse_sincos_1 (arg);
                  break;
@@ -725,3 +773,95 @@ 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;
+             bool md_code;
+             tree arg1;
+             tree stmt1;
+
+             code = DECL_FUNCTION_CODE (fndecl);
+             md_code = DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD;
+
+             fndecl = targetm.builtin_reciprocal (code, md_code, true);
+             if (!fndecl)
+               continue;
+
+             arg1 = CALL_EXPR_ARG (GIMPLE_STMT_OPERAND (stmt, 1), 0);
+
+             if (TREE_CODE (arg1) != SSA_NAME)
+               continue;
+
+             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 */
+};