diff options
author | Jakub Jelinek <jakub@redhat.com> | 2000-11-29 19:24:50 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2000-11-29 19:24:50 +0100 |
commit | 57814e5ea3528a521e997fcc6b5d658174b63e10 (patch) | |
tree | f0f32075fb72921dd130201ceba23d250949163a /gcc/expr.c | |
parent | 3632e1eaba7b8ccb91377e70657618d7b5cd2c39 (diff) | |
download | gcc-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.c | 211 |
1 files changed, 173 insertions, 38 deletions
@@ -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))); |