aboutsummaryrefslogtreecommitdiff
path: root/gcc/expr.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2000-11-29 19:24:50 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2000-11-29 19:24:50 +0100
commit57814e5ea3528a521e997fcc6b5d658174b63e10 (patch)
treef0f32075fb72921dd130201ceba23d250949163a /gcc/expr.c
parent3632e1eaba7b8ccb91377e70657618d7b5cd2c39 (diff)
downloadgcc-57814e5ea3528a521e997fcc6b5d658174b63e10.zip
gcc-57814e5ea3528a521e997fcc6b5d658174b63e10.tar.gz
gcc-57814e5ea3528a521e997fcc6b5d658174b63e10.tar.bz2
expr.h (store_by_pieces): Add prototype.
* expr.h (store_by_pieces): Add prototype. (can_store_by_pieces): Likewise. * expr.c (struct store_by_pieces): Renamed from clear_by_pieces. (can_store_by_pieces): New. (store_by_pieces): New. (clear_by_pieces): New. (clear_by_pieces_1): New. (store_by_pieces_1): Renamed from clear_by_pieces, handle storing arbitrary compiler generated constants into memory block. (store_by_pieces_2): Renamed from clear_by_pieces_1, likewise. * builtins.c (c_readstr): New. (builtin_memcpy_read_str): New. (expand_builtin_memcpy): If src is string constant and emit_block_move would move it by pieces, compute integer constants from the string and store it into memory block instead. (builtin_strncpy_read_str): New. (expand_builtin_strncpy): If N is not constant zero and c_strlen does not return INTEGER_CST, don't optimize. If N is larger than strlen(src) + 1, try to copy the string including padding with store_by_pieces. (expand_builtin_strcmp): If both arguments have side effects, don't optimize. (expand_builtin_fputs): If STR has side effects, don't optimize. * gcc.c-torture/execute/string-opt-5.c: Add some strcmp and strncpy tests. * gcc.c-torture/execute/string-opt-6.c: New test. From-SVN: r37851
Diffstat (limited to 'gcc/expr.c')
-rw-r--r--gcc/expr.c211
1 files changed, 173 insertions, 38 deletions
diff --git a/gcc/expr.c b/gcc/expr.c
index cbe46dd..e520c6d 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -127,10 +127,10 @@ struct move_by_pieces
int reverse;
};
-/* This structure is used by clear_by_pieces to describe the clear to
+/* This structure is used by store_by_pieces to describe the clear to
be performed. */
-struct clear_by_pieces
+struct store_by_pieces
{
rtx to;
rtx to_addr;
@@ -138,6 +138,8 @@ struct clear_by_pieces
int explicit_inc_to;
unsigned HOST_WIDE_INT len;
HOST_WIDE_INT offset;
+ rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
+ PTR constfundata;
int reverse;
};
@@ -151,11 +153,15 @@ static unsigned HOST_WIDE_INT move_by_pieces_ninsns
unsigned int));
static void move_by_pieces_1 PARAMS ((rtx (*) (rtx, ...), enum machine_mode,
struct move_by_pieces *));
+static rtx clear_by_pieces_1 PARAMS ((PTR, HOST_WIDE_INT,
+ enum machine_mode));
static void clear_by_pieces PARAMS ((rtx, unsigned HOST_WIDE_INT,
unsigned int));
-static void clear_by_pieces_1 PARAMS ((rtx (*) (rtx, ...),
+static void store_by_pieces_1 PARAMS ((struct store_by_pieces *,
+ unsigned int));
+static void store_by_pieces_2 PARAMS ((rtx (*) (rtx, ...),
enum machine_mode,
- struct clear_by_pieces *));
+ struct store_by_pieces *));
static rtx get_subtarget PARAMS ((rtx));
static int is_zeros_p PARAMS ((tree));
static int mostly_zeros_p PARAMS ((tree));
@@ -2249,6 +2255,105 @@ use_group_regs (call_fusage, regs)
}
}
+
+int
+can_store_by_pieces (len, constfun, constfundata, align)
+ unsigned HOST_WIDE_INT len;
+ rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
+ PTR constfundata;
+ unsigned int align;
+{
+ unsigned HOST_WIDE_INT max_size = MOVE_MAX_PIECES + 1, l;
+ HOST_WIDE_INT offset = 0;
+ enum machine_mode mode, tmode;
+ enum insn_code icode;
+ int reverse;
+ rtx cst;
+
+ if (! MOVE_BY_PIECES_P (len, align))
+ return 0;
+
+ if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
+ || align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
+ align = MOVE_MAX * BITS_PER_UNIT;
+
+ /* We would first store what we can in the largest integer mode, then go to
+ successively smaller modes. */
+
+ for (reverse = 0;
+ reverse <= (HAVE_PRE_DECREMENT || HAVE_POST_DECREMENT);
+ reverse++)
+ {
+ l = len;
+ mode = VOIDmode;
+ while (max_size > 1)
+ {
+ for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+ tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
+ if (GET_MODE_SIZE (tmode) < max_size)
+ mode = tmode;
+
+ if (mode == VOIDmode)
+ break;
+
+ icode = mov_optab->handlers[(int) mode].insn_code;
+ if (icode != CODE_FOR_nothing
+ && align >= GET_MODE_ALIGNMENT (mode))
+ {
+ unsigned int size = GET_MODE_SIZE (mode);
+
+ while (l >= size)
+ {
+ if (reverse)
+ offset -= size;
+
+ cst = (*constfun) (constfundata, offset, mode);
+ if (!LEGITIMATE_CONSTANT_P (cst))
+ return 0;
+
+ if (!reverse)
+ offset += size;
+
+ l -= size;
+ }
+ }
+
+ max_size = GET_MODE_SIZE (mode);
+ }
+
+ /* The code above should have handled everything. */
+ if (l != 0)
+ abort ();
+ }
+
+ return 1;
+}
+
+/* Generate several move instructions to store LEN bytes generated by
+ CONSTFUN to block TO. (A MEM rtx with BLKmode). CONSTFUNDATA is a
+ pointer which will be passed as argument in every CONSTFUN call.
+ ALIGN is maximum alignment we can assume. */
+
+void
+store_by_pieces (to, len, constfun, constfundata, align)
+ rtx to;
+ unsigned HOST_WIDE_INT len;
+ rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
+ PTR constfundata;
+ unsigned int align;
+{
+ struct store_by_pieces data;
+
+ if (! MOVE_BY_PIECES_P (len, align))
+ abort ();
+ to = protect_from_queue (to, 1);
+ data.constfun = constfun;
+ data.constfundata = constfundata;
+ data.len = len;
+ data.to = to;
+ store_by_pieces_1 (&data, align);
+}
+
/* Generate several move instructions to clear LEN bytes of block TO. (A MEM
rtx with BLKmode). The caller must pass TO through protect_from_queue
before calling. ALIGN is maximum alignment we can assume. */
@@ -2259,31 +2364,59 @@ clear_by_pieces (to, len, align)
unsigned HOST_WIDE_INT len;
unsigned int align;
{
- struct clear_by_pieces data;
- rtx to_addr = XEXP (to, 0);
+ struct store_by_pieces data;
+
+ data.constfun = clear_by_pieces_1;
+ data.constfundata = NULL_PTR;
+ data.len = len;
+ data.to = to;
+ store_by_pieces_1 (&data, align);
+}
+
+/* Callback routine for clear_by_pieces.
+ Return const0_rtx unconditionally. */
+
+static rtx
+clear_by_pieces_1 (data, offset, mode)
+ PTR data ATTRIBUTE_UNUSED;
+ HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return const0_rtx;
+}
+
+/* Subroutine of clear_by_pieces and store_by_pieces.
+ Generate several move instructions to store LEN bytes of block TO. (A MEM
+ rtx with BLKmode). The caller must pass TO through protect_from_queue
+ before calling. ALIGN is maximum alignment we can assume. */
+
+static void
+store_by_pieces_1 (data, align)
+ struct store_by_pieces *data;
+ unsigned int align;
+{
+ rtx to_addr = XEXP (data->to, 0);
unsigned HOST_WIDE_INT max_size = MOVE_MAX_PIECES + 1;
enum machine_mode mode = VOIDmode, tmode;
enum insn_code icode;
- data.offset = 0;
- data.to_addr = to_addr;
- data.to = to;
- data.autinc_to
+ data->offset = 0;
+ data->to_addr = to_addr;
+ 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.explicit_inc_to = 0;
- data.reverse
+ 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;
+ if (data->reverse)
+ data->offset = data->len;
- /* If copying requires more than two move insns,
+ /* If storing requires more than two move insns,
copy addresses to registers (to make displacements shorter)
and use post-increment if available. */
- if (!data.autinc_to
- && move_by_pieces_ninsns (len, align) > 2)
+ if (!data->autinc_to
+ && move_by_pieces_ninsns (data->len, align) > 2)
{
/* Determine the main mode we'll be using. */
for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
@@ -2291,30 +2424,30 @@ clear_by_pieces (to, len, align)
if (GET_MODE_SIZE (tmode) < max_size)
mode = tmode;
- if (USE_STORE_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_to)
+ if (USE_STORE_PRE_DECREMENT (mode) && data->reverse && ! data->autinc_to)
{
- data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len));
- data.autinc_to = 1;
- data.explicit_inc_to = -1;
+ data->to_addr = copy_addr_to_reg (plus_constant (to_addr, data->len));
+ data->autinc_to = 1;
+ data->explicit_inc_to = -1;
}
- if (USE_STORE_POST_INCREMENT (mode) && ! data.reverse
- && ! data.autinc_to)
+ if (USE_STORE_POST_INCREMENT (mode) && ! data->reverse
+ && ! data->autinc_to)
{
- data.to_addr = copy_addr_to_reg (to_addr);
- data.autinc_to = 1;
- data.explicit_inc_to = 1;
+ data->to_addr = copy_addr_to_reg (to_addr);
+ data->autinc_to = 1;
+ data->explicit_inc_to = 1;
}
- if ( !data.autinc_to && CONSTANT_P (to_addr))
- data.to_addr = copy_addr_to_reg (to_addr);
+ if ( !data->autinc_to && CONSTANT_P (to_addr))
+ data->to_addr = copy_addr_to_reg (to_addr);
}
if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
|| align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
align = MOVE_MAX * BITS_PER_UNIT;
- /* First move what we can in the largest integer mode, then go to
+ /* First store what we can in the largest integer mode, then go to
successively smaller modes. */
while (max_size > 1)
@@ -2329,28 +2462,28 @@ clear_by_pieces (to, len, align)
icode = mov_optab->handlers[(int) mode].insn_code;
if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
- clear_by_pieces_1 (GEN_FCN (icode), mode, &data);
+ store_by_pieces_2 (GEN_FCN (icode), mode, data);
max_size = GET_MODE_SIZE (mode);
}
/* The code above should have handled everything. */
- if (data.len != 0)
+ if (data->len != 0)
abort ();
}
-/* Subroutine of clear_by_pieces. Clear as many bytes as appropriate
+/* Subroutine of store_by_pieces_1. Store as many bytes as appropriate
with move instructions for mode MODE. GENFUN is the gen_... function
to make a move insn for that mode. DATA has all the other info. */
static void
-clear_by_pieces_1 (genfun, mode, data)
+store_by_pieces_2 (genfun, mode, data)
rtx (*genfun) PARAMS ((rtx, ...));
enum machine_mode mode;
- struct clear_by_pieces *data;
+ struct store_by_pieces *data;
{
unsigned int size = GET_MODE_SIZE (mode);
- rtx to1;
+ rtx to1, cst;
while (data->len >= size)
{
@@ -2367,9 +2500,11 @@ clear_by_pieces_1 (genfun, mode, data)
plus_constant (data->to_addr, data->offset));
if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
- emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size)));
+ emit_insn (gen_add2_insn (data->to_addr,
+ GEN_INT (-(HOST_WIDE_INT) size)));
- emit_insn ((*genfun) (to1, const0_rtx));
+ cst = (*data->constfun) (data->constfundata, data->offset, mode);
+ emit_insn ((*genfun) (to1, cst));
if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0)
emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));