OSDN Git Service

* function.h (incomming_args): Break out of struct function.
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-math-opts.c
index 0bb999c..49fd170 100644 (file)
@@ -5,7 +5,7 @@ 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;
@@ -276,7 +275,11 @@ is_division_by (tree use_stmt, tree def)
 {
   return TREE_CODE (use_stmt) == GIMPLE_MODIFY_STMT
         && TREE_CODE (GIMPLE_STMT_OPERAND (use_stmt, 1)) == RDIV_EXPR
-        && TREE_OPERAND (GIMPLE_STMT_OPERAND (use_stmt, 1), 1) == def;
+        && TREE_OPERAND (GIMPLE_STMT_OPERAND (use_stmt, 1), 1) == def
+        /* Do not recognize x / x as valid division, as we are getting
+           confused later by replacing all immediate uses x in such
+           a stmt.  */
+        && TREE_OPERAND (GIMPLE_STMT_OPERAND (use_stmt, 1), 0) != def;
 }
 
 /* Walk the subset of the dominator tree rooted at OCC, setting the
@@ -444,7 +447,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
@@ -496,6 +499,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);
@@ -504,8 +555,10 @@ execute_cse_reciprocals (void)
   return 0;
 }
 
-struct tree_opt_pass pass_cse_reciprocals =
+struct gimple_opt_pass pass_cse_reciprocals =
 {
+ {
+  GIMPLE_PASS,
   "recip",                             /* name */
   gate_cse_reciprocals,                        /* gate */
   execute_cse_reciprocals,             /* execute */
@@ -518,8 +571,8 @@ struct tree_opt_pass pass_cse_reciprocals =
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
   TODO_dump_func | TODO_update_ssa | TODO_verify_ssa
-    | TODO_verify_stmts,                /* todo_flags_finish */
-  0                                    /* letter */
+    | TODO_verify_stmts                /* todo_flags_finish */
+ }
 };
 
 /* Records an occurrence at statement USE_STMT in the vector of trees
@@ -610,8 +663,9 @@ execute_cse_sincos_1 (tree name)
   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)
+  if (!SSA_NAME_IS_DEFAULT_DEF (name)
+      && TREE_CODE (def_stmt) != PHI_NODE
+      && bb_for_stmt (def_stmt) == top_bb)
     {
       bsi = bsi_for_stmt (def_stmt);
       bsi_insert_after (&bsi, stmt, BSI_SAME_STMT);
@@ -709,8 +763,10 @@ gate_cse_sincos (void)
         && optimize;
 }
 
-struct tree_opt_pass pass_cse_sincos =
+struct gimple_opt_pass pass_cse_sincos =
 {
+ {
+  GIMPLE_PASS,
   "sincos",                            /* name */
   gate_cse_sincos,                     /* gate */
   execute_cse_sincos,                  /* execute */
@@ -723,6 +779,100 @@ struct tree_opt_pass pass_cse_sincos =
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
   TODO_dump_func | TODO_update_ssa | TODO_verify_ssa
-    | TODO_verify_stmts,                /* todo_flags_finish */
-  0                                    /* letter */
+    | TODO_verify_stmts                 /* todo_flags_finish */
+ }
+};
+
+/* 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 gimple_opt_pass pass_convert_to_rsqrt =
+{
+ {
+  GIMPLE_PASS,
+  "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 */
+ }
 };