This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: PATCH: fine-tuning for can_store_by_pieces
- From: Sandra Loosemore <sandra at codesourcery dot com>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>, Nigel Stephens <nigel at mips dot com>, Guy Morrogh <guym at mips dot com>, David Ung <davidu at mips dot com>, Thiemo Seufer <ths at mips dot com>, richard at codesourcery dot com, Mark Mitchell <mark at codesourcery dot com>
- Date: Sat, 18 Aug 2007 18:55:18 -0400
- Subject: Re: PATCH: fine-tuning for can_store_by_pieces
- References: <46C3343A.5080407@codesourcery.com> <87ps1nop2x.fsf@firetop.home>
Here's a revised version of the patch, incorporating comments from Richard and
Mark.
I did some fiddling around with CSiBE to further improve the cost estimate for a
call. Setting the base cost to 4, rather than 3 as in the original patch,
produced smaller code both with and without -mabicalls. With o32 abicalls,
which Richard indicated would be the worst case scenario for call overhead, base
cost of 5 gave similar size results to 4 (overall a tiny decrease, but it looked
like just as many individual tests went up as down), but code size went up for
everything else. So I think 4 is probably a reasonable value without having to
conditionalize it for -mabicalls.
OK to commit this time? I did the i686 bootstrap on this version of the patch
as well as MIPS testing.
-Sandra
2007-08-15 Sandra Loosemore <sandra@codesourcery.com>
Nigel Stephens <nigel@mips.com>
PR target/11787
gcc/
* doc/tm.texi (SET_RATIO, SET_BY_PIECES_P): Document new macros.
(STORE_BY_PIECES_P): No longer applies to __builtin_memset.
* expr.c (SET_BY_PIECES_P): Define.
(can_store_by_pieces, store_by_pieces): Add MEMSETP argument; use
it to decide whether to use SET_BY_PIECES_P or STORE_BY_PIECES_P.
* expr.h (SET_RATIO): Define.
(can_store_by_pieces, store_by_pieces): Update prototypes.
* builtins.c (expand_builtin_memcpy): Pass MEMSETP argument to
can_store_by_pieces/store_by_pieces.
(expand_builtin_memcpy_args): Likewise.
(expand_builtin_strncpy): Likewise.
(expand_builtin_memset_args): Likewise.
* value-prof.c (tree_stringops_transform): Likewise.
* config/sh/sh.h (SET_BY_PIECES_P): Clone from STORE_BY_PIECES_P.
* config/s390/s390.h (SET_BY_PIECES_P): Likewise.
* config/mips/mips.opt (mmemcpy): Change from Var to Mask.
* config/mips/mips.c (override_options): Make -Os default to -mmemcpy.
* config/mips/mips.h (MIPS_CALL_RATIO): Define.
(MOVE_RATIO, CLEAR_RATIO, SET_RATIO): Define.
(STORE_BY_PIECES_P): Define.
Index: gcc/doc/tm.texi
===================================================================
*** gcc/doc/tm.texi (revision 127324)
--- gcc/doc/tm.texi (working copy)
*************** will be used. Defaults to 1 if @code{mo
*** 5893,5904 ****
than @code{CLEAR_RATIO}.
@end defmac
@defmac STORE_BY_PIECES_P (@var{size}, @var{alignment})
A C expression used to determine whether @code{store_by_pieces} will be
! used to set a chunk of memory to a constant value, or whether some other
! mechanism will be used. Used by @code{__builtin_memset} when storing
! values other than constant zero and by @code{__builtin_strcpy} when
! when called with a constant source string.
Defaults to 1 if @code{move_by_pieces_ninsns} returns less
than @code{MOVE_RATIO}.
@end defmac
--- 5893,5922 ----
than @code{CLEAR_RATIO}.
@end defmac
+ @defmac SET_RATIO
+ The threshold of number of scalar move insns, @emph{below} which a sequence
+ of insns should be generated to set memory to a constant value, instead of
+ a block set insn or a library call.
+ Increasing the value will always make code faster, but
+ eventually incurs high cost in increased code size.
+
+ If you don't define this, it defaults to the value of @code{MOVE_RATIO}.
+ @end defmac
+
+ @defmac SET_BY_PIECES_P (@var{size}, @var{alignment})
+ A C expression used to determine whether @code{store_by_pieces} will be
+ used to set a chunk of memory to a constant value, or whether some
+ other mechanism will be used. Used by @code{__builtin_memset} when
+ storing values other than constant zero.
+ Defaults to 1 if @code{move_by_pieces_ninsns} returns less
+ than @code{SET_RATIO}.
+ @end defmac
+
@defmac STORE_BY_PIECES_P (@var{size}, @var{alignment})
A C expression used to determine whether @code{store_by_pieces} will be
! used to set a chunk of memory to a constant string value, or whether some
! other mechanism will be used. Used by @code{__builtin_strcpy} when
! called with a constant source string.
Defaults to 1 if @code{move_by_pieces_ninsns} returns less
than @code{MOVE_RATIO}.
@end defmac
Index: gcc/expr.c
===================================================================
*** gcc/expr.c (revision 127324)
--- gcc/expr.c (working copy)
*************** static bool float_extend_from_mem[NUM_MA
*** 186,193 ****
#endif
/* This macro is used to determine whether store_by_pieces should be
! called to "memset" storage with byte values other than zero, or
! to "memcpy" storage when the source is a constant string. */
#ifndef STORE_BY_PIECES_P
#define STORE_BY_PIECES_P(SIZE, ALIGN) \
(move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
--- 186,200 ----
#endif
/* This macro is used to determine whether store_by_pieces should be
! called to "memset" storage with byte values other than zero. */
! #ifndef SET_BY_PIECES_P
! #define SET_BY_PIECES_P(SIZE, ALIGN) \
! (move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
! < (unsigned int) SET_RATIO)
! #endif
!
! /* This macro is used to determine whether store_by_pieces should be
! called to "memcpy" storage when the source is a constant string. */
#ifndef STORE_BY_PIECES_P
#define STORE_BY_PIECES_P(SIZE, ALIGN) \
(move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
*************** use_group_regs (rtx *call_fusage, rtx re
*** 2191,2203 ****
/* Determine whether the LEN bytes generated by CONSTFUN can be
stored to memory using several move instructions. CONSTFUNDATA is
a pointer which will be passed as argument in every CONSTFUN call.
! ALIGN is maximum alignment we can assume. Return nonzero if a
! call to store_by_pieces should succeed. */
int
can_store_by_pieces (unsigned HOST_WIDE_INT len,
rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode),
! void *constfundata, unsigned int align)
{
unsigned HOST_WIDE_INT l;
unsigned int max_size;
--- 2198,2211 ----
/* Determine whether the LEN bytes generated by CONSTFUN can be
stored to memory using several move instructions. CONSTFUNDATA is
a pointer which will be passed as argument in every CONSTFUN call.
! ALIGN is maximum alignment we can assume. MEMSETP is true if this is
! a memset operation and false if it's a copy of a constant string.
! Return nonzero if a call to store_by_pieces should succeed. */
int
can_store_by_pieces (unsigned HOST_WIDE_INT len,
rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode),
! void *constfundata, unsigned int align, bool memsetp)
{
unsigned HOST_WIDE_INT l;
unsigned int max_size;
*************** can_store_by_pieces (unsigned HOST_WIDE_
*** 2210,2216 ****
if (len == 0)
return 1;
! if (! STORE_BY_PIECES_P (len, align))
return 0;
tmode = mode_for_size (STORE_MAX_PIECES * BITS_PER_UNIT, MODE_INT, 1);
--- 2218,2226 ----
if (len == 0)
return 1;
! if (! (memsetp
! ? SET_BY_PIECES_P (len, align)
! : STORE_BY_PIECES_P (len, align)))
return 0;
tmode = mode_for_size (STORE_MAX_PIECES * BITS_PER_UNIT, MODE_INT, 1);
*************** can_store_by_pieces (unsigned HOST_WIDE_
*** 2285,2291 ****
/* 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.
If ENDP is 0 return to, if ENDP is 1 return memory at the end ala
mempcpy, and if ENDP is 2 return memory the end minus one byte ala
stpcpy. */
--- 2295,2302 ----
/* 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. MEMSETP is true if this is
! a memset operation and false if it's a copy of a constant string.
If ENDP is 0 return to, if ENDP is 1 return memory at the end ala
mempcpy, and if ENDP is 2 return memory the end minus one byte ala
stpcpy. */
*************** can_store_by_pieces (unsigned HOST_WIDE_
*** 2293,2299 ****
rtx
store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode),
! void *constfundata, unsigned int align, int endp)
{
struct store_by_pieces data;
--- 2304,2310 ----
rtx
store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode),
! void *constfundata, unsigned int align, bool memsetp, int endp)
{
struct store_by_pieces data;
*************** store_by_pieces (rtx to, unsigned HOST_W
*** 2303,2309 ****
return to;
}
! gcc_assert (STORE_BY_PIECES_P (len, align));
data.constfun = constfun;
data.constfundata = constfundata;
data.len = len;
--- 2314,2322 ----
return to;
}
! gcc_assert (memsetp
! ? SET_BY_PIECES_P (len, align)
! : STORE_BY_PIECES_P (len, align));
data.constfun = constfun;
data.constfundata = constfundata;
data.len = len;
Index: gcc/expr.h
===================================================================
*** gcc/expr.h (revision 127324)
--- gcc/expr.h (working copy)
*************** enum expand_modifier {EXPAND_NORMAL = 0,
*** 84,89 ****
--- 84,96 ----
#define CLEAR_RATIO (optimize_size ? 3 : 15)
#endif
#endif
+
+ /* If a memory set (to value other than zero) operation would take
+ SET_RATIO or more simple move-instruction sequences, we will do a movmem
+ or libcall instead. */
+ #ifndef SET_RATIO
+ #define SET_RATIO MOVE_RATIO
+ #endif
enum direction {none, upward, downward};
*************** extern int can_move_by_pieces (unsigned
*** 443,462 ****
CONSTFUN with several move instructions by store_by_pieces
function. CONSTFUNDATA is a pointer which will be passed as argument
in every CONSTFUN call.
! ALIGN is maximum alignment we can assume. */
extern int can_store_by_pieces (unsigned HOST_WIDE_INT,
rtx (*) (void *, HOST_WIDE_INT,
enum machine_mode),
! void *, unsigned int);
/* 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.
Returns TO + LEN. */
extern rtx store_by_pieces (rtx, unsigned HOST_WIDE_INT,
rtx (*) (void *, HOST_WIDE_INT, enum machine_mode),
! void *, unsigned int, int);
/* Emit insns to set X from Y. */
extern rtx emit_move_insn (rtx, rtx);
--- 450,472 ----
CONSTFUN with several move instructions by store_by_pieces
function. CONSTFUNDATA is a pointer which will be passed as argument
in every CONSTFUN call.
! ALIGN is maximum alignment we can assume.
! MEMSETP is true if this is a real memset/bzero, not a copy
! of a const string. */
extern int can_store_by_pieces (unsigned HOST_WIDE_INT,
rtx (*) (void *, HOST_WIDE_INT,
enum machine_mode),
! void *, unsigned int, bool);
/* 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.
+ MEMSETP is true if this is a real memset/bzero, not a copy.
Returns TO + LEN. */
extern rtx store_by_pieces (rtx, unsigned HOST_WIDE_INT,
rtx (*) (void *, HOST_WIDE_INT, enum machine_mode),
! void *, unsigned int, bool, int);
/* Emit insns to set X from Y. */
extern rtx emit_move_insn (rtx, rtx);
Index: gcc/builtins.c
===================================================================
*** gcc/builtins.c (revision 127324)
--- gcc/builtins.c (working copy)
*************** expand_builtin_memcpy (tree exp, rtx tar
*** 3371,3381 ****
&& GET_CODE (len_rtx) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
&& can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
! (void *) src_str, dest_align))
{
dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
builtin_memcpy_read_str,
! (void *) src_str, dest_align, 0);
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
dest_mem = convert_memory_address (ptr_mode, dest_mem);
return dest_mem;
--- 3371,3381 ----
&& GET_CODE (len_rtx) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
&& can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
! (void *) src_str, dest_align, false))
{
dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
builtin_memcpy_read_str,
! (void *) src_str, dest_align, false, 0);
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
dest_mem = convert_memory_address (ptr_mode, dest_mem);
return dest_mem;
*************** expand_builtin_mempcpy_args (tree dest,
*** 3484,3496 ****
&& GET_CODE (len_rtx) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
&& can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
! (void *) src_str, dest_align))
{
dest_mem = get_memory_rtx (dest, len);
set_mem_align (dest_mem, dest_align);
dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
builtin_memcpy_read_str,
! (void *) src_str, dest_align, endp);
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
dest_mem = convert_memory_address (ptr_mode, dest_mem);
return dest_mem;
--- 3484,3497 ----
&& GET_CODE (len_rtx) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
&& can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
! (void *) src_str, dest_align, false))
{
dest_mem = get_memory_rtx (dest, len);
set_mem_align (dest_mem, dest_align);
dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
builtin_memcpy_read_str,
! (void *) src_str, dest_align,
! false, endp);
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
dest_mem = convert_memory_address (ptr_mode, dest_mem);
return dest_mem;
*************** expand_builtin_strncpy (tree exp, rtx ta
*** 3832,3844 ****
if (!p || dest_align == 0 || !host_integerp (len, 1)
|| !can_store_by_pieces (tree_low_cst (len, 1),
builtin_strncpy_read_str,
! (void *) p, dest_align))
return NULL_RTX;
dest_mem = get_memory_rtx (dest, len);
store_by_pieces (dest_mem, tree_low_cst (len, 1),
builtin_strncpy_read_str,
! (void *) p, dest_align, 0);
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
dest_mem = convert_memory_address (ptr_mode, dest_mem);
return dest_mem;
--- 3833,3845 ----
if (!p || dest_align == 0 || !host_integerp (len, 1)
|| !can_store_by_pieces (tree_low_cst (len, 1),
builtin_strncpy_read_str,
! (void *) p, dest_align, false))
return NULL_RTX;
dest_mem = get_memory_rtx (dest, len);
store_by_pieces (dest_mem, tree_low_cst (len, 1),
builtin_strncpy_read_str,
! (void *) p, dest_align, false, 0);
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
dest_mem = convert_memory_address (ptr_mode, dest_mem);
return dest_mem;
*************** expand_builtin_memset_args (tree dest, t
*** 3968,3979 ****
if (host_integerp (len, 1)
&& !(optimize_size && tree_low_cst (len, 1) > 1)
&& can_store_by_pieces (tree_low_cst (len, 1),
! builtin_memset_read_str, &c, dest_align))
{
val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node),
val_rtx);
store_by_pieces (dest_mem, tree_low_cst (len, 1),
! builtin_memset_gen_str, val_rtx, dest_align, 0);
}
else if (!set_storage_via_setmem (dest_mem, len_rtx, val_rtx,
dest_align, expected_align,
--- 3969,3982 ----
if (host_integerp (len, 1)
&& !(optimize_size && tree_low_cst (len, 1) > 1)
&& can_store_by_pieces (tree_low_cst (len, 1),
! builtin_memset_read_str, &c, dest_align,
! true))
{
val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node),
val_rtx);
store_by_pieces (dest_mem, tree_low_cst (len, 1),
! builtin_memset_gen_str, val_rtx, dest_align,
! true, 0);
}
else if (!set_storage_via_setmem (dest_mem, len_rtx, val_rtx,
dest_align, expected_align,
*************** expand_builtin_memset_args (tree dest, t
*** 3993,4001 ****
if (host_integerp (len, 1)
&& !(optimize_size && tree_low_cst (len, 1) > 1)
&& can_store_by_pieces (tree_low_cst (len, 1),
! builtin_memset_read_str, &c, dest_align))
store_by_pieces (dest_mem, tree_low_cst (len, 1),
! builtin_memset_read_str, &c, dest_align, 0);
else if (!set_storage_via_setmem (dest_mem, len_rtx, GEN_INT (c),
dest_align, expected_align,
expected_size))
--- 3996,4005 ----
if (host_integerp (len, 1)
&& !(optimize_size && tree_low_cst (len, 1) > 1)
&& can_store_by_pieces (tree_low_cst (len, 1),
! builtin_memset_read_str, &c, dest_align,
! true))
store_by_pieces (dest_mem, tree_low_cst (len, 1),
! builtin_memset_read_str, &c, dest_align, true, 0);
else if (!set_storage_via_setmem (dest_mem, len_rtx, GEN_INT (c),
dest_align, expected_align,
expected_size))
Index: gcc/value-prof.c
===================================================================
*** gcc/value-prof.c (revision 127324)
--- gcc/value-prof.c (working copy)
*************** tree_stringops_transform (block_stmt_ite
*** 1392,1404 ****
case BUILT_IN_MEMSET:
if (!can_store_by_pieces (val, builtin_memset_read_str,
CALL_EXPR_ARG (call, 1),
! dest_align))
return false;
break;
case BUILT_IN_BZERO:
if (!can_store_by_pieces (val, builtin_memset_read_str,
integer_zero_node,
! dest_align))
return false;
break;
default:
--- 1392,1404 ----
case BUILT_IN_MEMSET:
if (!can_store_by_pieces (val, builtin_memset_read_str,
CALL_EXPR_ARG (call, 1),
! dest_align, true))
return false;
break;
case BUILT_IN_BZERO:
if (!can_store_by_pieces (val, builtin_memset_read_str,
integer_zero_node,
! dest_align, true))
return false;
break;
default:
Index: gcc/config/sh/sh.h
===================================================================
*** gcc/config/sh/sh.h (revision 127324)
--- gcc/config/sh/sh.h (working copy)
*************** struct sh_args {
*** 2184,2189 ****
--- 2184,2191 ----
(move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
< (TARGET_SMALLCODE ? 2 : ((ALIGN >= 32) ? 16 : 2)))
+ #define SET_BY_PIECES_P(SIZE, ALIGN) STORE_BY_PIECES_P(SIZE, ALIGN)
+
/* Macros to check register numbers against specific register classes. */
/* These assume that REGNO is a hard or pseudo reg number.
Index: gcc/config/s390/s390.h
===================================================================
*** gcc/config/s390/s390.h (revision 127324)
--- gcc/config/s390/s390.h (working copy)
*************** extern struct rtx_def *s390_compare_op0,
*** 803,812 ****
|| (TARGET_64BIT && (SIZE) == 8) )
/* This macro is used to determine whether store_by_pieces should be
! called to "memset" storage with byte values other than zero, or
! to "memcpy" storage when the source is a constant string. */
#define STORE_BY_PIECES_P(SIZE, ALIGN) MOVE_BY_PIECES_P (SIZE, ALIGN)
/* Don't perform CSE on function addresses. */
#define NO_FUNCTION_CSE
--- 803,815 ----
|| (TARGET_64BIT && (SIZE) == 8) )
/* This macro is used to determine whether store_by_pieces should be
! called to "memcpy" storage when the source is a constant string. */
#define STORE_BY_PIECES_P(SIZE, ALIGN) MOVE_BY_PIECES_P (SIZE, ALIGN)
+ /* Likewise to decide whether to "memset" storage with byte values
+ other than zero. */
+ #define SET_BY_PIECES_P(SIZE, ALIGN) STORE_BY_PIECES_P (SIZE, ALIGN)
+
/* Don't perform CSE on function addresses. */
#define NO_FUNCTION_CSE
Index: gcc/config/mips/mips.opt
===================================================================
*** gcc/config/mips/mips.opt (revision 127325)
--- gcc/config/mips/mips.opt (working copy)
*************** Target Report RejectNegative Mask(LONG64
*** 173,179 ****
Use a 64-bit long type
mmemcpy
! Target Report Var(TARGET_MEMCPY)
Don't optimize block moves
mmips-tfile
--- 173,179 ----
Use a 64-bit long type
mmemcpy
! Target Report Mask(MEMCPY)
Don't optimize block moves
mmips-tfile
Index: gcc/config/mips/mips.c
===================================================================
*** gcc/config/mips/mips.c (revision 127325)
--- gcc/config/mips/mips.c (working copy)
*************** override_options (void)
*** 5299,5304 ****
--- 5299,5309 ----
flag_delayed_branch = 0;
}
+ /* Prefer a call to memcpy over inline code when optimizing for size,
+ though see MOVE_RATIO in mips.h. */
+ if (optimize_size && (target_flags_explicit & MASK_MEMCPY) == 0)
+ target_flags |= MASK_MEMCPY;
+
#ifdef MIPS_TFMODE_FORMAT
REAL_MODE_FORMAT (TFmode) = &MIPS_TFMODE_FORMAT;
#endif
Index: gcc/config/mips/mips.h
===================================================================
*** gcc/config/mips/mips.h (revision 127325)
--- gcc/config/mips/mips.h (working copy)
*************** while (0)
*** 2780,2785 ****
--- 2780,2829 ----
#undef PTRDIFF_TYPE
#define PTRDIFF_TYPE (POINTER_SIZE == 64 ? "long int" : "int")
+
+ /* The base cost of a memcpy call, for MOVE_RATIO and friends. This
+ was determined experimentally by benchmarking with CSiBE. In theory,
+ the call overhead is higher for TARGET_ABICALLS (especially for o32
+ where we have to restore $gp afterwards as well as make an indirect
+ call), but in practice, bumping this up higher for TARGET_ABICALLS
+ doesn't make much difference to code size. */
+
+ #define MIPS_CALL_RATIO 4
+
+ /* Define MOVE_RATIO to encourage use of movmemsi when enabled,
+ since it should always generate code at least as good as
+ move_by_pieces(). But when inline movmemsi pattern is disabled
+ (i.e., with -mips16 or -mmemcpy), instead use a value approximating
+ the length of a memcpy call sequence, so that move_by_pieces will
+ generate inline code if it is shorter than a function call.
+ The default value for MOVE_RATIO when HAVE_movmemsi is true is 2.
+ There is no point to setting it to less than this to try to disable
+ move_by_pieces entirely, because that also disables some desirable
+ tree-level optimizations, specifically related to optimizing a
+ one-byte string copy into a simple move byte operation. */
+
+ #define MOVE_RATIO ((TARGET_MIPS16 || TARGET_MEMCPY) ? MIPS_CALL_RATIO : 2)
+
+ /* For CLEAR_RATIO, when optimizing for size, give a better estimate
+ of the length of a memset call, but use the default otherwise. */
+
+ #define CLEAR_RATIO (optimize_size ? MIPS_CALL_RATIO + 2 : 15)
+
+ /* This is similar to CLEAR_RATIO, but for a non-zero constant, so when
+ optimizing for size adjust the ratio to account for the overhead of
+ loading the constant and replicating it across the word. In fact in
+ that case it is never worth inlining, since calling memset should
+ always be smaller. */
+
+ #define SET_RATIO (optimize_size ? MIPS_CALL_RATIO : 15)
+
+ /* STORE_BY_PIECES_P can be used when copying a constant string, but
+ in that case each word takes 3 insns (lui, ori, sw), or more in
+ 64-bit mode, instead of 2 (lw, sw). So better to always fail this
+ and let the move_by_pieces code copy the string from read-only
+ memory. */
+
+ #define STORE_BY_PIECES_P(SIZE, ALIGN) 0
#ifndef __mips16
/* Since the bits of the _init and _fini function is spread across