diff options
author | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-08-26 22:02:44 +0000 |
---|---|---|
committer | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-08-26 22:02:44 +0000 |
commit | d8ae1baae3e99dfbcbe2e7da2361de13a86d0395 (patch) | |
tree | 98ccbe9ec79be85a6d0adc7e6a8ae4dd1aafc086 /gcc/builtins.c | |
parent | 724912572b37ccd8531ff7dfeb33d19ed7742b4a (diff) | |
download | gcc-d8ae1baae3e99dfbcbe2e7da2361de13a86d0395.tar.gz |
PR rtl-optimization/23561
* builtins.c (get_memory_rtx): Add LEN argument. If MEM_EXPR is
a COMPONENT_REF, remove all COMPONENT_REF from MEM_EXPR unless
at most LEN bytes long memory fits into the field.
(expand_builtin_memcpy, expand_builtin_mempcpy, expand_movstr,
expand_builtin_strncpy, expand_builtin_memset, expand_builtin_memcmp,
expand_builtin_strcmp, expand_builtin_strncmp): Adjust callers.
* gcc.c-torture/execute/20050826-1.c: New test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@103541 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r-- | gcc/builtins.c | 119 |
1 files changed, 101 insertions, 18 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index 9975b751ef2..43bbd2427cc 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -75,7 +75,7 @@ static int get_pointer_alignment (tree, unsigned int); static const char *c_getstr (tree); static rtx c_readstr (const char *, enum machine_mode); static int target_char_cast (tree, char *); -static rtx get_memory_rtx (tree); +static rtx get_memory_rtx (tree, tree); static tree build_string_literal (int, const char *); static int apply_args_size (void); static int apply_result_size (void); @@ -1013,10 +1013,12 @@ expand_builtin_prefetch (tree arglist) } /* Get a MEM rtx for expression EXP which is the address of an operand - to be used to be used in a string instruction (cmpstrsi, movmemsi, ..). */ + to be used in a string instruction (cmpstrsi, movmemsi, ..). LEN is + the maximum length of the block of memory that might be accessed or + NULL if unknown. */ static rtx -get_memory_rtx (tree exp) +get_memory_rtx (tree exp, tree len) { rtx addr = expand_expr (exp, NULL_RTX, ptr_mode, EXPAND_NORMAL); rtx mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr)); @@ -1042,6 +1044,87 @@ get_memory_rtx (tree exp) if (exp) { set_mem_attributes (mem, exp, 0); + + /* Allow the string and memory builtins to overflow from one + field into another, see http://gcc.gnu.org/PR23561. + Thus avoid COMPONENT_REFs in MEM_EXPR unless we know the whole + memory accessed by the string or memory builtin will fit + within the field. */ + if (MEM_EXPR (mem) && TREE_CODE (MEM_EXPR (mem)) == COMPONENT_REF) + { + tree mem_expr = MEM_EXPR (mem); + HOST_WIDE_INT offset = -1, length = -1; + tree inner = exp; + + while (TREE_CODE (inner) == ARRAY_REF + || TREE_CODE (inner) == NOP_EXPR + || TREE_CODE (inner) == CONVERT_EXPR + || TREE_CODE (inner) == NON_LVALUE_EXPR + || TREE_CODE (inner) == VIEW_CONVERT_EXPR + || TREE_CODE (inner) == SAVE_EXPR) + inner = TREE_OPERAND (inner, 0); + + gcc_assert (TREE_CODE (inner) == COMPONENT_REF); + + if (MEM_OFFSET (mem) + && GET_CODE (MEM_OFFSET (mem)) == CONST_INT) + offset = INTVAL (MEM_OFFSET (mem)); + + if (offset >= 0 && len && host_integerp (len, 0)) + length = tree_low_cst (len, 0); + + while (TREE_CODE (inner) == COMPONENT_REF) + { + tree field = TREE_OPERAND (inner, 1); + gcc_assert (! DECL_BIT_FIELD (field)); + gcc_assert (TREE_CODE (mem_expr) == COMPONENT_REF); + gcc_assert (field == TREE_OPERAND (mem_expr, 1)); + + if (length >= 0 + && TYPE_SIZE_UNIT (TREE_TYPE (inner)) + && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (inner)), 0)) + { + HOST_WIDE_INT size + = tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (inner)), 0); + /* If we can prove the memory starting at XEXP (mem, 0) + and ending at XEXP (mem, 0) + LENGTH will fit into + this field, we can keep that COMPONENT_REF in MEM_EXPR. */ + if (offset <= size + && length <= size + && offset + length <= size) + break; + } + + if (offset >= 0 + && host_integerp (DECL_FIELD_OFFSET (field), 0)) + offset += tree_low_cst (DECL_FIELD_OFFSET (field), 0) + + tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1) + / BITS_PER_UNIT; + else + { + offset = -1; + length = -1; + } + + mem_expr = TREE_OPERAND (mem_expr, 0); + inner = TREE_OPERAND (inner, 0); + + while (TREE_CODE (inner) == NOP_EXPR + || TREE_CODE (inner) == CONVERT_EXPR + || TREE_CODE (inner) == NON_LVALUE_EXPR + || TREE_CODE (inner) == VIEW_CONVERT_EXPR + || TREE_CODE (inner) == SAVE_EXPR) + inner = TREE_OPERAND (inner, 0); + } + + if (mem_expr == NULL) + offset = -1; + if (mem_expr != MEM_EXPR (mem)) + { + set_mem_expr (mem, mem_expr); + set_mem_offset (mem, offset >= 0 ? GEN_INT (offset) : NULL_RTX); + } + } set_mem_alias_set (mem, 0); set_mem_size (mem, NULL_RTX); } @@ -2808,7 +2891,7 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode) if (src_align == 0) return 0; - dest_mem = get_memory_rtx (dest); + dest_mem = get_memory_rtx (dest, len); set_mem_align (dest_mem, dest_align); len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); src_str = c_getstr (src); @@ -2830,7 +2913,7 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode) return dest_mem; } - src_mem = get_memory_rtx (src); + src_mem = get_memory_rtx (src, len); set_mem_align (src_mem, src_align); /* Copy word part most expediently. */ @@ -2909,7 +2992,7 @@ expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode m && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str, (void *) src_str, dest_align)) { - dest_mem = get_memory_rtx (dest); + 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, @@ -2923,9 +3006,9 @@ expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode m && can_move_by_pieces (INTVAL (len_rtx), MIN (dest_align, src_align))) { - dest_mem = get_memory_rtx (dest); + dest_mem = get_memory_rtx (dest, len); set_mem_align (dest_mem, dest_align); - src_mem = get_memory_rtx (src); + src_mem = get_memory_rtx (src, len); set_mem_align (src_mem, src_align); dest_mem = move_by_pieces (dest_mem, src_mem, INTVAL (len_rtx), MIN (dest_align, src_align), endp); @@ -3053,8 +3136,8 @@ expand_movstr (tree dest, tree src, rtx target, int endp) if (!HAVE_movstr) return 0; - dest_mem = get_memory_rtx (dest); - src_mem = get_memory_rtx (src); + dest_mem = get_memory_rtx (dest, NULL); + src_mem = get_memory_rtx (src, NULL); if (!endp) { target = force_reg (Pmode, XEXP (dest_mem, 0)); @@ -3260,7 +3343,7 @@ expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode) (void *) p, dest_align)) return 0; - dest_mem = get_memory_rtx (dest); + 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); @@ -3351,7 +3434,7 @@ expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode, } len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); - dest_mem = get_memory_rtx (dest); + dest_mem = get_memory_rtx (dest, len); if (TREE_CODE (val) != INTEGER_CST) { @@ -3502,8 +3585,8 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target, && REGNO (result) >= FIRST_PSEUDO_REGISTER)) result = gen_reg_rtx (insn_mode); - arg1_rtx = get_memory_rtx (arg1); - arg2_rtx = get_memory_rtx (arg2); + arg1_rtx = get_memory_rtx (arg1, len); + arg2_rtx = get_memory_rtx (arg2, len); arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); /* Set MEM_SIZE as appropriate. */ @@ -3596,8 +3679,8 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode) arg1 = builtin_save_expr (arg1); arg2 = builtin_save_expr (arg2); - arg1_rtx = get_memory_rtx (arg1); - arg2_rtx = get_memory_rtx (arg2); + arg1_rtx = get_memory_rtx (arg1, NULL); + arg2_rtx = get_memory_rtx (arg2, NULL); #ifdef HAVE_cmpstrsi /* Try to call cmpstrsi. */ @@ -3801,8 +3884,8 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) arg2 = builtin_save_expr (arg2); len = builtin_save_expr (len); - arg1_rtx = get_memory_rtx (arg1); - arg2_rtx = get_memory_rtx (arg2); + arg1_rtx = get_memory_rtx (arg1, len); + arg2_rtx = get_memory_rtx (arg2, len); arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx, GEN_INT (MIN (arg1_align, arg2_align))); |