diff options
Diffstat (limited to 'gcc/expr.c')
-rw-r--r-- | gcc/expr.c | 112 |
1 files changed, 88 insertions, 24 deletions
diff --git a/gcc/expr.c b/gcc/expr.c index dc6615abac0..9f321c80ad9 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -186,8 +186,15 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES]; #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. */ + 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) \ @@ -236,11 +243,12 @@ enum insn_code sync_lock_release[NUM_MACHINE_MODES]; #define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) STRICT_ALIGNMENT #endif -/* This is run once per compilation to set up which modes can be used - directly in memory and to initialize the block move optab. */ +/* This is run to set up which modes can be used + directly in memory and to initialize the block move optab. It is run + at the beginning of compilation and when the target is reinitialized. */ void -init_expr_once (void) +init_expr_target (void) { rtx insn, pat; enum machine_mode mode; @@ -2191,13 +2199,14 @@ use_group_regs (rtx *call_fusage, rtx regs) /* 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. */ + 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) + void *constfundata, unsigned int align, bool memsetp) { unsigned HOST_WIDE_INT l; unsigned int max_size; @@ -2210,7 +2219,9 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len, if (len == 0) return 1; - if (! STORE_BY_PIECES_P (len, align)) + 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); @@ -2285,7 +2296,8 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len, /* 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. + 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. */ @@ -2293,7 +2305,7 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len, 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) + void *constfundata, unsigned int align, bool memsetp, int endp) { struct store_by_pieces data; @@ -2303,7 +2315,9 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len, return to; } - gcc_assert (STORE_BY_PIECES_P (len, align)); + gcc_assert (memsetp + ? SET_BY_PIECES_P (len, align) + : STORE_BY_PIECES_P (len, align)); data.constfun = constfun; data.constfundata = constfundata; data.len = len; @@ -4472,10 +4486,52 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) return NULL_RTX; } + else if (TREE_CODE (exp) == STRING_CST + && !nontemporal && !call_param_p + && TREE_STRING_LENGTH (exp) > 0 + && TYPE_MODE (TREE_TYPE (exp)) == BLKmode) + { + /* Optimize initialization of an array with a STRING_CST. */ + HOST_WIDE_INT exp_len, str_copy_len; + rtx dest_mem; + + exp_len = int_expr_size (exp); + if (exp_len <= 0) + goto normal_expr; + + str_copy_len = strlen (TREE_STRING_POINTER (exp)); + if (str_copy_len < TREE_STRING_LENGTH (exp) - 1) + goto normal_expr; + + str_copy_len = TREE_STRING_LENGTH (exp); + if ((STORE_MAX_PIECES & (STORE_MAX_PIECES - 1)) == 0) + { + str_copy_len += STORE_MAX_PIECES - 1; + str_copy_len &= ~(STORE_MAX_PIECES - 1); + } + str_copy_len = MIN (str_copy_len, exp_len); + if (!can_store_by_pieces (str_copy_len, builtin_strncpy_read_str, + (void *) TREE_STRING_POINTER (exp), + MEM_ALIGN (target), false)) + goto normal_expr; + + dest_mem = target; + + dest_mem = store_by_pieces (dest_mem, + str_copy_len, builtin_strncpy_read_str, + (void *) TREE_STRING_POINTER (exp), + MEM_ALIGN (target), false, + exp_len > str_copy_len ? 1 : 0); + if (exp_len > str_copy_len) + clear_storage (dest_mem, GEN_INT (exp_len - str_copy_len), + BLOCK_OP_NORMAL); + return NULL_RTX; + } else { rtx tmp_target; + normal_expr: /* If we want to use a nontemporal store, force the value to register first. */ tmp_target = nontemporal ? NULL_RTX : target; @@ -5782,7 +5838,6 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize, enum machine_mode mode = VOIDmode; tree offset = size_zero_node; tree bit_offset = bitsize_zero_node; - tree tem; /* First get the mode, signedness, and size. We do this from just the outermost expression. */ @@ -5825,6 +5880,8 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize, *pbitsize = tree_low_cst (size_tree, 1); } + *pmode = mode; + /* Compute cumulative bit-offset for nested component-refs and array-refs, and find the ultimate containing object. */ while (1) @@ -5909,18 +5966,25 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize, done: /* If OFFSET is constant, see if we can return the whole thing as a - constant bit position. Otherwise, split it up. */ - if (host_integerp (offset, 0) - && 0 != (tem = size_binop (MULT_EXPR, - fold_convert (bitsizetype, offset), - bitsize_unit_node)) - && 0 != (tem = size_binop (PLUS_EXPR, tem, bit_offset)) - && host_integerp (tem, 0)) - *pbitpos = tree_low_cst (tem, 0), *poffset = 0; - else - *pbitpos = tree_low_cst (bit_offset, 0), *poffset = offset; + constant bit position. Make sure to handle overflow during + this conversion. */ + if (host_integerp (offset, 0)) + { + double_int tem = double_int_mul (tree_to_double_int (offset), + uhwi_to_double_int (BITS_PER_UNIT)); + tem = double_int_add (tem, tree_to_double_int (bit_offset)); + if (double_int_fits_in_shwi_p (tem)) + { + *pbitpos = double_int_to_shwi (tem); + *poffset = NULL_TREE; + return exp; + } + } + + /* Otherwise, split it up. */ + *pbitpos = tree_low_cst (bit_offset, 0); + *poffset = offset; - *pmode = mode; return exp; } |