Commit 985e963f by Steven Bosscher

re PR middle-end/54146 (Very slow compile with attribute((flatten)))

	PR middle-end/54146
	* ifcvt.c: Include pointer-set.h.
	(cond_move_process_if_block): Change type of then_regs and
	else_regs from alloca'd array to pointer_sets.
	(check_cond_move_block): Update for this change.
	(cond_move_convert_if_block): Likewise.
	* Makefile.in: Fix dependencies for ifcvt.o.

From-SVN: r190222
parent 88ca9ea1
2012-08-08 Steven Bosscher <steven@gcc.gnu.org>
PR middle-end/54146
* ifcvt.c: Include pointer-set.h.
(cond_move_process_if_block): Change type of then_regs and
else_regs from alloca'd array to pointer_sets.
(check_cond_move_block): Update for this change.
(cond_move_convert_if_block): Likewise.
* Makefile.in: Fix dependencies for ifcvt.o.
2012-08-07 Bill Schmidt <wschmidt@linux.vnet.ibm.com> 2012-08-07 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
* gimple-ssa-strength-reduction.c (struct incr_info_d): New struct. * gimple-ssa-strength-reduction.c (struct incr_info_d): New struct.
......
...@@ -3350,7 +3350,7 @@ regrename.o : regrename.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ ...@@ -3350,7 +3350,7 @@ regrename.o : regrename.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
ifcvt.o : ifcvt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ ifcvt.o : ifcvt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(REGS_H) $(DIAGNOSTIC_CORE_H) $(FLAGS_H) insn-config.h $(FUNCTION_H) $(RECOG_H) \ $(REGS_H) $(DIAGNOSTIC_CORE_H) $(FLAGS_H) insn-config.h $(FUNCTION_H) $(RECOG_H) \
$(TARGET_H) $(BASIC_BLOCK_H) $(EXPR_H) output.h $(EXCEPT_H) $(TM_P_H) \ $(TARGET_H) $(BASIC_BLOCK_H) $(EXPR_H) output.h $(EXCEPT_H) $(TM_P_H) \
$(OPTABS_H) $(CFGLOOP_H) hard-reg-set.h \ $(OPTABS_H) $(CFGLOOP_H) hard-reg-set.h pointer-set.h \
$(TREE_PASS_H) $(DF_H) $(DBGCNT_H) $(TREE_PASS_H) $(DF_H) $(DBGCNT_H)
params.o : params.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(COMMON_TARGET_H) \ params.o : params.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(COMMON_TARGET_H) \
$(PARAMS_H) $(DIAGNOSTIC_CORE_H) $(PARAMS_H) $(DIAGNOSTIC_CORE_H)
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include "tree-pass.h" #include "tree-pass.h"
#include "df.h" #include "df.h"
#include "vec.h" #include "vec.h"
#include "pointer-set.h"
#include "vecprim.h" #include "vecprim.h"
#include "dbgcnt.h" #include "dbgcnt.h"
...@@ -2687,12 +2688,14 @@ noce_process_if_block (struct noce_if_info *if_info) ...@@ -2687,12 +2688,14 @@ noce_process_if_block (struct noce_if_info *if_info)
/* Check whether a block is suitable for conditional move conversion. /* Check whether a block is suitable for conditional move conversion.
Every insn must be a simple set of a register to a constant or a Every insn must be a simple set of a register to a constant or a
register. For each assignment, store the value in the array VALS, register. For each assignment, store the value in the pointer map
indexed by register number, then store the register number in VALS, keyed indexed by register pointer, then store the register
REGS. COND is the condition we will test. */ pointer in REGS. COND is the condition we will test. */
static int static int
check_cond_move_block (basic_block bb, rtx *vals, VEC (int, heap) **regs, check_cond_move_block (basic_block bb,
struct pointer_map_t *vals,
VEC (rtx, heap) **regs,
rtx cond) rtx cond)
{ {
rtx insn; rtx insn;
...@@ -2706,6 +2709,7 @@ check_cond_move_block (basic_block bb, rtx *vals, VEC (int, heap) **regs, ...@@ -2706,6 +2709,7 @@ check_cond_move_block (basic_block bb, rtx *vals, VEC (int, heap) **regs,
FOR_BB_INSNS (bb, insn) FOR_BB_INSNS (bb, insn)
{ {
rtx set, dest, src; rtx set, dest, src;
void **slot;
if (!NONDEBUG_INSN_P (insn) || JUMP_P (insn)) if (!NONDEBUG_INSN_P (insn) || JUMP_P (insn))
continue; continue;
...@@ -2732,14 +2736,14 @@ check_cond_move_block (basic_block bb, rtx *vals, VEC (int, heap) **regs, ...@@ -2732,14 +2736,14 @@ check_cond_move_block (basic_block bb, rtx *vals, VEC (int, heap) **regs,
/* Don't try to handle this if the source register was /* Don't try to handle this if the source register was
modified earlier in the block. */ modified earlier in the block. */
if ((REG_P (src) if ((REG_P (src)
&& vals[REGNO (src)] != NULL) && pointer_map_contains (vals, src))
|| (GET_CODE (src) == SUBREG && REG_P (SUBREG_REG (src)) || (GET_CODE (src) == SUBREG && REG_P (SUBREG_REG (src))
&& vals[REGNO (SUBREG_REG (src))] != NULL)) && pointer_map_contains (vals, SUBREG_REG (src))))
return FALSE; return FALSE;
/* Don't try to handle this if the destination register was /* Don't try to handle this if the destination register was
modified earlier in the block. */ modified earlier in the block. */
if (vals[REGNO (dest)] != NULL) if (pointer_map_contains (vals, dest))
return FALSE; return FALSE;
/* Don't try to handle this if the condition uses the /* Don't try to handle this if the condition uses the
...@@ -2753,17 +2757,18 @@ check_cond_move_block (basic_block bb, rtx *vals, VEC (int, heap) **regs, ...@@ -2753,17 +2757,18 @@ check_cond_move_block (basic_block bb, rtx *vals, VEC (int, heap) **regs,
&& modified_between_p (src, insn, NEXT_INSN (BB_END (bb)))) && modified_between_p (src, insn, NEXT_INSN (BB_END (bb))))
return FALSE; return FALSE;
vals[REGNO (dest)] = src; slot = pointer_map_insert (vals, (void *) dest);
*slot = (void *) src;
VEC_safe_push (int, heap, *regs, REGNO (dest)); VEC_safe_push (rtx, heap, *regs, dest);
} }
return TRUE; return TRUE;
} }
/* Given a basic block BB suitable for conditional move conversion, /* Given a basic block BB suitable for conditional move conversion,
a condition COND, and arrays THEN_VALS and ELSE_VALS containing the a condition COND, and pointer maps THEN_VALS and ELSE_VALS containing
register values depending on COND, emit the insns in the block as the register values depending on COND, emit the insns in the block as
conditional moves. If ELSE_BLOCK is true, THEN_BB was already conditional moves. If ELSE_BLOCK is true, THEN_BB was already
processed. The caller has started a sequence for the conversion. processed. The caller has started a sequence for the conversion.
Return true if successful, false if something goes wrong. */ Return true if successful, false if something goes wrong. */
...@@ -2771,7 +2776,8 @@ check_cond_move_block (basic_block bb, rtx *vals, VEC (int, heap) **regs, ...@@ -2771,7 +2776,8 @@ check_cond_move_block (basic_block bb, rtx *vals, VEC (int, heap) **regs,
static bool static bool
cond_move_convert_if_block (struct noce_if_info *if_infop, cond_move_convert_if_block (struct noce_if_info *if_infop,
basic_block bb, rtx cond, basic_block bb, rtx cond,
rtx *then_vals, rtx *else_vals, struct pointer_map_t *then_vals,
struct pointer_map_t *else_vals,
bool else_block_p) bool else_block_p)
{ {
enum rtx_code code; enum rtx_code code;
...@@ -2784,7 +2790,7 @@ cond_move_convert_if_block (struct noce_if_info *if_infop, ...@@ -2784,7 +2790,7 @@ cond_move_convert_if_block (struct noce_if_info *if_infop,
FOR_BB_INSNS (bb, insn) FOR_BB_INSNS (bb, insn)
{ {
rtx set, target, dest, t, e; rtx set, target, dest, t, e;
unsigned int regno; void **then_slot, **else_slot;
/* ??? Maybe emit conditional debug insn? */ /* ??? Maybe emit conditional debug insn? */
if (!NONDEBUG_INSN_P (insn) || JUMP_P (insn)) if (!NONDEBUG_INSN_P (insn) || JUMP_P (insn))
...@@ -2793,10 +2799,11 @@ cond_move_convert_if_block (struct noce_if_info *if_infop, ...@@ -2793,10 +2799,11 @@ cond_move_convert_if_block (struct noce_if_info *if_infop,
gcc_assert (set && REG_P (SET_DEST (set))); gcc_assert (set && REG_P (SET_DEST (set)));
dest = SET_DEST (set); dest = SET_DEST (set);
regno = REGNO (dest);
t = then_vals[regno]; then_slot = pointer_map_contains (then_vals, dest);
e = else_vals[regno]; else_slot = pointer_map_contains (else_vals, dest);
t = then_slot ? (rtx) *then_slot : NULL_RTX;
e = else_slot ? (rtx) *else_slot : NULL_RTX;
if (else_block_p) if (else_block_p)
{ {
...@@ -2840,31 +2847,25 @@ cond_move_process_if_block (struct noce_if_info *if_info) ...@@ -2840,31 +2847,25 @@ cond_move_process_if_block (struct noce_if_info *if_info)
rtx jump = if_info->jump; rtx jump = if_info->jump;
rtx cond = if_info->cond; rtx cond = if_info->cond;
rtx seq, loc_insn; rtx seq, loc_insn;
int max_reg, size, c, reg; rtx reg;
rtx *then_vals; int c;
rtx *else_vals; struct pointer_map_t *then_vals;
VEC (int, heap) *then_regs = NULL; struct pointer_map_t *else_vals;
VEC (int, heap) *else_regs = NULL; VEC (rtx, heap) *then_regs = NULL;
VEC (rtx, heap) *else_regs = NULL;
unsigned int i; unsigned int i;
int success_p = FALSE;
/* Build a mapping for each block to the value used for each /* Build a mapping for each block to the value used for each
register. */ register. */
max_reg = max_reg_num (); then_vals = pointer_map_create ();
size = (max_reg + 1) * sizeof (rtx); else_vals = pointer_map_create ();
then_vals = (rtx *) alloca (size);
else_vals = (rtx *) alloca (size);
memset (then_vals, 0, size);
memset (else_vals, 0, size);
/* Make sure the blocks are suitable. */ /* Make sure the blocks are suitable. */
if (!check_cond_move_block (then_bb, then_vals, &then_regs, cond) if (!check_cond_move_block (then_bb, then_vals, &then_regs, cond)
|| (else_bb || (else_bb
&& !check_cond_move_block (else_bb, else_vals, &else_regs, cond))) && !check_cond_move_block (else_bb, else_vals, &else_regs, cond)))
{ goto done;
VEC_free (int, heap, then_regs);
VEC_free (int, heap, else_regs);
return FALSE;
}
/* Make sure the blocks can be used together. If the same register /* Make sure the blocks can be used together. If the same register
is set in both blocks, and is not set to a constant in both is set in both blocks, and is not set to a constant in both
...@@ -2873,41 +2874,38 @@ cond_move_process_if_block (struct noce_if_info *if_info) ...@@ -2873,41 +2874,38 @@ cond_move_process_if_block (struct noce_if_info *if_info)
source register does not change after the assignment. Also count source register does not change after the assignment. Also count
the number of registers set in only one of the blocks. */ the number of registers set in only one of the blocks. */
c = 0; c = 0;
FOR_EACH_VEC_ELT (int, then_regs, i, reg) FOR_EACH_VEC_ELT (rtx, then_regs, i, reg)
{ {
if (!then_vals[reg] && !else_vals[reg]) void **then_slot = pointer_map_contains (then_vals, reg);
continue; void **else_slot = pointer_map_contains (else_vals, reg);
if (!else_vals[reg]) gcc_checking_assert (then_slot);
if (!else_slot)
++c; ++c;
else else
{ {
if (!CONSTANT_P (then_vals[reg]) rtx then_val = (rtx) *then_slot;
&& !CONSTANT_P (else_vals[reg]) rtx else_val = (rtx) *else_slot;
&& !rtx_equal_p (then_vals[reg], else_vals[reg])) if (!CONSTANT_P (then_val) && !CONSTANT_P (else_val)
{ && !rtx_equal_p (then_val, else_val))
VEC_free (int, heap, then_regs); goto done;
VEC_free (int, heap, else_regs);
return FALSE;
}
} }
} }
/* Finish off c for MAX_CONDITIONAL_EXECUTE. */ /* Finish off c for MAX_CONDITIONAL_EXECUTE. */
FOR_EACH_VEC_ELT (int, else_regs, i, reg) FOR_EACH_VEC_ELT (rtx, else_regs, i, reg)
if (!then_vals[reg]) {
++c; gcc_checking_assert (pointer_map_contains (else_vals, reg));
if (!pointer_map_contains (then_vals, reg))
++c;
}
/* Make sure it is reasonable to convert this block. What matters /* Make sure it is reasonable to convert this block. What matters
is the number of assignments currently made in only one of the is the number of assignments currently made in only one of the
branches, since if we convert we are going to always execute branches, since if we convert we are going to always execute
them. */ them. */
if (c > MAX_CONDITIONAL_EXECUTE) if (c > MAX_CONDITIONAL_EXECUTE)
{ goto done;
VEC_free (int, heap, then_regs);
VEC_free (int, heap, else_regs);
return FALSE;
}
/* Try to emit the conditional moves. First do the then block, /* Try to emit the conditional moves. First do the then block,
then do anything left in the else blocks. */ then do anything left in the else blocks. */
...@@ -2919,17 +2917,11 @@ cond_move_process_if_block (struct noce_if_info *if_info) ...@@ -2919,17 +2917,11 @@ cond_move_process_if_block (struct noce_if_info *if_info)
then_vals, else_vals, true))) then_vals, else_vals, true)))
{ {
end_sequence (); end_sequence ();
VEC_free (int, heap, then_regs); goto done;
VEC_free (int, heap, else_regs);
return FALSE;
} }
seq = end_ifcvt_sequence (if_info); seq = end_ifcvt_sequence (if_info);
if (!seq) if (!seq)
{ goto done;
VEC_free (int, heap, then_regs);
VEC_free (int, heap, else_regs);
return FALSE;
}
loc_insn = first_active_insn (then_bb); loc_insn = first_active_insn (then_bb);
if (!loc_insn) if (!loc_insn)
...@@ -2960,9 +2952,14 @@ cond_move_process_if_block (struct noce_if_info *if_info) ...@@ -2960,9 +2952,14 @@ cond_move_process_if_block (struct noce_if_info *if_info)
num_updated_if_blocks++; num_updated_if_blocks++;
VEC_free (int, heap, then_regs); success_p = TRUE;
VEC_free (int, heap, else_regs);
return TRUE; done:
pointer_map_destroy (then_vals);
pointer_map_destroy (else_vals);
VEC_free (rtx, heap, then_regs);
VEC_free (rtx, heap, else_regs);
return success_p;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment