OSDN Git Service

add tree-ssa-math-opts.c for real
authorbonzini <bonzini@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 17 May 2005 12:10:19 +0000 (12:10 +0000)
committerbonzini <bonzini@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 17 May 2005 12:10:19 +0000 (12:10 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@99828 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/tree-ssa-math-opts.c [new file with mode: 0644]

index a456ec1..93c58f7 100644 (file)
@@ -1,12 +1,15 @@
 2005-05-17  Paolo Bonzini  <bonzini@gnu.org>
 
+       * tree-ssa-math-opts.c: New file.
+
+2005-05-17  Paolo Bonzini  <bonzini@gnu.org>
+
        * Makefile.in: Add tree-ssa-math-opts.c.
        * expr.c (expand_expr_real_1) <case RDIV_EXPR>: Never emit as a*(1/b).
        * fold-const.c (distribute_real_division): New.
        (fold_binary) <case PLUS_EXPR, case MINUS_EXPR>: Use it.
        * tree-pass.h (pass_cse_reciprocals): New.
        * tree-optimize.c (init_tree_optimization_passes): Run it.
-       * tree-ssa-math-opts.c: New file.
        * doc/passes.texi: Document the new pass.
 
 2005-05-17  Richard Guenther  <rguenth@gcc.gnu.org>
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
new file mode 100644 (file)
index 0000000..1026704
--- /dev/null
@@ -0,0 +1,164 @@
+/* Global, SSA-based optimizations using mathematical identities.
+   Copyright (C) 2005 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
+later version.
+   
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+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, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* Currently, the only mini-pass in this file tries to CSE reciprocal
+   operations.  These are common in sequences such as this one:
+
+       modulus = sqrt(x*x + y*y + z*z);
+       x = x / modulus;
+       y = y / modulus;
+       z = z / modulus;
+
+   that can be optimized to
+
+       modulus = sqrt(x*x + y*y + z*z);
+        rmodulus = 1.0 / modulus;
+       x = x * rmodulus;
+       y = y * rmodulus;
+       z = z * rmodulus;
+
+   We do this for loop invariant divisors, and with this pass whenever
+   we notice that a division has the same divisor multiple times.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "flags.h"
+#include "tree.h"
+#include "tree-flow.h"
+#include "real.h"
+#include "timevar.h"
+#include "tree-pass.h"
+
+static bool
+gate_cse_reciprocals (void)
+{
+  return optimize && !optimize_size && flag_unsafe_math_optimizations;
+}
+
+/* Check if DEF's uses include more than one floating-point division,
+   and if so replace them by multiplications with the reciprocal.  If
+   PHI is true, insert the reciprocal calculation before BSI, otherwise
+   insert it after and move BSI to the new statement.
+
+   Does not check the type of DEF, nor that DEF is a GIMPLE register.
+   This is done in the caller for speed, because otherwise this routine
+   would be called for every definition and phi node.  */
+static void
+execute_cse_reciprocals_1 (block_stmt_iterator *bsi, tree def, bool phi)
+{
+  use_operand_p use_p;
+  imm_use_iterator use_iter;
+  tree t, new_stmt, type;
+  int count = 0;
+
+  /* Find uses.  */
+  FOR_EACH_IMM_USE_FAST (use_p, use_iter, def)
+    {
+      tree use_stmt = USE_STMT (use_p);
+      if (TREE_CODE (use_stmt) == MODIFY_EXPR
+         && TREE_CODE (TREE_OPERAND (use_stmt, 1)) == RDIV_EXPR
+         && TREE_OPERAND (TREE_OPERAND (use_stmt, 1), 1) == def)
+       {
+         if (++count == 2)
+           break;
+       }
+    }
+
+  if (count < 2)
+    return;
+
+  /* Make a variable with the replacement and substitute it.  */
+  type = TREE_TYPE (def);
+  t = make_rename_temp (type, "reciptmp");
+  new_stmt = build2 (MODIFY_EXPR, void_type_node, t,
+                    fold_build2 (RDIV_EXPR, type, build_real (type, dconst1),
+                                 def));
+
+  if (phi)
+    bsi_insert_before (bsi, new_stmt, BSI_SAME_STMT);
+  else
+    bsi_insert_after (bsi, new_stmt, BSI_NEW_STMT);
+
+  FOR_EACH_IMM_USE_SAFE (use_p, use_iter, def)
+    {
+      tree use_stmt = USE_STMT (use_p);
+      if (use_stmt != new_stmt
+         && TREE_CODE (use_stmt) == MODIFY_EXPR
+         && TREE_CODE (TREE_OPERAND (use_stmt, 1)) == RDIV_EXPR
+         && TREE_OPERAND (TREE_OPERAND (use_stmt, 1), 1) == def)
+       {
+         TREE_SET_CODE (TREE_OPERAND (use_stmt, 1), MULT_EXPR);
+         SET_USE (use_p, t);
+       }
+    }
+}
+
+static void
+execute_cse_reciprocals (void)
+{
+  basic_block bb;
+  FOR_EACH_BB (bb)
+    {
+      block_stmt_iterator bsi;
+      tree phi, def;
+      for (bsi = bsi_start (bb);
+          !bsi_end_p (bsi) && TREE_CODE (bsi_stmt (bsi)) == LABEL_EXPR;
+          bsi_next (&bsi))
+        ;
+
+      for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+       {
+         def = PHI_RESULT (phi);
+         if (FLOAT_TYPE_P (TREE_TYPE (def))
+             && is_gimple_reg (def))
+           execute_cse_reciprocals_1 (&bsi, def, true);
+       }
+
+      for (; !bsi_end_p (bsi); bsi_next (&bsi))
+        {
+         tree stmt = bsi_stmt (bsi);
+         if (TREE_CODE (stmt) == MODIFY_EXPR
+             && (def = SINGLE_SSA_TREE_OPERAND (stmt, SSA_OP_DEF)) != NULL
+             && FLOAT_TYPE_P (TREE_TYPE (def))
+             && is_gimple_reg (def))
+           execute_cse_reciprocals_1 (&bsi, def, false);
+       }
+    }
+}
+
+struct tree_opt_pass pass_cse_reciprocals =
+{
+  "recip",                             /* name */
+  gate_cse_reciprocals,                        /* gate */
+  execute_cse_reciprocals,             /* 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 */
+};