diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index beb69e756cb83f4efde5cadda4a418fd91581b0e..60e5aa3a7d2999572f2df07788dd6e2347a3451f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2005-04-11  David Edelsohn  <edelsohn@gnu.org>
+
+	* tree-ssa-loop-im.c: Include real.h.
+	(determine_invariantness_stmt): If real division divisor is
+	invariant and flag_unsafe_math_optimizations enabled, generate
+	invariant reciprocal for hoisting.
+	* Makefile.in (tree-ssa-loop-im.o): Add real.h dependency.
+
 2005-04-11  Daniel Berlin  <dberlin@dberlin.org>
 
 	Fix PR tree-optimization/20926
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 02599fb3bfb1c0ed4a35195c6986d16142369ac6..57f3d1a5365af4e885d757acd4eeb05bbe7fce47 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1761,7 +1761,7 @@ tree-ssa-loop-manip.o : tree-ssa-loop-manip.c $(TREE_FLOW_H) $(CONFIG_H) \
 tree-ssa-loop-im.o : tree-ssa-loop-im.c $(TREE_FLOW_H) $(CONFIG_H) \
    $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) domwalk.h $(PARAMS_H)\
    output.h diagnostic.h $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \
-   tree-pass.h $(FLAGS_H) $(HASHTAB_H)
+   tree-pass.h $(FLAGS_H) $(HASHTAB_H) real.h
 tree-ssa-alias.o : tree-ssa-alias.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
    $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) tree-inline.h $(FLAGS_H) \
    function.h $(TIMEVAR_H) convert.h $(TM_H) coretypes.h \
diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c
index a0c45821cdb0e701db993e709e11ab84dee7057a..4e123f2c8a57a633788ed4ef33ae744e22249753 100644
--- a/gcc/tree-ssa-loop-im.c
+++ b/gcc/tree-ssa-loop-im.c
@@ -37,6 +37,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "params.h"
 #include "tree-pass.h"
 #include "flags.h"
+#include "real.h"
 
 /* TODO:  Support for predicated code motion.  I.e.
 
@@ -562,7 +563,7 @@ determine_invariantness_stmt (struct dom_walk_data *dw_data ATTRIBUTE_UNUSED,
 {
   enum move_pos pos;
   block_stmt_iterator bsi;
-  tree stmt;
+  tree stmt, rhs;
   bool maybe_never = ALWAYS_EXECUTED_IN (bb) == NULL;
   struct loop *outermost = ALWAYS_EXECUTED_IN (bb);
 
@@ -588,6 +589,47 @@ determine_invariantness_stmt (struct dom_walk_data *dw_data ATTRIBUTE_UNUSED,
 	  continue;
 	}
 
+      /* If divisor is invariant, convert a/b to a*(1/b), allowing reciprocal
+	 to be hoisted out of loop, saving expensive divide.  */
+      if (pos == MOVE_POSSIBLE
+	  && (rhs = TREE_OPERAND (stmt, 1)) != NULL
+	  && TREE_CODE (rhs) == RDIV_EXPR
+	  && flag_unsafe_math_optimizations
+	  && outermost_invariant_loop_expr (TREE_OPERAND (rhs, 1),
+					    loop_containing_stmt (stmt)) != NULL
+	  && outermost_invariant_loop_expr (rhs,
+					    loop_containing_stmt (stmt)) == NULL)
+	{
+	  tree lhs, stmt1, stmt2, var, name;
+
+	  lhs = TREE_OPERAND (stmt, 0);
+
+	  /* stmt must be MODIFY_EXPR.  */
+	  var = create_tmp_var (TREE_TYPE (rhs), "reciptmp");
+	  add_referenced_tmp_var (var);
+
+	  stmt1 = build2 (MODIFY_EXPR, void_type_node, var,
+			  build2 (RDIV_EXPR, TREE_TYPE (rhs),
+				  build_real (TREE_TYPE (rhs), dconst1),
+				  TREE_OPERAND (rhs, 1)));
+	  name = make_ssa_name (var, stmt1);
+	  TREE_OPERAND (stmt1, 0) = name;
+	  stmt2 = build2 (MODIFY_EXPR, void_type_node, lhs,
+			  build2 (MULT_EXPR, TREE_TYPE (rhs),
+				  name, TREE_OPERAND (rhs, 0)));
+
+	  /* Replace division stmt with reciprocal and multiply stmts.
+	     The multiply stmt is not invariant, so update iterator
+	     and avoid rescanning.  */
+	  bsi_replace (&bsi, stmt1, true);
+	  get_stmt_operands (stmt1);  /* Should not be necessary.  */
+	  bsi_insert_after (&bsi, stmt2, BSI_NEW_STMT);
+	  SSA_NAME_DEF_STMT (lhs) = stmt2;
+
+	  /* Continue processing with invariant reciprocal statment.  */
+	  stmt = stmt1;
+	}
+
       stmt_ann (stmt)->common.aux = xcalloc (1, sizeof (struct lim_aux_data));
       LIM_DATA (stmt)->always_executed_in = outermost;