This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PRE_DEC/PUSH_ROUNDING inconsistency fix
- To: gcc-patches at gcc dot gnu dot org, patches at x86-64 dot org, rth at cygnus dot com
- Subject: PRE_DEC/PUSH_ROUNDING inconsistency fix
- From: Jan Hubicka <jh at suse dot cz>
- Date: Sat, 4 Nov 2000 10:42:39 +0100
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)
{