This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GCSE cleanup/fix


Hi,
this patch makes gcse to use code hoisting infrastructure.  I am no longer
targetting to switch gcse to use liveness in this period, but using the new
functions saves some black magic and avoids gcse from converting adds into leas
that cause perofmrance problems on i386.

Bootstraped/regtested i386 and ppc.

Honza

Mon Aug 12 15:14:21 CEST 2002  Jan Hubicka  <jh@suse.cz>
	* gcse.c (struct expr): Add insn field.
	(end_bb_insertion_point): Split out from ...
	(insert_insn_end_bb): .. here; use hoisting code.
	(process_insert_insn): Kill.
	(want_to_gcse_p): Simplify as validity of movement is already verified.
	(insert_expr_in_table, insert_set_in_table): Set insn field.
	(hash_scan_set): Verify can_hoist_insn_p globally for the moment.
	(hoist_code): FIx formating.

Index: gcse.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/gcse.c,v
retrieving revision 1.217
diff -c -3 -p -r1.217 gcse.c
*** gcse.c	1 Aug 2002 19:10:14 -0000	1.217
--- gcse.c	12 Aug 2002 13:11:53 -0000
*************** struct expr
*** 313,318 ****
--- 313,320 ----
  {
    /* The expression (SET_SRC for expressions, PATTERN for assignments).  */
    rtx expr;
+   /* The insn used to compute expression used for purposes of code movement.  */
+   rtx insn;
    /* Index in the available expression bitmaps.  */
    int bitmap_index;
    /* Next entry with the same hash.  */
*************** static void compute_pre_data	PARAMS ((vo
*** 623,628 ****
--- 625,631 ----
  static int pre_expr_reaches_here_p PARAMS ((basic_block, struct expr *,
  					    basic_block));
  static void insert_insn_end_bb	PARAMS ((struct expr *, basic_block, int));
+ static rtx end_bb_insertion_point PARAMS ((struct expr *, basic_block, int));
  static void pre_insert_copy_insn PARAMS ((struct expr *, rtx));
  static void pre_insert_copies	PARAMS ((void));
  static int pre_delete		PARAMS ((void));
*************** static void invalidate_nonnull_info PARA
*** 659,665 ****
  static int delete_null_pointer_checks_1 PARAMS ((unsigned int *,
  						  sbitmap *, sbitmap *,
  						  struct null_pointer_info *));
- static rtx process_insert_insn	PARAMS ((struct expr *));
  static int pre_edge_insert	PARAMS ((struct edge_list *, struct expr **));
  static int expr_reaches_here_p_work PARAMS ((struct occr *, struct expr *,
  					     basic_block, int, char *));
--- 662,667 ----
*************** static int
*** 1297,1343 ****
  want_to_gcse_p (x)
       rtx x;
  {
!   int num_clobbers = 0;
!   int icode;
! 
!   switch (GET_CODE (x))
!     {
!     case REG:
!     case SUBREG:
!     case CONST_INT:
!     case CONST_DOUBLE:
!     case CONST_VECTOR:
!     case CALL:
!       return 0;
! 
!     default:
!       break;
!     }
! 
!   /* If this is a valid operand, we are OK.  If it's VOIDmode, we aren't.  */
!   if (general_operand (x, GET_MODE (x)))
!     return 1;
!   else if (GET_MODE (x) == VOIDmode)
      return 0;
! 
!   /* Otherwise, check if we can make a valid insn from it.  First initialize
!      our test insn if we haven't already.  */
!   if (test_insn == 0)
!     {
!       test_insn
! 	= make_insn_raw (gen_rtx_SET (VOIDmode,
! 				      gen_rtx_REG (word_mode,
! 						   FIRST_PSEUDO_REGISTER * 2),
! 				      const0_rtx));
!       NEXT_INSN (test_insn) = PREV_INSN (test_insn) = 0;
!     }
! 
!   /* Now make an insn like the one we would make when GCSE'ing and see if
!      valid.  */
!   PUT_MODE (SET_DEST (PATTERN (test_insn)), GET_MODE (x));
!   SET_SRC (PATTERN (test_insn)) = x;
!   return ((icode = recog (PATTERN (test_insn), test_insn, &num_clobbers)) >= 0
! 	  && (num_clobbers == 0 || ! added_clobbers_hard_reg_p (icode)));
  }
  
  /* Return non-zero if the operands of expression X are unchanged from the
--- 1299,1310 ----
  want_to_gcse_p (x)
       rtx x;
  {
!   /* We can not move CALL and currently GCSE expects each expression
!      to have mode.  Avoid GCSE on constants as constant propagation
!      handles these in proper way.  */
!   if (GET_CODE (x) == CALL || GET_MODE (x) == VOIDmode || CONSTANT_P (x))
      return 0;
!   return rtx_cost (x, SET) != 0;
  }
  
  /* Return non-zero if the operands of expression X are unchanged from the
*************** insert_expr_in_table (x, mode, insn, ant
*** 1985,1990 ****
--- 1952,1958 ----
  
        /* Set the fields of the expr element.  */
        cur_expr->expr = x;
+       cur_expr->insn = insn;
        cur_expr->bitmap_index = table->n_elems++;
        cur_expr->next_same_hash = NULL;
        cur_expr->antic_occr = NULL;
*************** insert_set_in_table (x, insn, table)
*** 2111,2116 ****
--- 2079,2085 ----
  	 We must copy X because it can be modified when copy propagation is
  	 performed on its operands.  */
        cur_expr->expr = copy_rtx (x);
+       cur_expr->insn = insn;
        cur_expr->bitmap_index = table->n_elems++;
        cur_expr->next_same_hash = NULL;
        cur_expr->antic_occr = NULL;
*************** hash_scan_set (pat, insn, table)
*** 2188,2193 ****
--- 2157,2168 ----
  	  && !find_reg_note (insn, REG_EH_REGION, NULL_RTX)
  	  /* Is SET_SRC something we want to gcse?  */
  	  && want_to_gcse_p (src)
+ 	  /* At the moment PRE is built around assumption that the expressions
+ 	     can be inserted frelly around the CFG.  In future we will check
+ 	     this locally for each insertion point considered and use the
+ 	     liveness information to allow movement of instructions clobbering
+ 	     hard registers.  */
+ 	  && can_hoist_insn_p (insn, SET_DEST (pat), NULL)
  	  /* Don't CSE a nop.  */
  	  && ! set_noop_p (pat)
  	  /* Don't GCSE if it has attached REG_EQUIV note.
*************** pre_expr_reaches_here_p (occr_bb, expr, 
*** 4849,4913 ****
    return rval;
  }
  
! 
! /* Given an expr, generate RTL which we can insert at the end of a BB,
!    or on an edge.  Set the block number of any insns generated to
!    the value of BB.  */
! 
  static rtx
! process_insert_insn (expr)
!      struct expr *expr;
! {
!   rtx reg = expr->reaching_reg;
!   rtx exp = copy_rtx (expr->expr);
!   rtx pat;
! 
!   start_sequence ();
! 
!   /* If the expression is something that's an operand, like a constant,
!      just copy it to a register.  */
!   if (general_operand (exp, GET_MODE (reg)))
!     emit_move_insn (reg, exp);
! 
!   /* Otherwise, make a new insn to compute this expression and make sure the
!      insn will be recognized (this also adds any needed CLOBBERs).  Copy the
!      expression to make sure we don't have any sharing issues.  */
!   else if (insn_invalid_p (emit_insn (gen_rtx_SET (VOIDmode, reg, exp))))
!     abort ();
! 
!   pat = get_insns ();
!   end_sequence ();
! 
!   return pat;
! }
! 
! /* Add EXPR to the end of basic block BB.
! 
!    This is used by both the PRE and code hoisting.
! 
!    For PRE, we want to verify that the expr is either transparent
!    or locally anticipatable in the target block.  This check makes
!    no sense for code hoisting.  */
! 
! static void
! insert_insn_end_bb (expr, bb, pre)
       struct expr *expr;
       basic_block bb;
       int pre;
  {
    rtx insn = bb->end;
-   rtx new_insn;
-   rtx reg = expr->reaching_reg;
-   int regno = REGNO (reg);
-   rtx pat, pat_end;
- 
-   pat = process_insert_insn (expr);
-   if (pat == NULL_RTX || ! INSN_P (pat))
-     abort ();
- 
-   pat_end = pat;
-   while (NEXT_INSN (pat_end) != NULL_RTX)
-     pat_end = NEXT_INSN (pat_end);
  
    /* If the last insn is a jump, insert EXPR in front [taking care to
       handle cc0, etc. properly].  Similary we need to care trapping
--- 4824,4839 ----
    return rval;
  }
  
! /* Return instruction where new insns should be inserted when thy should
!    appear last in the bb.  This is usually just before final jump instruction
!    or the last instruction in the block.  */
  static rtx
! end_bb_insertion_point (expr, bb, pre)
       struct expr *expr;
       basic_block bb;
       int pre;
  {
    rtx insn = bb->end;
  
    /* If the last insn is a jump, insert EXPR in front [taking care to
       handle cc0, etc. properly].  Similary we need to care trapping
*************** insert_insn_end_bb (expr, bb, pre)
*** 4951,4957 ****
  	}
  #endif
        /* FIXME: What if something in cc0/jump uses value set in new insn?  */
!       new_insn = emit_insn_before (pat, insn);
      }
  
    /* Likewise if the last insn is a call, as will happen in the presence
--- 4877,4883 ----
  	}
  #endif
        /* FIXME: What if something in cc0/jump uses value set in new insn?  */
!       return PREV_INSN (insn);
      }
  
    /* Likewise if the last insn is a call, as will happen in the presence
*************** insert_insn_end_bb (expr, bb, pre)
*** 4990,5011 ****
  	     || NOTE_INSN_BASIC_BLOCK_P (insn))
  	insn = NEXT_INSN (insn);
  
!       new_insn = emit_insn_before (pat, insn);
      }
    else
!     new_insn = emit_insn_after (pat, insn);
  
!   while (1)
!     {
!       if (INSN_P (pat))
! 	{
! 	  add_label_notes (PATTERN (pat), new_insn);
! 	  note_stores (PATTERN (pat), record_set_info, pat);
! 	}
!       if (pat == pat_end)
! 	break;
!       pat = NEXT_INSN (pat);
!     }
  
    gcse_create_count++;
  
--- 4916,4950 ----
  	     || NOTE_INSN_BASIC_BLOCK_P (insn))
  	insn = NEXT_INSN (insn);
  
!       return PREV_INSN (insn);
      }
    else
!     return insn;
! }
  
! /* Add EXPR to the end of basic block BB.
! 
!    This is used by both the PRE and code hoisting.
! 
!    For PRE, we want to verify that the expr is either transparent
!    or locally anticipatable in the target block.  This check makes
!    no sense for code hoisting.  */
! 
! static void
! insert_insn_end_bb (expr, bb, pre)
!      struct expr *expr;
!      basic_block bb;
!      int pre;
! {
!   rtx new_insn;
!   rtx reg = expr->reaching_reg;
!   int regno = REGNO (reg);
!   rtx after = end_bb_insertion_point (expr, bb, pre);
! 
!   new_insn = hoist_insn_after (expr->insn, after, SET_DEST (single_set
! 			       (expr->insn)), reg);
! 
!   note_stores (PATTERN (new_insn), record_set_info, new_insn);
  
    gcse_create_count++;
  
*************** pre_edge_insert (edge_list, index_map)
*** 5062,5068 ****
  		       reach the deleted occurrence in BB.  */
  		    if (!TEST_BIT (inserted[e], j))
  		      {
- 			rtx insn;
  			edge eg = INDEX_EDGE (edge_list, e);
  
  			/* We can't insert anything on an abnormal and
--- 5001,5006 ----
*************** pre_edge_insert (edge_list, index_map)
*** 5076,5083 ****
  			  insert_insn_end_bb (index_map[j], bb, 0);
  			else
  			  {
! 			    insn = process_insert_insn (index_map[j]);
! 			    insert_insn_on_edge (insn, eg);
  			  }
  
  			if (gcse_file)
--- 5014,5022 ----
  			  insert_insn_end_bb (index_map[j], bb, 0);
  			else
  			  {
! 			    hoist_insn_to_edge (expr->insn, eg,
! 					    	SET_DEST (single_set (expr->insn)),
! 						expr->reaching_reg);
  			  }
  
  			if (gcse_file)
*************** hoist_code ()
*** 6044,6050 ****
        if (! found)
          {
    	  free (domby);
! 	continue;
  	}
  
        /* Loop over all the hoistable expressions.  */
--- 5983,5989 ----
        if (! found)
          {
    	  free (domby);
! 	  continue;
  	}
  
        /* Loop over all the hoistable expressions.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]