mirror of git://gcc.gnu.org/git/gcc.git
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
This commit is contained in:
parent
88ca9ea18f
commit
985e963f0c
|
|
@ -1,3 +1,13 @@
|
||||||
|
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) \
|
||||||
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)
|
||||||
|
|
|
||||||
121
gcc/ifcvt.c
121
gcc/ifcvt.c
|
|
@ -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)
|
||||||
|
|
||||||
/* 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,
|
||||||
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,
|
||||||
/* 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,
|
||||||
&& 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,
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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])
|
{
|
||||||
|
gcc_checking_assert (pointer_map_contains (else_vals, reg));
|
||||||
|
if (!pointer_map_contains (then_vals, reg))
|
||||||
++c;
|
++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)
|
||||||
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)
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue