diff options
author | Richard Guenther <rguenther@suse.de> | 2010-08-10 09:16:22 +0000 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2010-08-10 09:16:22 +0000 |
commit | e80c2726d26a882c2ef35108b46aa5981a7a4513 (patch) | |
tree | 69f85b0d583ceda0fdc88c84ebf0b408827b5505 /gcc/builtins.c | |
parent | a024390f71187444954cc0001bdea390fb31551f (diff) | |
download | gcc-e80c2726d26a882c2ef35108b46aa5981a7a4513.zip gcc-e80c2726d26a882c2ef35108b46aa5981a7a4513.tar.gz gcc-e80c2726d26a882c2ef35108b46aa5981a7a4513.tar.bz2 |
tree.h (get_object_alignment): Adjust prototype.
2010-08-10 Richard Guenther <rguenther@suse.de>
* tree.h (get_object_alignment): Adjust prototype.
* builtins.c (get_object_alignment): Return unsigned int,
drop the align parameter. Handle MEM_REF, MISALIGNED_INDIRECT_REF
and TARGET_MEM_REF properly.
(get_pointer_alignment): Adjust.
* emit-rtl.c (get_mem_align_offset): Adjust comment.
(set_mem_attributes_minus_bitpos): Adjust.
* tree-ssa-ccp.c (get_value_from_alignment): Adjust.
From-SVN: r163051
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r-- | gcc/builtins.c | 184 |
1 files changed, 119 insertions, 65 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index 3b9ca5a..3d5ca33 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -267,81 +267,135 @@ called_as_built_in (tree node) } /* Return the alignment in bits of EXP, an object. - Don't return more than MAX_ALIGN no matter what, ALIGN is the inital - guessed alignment e.g. from type alignment. */ + Don't return more than MAX_ALIGN no matter what. */ -int -get_object_alignment (tree exp, unsigned int align, unsigned int max_align) +unsigned int +get_object_alignment (tree exp, unsigned int max_align) { - unsigned int inner; - - inner = max_align; - if (handled_component_p (exp)) - { - HOST_WIDE_INT bitsize, bitpos; - tree offset; - enum machine_mode mode; - int unsignedp, volatilep; + HOST_WIDE_INT bitsize, bitpos; + tree offset; + enum machine_mode mode; + int unsignedp, volatilep; + unsigned int align, inner; - exp = get_inner_reference (exp, &bitsize, &bitpos, &offset, - &mode, &unsignedp, &volatilep, true); - if (bitpos) - inner = MIN (inner, (unsigned) (bitpos & -bitpos)); - while (offset) - { - tree next_offset; + /* Get the innermost object and the constant (bitpos) and possibly + variable (offset) offset of the access. */ + exp = get_inner_reference (exp, &bitsize, &bitpos, &offset, + &mode, &unsignedp, &volatilep, true); - if (TREE_CODE (offset) == PLUS_EXPR) - { - next_offset = TREE_OPERAND (offset, 0); - offset = TREE_OPERAND (offset, 1); - } - else - next_offset = NULL; - if (host_integerp (offset, 1)) - { - /* Any overflow in calculating offset_bits won't change - the alignment. */ - unsigned offset_bits - = ((unsigned) tree_low_cst (offset, 1) * BITS_PER_UNIT); - - if (offset_bits) - inner = MIN (inner, (offset_bits & -offset_bits)); - } - else if (TREE_CODE (offset) == MULT_EXPR - && host_integerp (TREE_OPERAND (offset, 1), 1)) - { - /* Any overflow in calculating offset_factor won't change - the alignment. */ - unsigned offset_factor - = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1) - * BITS_PER_UNIT); - - if (offset_factor) - inner = MIN (inner, (offset_factor & -offset_factor)); - } - else - { - inner = MIN (inner, BITS_PER_UNIT); - break; - } - offset = next_offset; - } - } + /* Extract alignment information from the innermost object and + possibly adjust bitpos and offset. */ if (TREE_CODE (exp) == CONST_DECL) exp = DECL_INITIAL (exp); if (DECL_P (exp) && TREE_CODE (exp) != LABEL_DECL) - align = MIN (inner, DECL_ALIGN (exp)); -#ifdef CONSTANT_ALIGNMENT + align = DECL_ALIGN (exp); else if (CONSTANT_CLASS_P (exp)) - align = MIN (inner, (unsigned)CONSTANT_ALIGNMENT (exp, align)); + { + align = TYPE_ALIGN (TREE_TYPE (exp)); +#ifdef CONSTANT_ALIGNMENT + align = (unsigned)CONSTANT_ALIGNMENT (exp, align); #endif - else if (TREE_CODE (exp) == VIEW_CONVERT_EXPR - || TREE_CODE (exp) == INDIRECT_REF) - align = MIN (TYPE_ALIGN (TREE_TYPE (exp)), inner); + } + else if (TREE_CODE (exp) == VIEW_CONVERT_EXPR) + align = TYPE_ALIGN (TREE_TYPE (exp)); + else if (TREE_CODE (exp) == INDIRECT_REF) + align = TYPE_ALIGN (TREE_TYPE (exp)); + else if (TREE_CODE (exp) == MISALIGNED_INDIRECT_REF) + { + tree op1 = TREE_OPERAND (exp, 1); + align = integer_zerop (op1) ? BITS_PER_UNIT : TREE_INT_CST_LOW (op1); + } + else if (TREE_CODE (exp) == MEM_REF) + { + tree addr = TREE_OPERAND (exp, 0); + 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) == 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_SYMBOL (exp)) + { + align = get_object_alignment (TMR_SYMBOL (exp), 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 - align = MIN (align, inner); + align = BITS_PER_UNIT; + + /* If there is a non-constant offset part extract the maximum + alignment that can prevail. */ + inner = max_align; + while (offset) + { + tree next_offset; + + if (TREE_CODE (offset) == PLUS_EXPR) + { + next_offset = TREE_OPERAND (offset, 0); + offset = TREE_OPERAND (offset, 1); + } + else + next_offset = NULL; + if (host_integerp (offset, 1)) + { + /* Any overflow in calculating offset_bits won't change + the alignment. */ + unsigned offset_bits + = ((unsigned) tree_low_cst (offset, 1) * BITS_PER_UNIT); + + if (offset_bits) + inner = MIN (inner, (offset_bits & -offset_bits)); + } + else if (TREE_CODE (offset) == MULT_EXPR + && host_integerp (TREE_OPERAND (offset, 1), 1)) + { + /* Any overflow in calculating offset_factor won't change + the alignment. */ + unsigned offset_factor + = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1) + * BITS_PER_UNIT); + + if (offset_factor) + inner = MIN (inner, (offset_factor & -offset_factor)); + } + else + { + inner = MIN (inner, BITS_PER_UNIT); + break; + } + offset = next_offset; + } + + /* Alignment is innermost object alignment adjusted by the constant + and non-constant offset parts. */ + align = MIN (align, inner); + bitpos = bitpos & (align - 1); + + /* align and bitpos now specify known low bits of the pointer. + ptr & (align - 1) == bitpos. */ + + if (bitpos != 0) + align = (bitpos & -bitpos); + return MIN (align, max_align); } @@ -407,7 +461,7 @@ get_pointer_alignment (tree exp, unsigned int max_align) case ADDR_EXPR: /* See what we are pointing at and look at its alignment. */ - return get_object_alignment (TREE_OPERAND (exp, 0), align, max_align); + return get_object_alignment (TREE_OPERAND (exp, 0), max_align); default: return align; |