#include "vec.h"
#include "langhooks.h"
#include "pointer-set.h"
+#include "cfgloop.h"
+#include "flags.h"
/* This is a simple global reassociation pass. It is, in part, based
on the LLVM pass of the same name (They do some things more/less
}
/* Return true if STMT is reassociable operation containing a binary
- operation with tree code CODE. */
+ operation with tree code CODE, and is inside LOOP. */
static bool
-is_reassociable_op (tree stmt, enum tree_code code)
+is_reassociable_op (tree stmt, enum tree_code code, struct loop *loop)
{
- if (!IS_EMPTY_STMT (stmt)
- && TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
+ basic_block bb;
+
+ if (IS_EMPTY_STMT (stmt))
+ return false;
+
+ bb = bb_for_stmt (stmt);
+ if (!flow_bb_inside_loop_p (loop, bb))
+ return false;
+
+ if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
&& TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == code
&& has_single_use (GIMPLE_STMT_OPERAND (stmt, 0)))
return true;
VEC(operand_entry_t, heap) **ops)
{
operand_entry_t oelast = VEC_last (operand_entry_t, *ops);
+ tree type = TREE_TYPE (oelast->op);
- if (oelast->rank == 0 && INTEGRAL_TYPE_P (TREE_TYPE (oelast->op)))
+ if (oelast->rank == 0
+ && (INTEGRAL_TYPE_P (type) || FLOAT_TYPE_P (type)))
{
switch (opcode)
{
}
break;
case MULT_EXPR:
- if (integer_zerop (oelast->op))
+ if (integer_zerop (oelast->op)
+ || (FLOAT_TYPE_P (type)
+ && !HONOR_NANS (TYPE_MODE (type))
+ && !HONOR_SIGNED_ZEROS (TYPE_MODE (type))
+ && real_zerop (oelast->op)))
{
if (VEC_length (operand_entry_t, *ops) != 1)
{
return;
}
}
- else if (integer_onep (oelast->op))
+ else if (integer_onep (oelast->op)
+ || (FLOAT_TYPE_P (type)
+ && !HONOR_SNANS (TYPE_MODE (type))
+ && real_onep (oelast->op)))
{
if (VEC_length (operand_entry_t, *ops) != 1)
{
case BIT_XOR_EXPR:
case PLUS_EXPR:
case MINUS_EXPR:
- if (integer_zerop (oelast->op))
+ if (integer_zerop (oelast->op)
+ || (FLOAT_TYPE_P (type)
+ && (opcode == PLUS_EXPR || opcode == MINUS_EXPR)
+ && fold_real_zero_addition_p (type, oelast->op,
+ opcode == MINUS_EXPR)))
{
if (VEC_length (operand_entry_t, *ops) != 1)
{
oe1->op = temp.op;
oe1->rank= temp.rank;
}
+ else if ((oe1->rank == oe3->rank
+ && oe2->rank != oe3->rank)
+ || (is_phi_for_stmt (stmt, oe2->op)
+ && !is_phi_for_stmt (stmt, oe1->op)
+ && !is_phi_for_stmt (stmt, oe3->op)))
+ {
+ struct operand_entry temp = *oe2;
+ oe2->op = oe1->op;
+ oe2->rank = oe1->rank;
+ oe1->op = temp.op;
+ oe1->rank= temp.rank;
+ }
}
/* The final recursion case for this function is that you have
tree binrhs = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 1));
tree binlhs = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0));
tree newbinrhs = NULL_TREE;
+ struct loop *loop = loop_containing_stmt (stmt);
- gcc_assert (is_reassociable_op (binlhs, TREE_CODE (rhs))
- && is_reassociable_op (binrhs, TREE_CODE (rhs)));
+ gcc_assert (is_reassociable_op (binlhs, TREE_CODE (rhs), loop)
+ && is_reassociable_op (binrhs, TREE_CODE (rhs), loop));
bsinow = bsi_for_stmt (stmt);
bsirhs = bsi_for_stmt (binrhs);
TREE_VISITED (stmt) = 1;
/* Tail recurse on the new rhs if it still needs reassociation. */
- if (newbinrhs && is_reassociable_op (newbinrhs, rhscode))
+ if (newbinrhs && is_reassociable_op (newbinrhs, rhscode, loop))
linearize_expr (stmt);
-
}
/* If LHS has a single immediate use that is a GIMPLE_MODIFY_STMT, return
tree binlhs = TREE_OPERAND (rhs, 0);
tree binrhs = TREE_OPERAND (rhs, 1);
tree immusestmt;
+ struct loop *loop = loop_containing_stmt (stmt);
if (TREE_CODE (binlhs) == SSA_NAME
- && is_reassociable_op (SSA_NAME_DEF_STMT (binlhs), PLUS_EXPR))
+ && is_reassociable_op (SSA_NAME_DEF_STMT (binlhs), PLUS_EXPR, loop))
return true;
if (TREE_CODE (binrhs) == SSA_NAME
- && is_reassociable_op (SSA_NAME_DEF_STMT (binrhs), PLUS_EXPR))
+ && is_reassociable_op (SSA_NAME_DEF_STMT (binrhs), PLUS_EXPR, loop))
return true;
if (TREE_CODE (lhs) == SSA_NAME
bool binlhsisreassoc = false;
bool binrhsisreassoc = false;
enum tree_code rhscode = TREE_CODE (rhs);
+ struct loop *loop = loop_containing_stmt (stmt);
TREE_VISITED (stmt) = 1;
if (TREE_CODE (binlhs) == SSA_NAME)
{
binlhsdef = SSA_NAME_DEF_STMT (binlhs);
- binlhsisreassoc = is_reassociable_op (binlhsdef, rhscode);
+ binlhsisreassoc = is_reassociable_op (binlhsdef, rhscode, loop);
}
if (TREE_CODE (binrhs) == SSA_NAME)
{
binrhsdef = SSA_NAME_DEF_STMT (binrhs);
- binrhsisreassoc = is_reassociable_op (binrhsdef, rhscode);
+ binrhsisreassoc = is_reassociable_op (binrhsdef, rhscode, loop);
}
/* If the LHS is not reassociable, but the RHS is, we need to swap
}
gcc_assert (TREE_CODE (binrhs) != SSA_NAME
- || !is_reassociable_op (SSA_NAME_DEF_STMT (binrhs), rhscode));
+ || !is_reassociable_op (SSA_NAME_DEF_STMT (binrhs),
+ rhscode, loop));
bsinow = bsi_for_stmt (stmt);
bsilhs = bsi_for_stmt (SSA_NAME_DEF_STMT (binlhs));
bsi_move_before (&bsilhs, &bsinow);
tree rhs = GIMPLE_STMT_OPERAND (stmt, 1);
TREE_VISITED (stmt) = 0;
- /* If unsafe math optimizations we can do reassociation for
- non-integral types. */
+ /* If associative-math we can do reassociation for
+ non-integral types. Or, we can do reassociation for
+ non-saturating fixed-point types. */
if ((!INTEGRAL_TYPE_P (TREE_TYPE (lhs))
|| !INTEGRAL_TYPE_P (TREE_TYPE (rhs)))
&& (!SCALAR_FLOAT_TYPE_P (TREE_TYPE (rhs))
|| !SCALAR_FLOAT_TYPE_P (TREE_TYPE(lhs))
- || !flag_unsafe_math_optimizations))
+ || !flag_associative_math)
+ && (!NON_SAT_FIXED_POINT_TYPE_P (TREE_TYPE (rhs))
+ || !NON_SAT_FIXED_POINT_TYPE_P (TREE_TYPE(lhs))))
continue;
/* Check for a subtract used only in an addition. If this
if (TREE_VISITED (stmt))
continue;
- /* If unsafe math optimizations we can do reassociation for
- non-integral types. */
+ /* If associative-math we can do reassociation for
+ non-integral types. Or, we can do reassociation for
+ non-saturating fixed-point types. */
if ((!INTEGRAL_TYPE_P (TREE_TYPE (lhs))
|| !INTEGRAL_TYPE_P (TREE_TYPE (rhs)))
&& (!SCALAR_FLOAT_TYPE_P (TREE_TYPE (rhs))
|| !SCALAR_FLOAT_TYPE_P (TREE_TYPE(lhs))
- || !flag_unsafe_math_optimizations))
+ || !flag_associative_math)
+ && (!NON_SAT_FIXED_POINT_TYPE_P (TREE_TYPE (rhs))
+ || !NON_SAT_FIXED_POINT_TYPE_P (TREE_TYPE(lhs))))
continue;
if (associative_tree_code (TREE_CODE (rhs)))
tree param;
int *bbs = XNEWVEC (int, last_basic_block + 1);
+ /* Find the loops, so that we can prevent moving calculations in
+ them. */
+ loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
+
memset (&reassociate_stats, 0, sizeof (reassociate_stats));
operand_entry_pool = create_alloc_pool ("operand entry pool",
bb_rank[bbs[i]] = ++rank << 16;
free (bbs);
- calculate_dominance_info (CDI_DOMINATORS);
calculate_dominance_info (CDI_POST_DOMINATORS);
broken_up_subtracts = NULL;
}
static void
fini_reassoc (void)
{
-
if (dump_file && (dump_flags & TDF_STATS))
{
fprintf (dump_file, "Reassociation stats:\n");
free (bb_rank);
VEC_free (tree, heap, broken_up_subtracts);
free_dominance_info (CDI_POST_DOMINATORS);
+ loop_optimizer_finalize ();
}
/* Gate and execute functions for Reassociation. */