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) | ||||||
|  |  | ||||||
							
								
								
									
										123
									
								
								gcc/ifcvt.c
								
								
								
								
							
							
						
						
									
										123
									
								
								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]) |     { | ||||||
|       ++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) | ||||||
| 					  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
	
	 Steven Bosscher
						Steven Bosscher