re PR middle-end/31150 (Not promoting an whole array to be static const)
PR middle-end/31150 * dse.c (struct store_info): Add const_rhs field. (clear_rhs_from_active_local_stores): Clear also const_rhs. (record_store): Try also cselib_expand_value_rtx to get a constant. (find_shift_sequence, get_stored_val): Use const_rhs instead of rhs if worthwhile. * cselib.c (cselib_record_sets): If !cselib_record_memory and there is just one set from read-only MEM, look at REG_EQUAL or REG_EQUIV note. * dse.c (struct store_info): Add redundant_reason field. (record_store): When storing the same constant as has been stored by an earlier store, set redundant_reason field to the earlier store's insn_info_t. Don't delete cannot_delete insns. (find_shift_sequence): Remove read_info argument, add read_mode and require_cst arguments. Return early if require_cst and constant wouldn't be returned. (get_stored_val): New function. (replace_read): Use it. (scan_insn): Put even cannot_delete insns with exactly 1 store into active_local_stores. (dse_step1): Don't delete cannot_delete insns. Remove redundant constant stores if contains_cselib_groups and earlier store storing the same value hasn't been eliminated. (dse_step6): Renamed to dse_step7. New function. (dse_step7): Renamed from dse_step6. (rest_of_handle_dse): Call dse_step6 and dse_step7 at the end. * cselib.c (cselib_expand_value_rtx): Don't wrap CONST_INTs into CONST unless really necessary. Handle SUBREG, unary, ternary, bitfield and compares specially, to be able to simplify operations on constants. (expand_loc): Try to optimize LO_SUM. * dse.c (get_call_args): New function. (scan_insn): Don't handle BUILT_IN_BZERO. For memset, attempt to get call arguments and if successful and both len and val are constants, handle the call as (mem:BLK) (const_int) store. * dse.c (struct store_info): Add is_large bool field, change positions_needed into a union of a bitmask and bitmap + count. (free_store_info): Free bitmap if is_large. (set_usage_bits): Don't look at stores where offset + width >= MAX_OFFSET. (set_position_unneeded, set_all_positions_unneeded, any_positions_needed_p, all_positions_needed_p): New static inline functions. (record_store): Handle BLKmode stores of CONST_INT, if MEM_SIZE is set on the MEM. Use the new positions_needed accessor inlines. (replace_read): Handle reads from BLKmode CONST_INT stores. (check_mem_read_rtx): Use all_positions_needed_p function. (dse_step1): Free large positions_needed bitmaps and clear is_large. * dse.c (struct store_info): Change begin and end types to HOST_WIDE_INT. * dse.c (record_store): Fix check for unused store. * expr.c (block_clear_fn): No longer static. * expr.h (block_clear_fn): Declare. * dse.c (scan_insn): Memset and bzero can just read their arguments. * gcc.c-torture/execute/20081218-1.c: New test. From-SVN: r142892
This commit is contained in:
parent
805903b525
commit
8dd5516b4c
|
@ -1,5 +1,69 @@
|
|||
2008-12-23 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR middle-end/31150
|
||||
* dse.c (struct store_info): Add const_rhs field.
|
||||
(clear_rhs_from_active_local_stores): Clear also const_rhs.
|
||||
(record_store): Try also cselib_expand_value_rtx to get a constant.
|
||||
(find_shift_sequence, get_stored_val): Use const_rhs instead of
|
||||
rhs if worthwhile.
|
||||
* cselib.c (cselib_record_sets): If !cselib_record_memory and
|
||||
there is just one set from read-only MEM, look at REG_EQUAL or
|
||||
REG_EQUIV note.
|
||||
|
||||
* dse.c (struct store_info): Add redundant_reason field.
|
||||
(record_store): When storing the same constant as has been
|
||||
stored by an earlier store, set redundant_reason field
|
||||
to the earlier store's insn_info_t. Don't delete cannot_delete
|
||||
insns.
|
||||
(find_shift_sequence): Remove read_info argument, add read_mode
|
||||
and require_cst arguments. Return early if require_cst and
|
||||
constant wouldn't be returned.
|
||||
(get_stored_val): New function.
|
||||
(replace_read): Use it.
|
||||
(scan_insn): Put even cannot_delete insns with exactly 1 store
|
||||
into active_local_stores.
|
||||
(dse_step1): Don't delete cannot_delete insns. Remove redundant
|
||||
constant stores if contains_cselib_groups and earlier store storing
|
||||
the same value hasn't been eliminated.
|
||||
(dse_step6): Renamed to dse_step7. New function.
|
||||
(dse_step7): Renamed from dse_step6.
|
||||
(rest_of_handle_dse): Call dse_step6 and dse_step7 at the end.
|
||||
* cselib.c (cselib_expand_value_rtx): Don't wrap CONST_INTs
|
||||
into CONST unless really necessary. Handle SUBREG, unary,
|
||||
ternary, bitfield and compares specially, to be able to simplify
|
||||
operations on constants.
|
||||
(expand_loc): Try to optimize LO_SUM.
|
||||
|
||||
* dse.c (get_call_args): New function.
|
||||
(scan_insn): Don't handle BUILT_IN_BZERO. For memset, attempt
|
||||
to get call arguments and if successful and both len and val are
|
||||
constants, handle the call as (mem:BLK) (const_int) store.
|
||||
|
||||
* dse.c (struct store_info): Add is_large bool field, change
|
||||
positions_needed into a union of a bitmask and bitmap + count.
|
||||
(free_store_info): Free bitmap if is_large.
|
||||
(set_usage_bits): Don't look at stores where
|
||||
offset + width >= MAX_OFFSET.
|
||||
(set_position_unneeded, set_all_positions_unneeded,
|
||||
any_positions_needed_p, all_positions_needed_p): New static inline
|
||||
functions.
|
||||
(record_store): Handle BLKmode stores of CONST_INT, if
|
||||
MEM_SIZE is set on the MEM. Use the new positions_needed
|
||||
accessor inlines.
|
||||
(replace_read): Handle reads from BLKmode CONST_INT stores.
|
||||
(check_mem_read_rtx): Use all_positions_needed_p function.
|
||||
(dse_step1): Free large positions_needed bitmaps and clear is_large.
|
||||
|
||||
* dse.c (struct store_info): Change begin and end types to
|
||||
HOST_WIDE_INT.
|
||||
|
||||
* dse.c (record_store): Fix check for unused store.
|
||||
|
||||
* expr.c (block_clear_fn): No longer static.
|
||||
* expr.h (block_clear_fn): Declare.
|
||||
* dse.c (scan_insn): Memset and bzero can just read their
|
||||
arguments.
|
||||
|
||||
* config/i386/i386.c (expand_setmem_via_rep_stos): Add ORIG_VALUE
|
||||
argument. If ORIG_VALUE is const0_rtx and COUNT is constant,
|
||||
set MEM_SIZE on DESTMEM.
|
||||
|
|
130
gcc/cselib.c
130
gcc/cselib.c
|
@ -1,6 +1,7 @@
|
|||
/* Common subexpression elimination library for GNU compiler.
|
||||
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
|
||||
1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
|
||||
1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
|
@ -865,12 +866,18 @@ expand_loc (struct elt_loc_list *p, bitmap regs_active, int max_depth)
|
|||
continue;
|
||||
else if (!REG_P (p->loc))
|
||||
{
|
||||
rtx result;
|
||||
rtx result, note;
|
||||
if (dump_file)
|
||||
{
|
||||
print_inline_rtx (dump_file, p->loc, 0);
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
if (GET_CODE (p->loc) == LO_SUM
|
||||
&& GET_CODE (XEXP (p->loc, 1)) == SYMBOL_REF
|
||||
&& p->setting_insn
|
||||
&& (note = find_reg_note (p->setting_insn, REG_EQUAL, NULL_RTX))
|
||||
&& XEXP (note, 0) == XEXP (p->loc, 1))
|
||||
return XEXP (p->loc, 1);
|
||||
result = cselib_expand_value_rtx (p->loc, regs_active, max_depth - 1);
|
||||
if (result)
|
||||
return result;
|
||||
|
@ -928,6 +935,7 @@ cselib_expand_value_rtx (rtx orig, bitmap regs_active, int max_depth)
|
|||
int i, j;
|
||||
RTX_CODE code;
|
||||
const char *format_ptr;
|
||||
enum machine_mode mode;
|
||||
|
||||
code = GET_CODE (orig);
|
||||
|
||||
|
@ -1007,25 +1015,30 @@ cselib_expand_value_rtx (rtx orig, bitmap regs_active, int max_depth)
|
|||
return orig;
|
||||
break;
|
||||
|
||||
case SUBREG:
|
||||
{
|
||||
rtx subreg = cselib_expand_value_rtx (SUBREG_REG (orig), regs_active,
|
||||
max_depth - 1);
|
||||
if (!subreg)
|
||||
return NULL;
|
||||
scopy = simplify_gen_subreg (GET_MODE (orig), subreg,
|
||||
GET_MODE (SUBREG_REG (orig)),
|
||||
SUBREG_BYTE (orig));
|
||||
if (scopy == NULL
|
||||
|| (GET_CODE (scopy) == SUBREG
|
||||
&& !REG_P (SUBREG_REG (scopy))
|
||||
&& !MEM_P (SUBREG_REG (scopy))))
|
||||
return shallow_copy_rtx (orig);
|
||||
return scopy;
|
||||
}
|
||||
|
||||
case VALUE:
|
||||
{
|
||||
rtx result;
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "expanding value %s into: ", GET_MODE_NAME (GET_MODE (orig)));
|
||||
|
||||
result = expand_loc (CSELIB_VAL_PTR (orig)->locs, regs_active, max_depth);
|
||||
if (result
|
||||
&& GET_CODE (result) == CONST_INT
|
||||
&& GET_MODE (orig) != VOIDmode)
|
||||
{
|
||||
result = gen_rtx_CONST (GET_MODE (orig), result);
|
||||
if (dump_file)
|
||||
fprintf (dump_file, " wrapping const_int result in const to preserve mode %s\n",
|
||||
GET_MODE_NAME (GET_MODE (orig)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "expanding value %s into: ",
|
||||
GET_MODE_NAME (GET_MODE (orig)));
|
||||
|
||||
return expand_loc (CSELIB_VAL_PTR (orig)->locs, regs_active, max_depth);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1036,9 +1049,9 @@ cselib_expand_value_rtx (rtx orig, bitmap regs_active, int max_depth)
|
|||
us to explicitly document why we are *not* copying a flag. */
|
||||
copy = shallow_copy_rtx (orig);
|
||||
|
||||
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
|
||||
format_ptr = GET_RTX_FORMAT (code);
|
||||
|
||||
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
|
||||
for (i = 0; i < GET_RTX_LENGTH (code); i++)
|
||||
switch (*format_ptr++)
|
||||
{
|
||||
case 'e':
|
||||
|
@ -1082,6 +1095,70 @@ cselib_expand_value_rtx (rtx orig, bitmap regs_active, int max_depth)
|
|||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
mode = GET_MODE (copy);
|
||||
/* If an operand has been simplified into CONST_INT, which doesn't
|
||||
have a mode and the mode isn't derivable from whole rtx's mode,
|
||||
try simplify_*_operation first with mode from original's operand
|
||||
and as a fallback wrap CONST_INT into gen_rtx_CONST. */
|
||||
scopy = copy;
|
||||
switch (GET_RTX_CLASS (code))
|
||||
{
|
||||
case RTX_UNARY:
|
||||
if (CONST_INT_P (XEXP (copy, 0))
|
||||
&& GET_MODE (XEXP (orig, 0)) != VOIDmode)
|
||||
{
|
||||
scopy = simplify_unary_operation (code, mode, XEXP (copy, 0),
|
||||
GET_MODE (XEXP (orig, 0)));
|
||||
if (scopy)
|
||||
return scopy;
|
||||
}
|
||||
break;
|
||||
case RTX_COMM_ARITH:
|
||||
case RTX_BIN_ARITH:
|
||||
/* These expressions can derive operand modes from the whole rtx's mode. */
|
||||
break;
|
||||
case RTX_TERNARY:
|
||||
case RTX_BITFIELD_OPS:
|
||||
if (CONST_INT_P (XEXP (copy, 0))
|
||||
&& GET_MODE (XEXP (orig, 0)) != VOIDmode)
|
||||
{
|
||||
scopy = simplify_ternary_operation (code, mode,
|
||||
GET_MODE (XEXP (orig, 0)),
|
||||
XEXP (copy, 0), XEXP (copy, 1),
|
||||
XEXP (copy, 2));
|
||||
if (scopy)
|
||||
return scopy;
|
||||
}
|
||||
break;
|
||||
case RTX_COMPARE:
|
||||
case RTX_COMM_COMPARE:
|
||||
if (CONST_INT_P (XEXP (copy, 0))
|
||||
&& GET_MODE (XEXP (copy, 1)) == VOIDmode
|
||||
&& (GET_MODE (XEXP (orig, 0)) != VOIDmode
|
||||
|| GET_MODE (XEXP (orig, 1)) != VOIDmode))
|
||||
{
|
||||
scopy = simplify_relational_operation (code, mode,
|
||||
(GET_MODE (XEXP (orig, 0))
|
||||
!= VOIDmode)
|
||||
? GET_MODE (XEXP (orig, 0))
|
||||
: GET_MODE (XEXP (orig, 1)),
|
||||
XEXP (copy, 0),
|
||||
XEXP (copy, 1));
|
||||
if (scopy)
|
||||
return scopy;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (scopy == NULL_RTX)
|
||||
{
|
||||
XEXP (copy, 0)
|
||||
= gen_rtx_CONST (GET_MODE (XEXP (orig, 0)), XEXP (copy, 0));
|
||||
if (dump_file)
|
||||
fprintf (dump_file, " wrapping const_int result in const to preserve mode %s\n",
|
||||
GET_MODE_NAME (GET_MODE (XEXP (copy, 0))));
|
||||
}
|
||||
scopy = simplify_rtx (copy);
|
||||
if (scopy)
|
||||
return scopy;
|
||||
|
@ -1581,6 +1658,17 @@ cselib_record_sets (rtx insn)
|
|||
}
|
||||
}
|
||||
|
||||
if (n_sets == 1
|
||||
&& MEM_P (sets[0].src)
|
||||
&& !cselib_record_memory
|
||||
&& MEM_READONLY_P (sets[0].src))
|
||||
{
|
||||
rtx note = find_reg_equal_equiv_note (insn);
|
||||
|
||||
if (note && CONSTANT_P (XEXP (note, 0)))
|
||||
sets[0].src = XEXP (note, 0);
|
||||
}
|
||||
|
||||
/* Look up the values that are read. Do this before invalidating the
|
||||
locations that are written. */
|
||||
for (i = 0; i < n_sets; i++)
|
||||
|
|
662
gcc/dse.c
662
gcc/dse.c
|
@ -91,7 +91,10 @@ along with GCC; see the file COPYING3. If not see
|
|||
5) Delete the insns that the global analysis has indicated are
|
||||
unnecessary.
|
||||
|
||||
6) Cleanup.
|
||||
6) Delete insns that store the same value as preceeding store
|
||||
where the earlier store couldn't be eliminated.
|
||||
|
||||
7) Cleanup.
|
||||
|
||||
This step uses cselib and canon_rtx to build the largest expression
|
||||
possible for each address. This pass is a forwards pass through
|
||||
|
@ -205,6 +208,9 @@ struct store_info
|
|||
/* False means this is a clobber. */
|
||||
bool is_set;
|
||||
|
||||
/* False if a single HOST_WIDE_INT bitmap is used for positions_needed. */
|
||||
bool is_large;
|
||||
|
||||
/* The id of the mem group of the base address. If rtx_varies_p is
|
||||
true, this is -1. Otherwise, it is the index into the group
|
||||
table. */
|
||||
|
@ -224,12 +230,26 @@ struct store_info
|
|||
|
||||
/* The offset of the first and byte before the last byte associated
|
||||
with the operation. */
|
||||
int begin, end;
|
||||
HOST_WIDE_INT begin, end;
|
||||
|
||||
/* An bitmask as wide as the number of bytes in the word that
|
||||
contains a 1 if the byte may be needed. The store is unused if
|
||||
all of the bits are 0. */
|
||||
unsigned HOST_WIDE_INT positions_needed;
|
||||
union
|
||||
{
|
||||
/* A bitmask as wide as the number of bytes in the word that
|
||||
contains a 1 if the byte may be needed. The store is unused if
|
||||
all of the bits are 0. This is used if IS_LARGE is false. */
|
||||
unsigned HOST_WIDE_INT small_bitmask;
|
||||
|
||||
struct
|
||||
{
|
||||
/* A bitmap with one bit per byte. Cleared bit means the position
|
||||
is needed. Used if IS_LARGE is false. */
|
||||
bitmap bitmap;
|
||||
|
||||
/* Number of set bits (i.e. unneeded bytes) in BITMAP. If it is
|
||||
equal to END - BEGIN, the whole store is unused. */
|
||||
int count;
|
||||
} large;
|
||||
} positions_needed;
|
||||
|
||||
/* The next store info for this insn. */
|
||||
struct store_info *next;
|
||||
|
@ -237,7 +257,16 @@ struct store_info
|
|||
/* The right hand side of the store. This is used if there is a
|
||||
subsequent reload of the mems address somewhere later in the
|
||||
basic block. */
|
||||
rtx rhs;
|
||||
rtx rhs;
|
||||
|
||||
/* If rhs is or holds a constant, this contains that constant,
|
||||
otherwise NULL. */
|
||||
rtx const_rhs;
|
||||
|
||||
/* Set if this store stores the same constant value as REDUNDANT_REASON
|
||||
insn stored. These aren't eliminated early, because doing that
|
||||
might prevent the earlier larger store to be eliminated. */
|
||||
struct insn_info *redundant_reason;
|
||||
};
|
||||
|
||||
/* Return a bitmask with the first N low bits set. */
|
||||
|
@ -760,6 +789,8 @@ free_store_info (insn_info_t insn_info)
|
|||
while (store_info)
|
||||
{
|
||||
store_info_t next = store_info->next;
|
||||
if (store_info->is_large)
|
||||
BITMAP_FREE (store_info->positions_needed.large.bitmap);
|
||||
if (store_info->cse_base)
|
||||
pool_free (cse_store_info_pool, store_info);
|
||||
else
|
||||
|
@ -911,7 +942,7 @@ set_usage_bits (group_info_t group, HOST_WIDE_INT offset, HOST_WIDE_INT width)
|
|||
{
|
||||
HOST_WIDE_INT i;
|
||||
|
||||
if ((offset > -MAX_OFFSET) && (offset < MAX_OFFSET))
|
||||
if (offset > -MAX_OFFSET && offset + width < MAX_OFFSET)
|
||||
for (i=offset; i<offset+width; i++)
|
||||
{
|
||||
bitmap store1;
|
||||
|
@ -1167,12 +1198,86 @@ clear_rhs_from_active_local_stores (void)
|
|||
store_info = store_info->next;
|
||||
|
||||
store_info->rhs = NULL;
|
||||
store_info->const_rhs = NULL;
|
||||
|
||||
ptr = ptr->next_local_store;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Mark byte POS bytes from the beginning of store S_INFO as unneeded. */
|
||||
|
||||
static inline void
|
||||
set_position_unneeded (store_info_t s_info, int pos)
|
||||
{
|
||||
if (__builtin_expect (s_info->is_large, false))
|
||||
{
|
||||
if (!bitmap_bit_p (s_info->positions_needed.large.bitmap, pos))
|
||||
{
|
||||
s_info->positions_needed.large.count++;
|
||||
bitmap_set_bit (s_info->positions_needed.large.bitmap, pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
s_info->positions_needed.small_bitmask
|
||||
&= ~(((unsigned HOST_WIDE_INT) 1) << pos);
|
||||
}
|
||||
|
||||
/* Mark the whole store S_INFO as unneeded. */
|
||||
|
||||
static inline void
|
||||
set_all_positions_unneeded (store_info_t s_info)
|
||||
{
|
||||
if (__builtin_expect (s_info->is_large, false))
|
||||
{
|
||||
int pos, end = s_info->end - s_info->begin;
|
||||
for (pos = 0; pos < end; pos++)
|
||||
bitmap_set_bit (s_info->positions_needed.large.bitmap, pos);
|
||||
s_info->positions_needed.large.count = end;
|
||||
}
|
||||
else
|
||||
s_info->positions_needed.small_bitmask = (unsigned HOST_WIDE_INT) 0;
|
||||
}
|
||||
|
||||
/* Return TRUE if any bytes from S_INFO store are needed. */
|
||||
|
||||
static inline bool
|
||||
any_positions_needed_p (store_info_t s_info)
|
||||
{
|
||||
if (__builtin_expect (s_info->is_large, false))
|
||||
return (s_info->positions_needed.large.count
|
||||
< s_info->end - s_info->begin);
|
||||
else
|
||||
return (s_info->positions_needed.small_bitmask
|
||||
!= (unsigned HOST_WIDE_INT) 0);
|
||||
}
|
||||
|
||||
/* Return TRUE if all bytes START through START+WIDTH-1 from S_INFO
|
||||
store are needed. */
|
||||
|
||||
static inline bool
|
||||
all_positions_needed_p (store_info_t s_info, int start, int width)
|
||||
{
|
||||
if (__builtin_expect (s_info->is_large, false))
|
||||
{
|
||||
int end = start + width;
|
||||
while (start < end)
|
||||
if (bitmap_bit_p (s_info->positions_needed.large.bitmap, start++))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned HOST_WIDE_INT mask = lowpart_bitmask (width) << start;
|
||||
return (s_info->positions_needed.small_bitmask & mask) == mask;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static rtx get_stored_val (store_info_t, enum machine_mode, HOST_WIDE_INT,
|
||||
HOST_WIDE_INT, basic_block, bool);
|
||||
|
||||
|
||||
/* BODY is an instruction pattern that belongs to INSN. Return 1 if
|
||||
there is a candidate store, after adding it to the appropriate
|
||||
local store group if so. */
|
||||
|
@ -1180,7 +1285,7 @@ clear_rhs_from_active_local_stores (void)
|
|||
static int
|
||||
record_store (rtx body, bb_info_t bb_info)
|
||||
{
|
||||
rtx mem;
|
||||
rtx mem, rhs, const_rhs;
|
||||
HOST_WIDE_INT offset = 0;
|
||||
HOST_WIDE_INT width = 0;
|
||||
alias_set_type spill_alias_set;
|
||||
|
@ -1188,20 +1293,21 @@ record_store (rtx body, bb_info_t bb_info)
|
|||
store_info_t store_info = NULL;
|
||||
int group_id;
|
||||
cselib_val *base = NULL;
|
||||
insn_info_t ptr, last;
|
||||
insn_info_t ptr, last, redundant_reason;
|
||||
bool store_is_unused;
|
||||
|
||||
if (GET_CODE (body) != SET && GET_CODE (body) != CLOBBER)
|
||||
return 0;
|
||||
|
||||
mem = SET_DEST (body);
|
||||
|
||||
/* If this is not used, then this cannot be used to keep the insn
|
||||
from being deleted. On the other hand, it does provide something
|
||||
that can be used to prove that another store is dead. */
|
||||
store_is_unused
|
||||
= (find_reg_note (insn_info->insn, REG_UNUSED, body) != NULL);
|
||||
= (find_reg_note (insn_info->insn, REG_UNUSED, mem) != NULL);
|
||||
|
||||
/* Check whether that value is a suitable memory location. */
|
||||
mem = SET_DEST (body);
|
||||
if (!MEM_P (mem))
|
||||
{
|
||||
/* If the set or clobber is unused, then it does not effect our
|
||||
|
@ -1220,20 +1326,31 @@ record_store (rtx body, bb_info_t bb_info)
|
|||
fprintf (dump_file, " adding wild read for (clobber (mem:BLK (scratch))\n");
|
||||
add_wild_read (bb_info);
|
||||
insn_info->cannot_delete = true;
|
||||
return 0;
|
||||
}
|
||||
else if (!store_is_unused)
|
||||
/* Handle (set (mem:BLK (addr) [... S36 ...]) (const_int 0))
|
||||
as memset (addr, 0, 36); */
|
||||
else if (!MEM_SIZE (mem)
|
||||
|| !CONST_INT_P (MEM_SIZE (mem))
|
||||
|| GET_CODE (body) != SET
|
||||
|| INTVAL (MEM_SIZE (mem)) <= 0
|
||||
|| INTVAL (MEM_SIZE (mem)) > MAX_OFFSET
|
||||
|| !CONST_INT_P (SET_SRC (body)))
|
||||
{
|
||||
/* If the set or clobber is unused, then it does not effect our
|
||||
ability to get rid of the entire insn. */
|
||||
insn_info->cannot_delete = true;
|
||||
clear_rhs_from_active_local_stores ();
|
||||
if (!store_is_unused)
|
||||
{
|
||||
/* If the set or clobber is unused, then it does not effect our
|
||||
ability to get rid of the entire insn. */
|
||||
insn_info->cannot_delete = true;
|
||||
clear_rhs_from_active_local_stores ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We can still process a volatile mem, we just cannot delete it. */
|
||||
if (MEM_VOLATILE_P (mem))
|
||||
insn_info->cannot_delete = true;
|
||||
insn_info->cannot_delete = true;
|
||||
|
||||
if (!canon_address (mem, &spill_alias_set, &group_id, &offset, &base))
|
||||
{
|
||||
|
@ -1241,12 +1358,20 @@ record_store (rtx body, bb_info_t bb_info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
width = GET_MODE_SIZE (GET_MODE (mem));
|
||||
if (GET_MODE (mem) == BLKmode)
|
||||
width = INTVAL (MEM_SIZE (mem));
|
||||
else
|
||||
{
|
||||
width = GET_MODE_SIZE (GET_MODE (mem));
|
||||
gcc_assert ((unsigned) width <= HOST_BITS_PER_WIDE_INT);
|
||||
}
|
||||
|
||||
if (spill_alias_set)
|
||||
{
|
||||
bitmap store1 = clear_alias_group->store1_p;
|
||||
bitmap store2 = clear_alias_group->store2_p;
|
||||
|
||||
gcc_assert (GET_MODE (mem) != BLKmode);
|
||||
|
||||
if (bitmap_bit_p (store1, spill_alias_set))
|
||||
bitmap_set_bit (store2, spill_alias_set);
|
||||
|
@ -1295,10 +1420,41 @@ record_store (rtx body, bb_info_t bb_info)
|
|||
(int)offset, (int)(offset+width));
|
||||
}
|
||||
|
||||
const_rhs = rhs = NULL_RTX;
|
||||
if (GET_CODE (body) == SET
|
||||
/* No place to keep the value after ra. */
|
||||
&& !reload_completed
|
||||
&& (REG_P (SET_SRC (body))
|
||||
|| GET_CODE (SET_SRC (body)) == SUBREG
|
||||
|| CONSTANT_P (SET_SRC (body)))
|
||||
&& !MEM_VOLATILE_P (mem)
|
||||
/* Sometimes the store and reload is used for truncation and
|
||||
rounding. */
|
||||
&& !(FLOAT_MODE_P (GET_MODE (mem)) && (flag_float_store)))
|
||||
{
|
||||
rhs = SET_SRC (body);
|
||||
if (CONSTANT_P (rhs))
|
||||
const_rhs = rhs;
|
||||
else if (body == PATTERN (insn_info->insn))
|
||||
{
|
||||
rtx tem = find_reg_note (insn_info->insn, REG_EQUAL, NULL_RTX);
|
||||
if (tem && CONSTANT_P (XEXP (tem, 0)))
|
||||
const_rhs = XEXP (tem, 0);
|
||||
}
|
||||
if (const_rhs == NULL_RTX && REG_P (rhs))
|
||||
{
|
||||
rtx tem = cselib_expand_value_rtx (rhs, scratch, 5);
|
||||
|
||||
if (tem && CONSTANT_P (tem))
|
||||
const_rhs = tem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check to see if this stores causes some other stores to be
|
||||
dead. */
|
||||
ptr = active_local_stores;
|
||||
last = NULL;
|
||||
redundant_reason = NULL;
|
||||
|
||||
while (ptr)
|
||||
{
|
||||
|
@ -1327,7 +1483,7 @@ record_store (rtx body, bb_info_t bb_info)
|
|||
&& (GET_MODE (mem) == entry->mode))
|
||||
{
|
||||
del = true;
|
||||
s_info->positions_needed = (unsigned HOST_WIDE_INT) 0;
|
||||
set_all_positions_unneeded (s_info);
|
||||
}
|
||||
if (dump_file)
|
||||
fprintf (dump_file, " trying spill store in insn=%d alias_set=%d\n",
|
||||
|
@ -1341,10 +1497,46 @@ record_store (rtx body, bb_info_t bb_info)
|
|||
fprintf (dump_file, " trying store in insn=%d gid=%d[%d..%d)\n",
|
||||
INSN_UID (ptr->insn), s_info->group_id,
|
||||
(int)s_info->begin, (int)s_info->end);
|
||||
for (i = offset; i < offset+width; i++)
|
||||
if (i >= s_info->begin && i < s_info->end)
|
||||
s_info->positions_needed
|
||||
&= ~(((unsigned HOST_WIDE_INT) 1) << (i - s_info->begin));
|
||||
|
||||
/* Even if PTR won't be eliminated as unneeded, if both
|
||||
PTR and this insn store the same constant value, we might
|
||||
eliminate this insn instead. */
|
||||
if (s_info->const_rhs
|
||||
&& const_rhs
|
||||
&& offset >= s_info->begin
|
||||
&& offset + width <= s_info->end
|
||||
&& all_positions_needed_p (s_info, offset - s_info->begin,
|
||||
width))
|
||||
{
|
||||
if (GET_MODE (mem) == BLKmode)
|
||||
{
|
||||
if (GET_MODE (s_info->mem) == BLKmode
|
||||
&& s_info->const_rhs == const_rhs)
|
||||
redundant_reason = ptr;
|
||||
}
|
||||
else if (s_info->const_rhs == const0_rtx
|
||||
&& const_rhs == const0_rtx)
|
||||
redundant_reason = ptr;
|
||||
else
|
||||
{
|
||||
rtx val;
|
||||
start_sequence ();
|
||||
val = get_stored_val (s_info, GET_MODE (mem),
|
||||
offset, offset + width,
|
||||
BLOCK_FOR_INSN (insn_info->insn),
|
||||
true);
|
||||
if (get_insns () != NULL)
|
||||
val = NULL_RTX;
|
||||
end_sequence ();
|
||||
if (val && rtx_equal_p (val, const_rhs))
|
||||
redundant_reason = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = MAX (offset, s_info->begin);
|
||||
i < offset + width && i < s_info->end;
|
||||
i++)
|
||||
set_position_unneeded (s_info, i - s_info->begin);
|
||||
}
|
||||
else if (s_info->rhs)
|
||||
/* Need to see if it is possible for this store to overwrite
|
||||
|
@ -1355,14 +1547,18 @@ record_store (rtx body, bb_info_t bb_info)
|
|||
GET_MODE (s_info->mem),
|
||||
s_info->mem_addr,
|
||||
mem, rtx_varies_p))
|
||||
s_info->rhs = NULL;
|
||||
{
|
||||
s_info->rhs = NULL;
|
||||
s_info->const_rhs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* An insn can be deleted if every position of every one of
|
||||
its s_infos is zero. */
|
||||
if (s_info->positions_needed != (unsigned HOST_WIDE_INT) 0)
|
||||
if (any_positions_needed_p (s_info)
|
||||
|| ptr->cannot_delete)
|
||||
del = false;
|
||||
|
||||
|
||||
if (del)
|
||||
{
|
||||
insn_info_t insn_to_delete = ptr;
|
||||
|
@ -1380,8 +1576,6 @@ record_store (rtx body, bb_info_t bb_info)
|
|||
ptr = next;
|
||||
}
|
||||
|
||||
gcc_assert ((unsigned) width <= HOST_BITS_PER_WIDE_INT);
|
||||
|
||||
/* Finish filling in the store_info. */
|
||||
store_info->next = insn_info->store_rec;
|
||||
insn_info->store_rec = store_info;
|
||||
|
@ -1389,25 +1583,25 @@ record_store (rtx body, bb_info_t bb_info)
|
|||
store_info->alias_set = spill_alias_set;
|
||||
store_info->mem_addr = get_addr (XEXP (mem, 0));
|
||||
store_info->cse_base = base;
|
||||
store_info->positions_needed = lowpart_bitmask (width);
|
||||
if (width > HOST_BITS_PER_WIDE_INT)
|
||||
{
|
||||
store_info->is_large = true;
|
||||
store_info->positions_needed.large.count = 0;
|
||||
store_info->positions_needed.large.bitmap = BITMAP_ALLOC (NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
store_info->is_large = false;
|
||||
store_info->positions_needed.small_bitmask = lowpart_bitmask (width);
|
||||
}
|
||||
store_info->group_id = group_id;
|
||||
store_info->begin = offset;
|
||||
store_info->end = offset + width;
|
||||
store_info->is_set = GET_CODE (body) == SET;
|
||||
store_info->rhs = rhs;
|
||||
store_info->const_rhs = const_rhs;
|
||||
store_info->redundant_reason = redundant_reason;
|
||||
|
||||
if (store_info->is_set
|
||||
/* No place to keep the value after ra. */
|
||||
&& !reload_completed
|
||||
&& (REG_P (SET_SRC (body))
|
||||
|| GET_CODE (SET_SRC (body)) == SUBREG
|
||||
|| CONSTANT_P (SET_SRC (body)))
|
||||
/* Sometimes the store and reload is used for truncation and
|
||||
rounding. */
|
||||
&& !(FLOAT_MODE_P (GET_MODE (mem)) && (flag_float_store)))
|
||||
store_info->rhs = SET_SRC (body);
|
||||
else
|
||||
store_info->rhs = NULL;
|
||||
|
||||
/* If this is a clobber, we return 0. We will only be able to
|
||||
delete this insn if there is only one store USED store, but we
|
||||
can use the clobber to delete other stores earlier. */
|
||||
|
@ -1435,12 +1629,10 @@ dump_insn_info (const char * start, insn_info_t insn_info)
|
|||
static rtx
|
||||
find_shift_sequence (int access_size,
|
||||
store_info_t store_info,
|
||||
read_info_t read_info,
|
||||
int shift,
|
||||
bool speed)
|
||||
enum machine_mode read_mode,
|
||||
int shift, bool speed, bool require_cst)
|
||||
{
|
||||
enum machine_mode store_mode = GET_MODE (store_info->mem);
|
||||
enum machine_mode read_mode = GET_MODE (read_info->mem);
|
||||
enum machine_mode new_mode;
|
||||
rtx read_reg = NULL;
|
||||
|
||||
|
@ -1462,11 +1654,11 @@ find_shift_sequence (int access_size,
|
|||
/* If a constant was stored into memory, try to simplify it here,
|
||||
otherwise the cost of the shift might preclude this optimization
|
||||
e.g. at -Os, even when no actual shift will be needed. */
|
||||
if (CONSTANT_P (store_info->rhs))
|
||||
if (store_info->const_rhs)
|
||||
{
|
||||
unsigned int byte = subreg_lowpart_offset (new_mode, store_mode);
|
||||
rtx ret = simplify_subreg (new_mode, store_info->rhs, store_mode,
|
||||
byte);
|
||||
rtx ret = simplify_subreg (new_mode, store_info->const_rhs,
|
||||
store_mode, byte);
|
||||
if (ret && CONSTANT_P (ret))
|
||||
{
|
||||
ret = simplify_const_binary_operation (LSHIFTRT, new_mode,
|
||||
|
@ -1482,6 +1674,9 @@ find_shift_sequence (int access_size,
|
|||
}
|
||||
}
|
||||
|
||||
if (require_cst)
|
||||
return NULL_RTX;
|
||||
|
||||
/* Try a wider mode if truncating the store mode to NEW_MODE
|
||||
requires a real instruction. */
|
||||
if (GET_MODE_BITSIZE (new_mode) < GET_MODE_BITSIZE (store_mode)
|
||||
|
@ -1563,6 +1758,79 @@ look_for_hardregs (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
|
|||
}
|
||||
}
|
||||
|
||||
/* Helper function for replace_read and record_store.
|
||||
Attempt to return a value stored in STORE_INFO, from READ_BEGIN
|
||||
to one before READ_END bytes read in READ_MODE. Return NULL
|
||||
if not successful. If REQUIRE_CST is true, return always constant. */
|
||||
|
||||
static rtx
|
||||
get_stored_val (store_info_t store_info, enum machine_mode read_mode,
|
||||
HOST_WIDE_INT read_begin, HOST_WIDE_INT read_end,
|
||||
basic_block bb, bool require_cst)
|
||||
{
|
||||
enum machine_mode store_mode = GET_MODE (store_info->mem);
|
||||
int shift;
|
||||
int access_size; /* In bytes. */
|
||||
rtx read_reg;
|
||||
|
||||
/* To get here the read is within the boundaries of the write so
|
||||
shift will never be negative. Start out with the shift being in
|
||||
bytes. */
|
||||
if (store_mode == BLKmode)
|
||||
shift = 0;
|
||||
else if (BYTES_BIG_ENDIAN)
|
||||
shift = store_info->end - read_end;
|
||||
else
|
||||
shift = read_begin - store_info->begin;
|
||||
|
||||
access_size = shift + GET_MODE_SIZE (read_mode);
|
||||
|
||||
/* From now on it is bits. */
|
||||
shift *= BITS_PER_UNIT;
|
||||
|
||||
if (shift)
|
||||
read_reg = find_shift_sequence (access_size, store_info, read_mode, shift,
|
||||
optimize_bb_for_speed_p (bb),
|
||||
require_cst);
|
||||
else if (store_mode == BLKmode)
|
||||
{
|
||||
/* The store is a memset (addr, const_val, const_size). */
|
||||
gcc_assert (CONST_INT_P (store_info->rhs));
|
||||
store_mode = int_mode_for_mode (read_mode);
|
||||
if (store_mode == BLKmode)
|
||||
read_reg = NULL_RTX;
|
||||
else if (store_info->rhs == const0_rtx)
|
||||
read_reg = extract_low_bits (read_mode, store_mode, const0_rtx);
|
||||
else if (GET_MODE_BITSIZE (store_mode) > HOST_BITS_PER_WIDE_INT
|
||||
|| BITS_PER_UNIT >= HOST_BITS_PER_WIDE_INT)
|
||||
read_reg = NULL_RTX;
|
||||
else
|
||||
{
|
||||
unsigned HOST_WIDE_INT c
|
||||
= INTVAL (store_info->rhs)
|
||||
& (((HOST_WIDE_INT) 1 << BITS_PER_UNIT) - 1);
|
||||
int shift = BITS_PER_UNIT;
|
||||
while (shift < HOST_BITS_PER_WIDE_INT)
|
||||
{
|
||||
c |= (c << shift);
|
||||
shift <<= 1;
|
||||
}
|
||||
read_reg = GEN_INT (trunc_int_for_mode (c, store_mode));
|
||||
read_reg = extract_low_bits (read_mode, store_mode, read_reg);
|
||||
}
|
||||
}
|
||||
else if (store_info->const_rhs
|
||||
&& (require_cst
|
||||
|| GET_MODE_CLASS (read_mode) != GET_MODE_CLASS (store_mode)))
|
||||
read_reg = extract_low_bits (read_mode, store_mode,
|
||||
copy_rtx (store_info->const_rhs));
|
||||
else
|
||||
read_reg = extract_low_bits (read_mode, store_mode,
|
||||
copy_rtx (store_info->rhs));
|
||||
if (require_cst && read_reg && !CONSTANT_P (read_reg))
|
||||
read_reg = NULL_RTX;
|
||||
return read_reg;
|
||||
}
|
||||
|
||||
/* Take a sequence of:
|
||||
A <- r1
|
||||
|
@ -1597,30 +1865,17 @@ look_for_hardregs (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
|
|||
|
||||
static bool
|
||||
replace_read (store_info_t store_info, insn_info_t store_insn,
|
||||
read_info_t read_info, insn_info_t read_insn, rtx *loc, bitmap regs_live)
|
||||
read_info_t read_info, insn_info_t read_insn, rtx *loc,
|
||||
bitmap regs_live)
|
||||
{
|
||||
enum machine_mode store_mode = GET_MODE (store_info->mem);
|
||||
enum machine_mode read_mode = GET_MODE (read_info->mem);
|
||||
int shift;
|
||||
int access_size; /* In bytes. */
|
||||
rtx insns, this_insn, read_reg;
|
||||
basic_block bb;
|
||||
|
||||
if (!dbg_cnt (dse))
|
||||
return false;
|
||||
|
||||
/* To get here the read is within the boundaries of the write so
|
||||
shift will never be negative. Start out with the shift being in
|
||||
bytes. */
|
||||
if (BYTES_BIG_ENDIAN)
|
||||
shift = store_info->end - read_info->end;
|
||||
else
|
||||
shift = read_info->begin - store_info->begin;
|
||||
|
||||
access_size = shift + GET_MODE_SIZE (read_mode);
|
||||
|
||||
/* From now on it is bits. */
|
||||
shift *= BITS_PER_UNIT;
|
||||
|
||||
/* Create a sequence of instructions to set up the read register.
|
||||
This sequence goes immediately before the store and its result
|
||||
is read by the load.
|
||||
|
@ -1636,12 +1891,10 @@ replace_read (store_info_t store_info, insn_info_t store_insn,
|
|||
GET_MODE_NAME (read_mode), INSN_UID (read_insn->insn),
|
||||
GET_MODE_NAME (store_mode), INSN_UID (store_insn->insn));
|
||||
start_sequence ();
|
||||
if (shift)
|
||||
read_reg = find_shift_sequence (access_size, store_info, read_info, shift,
|
||||
optimize_bb_for_speed_p (BLOCK_FOR_INSN (read_insn->insn)));
|
||||
else
|
||||
read_reg = extract_low_bits (read_mode, store_mode,
|
||||
copy_rtx (store_info->rhs));
|
||||
bb = BLOCK_FOR_INSN (read_insn->insn);
|
||||
read_reg = get_stored_val (store_info,
|
||||
read_mode, read_info->begin, read_info->end,
|
||||
bb, false);
|
||||
if (read_reg == NULL_RTX)
|
||||
{
|
||||
end_sequence ();
|
||||
|
@ -1892,18 +2145,15 @@ check_mem_read_rtx (rtx *loc, void *data)
|
|||
else
|
||||
{
|
||||
if (store_info->rhs
|
||||
&& (offset >= store_info->begin)
|
||||
&& (offset + width <= store_info->end))
|
||||
{
|
||||
unsigned HOST_WIDE_INT mask
|
||||
= (lowpart_bitmask (width)
|
||||
<< (offset - store_info->begin));
|
||||
&& offset >= store_info->begin
|
||||
&& offset + width <= store_info->end
|
||||
&& all_positions_needed_p (store_info,
|
||||
offset - store_info->begin,
|
||||
width)
|
||||
&& replace_read (store_info, i_ptr, read_info,
|
||||
insn_info, loc, bb_info->regs_live))
|
||||
return 0;
|
||||
|
||||
if ((store_info->positions_needed & mask) == mask
|
||||
&& replace_read (store_info, i_ptr,
|
||||
read_info, insn_info, loc, bb_info->regs_live))
|
||||
return 0;
|
||||
}
|
||||
/* The bases are the same, just see if the offsets
|
||||
overlap. */
|
||||
if ((offset < store_info->end)
|
||||
|
@ -1961,18 +2211,13 @@ check_mem_read_rtx (rtx *loc, void *data)
|
|||
if (store_info->rhs
|
||||
&& store_info->group_id == -1
|
||||
&& store_info->cse_base == base
|
||||
&& (offset >= store_info->begin)
|
||||
&& (offset + width <= store_info->end))
|
||||
{
|
||||
unsigned HOST_WIDE_INT mask
|
||||
= (lowpart_bitmask (width)
|
||||
<< (offset - store_info->begin));
|
||||
|
||||
if ((store_info->positions_needed & mask) == mask
|
||||
&& replace_read (store_info, i_ptr,
|
||||
read_info, insn_info, loc, bb_info->regs_live))
|
||||
return 0;
|
||||
}
|
||||
&& offset >= store_info->begin
|
||||
&& offset + width <= store_info->end
|
||||
&& all_positions_needed_p (store_info,
|
||||
offset - store_info->begin, width)
|
||||
&& replace_read (store_info, i_ptr, read_info, insn_info, loc,
|
||||
bb_info->regs_live))
|
||||
return 0;
|
||||
|
||||
if (!store_info->alias_set)
|
||||
remove = canon_true_dependence (store_info->mem,
|
||||
|
@ -2008,6 +2253,67 @@ check_mem_read_use (rtx *loc, void *data)
|
|||
for_each_rtx (loc, check_mem_read_rtx, data);
|
||||
}
|
||||
|
||||
|
||||
/* Get arguments passed to CALL_INSN. Return TRUE if successful.
|
||||
So far it only handles arguments passed in registers. */
|
||||
|
||||
static bool
|
||||
get_call_args (rtx call_insn, tree fn, rtx *args, int nargs)
|
||||
{
|
||||
CUMULATIVE_ARGS args_so_far;
|
||||
tree arg;
|
||||
int idx;
|
||||
|
||||
INIT_CUMULATIVE_ARGS (args_so_far, TREE_TYPE (fn), NULL_RTX, 0, 3);
|
||||
|
||||
arg = TYPE_ARG_TYPES (TREE_TYPE (fn));
|
||||
for (idx = 0;
|
||||
arg != void_list_node && idx < nargs;
|
||||
arg = TREE_CHAIN (arg), idx++)
|
||||
{
|
||||
enum machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
|
||||
rtx reg = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1), link, tmp;
|
||||
if (!reg || !REG_P (reg) || GET_MODE (reg) != mode
|
||||
|| GET_MODE_CLASS (mode) != MODE_INT)
|
||||
return false;
|
||||
|
||||
for (link = CALL_INSN_FUNCTION_USAGE (call_insn);
|
||||
link;
|
||||
link = XEXP (link, 1))
|
||||
if (GET_CODE (XEXP (link, 0)) == USE)
|
||||
{
|
||||
args[idx] = XEXP (XEXP (link, 0), 0);
|
||||
if (REG_P (args[idx])
|
||||
&& REGNO (args[idx]) == REGNO (reg)
|
||||
&& (GET_MODE (args[idx]) == mode
|
||||
|| (GET_MODE_CLASS (GET_MODE (args[idx])) == MODE_INT
|
||||
&& (GET_MODE_SIZE (GET_MODE (args[idx]))
|
||||
<= UNITS_PER_WORD)
|
||||
&& (GET_MODE_SIZE (GET_MODE (args[idx]))
|
||||
> GET_MODE_SIZE (mode)))))
|
||||
break;
|
||||
}
|
||||
if (!link)
|
||||
return false;
|
||||
|
||||
tmp = cselib_expand_value_rtx (args[idx], scratch, 5);
|
||||
if (GET_MODE (args[idx]) != mode)
|
||||
{
|
||||
if (!tmp || !CONST_INT_P (tmp))
|
||||
return false;
|
||||
tmp = GEN_INT (trunc_int_for_mode (INTVAL (tmp), mode));
|
||||
}
|
||||
if (tmp)
|
||||
args[idx] = tmp;
|
||||
|
||||
FUNCTION_ARG_ADVANCE (args_so_far, mode, NULL_TREE, 1);
|
||||
}
|
||||
if (arg != void_list_node || idx != nargs)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Apply record_store to all candidate stores in INSN. Mark INSN
|
||||
if some part of it is not a candidate store and assigns to a
|
||||
non-register target. */
|
||||
|
@ -2045,18 +2351,48 @@ scan_insn (bb_info_t bb_info, rtx insn)
|
|||
|
||||
if (CALL_P (insn))
|
||||
{
|
||||
bool const_call;
|
||||
tree memset_call = NULL_TREE;
|
||||
|
||||
insn_info->cannot_delete = true;
|
||||
|
||||
/* Const functions cannot do anything bad i.e. read memory,
|
||||
however, they can read their parameters which may have
|
||||
been pushed onto the stack. */
|
||||
if (RTL_CONST_CALL_P (insn))
|
||||
been pushed onto the stack.
|
||||
memset and bzero don't read memory either. */
|
||||
const_call = RTL_CONST_CALL_P (insn);
|
||||
if (!const_call)
|
||||
{
|
||||
rtx call = PATTERN (insn);
|
||||
if (GET_CODE (call) == PARALLEL)
|
||||
call = XVECEXP (call, 0, 0);
|
||||
if (GET_CODE (call) == SET)
|
||||
call = SET_SRC (call);
|
||||
if (GET_CODE (call) == CALL
|
||||
&& MEM_P (XEXP (call, 0))
|
||||
&& GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF)
|
||||
{
|
||||
rtx symbol = XEXP (XEXP (call, 0), 0);
|
||||
if (SYMBOL_REF_DECL (symbol)
|
||||
&& TREE_CODE (SYMBOL_REF_DECL (symbol)) == FUNCTION_DECL)
|
||||
{
|
||||
if ((DECL_BUILT_IN_CLASS (SYMBOL_REF_DECL (symbol))
|
||||
== BUILT_IN_NORMAL
|
||||
&& (DECL_FUNCTION_CODE (SYMBOL_REF_DECL (symbol))
|
||||
== BUILT_IN_MEMSET))
|
||||
|| SYMBOL_REF_DECL (symbol) == block_clear_fn)
|
||||
memset_call = SYMBOL_REF_DECL (symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (const_call || memset_call)
|
||||
{
|
||||
insn_info_t i_ptr = active_local_stores;
|
||||
insn_info_t last = NULL;
|
||||
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "const call %d\n", INSN_UID (insn));
|
||||
fprintf (dump_file, "%s call %d\n",
|
||||
const_call ? "const" : "memset", INSN_UID (insn));
|
||||
|
||||
/* See the head comment of the frame_read field. */
|
||||
if (reload_completed)
|
||||
|
@ -2102,6 +2438,28 @@ scan_insn (bb_info_t bb_info, rtx insn)
|
|||
|
||||
i_ptr = i_ptr->next_local_store;
|
||||
}
|
||||
|
||||
if (memset_call)
|
||||
{
|
||||
rtx args[3];
|
||||
if (get_call_args (insn, memset_call, args, 3)
|
||||
&& CONST_INT_P (args[1])
|
||||
&& CONST_INT_P (args[2])
|
||||
&& INTVAL (args[2]) > 0)
|
||||
{
|
||||
rtx mem = gen_rtx_MEM (BLKmode, args[0]);
|
||||
set_mem_size (mem, args[2]);
|
||||
body = gen_rtx_SET (VOIDmode, mem, args[1]);
|
||||
mems_found += record_store (body, bb_info);
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "handling memset as BLKmode store\n");
|
||||
if (mems_found == 1)
|
||||
{
|
||||
insn_info->next_local_store = active_local_stores;
|
||||
active_local_stores = insn_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
|
@ -2134,11 +2492,11 @@ scan_insn (bb_info_t bb_info, rtx insn)
|
|||
fprintf (dump_file, "mems_found = %d, cannot_delete = %s\n",
|
||||
mems_found, insn_info->cannot_delete ? "true" : "false");
|
||||
|
||||
/* If we found some sets of mems, and the insn has not been marked
|
||||
cannot delete, add it into the active_local_stores so that it can
|
||||
be locally deleted if found dead. Otherwise mark it as cannot
|
||||
delete. This simplifies the processing later. */
|
||||
if (mems_found == 1 && !insn_info->cannot_delete)
|
||||
/* If we found some sets of mems, add it into the active_local_stores so
|
||||
that it can be locally deleted if found dead or used for
|
||||
replace_read and redundant constant store elimination. Otherwise mark
|
||||
it as cannot delete. This simplifies the processing later. */
|
||||
if (mems_found == 1)
|
||||
{
|
||||
insn_info->next_local_store = active_local_stores;
|
||||
active_local_stores = insn_info;
|
||||
|
@ -2263,14 +2621,14 @@ dse_step1 (void)
|
|||
/* Skip the clobbers. */
|
||||
while (!store_info->is_set)
|
||||
store_info = store_info->next;
|
||||
if (store_info->alias_set)
|
||||
if (store_info->alias_set && !i_ptr->cannot_delete)
|
||||
delete_dead_store_insn (i_ptr);
|
||||
else
|
||||
if (store_info->group_id >= 0)
|
||||
{
|
||||
group_info_t group
|
||||
= VEC_index (group_info_t, rtx_group_vec, store_info->group_id);
|
||||
if (group->frame_related)
|
||||
if (group->frame_related && !i_ptr->cannot_delete)
|
||||
delete_dead_store_insn (i_ptr);
|
||||
}
|
||||
|
||||
|
@ -2298,7 +2656,40 @@ dse_step1 (void)
|
|||
while (ptr)
|
||||
{
|
||||
if (ptr->contains_cselib_groups)
|
||||
free_store_info (ptr);
|
||||
{
|
||||
store_info_t s_info = ptr->store_rec;
|
||||
while (s_info && !s_info->is_set)
|
||||
s_info = s_info->next;
|
||||
if (s_info
|
||||
&& s_info->redundant_reason
|
||||
&& s_info->redundant_reason->insn
|
||||
&& !ptr->cannot_delete)
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "Locally deleting insn %d "
|
||||
"because insn %d stores the "
|
||||
"same value and couldn't be "
|
||||
"eliminated\n",
|
||||
INSN_UID (ptr->insn),
|
||||
INSN_UID (s_info->redundant_reason->insn));
|
||||
delete_dead_store_insn (ptr);
|
||||
}
|
||||
if (s_info)
|
||||
s_info->redundant_reason = NULL;
|
||||
free_store_info (ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
store_info_t s_info;
|
||||
|
||||
/* Free at least positions_needed bitmaps. */
|
||||
for (s_info = ptr->store_rec; s_info; s_info = s_info->next)
|
||||
if (s_info->is_large)
|
||||
{
|
||||
BITMAP_FREE (s_info->positions_needed.large.bitmap);
|
||||
s_info->is_large = false;
|
||||
}
|
||||
}
|
||||
ptr = ptr->prev_insn;
|
||||
}
|
||||
|
||||
|
@ -3236,11 +3627,61 @@ dse_step5_spill (void)
|
|||
/*----------------------------------------------------------------------------
|
||||
Sixth step.
|
||||
|
||||
Delete stores made redundant by earlier stores (which store the same
|
||||
value) that couldn't be eliminated.
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
static void
|
||||
dse_step6 (void)
|
||||
{
|
||||
basic_block bb;
|
||||
|
||||
FOR_ALL_BB (bb)
|
||||
{
|
||||
bb_info_t bb_info = bb_table[bb->index];
|
||||
insn_info_t insn_info = bb_info->last_insn;
|
||||
|
||||
while (insn_info)
|
||||
{
|
||||
/* There may have been code deleted by the dce pass run before
|
||||
this phase. */
|
||||
if (insn_info->insn
|
||||
&& INSN_P (insn_info->insn)
|
||||
&& !insn_info->cannot_delete)
|
||||
{
|
||||
store_info_t s_info = insn_info->store_rec;
|
||||
|
||||
while (s_info && !s_info->is_set)
|
||||
s_info = s_info->next;
|
||||
if (s_info
|
||||
&& s_info->redundant_reason
|
||||
&& s_info->redundant_reason->insn
|
||||
&& INSN_P (s_info->redundant_reason->insn))
|
||||
{
|
||||
rtx rinsn = s_info->redundant_reason->insn;
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "Locally deleting insn %d "
|
||||
"because insn %d stores the "
|
||||
"same value and couldn't be "
|
||||
"eliminated\n",
|
||||
INSN_UID (insn_info->insn),
|
||||
INSN_UID (rinsn));
|
||||
delete_dead_store_insn (insn_info);
|
||||
}
|
||||
}
|
||||
insn_info = insn_info->prev_insn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
Seventh step.
|
||||
|
||||
Destroy everything left standing.
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
static void
|
||||
dse_step6 (bool global_done)
|
||||
dse_step7 (bool global_done)
|
||||
{
|
||||
unsigned int i;
|
||||
group_info_t group;
|
||||
|
@ -3346,8 +3787,9 @@ rest_of_handle_dse (void)
|
|||
dse_step4 ();
|
||||
dse_step5_spill ();
|
||||
}
|
||||
|
||||
dse_step6 (did_global);
|
||||
|
||||
dse_step6 ();
|
||||
dse_step7 (did_global);
|
||||
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "dse: local deletions = %d, global deletions = %d, spill deletions = %d\n",
|
||||
|
|
|
@ -2698,7 +2698,7 @@ set_storage_via_libcall (rtx object, rtx size, rtx val, bool tailcall)
|
|||
for the function we use for block clears. The first time FOR_CALL
|
||||
is true, we call assemble_external. */
|
||||
|
||||
static GTY(()) tree block_clear_fn;
|
||||
tree block_clear_fn;
|
||||
|
||||
void
|
||||
init_block_clear_fn (const char *asmspec)
|
||||
|
|
|
@ -404,6 +404,7 @@ enum block_op_methods
|
|||
BLOCK_OP_TAILCALL
|
||||
};
|
||||
|
||||
extern tree GTY(()) block_clear_fn;
|
||||
extern void init_block_move_fn (const char *);
|
||||
extern void init_block_clear_fn (const char *);
|
||||
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2008-12-18 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR middle-end/31150
|
||||
* gcc.c-torture/execute/20081218-1.c: New test.
|
||||
|
||||
2008-12-22 Paul Thomas <pault@gcc.gnu.org>
|
||||
|
||||
PR fortran/35780
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
struct A { int i, j; char pad[512]; } a;
|
||||
|
||||
int __attribute__((noinline))
|
||||
foo (void)
|
||||
{
|
||||
__builtin_memset (&a, 0x26, sizeof a);
|
||||
return a.i;
|
||||
}
|
||||
|
||||
void __attribute__((noinline))
|
||||
bar (void)
|
||||
{
|
||||
__builtin_memset (&a, 0x36, sizeof a);
|
||||
a.i = 0x36363636;
|
||||
a.j = 0x36373636;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
int i;
|
||||
if (sizeof (int) != 4 || __CHAR_BIT__ != 8)
|
||||
return 0;
|
||||
|
||||
if (foo () != 0x26262626)
|
||||
__builtin_abort ();
|
||||
for (i = 0; i < sizeof a; i++)
|
||||
if (((char *)&a)[i] != 0x26)
|
||||
__builtin_abort ();
|
||||
|
||||
bar ();
|
||||
if (a.j != 0x36373636)
|
||||
__builtin_abort ();
|
||||
a.j = 0x36363636;
|
||||
for (i = 0; i < sizeof a; i++)
|
||||
if (((char *)&a)[i] != 0x36)
|
||||
__builtin_abort ();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue