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]

PRE_DEC/PUSH_ROUNDING inconsistency fix



Hi
This patch attempts to solve inconsistency in the PRE_INC/PRE_DEC handling.
For most of autoinc code these operations always modify the operand by the size
of memory mode they are boundled in. However for calls.c and some other
function calling bits this is not true and they are expect it to modify by
PUSH_ROUNDING (GET_MODE_SIZE (mode)) resulting in missoptimizations of the
code.

The patch changes the representation of push_operands of such instructions from
   (mem:M (pre_dec:P (stack)))
to
   (mem:M (pre_modify (stack) (plus:P (stack) (const_int amount))))

The push_operand/pop_operand are modified to accept such representation.
Note that for x86-64 case I am shooting for this is still not quite correct
representation, since the push instruction always stores 64bits, so push
should look like:
(set (mem:DI (pre_dec:DI (stack))) (subreg:DI (operand)))
but doing this by default is asking for troubles because of tricky behaviour
of subreg expression.

I would like to handle this by followup patch that will avoid mov expanders
from being used to emit push and pop insns. Preparation work is in place by
introducting the emit_single_push_insn that is now used to emit all push insns
from generic code and thus may be easilly redirected to use different
expanders.  This introduced complications in the move_by_pieces code I am
not quite happy about, but probably worth it.

Honza

Pá lis  3 22:41:35 CET 2000  Jan Hubicka  <jh@suse.cz>
	* recog.c (push_operand):  Accept POST_MODIFY.
	(pop_operand): Accept PRE_MODIFY.
	* expr.h (gen_push_operand): Remove.
	* expr.c (emit_single_push_insn): New.
	(move_by_pieces): Accept NULL as TO.
	(move_by_pieces_1): Call emit_single_push_insn when TO is NULL.
	(gen_push_operand): Kill.
	(emit_single_push_insn): New.
	(emit_push_insn): Use emit_single_push_insn; update call
	to move_by_pieces.

*** expr.h.old	Fri Nov  3 21:41:53 2000
--- expr.h	Fri Nov  3 21:42:01 2000
*************** extern rtx emit_move_insn_1 PARAMS ((rtx
*** 1008,1016 ****
     and return an rtx to address the beginning of the block.  */
  extern rtx push_block PARAMS ((rtx, int, int));
  
- /* Make an operand to push something on the stack.  */
- extern rtx gen_push_operand PARAMS ((void));
- 
  #ifdef TREE_CODE
  /* Generate code to push something onto the stack, given its mode and type.  */
  extern void emit_push_insn PARAMS ((rtx, enum machine_mode, tree, rtx,
--- 1008,1013 ----
*** recog.c.old	Fri Nov  3 21:46:27 2000
--- recog.c	Fri Nov  3 22:13:06 2000
*************** push_operand (op, mode)
*** 1266,1273 ****
  
    op = XEXP (op, 0);
  
!   if (GET_CODE (op) != STACK_PUSH_CODE)
!     return 0;
  
    return XEXP (op, 0) == stack_pointer_rtx;
  }
--- 1266,1292 ----
  
    op = XEXP (op, 0);
  
!   if (mode == VOIDmode
!       || PUSH_ROUNDING (GET_MODE_SIZE (mode)) == GET_MODE_SIZE (mode))
!     {
!       if (GET_CODE (op) != STACK_PUSH_CODE)
! 	return 0;
!     }
!   else
!     {
!       int rounded_size = PUSH_ROUNDING (GET_MODE_SIZE (mode));
!       if (GET_CODE (op) != PRE_MODIFY
! 	  || GET_CODE (XEXP (op, 1)) != PLUS
! 	  || XEXP (XEXP (op, 1), 0) != XEXP (op, 0)
! 	  || GET_CODE (XEXP (XEXP (op, 1), 1)) != CONST_INT
! #ifdef STACK_GROWS_DOWNWARD
! 	  || INTVAL (XEXP (XEXP (op, 1), 1)) != -rounded_size
! #else
! 	  || INTVAL (XEXP (XEXP (op, 1), 1)) != rounded_size
! #endif
! 	  )
! 	return 0;
!     }
  
    return XEXP (op, 0) == stack_pointer_rtx;
  }
*************** pop_operand (op, mode)
*** 1291,1298 ****
  
    op = XEXP (op, 0);
  
!   if (GET_CODE (op) != STACK_POP_CODE)
!     return 0;
  
    return XEXP (op, 0) == stack_pointer_rtx;
  }
--- 1310,1336 ----
  
    op = XEXP (op, 0);
  
!   if (mode == VOIDmode
!       || PUSH_ROUNDING (GET_MODE_SIZE (mode)) == GET_MODE_SIZE (mode))
!     {
!       if (GET_CODE (op) != STACK_POP_CODE)
! 	return 0;
!     }
!   else
!     {
!       int rounded_size = PUSH_ROUNDING (GET_MODE_SIZE (mode));
!       if (GET_CODE (op) != POST_MODIFY
! 	  || GET_CODE (XEXP (op, 1)) != PLUS
! 	  || XEXP (XEXP (op, 1), 0) != XEXP (op, 0)
! 	  || GET_CODE (XEXP (XEXP (op, 1), 1)) != CONST_INT
! #ifdef STACK_GROWS_DOWNWARD
! 	  || INTVAL (XEXP (XEXP (op, 1), 1)) != rounded_size
! #else
! 	  || INTVAL (XEXP (XEXP (op, 1), 1)) != -rounded_size
! #endif
! 	  )
! 	return 0;
!     }
  
    return XEXP (op, 0) == stack_pointer_rtx;
  }
*** expr.h.old	Fri Nov  3 21:41:53 2000
--- expr.h	Fri Nov  3 21:42:01 2000
*************** extern rtx emit_move_insn_1 PARAMS ((rtx
*** 1008,1016 ****
     and return an rtx to address the beginning of the block.  */
  extern rtx push_block PARAMS ((rtx, int, int));
  
- /* Make an operand to push something on the stack.  */
- extern rtx gen_push_operand PARAMS ((void));
- 
  #ifdef TREE_CODE
  /* Generate code to push something onto the stack, given its mode and type.  */
  extern void emit_push_insn PARAMS ((rtx, enum machine_mode, tree, rtx,
--- 1008,1013 ----
*** expr.c.old	Fri Nov  3 18:17:42 2000
--- expr.c	Fri Nov  3 22:43:21 2000
*************** static void do_jump_by_parts_equality PA
*** 189,194 ****
--- 189,195 ----
  static void do_compare_and_jump	PARAMS ((tree, enum rtx_code, enum rtx_code,
  					 rtx, rtx));
  static rtx do_store_flag	PARAMS ((tree, rtx, enum machine_mode, int));
+ static void emit_single_push_insn PARAMS ((enum machine_mode, rtx, tree));
  
  /* Record for each mode whether we can move a register directly to or
     from an object of that mode in memory.  If we can't, we won't try
*************** convert_modes (mode, oldmode, x, unsigne
*** 1402,1407 ****
--- 1403,1412 ----
     from block FROM to block TO.  (These are MEM rtx's with BLKmode).
     The caller must pass FROM and TO
      through protect_from_queue before calling.
+ 
+    When TO is NULL, the emit_single_push_insn is used to push the
+    FROM to stack.
+ 
     ALIGN is maximum alignment we can assume.  */
  
  void
*************** move_by_pieces (to, from, len, align)
*** 1411,1417 ****
       unsigned int align;
  {
    struct move_by_pieces data;
!   rtx to_addr = XEXP (to, 0), from_addr = XEXP (from, 0);
    unsigned int max_size = MOVE_MAX_PIECES + 1;
    enum machine_mode mode = VOIDmode, tmode;
    enum insn_code icode;
--- 1416,1422 ----
       unsigned int align;
  {
    struct move_by_pieces data;
!   rtx to_addr, from_addr = XEXP (from, 0);
    unsigned int max_size = MOVE_MAX_PIECES + 1;
    enum machine_mode mode = VOIDmode, tmode;
    enum insn_code icode;
*************** move_by_pieces (to, from, len, align)
*** 1419,1429 ****
    data.offset = 0;
    data.to_addr = to_addr;
    data.from_addr = from_addr;
!   data.to = to;
    data.from = from;
-   data.autinc_to
-     = (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC
-        || GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC);
    data.autinc_from
      = (GET_CODE (from_addr) == PRE_INC || GET_CODE (from_addr) == PRE_DEC
         || GET_CODE (from_addr) == POST_INC
--- 1424,1451 ----
    data.offset = 0;
    data.to_addr = to_addr;
    data.from_addr = from_addr;
!   if (to)
!     {
!       to_addr = XEXP (to, 0);
!       data.to = to;
!       data.autinc_to
! 	= (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC
! 	   || GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC);
!       data.reverse
! 	= (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
!     }
!   else
!     {
!       to_addr = NULL_RTX;
!       data.to = NULL_RTX;
!       data.autinc_to = 1;
! #ifdef STACK_GROWS_DOWNWARD
!       data.reverse = 1;
! #else
!       data.reverse = 0;
! #endif
!     }
    data.from = from;
    data.autinc_from
      = (GET_CODE (from_addr) == PRE_INC || GET_CODE (from_addr) == PRE_DEC
         || GET_CODE (from_addr) == POST_INC
*************** move_by_pieces (to, from, len, align)
*** 1431,1438 ****
  
    data.explicit_inc_from = 0;
    data.explicit_inc_to = 0;
-   data.reverse
-     = (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
    if (data.reverse) data.offset = len;
    data.len = len;
  
--- 1453,1458 ----
*************** move_by_pieces_1 (genfun, mode, data)
*** 1563,1576 ****
        if (data->reverse)
  	data->offset -= size;
  
!       if (data->autinc_to)
  	{
! 	  to1 = gen_rtx_MEM (mode, data->to_addr);
! 	  MEM_COPY_ATTRIBUTES (to1, data->to);
  	}
-       else
- 	to1 = change_address (data->to, mode,
- 			      plus_constant (data->to_addr, data->offset));
  
        if (data->autinc_from)
  	{
--- 1583,1599 ----
        if (data->reverse)
  	data->offset -= size;
  
!       if (data->to)
  	{
! 	  if (data->autinc_to)
! 	    {
! 	      to1 = gen_rtx_MEM (mode, data->to_addr);
! 	      MEM_COPY_ATTRIBUTES (to1, data->to);
! 	    }
! 	  else
! 	    to1 = change_address (data->to, mode,
! 				  plus_constant (data->to_addr, data->offset));
  	}
  
        if (data->autinc_from)
  	{
*************** move_by_pieces_1 (genfun, mode, data)
*** 1586,1592 ****
        if (HAVE_PRE_DECREMENT && data->explicit_inc_from < 0)
  	emit_insn (gen_add2_insn (data->from_addr, GEN_INT (-size)));
  
!       emit_insn ((*genfun) (to1, from1));
  
        if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0)
  	emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
--- 1609,1618 ----
        if (HAVE_PRE_DECREMENT && data->explicit_inc_from < 0)
  	emit_insn (gen_add2_insn (data->from_addr, GEN_INT (-size)));
  
!       if (data->to)
! 	emit_insn ((*genfun) (to1, from1));
!       else
! 	emit_single_push_insn (mode, from1, NULL);
  
        if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0)
  	emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
*************** push_block (size, extra, below)
*** 2899,2909 ****
    return memory_address (GET_CLASS_NARROWEST_MODE (MODE_INT), temp);
  }
  
- rtx
- gen_push_operand ()
- {
-   return gen_rtx_fmt_e (STACK_PUSH_CODE, Pmode, stack_pointer_rtx);
- }
  
  /* Return an rtx for the address of the beginning of a as-if-it-was-pushed
     block of SIZE bytes.  */
--- 2925,2930 ----
*************** get_push_address (size)
*** 2924,2929 ****
--- 2945,2995 ----
    return copy_to_reg (temp);
  }
  
+ /* Emit single push insn.  */
+ static void
+ emit_single_push_insn (mode, x, type)
+      rtx x;
+      enum machine_mode mode;
+      tree type;
+ {
+ #ifdef PUSH_ROUNDING
+   rtx dest_addr;
+   int rounded_size = PUSH_ROUNDING (GET_MODE_SIZE (mode));
+   rtx dest;
+ 
+   if (GET_MODE_SIZE (mode) == rounded_size)
+     dest_addr = gen_rtx_fmt_e (STACK_PUSH_CODE, Pmode, stack_pointer_rtx);
+   else
+     {
+ #ifdef STACK_GROWS_DOWNWARD
+       dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ 				GEN_INT (-rounded_size));
+ #else
+       dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ 				GEN_INT (rounded_size));
+ #endif
+       dest_addr = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx, dest_addr);
+     }
+ 
+   dest = gen_rtx_MEM (mode, dest_addr);
+ 
+   stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode));
+ 
+   if (type != 0)
+     {
+       set_mem_attributes (dest, type, 1);
+       /* Function incoming arguments may overlap with sibling call
+          outgoing arguments and we cannot allow reordering of reads
+          from function arguments with stores to outgoing arguments
+          of sibling calls.  */
+       MEM_ALIAS_SET (dest) = 0;
+     }
+   emit_move_insn (dest, x);
+ #else
+   abort();
+ #endif
+ }
+ 
  /* Generate code to push X onto the stack, assuming it has mode MODE and
     type TYPE.
     MODE is redundant except when X is a CONST_INT (since they don't
*************** emit_push_insn (x, mode, type, size, ali
*** 3044,3052 ****
  	      && where_pad != none && where_pad != stack_direction)
  	    anti_adjust_stack (GEN_INT (extra));
  
! 	  stack_pointer_delta += INTVAL (size) - used;
! 	  move_by_pieces (gen_rtx_MEM (BLKmode, gen_push_operand ()), xinner,
! 			  INTVAL (size) - used, align);
  
  	  if (current_function_check_memory_usage && ! in_check_memory_usage)
  	    {
--- 3110,3116 ----
  	      && where_pad != none && where_pad != stack_direction)
  	    anti_adjust_stack (GEN_INT (extra));
  
! 	  move_by_pieces (NULL, xinner, INTVAL (size) - used, align);
  
  	  if (current_function_check_memory_usage && ! in_check_memory_usage)
  	    {
*************** emit_push_insn (x, mode, type, size, ali
*** 3298,3307 ****
  
  #ifdef PUSH_ROUNDING
        if (args_addr == 0 && PUSH_ARGS)
! 	{
! 	  addr = gen_push_operand ();
! 	  stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode));
! 	}
        else
  #endif
  	{
--- 3362,3368 ----
  
  #ifdef PUSH_ROUNDING
        if (args_addr == 0 && PUSH_ARGS)
! 	emit_single_push_insn (mode, x, type);
        else
  #endif
  	{
*************** emit_push_insn (x, mode, type, size, ali
*** 3314,3333 ****
  	    addr = memory_address (mode, gen_rtx_PLUS (Pmode, args_addr,
  						       args_so_far));
  	  target = addr;
! 	}
  
!       dest = gen_rtx_MEM (mode, addr);
!       if (type != 0)
! 	{
! 	  set_mem_attributes (dest, type, 1);
! 	  /* Function incoming arguments may overlap with sibling call
! 	     outgoing arguments and we cannot allow reordering of reads
! 	     from function arguments with stores to outgoing arguments
! 	     of sibling calls.  */
! 	  MEM_ALIAS_SET (dest) = 0;
! 	}
  
!       emit_move_insn (dest, x);
  
        if (current_function_check_memory_usage && ! in_check_memory_usage)
  	{
--- 3375,3394 ----
  	    addr = memory_address (mode, gen_rtx_PLUS (Pmode, args_addr,
  						       args_so_far));
  	  target = addr;
! 	  dest = gen_rtx_MEM (mode, addr);
! 	  if (type != 0)
! 	    {
! 	      set_mem_attributes (dest, type, 1);
! 	      /* Function incoming arguments may overlap with sibling call
! 		 outgoing arguments and we cannot allow reordering of reads
! 		 from function arguments with stores to outgoing arguments
! 		 of sibling calls.  */
! 	      MEM_ALIAS_SET (dest) = 0;
! 	    }
  
! 	  emit_move_insn (dest, x);
  
! 	}
  
        if (current_function_check_memory_usage && ! in_check_memory_usage)
  	{

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