From 153c3b5050025f879d92be6cd675dbb0686255e3 Mon Sep 17 00:00:00 2001 From: rguenth Date: Thu, 12 Aug 2010 10:36:08 +0000 Subject: 2010-08-12 Richard Guenther * tree-flow.h (struct ptr_info_def): Add align and misalign fields. * tree-ssa-alias.c (get_ptr_info): Move ... * tree-ssanames.c (get_ptr_info): ... here. Initialize align and misalign fields conservatively. * tree-ssa-ccp.c (ccp_finalize): From partially constant pointers derive alignment information. (evaluate_stmt): Derive alignment information from memory allocation functions. * tree.h (get_pointer_alignment): Make unsigned. * builtins.c (get_object_alignment): Use alignment information we have computed for pointers. (get_pointer_alignment): Likewise. Make conservative, return and unsigned value. (expand_builtin_strlen): Adjust. (expand_builtin_memcmp): Likewise. (expand_builtin_strcmp): Likewise. (expand_builtin_strncmp): Likewise. (get_builtin_sync_mem): Use at least mode alignment. (fold_builtin_memset): Adjust. (fold_builtin_memory_op): Likewise. * gimple-pretty-print.c (dump_gimple_phi): Alongside alias information also dump pointer alignment knowledge. (dump_gimple_stmt): Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@163189 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 26 +++++++++ gcc/builtins.c | 140 ++++++++++++++++++++++++++-------------------- gcc/gimple-pretty-print.c | 16 +++++- gcc/tree-flow.h | 12 ++++ gcc/tree-ssa-alias.c | 21 ------- gcc/tree-ssa-ccp.c | 60 ++++++++++++++++++++ gcc/tree-ssanames.c | 42 +++++++++++--- gcc/tree.h | 2 +- 8 files changed, 224 insertions(+), 95 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a20fb37df3d..61b30e9f751 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,29 @@ +2010-08-12 Richard Guenther + + * tree-flow.h (struct ptr_info_def): Add align and misalign fields. + * tree-ssa-alias.c (get_ptr_info): Move ... + * tree-ssanames.c (get_ptr_info): ... here. Initialize + align and misalign fields conservatively. + * tree-ssa-ccp.c (ccp_finalize): From partially constant pointers + derive alignment information. + (evaluate_stmt): Derive alignment information from memory + allocation functions. + * tree.h (get_pointer_alignment): Make unsigned. + * builtins.c (get_object_alignment): Use alignment information we + have computed for pointers. + (get_pointer_alignment): Likewise. Make conservative, return + and unsigned value. + (expand_builtin_strlen): Adjust. + (expand_builtin_memcmp): Likewise. + (expand_builtin_strcmp): Likewise. + (expand_builtin_strncmp): Likewise. + (get_builtin_sync_mem): Use at least mode alignment. + (fold_builtin_memset): Adjust. + (fold_builtin_memory_op): Likewise. + * gimple-pretty-print.c (dump_gimple_phi): Alongside alias + information also dump pointer alignment knowledge. + (dump_gimple_stmt): Likewise. + 2010-08-12 Uros Bizjak * config/i386/i386.c (LONG_TYPE_SIZE): Remove. diff --git a/gcc/builtins.c b/gcc/builtins.c index 3d5ca33989c..ad5d6aae048 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -309,6 +309,7 @@ get_object_alignment (tree exp, unsigned int max_align) else if (TREE_CODE (exp) == MEM_REF) { tree addr = TREE_OPERAND (exp, 0); + struct ptr_info_def *pi; if (TREE_CODE (addr) == BIT_AND_EXPR && TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST) { @@ -319,11 +320,52 @@ get_object_alignment (tree exp, unsigned int max_align) } else align = BITS_PER_UNIT; - if (TREE_CODE (addr) == ADDR_EXPR) + if (TREE_CODE (addr) == SSA_NAME + && (pi = SSA_NAME_PTR_INFO (addr))) + { + bitpos += (pi->misalign * BITS_PER_UNIT) & ~(align - 1); + align = MAX (pi->align * BITS_PER_UNIT, align); + } + else if (TREE_CODE (addr) == ADDR_EXPR) align = MAX (align, get_object_alignment (TREE_OPERAND (addr, 0), max_align)); bitpos += mem_ref_offset (exp).low * BITS_PER_UNIT; } + else if (TREE_CODE (exp) == TARGET_MEM_REF + && TMR_BASE (exp) + && POINTER_TYPE_P (TREE_TYPE (TMR_BASE (exp)))) + { + struct ptr_info_def *pi; + tree addr = TMR_BASE (exp); + if (TREE_CODE (addr) == BIT_AND_EXPR + && TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST) + { + align = (TREE_INT_CST_LOW (TREE_OPERAND (addr, 1)) + & -TREE_INT_CST_LOW (TREE_OPERAND (addr, 1))); + align *= BITS_PER_UNIT; + addr = TREE_OPERAND (addr, 0); + } + else + align = BITS_PER_UNIT; + if (TREE_CODE (addr) == SSA_NAME + && (pi = SSA_NAME_PTR_INFO (addr))) + { + bitpos += (pi->misalign * BITS_PER_UNIT) & ~(align - 1); + align = MAX (pi->align * BITS_PER_UNIT, align); + } + else if (TREE_CODE (addr) == ADDR_EXPR) + align = MAX (align, get_object_alignment (TREE_OPERAND (addr, 0), + max_align)); + if (TMR_OFFSET (exp)) + bitpos += TREE_INT_CST_LOW (TMR_OFFSET (exp)) * BITS_PER_UNIT; + if (TMR_INDEX (exp) && TMR_STEP (exp)) + { + unsigned HOST_WIDE_INT step = TREE_INT_CST_LOW (TMR_STEP (exp)); + align = MIN (align, (step & -step) * BITS_PER_UNIT); + } + else if (TMR_INDEX (exp)) + align = BITS_PER_UNIT; + } else if (TREE_CODE (exp) == TARGET_MEM_REF && TMR_SYMBOL (exp)) { @@ -417,56 +459,28 @@ can_trust_pointer_alignment (void) Otherwise, look at the expression to see if we can do better, i.e., if the expression is actually pointing at an object whose alignment is tighter. */ -int +unsigned int get_pointer_alignment (tree exp, unsigned int max_align) { - unsigned int align, inner; - - if (!can_trust_pointer_alignment ()) - return 0; - - if (!POINTER_TYPE_P (TREE_TYPE (exp))) - return 0; - - align = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp))); - align = MIN (align, max_align); - - while (1) - { - switch (TREE_CODE (exp)) - { - CASE_CONVERT: - exp = TREE_OPERAND (exp, 0); - if (! POINTER_TYPE_P (TREE_TYPE (exp))) - return align; - - inner = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp))); - align = MIN (inner, max_align); - break; - - case POINTER_PLUS_EXPR: - /* If sum of pointer + int, restrict our maximum alignment to that - imposed by the integer. If not, we can't do any better than - ALIGN. */ - if (! host_integerp (TREE_OPERAND (exp, 1), 1)) - return align; - - while (((tree_low_cst (TREE_OPERAND (exp, 1), 1)) - & (max_align / BITS_PER_UNIT - 1)) - != 0) - max_align >>= 1; - - exp = TREE_OPERAND (exp, 0); - break; - - case ADDR_EXPR: - /* See what we are pointing at and look at its alignment. */ - return get_object_alignment (TREE_OPERAND (exp, 0), max_align); + STRIP_NOPS (exp); - default: - return align; - } + if (TREE_CODE (exp) == ADDR_EXPR) + return get_object_alignment (TREE_OPERAND (exp, 0), max_align); + else if (TREE_CODE (exp) == SSA_NAME + && POINTER_TYPE_P (TREE_TYPE (exp))) + { + struct ptr_info_def *pi = SSA_NAME_PTR_INFO (exp); + unsigned align; + if (!pi) + return BITS_PER_UNIT; + if (pi->misalign != 0) + align = (pi->misalign & -pi->misalign); + else + align = pi->align; + return MIN (max_align, align * BITS_PER_UNIT); } + + return POINTER_TYPE_P (TREE_TYPE (exp)) ? BITS_PER_UNIT : 0; } /* Compute the length of a C string. TREE_STRING_LENGTH is not the right @@ -3293,7 +3307,7 @@ expand_builtin_strlen (tree exp, rtx target, rtx result, src_reg, char_rtx, before_strlen; enum machine_mode insn_mode = target_mode, char_mode; enum insn_code icode = CODE_FOR_nothing; - int align; + unsigned int align; /* If the length can be computed at compile-time, return it. */ len = c_strlen (src, 0); @@ -4066,9 +4080,9 @@ expand_builtin_memcmp (tree exp, ATTRIBUTE_UNUSED rtx target, tree arg2 = CALL_EXPR_ARG (exp, 1); tree len = CALL_EXPR_ARG (exp, 2); - int arg1_align + unsigned int arg1_align = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; - int arg2_align + unsigned int arg2_align = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; enum machine_mode insn_mode; @@ -4168,9 +4182,9 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target) tree arg1 = CALL_EXPR_ARG (exp, 0); tree arg2 = CALL_EXPR_ARG (exp, 1); - int arg1_align + unsigned int arg1_align = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; - int arg2_align + unsigned int arg2_align = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; /* If we don't have POINTER_TYPE, call the function. */ @@ -4319,9 +4333,9 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target, tree arg2 = CALL_EXPR_ARG (exp, 1); tree arg3 = CALL_EXPR_ARG (exp, 2); - int arg1_align + unsigned int arg1_align = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; - int arg2_align + unsigned int arg2_align = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; enum machine_mode insn_mode = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode; @@ -5505,7 +5519,9 @@ get_builtin_sync_mem (tree loc, enum machine_mode mode) satisfy the full barrier semantics of the intrinsic. */ mem = validize_mem (gen_rtx_MEM (mode, addr)); - set_mem_align (mem, get_pointer_alignment (loc, BIGGEST_ALIGNMENT)); + /* The alignment needs to be at least according to that of the mode. */ + set_mem_align (mem, MAX (GET_MODE_ALIGNMENT (mode), + get_pointer_alignment (loc, BIGGEST_ALIGNMENT))); set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER); MEM_VOLATILE_P (mem) = 1; @@ -8280,7 +8296,7 @@ fold_builtin_memset (location_t loc, tree dest, tree c, tree len, length = tree_low_cst (len, 1); if (GET_MODE_SIZE (TYPE_MODE (etype)) != length || get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT - < (int) length) + < length) return NULL_TREE; if (length > HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT) @@ -8365,7 +8381,7 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src, else { tree srctype, desttype; - int src_align, dest_align; + unsigned int src_align, dest_align; tree off0; if (endp == 3) @@ -8504,8 +8520,8 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src, src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT); dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); - if (dest_align < (int) TYPE_ALIGN (desttype) - || src_align < (int) TYPE_ALIGN (srctype)) + if (dest_align < TYPE_ALIGN (desttype) + || src_align < TYPE_ALIGN (srctype)) return NULL_TREE; if (!ignore) @@ -8531,7 +8547,7 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src, && tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len) && (!STRICT_ALIGNMENT || !destvar - || src_align >= (int) TYPE_ALIGN (desttype))) + || src_align >= TYPE_ALIGN (desttype))) srcvar = fold_build2 (MEM_REF, destvar ? desttype : srctype, srcvar, off0); else @@ -8543,7 +8559,7 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src, if (srcvar == NULL_TREE) { if (STRICT_ALIGNMENT - && src_align < (int) TYPE_ALIGN (desttype)) + && src_align < TYPE_ALIGN (desttype)) return NULL_TREE; STRIP_NOPS (src); srcvar = fold_build2 (MEM_REF, desttype, src, off0); @@ -8551,7 +8567,7 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src, else if (destvar == NULL_TREE) { if (STRICT_ALIGNMENT - && dest_align < (int) TYPE_ALIGN (srctype)) + && dest_align < TYPE_ALIGN (srctype)) return NULL_TREE; STRIP_NOPS (dest); destvar = fold_build2 (MEM_REF, srctype, dest, off0); diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 6e1f6b782c2..941d3236eea 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1363,8 +1363,13 @@ dump_gimple_phi (pretty_printer *buffer, gimple phi, int spc, int flags) && POINTER_TYPE_P (TREE_TYPE (lhs)) && SSA_NAME_PTR_INFO (lhs)) { + struct ptr_info_def *pi = SSA_NAME_PTR_INFO (lhs); pp_string (buffer, "PT = "); - pp_points_to_solution (buffer, &SSA_NAME_PTR_INFO (lhs)->pt); + pp_points_to_solution (buffer, &pi->pt); + newline_and_indent (buffer, spc); + if (pi->align != 1) + pp_printf (buffer, "# ALIGN = %u, MISALIGN = %u", + pi->align, pi->misalign); newline_and_indent (buffer, spc); pp_string (buffer, "# "); } @@ -1650,9 +1655,16 @@ dump_gimple_stmt (pretty_printer *buffer, gimple gs, int spc, int flags) && POINTER_TYPE_P (TREE_TYPE (lhs)) && SSA_NAME_PTR_INFO (lhs)) { + struct ptr_info_def *pi = SSA_NAME_PTR_INFO (lhs); pp_string (buffer, "# PT = "); - pp_points_to_solution (buffer, &SSA_NAME_PTR_INFO (lhs)->pt); + pp_points_to_solution (buffer, &pi->pt); newline_and_indent (buffer, spc); + if (pi->align != 1) + { + pp_printf (buffer, "# ALIGN = %u, MISALIGN = %u", + pi->align, pi->misalign); + newline_and_indent (buffer, spc); + } } } diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index abbf9172a1c..04ba5325f11 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -119,6 +119,18 @@ struct GTY(()) ptr_info_def { /* The points-to solution. */ struct pt_solution pt; + + /* Alignment and misalignment of the pointer in bytes. Together + align and misalign specify low known bits of the pointer. + ptr & (align - 1) == misalign. */ + + /* The power-of-two byte alignment of the object this pointer + points into. This is usually DECL_ALIGN_UNIT for decls and + MALLOC_ABI_ALIGNMENT for allocated storage. */ + unsigned int align; + + /* The byte offset this pointer differs from the above alignment. */ + unsigned int misalign; }; diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index a95d78caca1..eddb9b987c3 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -368,27 +368,6 @@ debug_alias_info (void) } -/* Return the alias information associated with pointer T. It creates a - new instance if none existed. */ - -struct ptr_info_def * -get_ptr_info (tree t) -{ - struct ptr_info_def *pi; - - gcc_assert (POINTER_TYPE_P (TREE_TYPE (t))); - - pi = SSA_NAME_PTR_INFO (t); - if (pi == NULL) - { - pi = ggc_alloc_cleared_ptr_info_def (); - pt_solution_reset (&pi->pt); - SSA_NAME_PTR_INFO (t) = pi; - } - - return pi; -} - /* Dump the points-to set *PT into FILE. */ void diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 622fe146315..5551df2d5a3 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -839,8 +839,40 @@ static bool ccp_finalize (void) { bool something_changed; + unsigned i; do_dbg_cnt (); + + /* Derive alignment and misalignment information from partially + constant pointers in the lattice. */ + for (i = 1; i < num_ssa_names; ++i) + { + tree name = ssa_name (i); + prop_value_t *val; + struct ptr_info_def *pi; + unsigned int tem, align; + + if (!name + || !POINTER_TYPE_P (TREE_TYPE (name))) + continue; + + val = get_value (name); + if (val->lattice_val != CONSTANT + || TREE_CODE (val->value) != INTEGER_CST) + continue; + + /* Trailing constant bits specify the alignment, trailing value + bits the misalignment. */ + tem = val->mask.low; + align = (tem & -tem); + if (align == 1) + continue; + + pi = get_ptr_info (name); + pi->align = align; + pi->misalign = TREE_INT_CST_LOW (val->value) & (align - 1); + } + /* Perform substitutions based on the known constant values. */ something_changed = substitute_and_fold (get_constant_value, ccp_fold_stmt, true); @@ -1981,6 +2013,7 @@ evaluate_stmt (gimple stmt) && !is_constant) { enum gimple_code code = gimple_code (stmt); + tree fndecl; val.lattice_val = VARYING; val.value = NULL_TREE; val.mask = double_int_minus_one; @@ -2026,6 +2059,33 @@ evaluate_stmt (gimple stmt) || POINTER_TYPE_P (TREE_TYPE (rhs1))) val = bit_value_binop (code, TREE_TYPE (rhs1), rhs1, rhs2); } + else if (code == GIMPLE_CALL + && (fndecl = gimple_call_fndecl (stmt)) + && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) + { + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_MALLOC: + case BUILT_IN_REALLOC: + case BUILT_IN_CALLOC: + val.lattice_val = CONSTANT; + val.value = build_int_cst (TREE_TYPE (gimple_get_lhs (stmt)), 0); + val.mask = shwi_to_double_int + (~(((HOST_WIDE_INT) MALLOC_ABI_ALIGNMENT) + / BITS_PER_UNIT - 1)); + break; + + case BUILT_IN_ALLOCA: + val.lattice_val = CONSTANT; + val.value = build_int_cst (TREE_TYPE (gimple_get_lhs (stmt)), 0); + val.mask = shwi_to_double_int + (~(((HOST_WIDE_INT) BIGGEST_ALIGNMENT) + / BITS_PER_UNIT - 1)); + break; + + default:; + } + } is_constant = (val.lattice_val == CONSTANT); } diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c index 79b844ffe7c..0d63fe9fe63 100644 --- a/gcc/tree-ssanames.c +++ b/gcc/tree-ssanames.c @@ -240,20 +240,29 @@ release_ssa_name (tree var) } } -/* Creates a duplicate of a ssa name NAME defined in statement STMT. */ -tree -duplicate_ssa_name (tree name, gimple stmt) +/* Return the alias information associated with pointer T. It creates a + new instance if none existed. */ + +struct ptr_info_def * +get_ptr_info (tree t) { - tree new_name = make_ssa_name (SSA_NAME_VAR (name), stmt); - struct ptr_info_def *old_ptr_info = SSA_NAME_PTR_INFO (name); + struct ptr_info_def *pi; - if (old_ptr_info) - duplicate_ssa_name_ptr_info (new_name, old_ptr_info); + gcc_assert (POINTER_TYPE_P (TREE_TYPE (t))); - return new_name; -} + pi = SSA_NAME_PTR_INFO (t); + if (pi == NULL) + { + pi = ggc_alloc_cleared_ptr_info_def (); + pt_solution_reset (&pi->pt); + pi->align = 1; + pi->misalign = 0; + SSA_NAME_PTR_INFO (t) = pi; + } + return pi; +} /* Creates a duplicate of the ptr_info_def at PTR_INFO for use by the SSA name NAME. */ @@ -276,6 +285,21 @@ duplicate_ssa_name_ptr_info (tree name, struct ptr_info_def *ptr_info) } +/* Creates a duplicate of a ssa name NAME tobe defined by statement STMT. */ + +tree +duplicate_ssa_name (tree name, gimple stmt) +{ + tree new_name = make_ssa_name (SSA_NAME_VAR (name), stmt); + struct ptr_info_def *old_ptr_info = SSA_NAME_PTR_INFO (name); + + if (old_ptr_info) + duplicate_ssa_name_ptr_info (new_name, old_ptr_info); + + return new_name; +} + + /* Release all the SSA_NAMEs created by STMT. */ void diff --git a/gcc/tree.h b/gcc/tree.h index bdf4f727c45..9a3c93d356f 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -5033,7 +5033,7 @@ extern tree build_string_literal (int, const char *); extern bool validate_arglist (const_tree, ...); extern rtx builtin_memset_read_str (void *, HOST_WIDE_INT, enum machine_mode); extern bool can_trust_pointer_alignment (void); -extern int get_pointer_alignment (tree, unsigned int); +extern unsigned int get_pointer_alignment (tree, unsigned int); extern bool is_builtin_name (const char *); extern bool is_builtin_fn (tree); extern unsigned int get_object_alignment (tree, unsigned int); -- cgit v1.2.1