on the address at which an object is actually located.  These two
    addresses are not always the same.  For example, on ARM targets,
    the address &foo of a Thumb function foo() has the lowest bit set,
-   whereas foo() itself starts on an even address.  */
+   whereas foo() itself starts on an even address.
 
-bool
-get_object_alignment_1 (tree exp, unsigned int *alignp,
-                       unsigned HOST_WIDE_INT *bitposp)
+   If ADDR_P is true we are taking the address of the memory reference EXP
+   and thus cannot rely on the access taking place.  */
+
+static bool
+get_object_alignment_2 (tree exp, unsigned int *alignp,
+                       unsigned HOST_WIDE_INT *bitposp, bool addr_p)
 {
   HOST_WIDE_INT bitsize, bitpos;
   tree 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)
-    {
-      if (TREE_CODE (exp) == FUNCTION_DECL)
-       {
-         /* Function addresses can encode extra information besides their
-            alignment.  However, if TARGET_PTRMEMFUNC_VBIT_LOCATION
-            allows the low bit to be used as a virtual bit, we know
-            that the address itself must be 2-byte aligned.  */
-         if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn)
-           {
-             known_alignment = true;
-             align = 2 * BITS_PER_UNIT;
-           }
-       }
-      else
-       {
-         known_alignment = true;
-         align = DECL_ALIGN (exp);
-       }
+  if (TREE_CODE (exp) == FUNCTION_DECL)
+    {
+      /* Function addresses can encode extra information besides their
+        alignment.  However, if TARGET_PTRMEMFUNC_VBIT_LOCATION
+        allows the low bit to be used as a virtual bit, we know
+        that the address itself must be at least 2-byte aligned.  */
+      if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn)
+       align = 2 * BITS_PER_UNIT;
     }
-  else if (CONSTANT_CLASS_P (exp))
+  else if (TREE_CODE (exp) == LABEL_DECL)
+    ;
+  else if (TREE_CODE (exp) == CONST_DECL)
     {
-      known_alignment = true;
+      /* The alignment of a CONST_DECL is determined by its initializer.  */
+      exp = DECL_INITIAL (exp);
       align = TYPE_ALIGN (TREE_TYPE (exp));
 #ifdef CONSTANT_ALIGNMENT
-      align = (unsigned)CONSTANT_ALIGNMENT (exp, align);
+      if (CONSTANT_CLASS_P (exp))
+       align = (unsigned) CONSTANT_ALIGNMENT (exp, align);
 #endif
+      known_alignment = true;
     }
-  else if (TREE_CODE (exp) == VIEW_CONVERT_EXPR)
+  else if (DECL_P (exp))
     {
+      align = DECL_ALIGN (exp);
       known_alignment = true;
-      align = TYPE_ALIGN (TREE_TYPE (exp));
     }
-  else if (TREE_CODE (exp) == INDIRECT_REF)
+  else if (TREE_CODE (exp) == VIEW_CONVERT_EXPR)
     {
-      known_alignment = true;
       align = TYPE_ALIGN (TREE_TYPE (exp));
     }
-  else if (TREE_CODE (exp) == MEM_REF)
+  else if (TREE_CODE (exp) == INDIRECT_REF
+          || TREE_CODE (exp) == MEM_REF
+          || TREE_CODE (exp) == TARGET_MEM_REF)
     {
       tree addr = TREE_OPERAND (exp, 0);
       unsigned ptr_align;
       if (TREE_CODE (addr) == BIT_AND_EXPR
          && TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST)
        {
-         known_alignment = true;
          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);
        }
 
-      if (get_pointer_alignment_1 (addr, &ptr_align, &ptr_bitpos))
+      known_alignment
+       = get_pointer_alignment_1 (addr, &ptr_align, &ptr_bitpos);
+      bitpos += ptr_bitpos;
+      align = MAX (ptr_align, align);
+
+      if (TREE_CODE (exp) == MEM_REF
+         || TREE_CODE (exp) == TARGET_MEM_REF)
+       bitpos += mem_ref_offset (exp).low * BITS_PER_UNIT;
+      if (TREE_CODE (exp) == TARGET_MEM_REF)
        {
-         known_alignment = true;
-         bitpos += ptr_bitpos & ~(align - 1);
-         align = MAX (ptr_align, align);
+         if (TMR_INDEX (exp))
+           {
+             unsigned HOST_WIDE_INT step = 1;
+             if (TMR_STEP (exp))
+               step = TREE_INT_CST_LOW (TMR_STEP (exp));
+             align = MIN (align, (step & -step) * BITS_PER_UNIT);
+           }
+         if (TMR_INDEX2 (exp))
+           align = BITS_PER_UNIT;
+         known_alignment = false;
        }
 
-      bitpos += mem_ref_offset (exp).low * BITS_PER_UNIT;
+      /* When EXP is an actual memory reference then we can use
+        TYPE_ALIGN of a pointer indirection to derive alignment.
+        Do so only if get_pointer_alignment_1 did not reveal absolute
+        alignment knowledge.  */
+      if (!addr_p && !known_alignment)
+       align = MAX (TYPE_ALIGN (TREE_TYPE (exp)), align);
     }
-  else if (TREE_CODE (exp) == TARGET_MEM_REF)
+  else if (TREE_CODE (exp) == STRING_CST)
     {
-      unsigned ptr_align;
-      unsigned HOST_WIDE_INT ptr_bitpos;
-      tree addr = TMR_BASE (exp);
-
-      if (TREE_CODE (addr) == BIT_AND_EXPR
-         && TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST)
-       {
-         known_alignment = true;
-         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);
-       }
-
-      if (get_pointer_alignment_1 (addr, &ptr_align, &ptr_bitpos))
-       {
-         known_alignment = true;
-         bitpos += ptr_bitpos & ~(align - 1);
-         align = MAX (ptr_align, 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);
-         known_alignment = true;
-       }
-      else if (TMR_INDEX (exp))
-       known_alignment = false;
-
-      if (TMR_INDEX2 (exp))
-       known_alignment = false;
+      /* STRING_CST are the only constant objects we allow to be not
+         wrapped inside a CONST_DECL.  */
+      align = TYPE_ALIGN (TREE_TYPE (exp));
+#ifdef CONSTANT_ALIGNMENT
+      if (CONSTANT_CLASS_P (exp))
+       align = (unsigned) CONSTANT_ALIGNMENT (exp, align);
+#endif
+      known_alignment = true;
     }
 
   /* If there is a non-constant offset part extract the maximum
        }
       else
        {
-         known_alignment = false;
+         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);
 
-  if (known_alignment)
-    {
-      /* Alignment is innermost object alignment adjusted by the constant
-        and non-constant offset parts.  */
-      align = MIN (align, inner);
-      bitpos = bitpos & (align - 1);
-      *alignp = align;
-    }
-  else
-    {
-      bitpos = bitpos & (BITS_PER_UNIT - 1);
-      *alignp = BITS_PER_UNIT;
-    }
-  *bitposp = bitpos;
+  *alignp = align;
+  *bitposp = bitpos & (*alignp - 1);
   return known_alignment;
 }
 
+/* For a memory reference expression EXP compute values M and N such that M
+   divides (&EXP - N) and such that N < M.  If these numbers can be determined,
+   store M in alignp and N in *BITPOSP and return true.  Otherwise return false
+   and store BITS_PER_UNIT to *alignp and any bit-offset to *bitposp.  */
+
+bool
+get_object_alignment_1 (tree exp, unsigned int *alignp,
+                       unsigned HOST_WIDE_INT *bitposp)
+{
+  return get_object_alignment_2 (exp, alignp, bitposp, false);
+}
+
 /* Return the alignment in bits of EXP, an object.  */
 
 unsigned int
   return align;
 }
 
-/* Return the alignment of object EXP, also considering its type when we do
-   not know of explicit misalignment.  Only handle MEM_REF and TARGET_MEM_REF.
-
-   ??? Note that, in the general case, the type of an expression is not kept
-   consistent with misalignment information by the front-end, for example when
-   taking the address of a member of a packed structure.  However, in most of
-   the cases, expressions have the alignment of their type so we optimistically
-   fall back to this alignment when we cannot compute a misalignment.  */
-
-unsigned int
-get_object_or_type_alignment (tree exp)
-{
-  unsigned HOST_WIDE_INT misalign;
-  unsigned int align;
-  bool known_alignment;
-
-  gcc_assert (TREE_CODE (exp) == MEM_REF || TREE_CODE (exp) == TARGET_MEM_REF);
-  known_alignment = get_object_alignment_1 (exp, &align, &misalign);
-  if (misalign != 0)
-    align = (misalign & -misalign);
-  else if (!known_alignment)
-    align = TYPE_ALIGN (TREE_TYPE (exp));
-
-  return align;
-}
-
 /* For a pointer valued expression EXP compute values M and N such that M
    divides (EXP - N) and such that N < M.  If these numbers can be determined,
-   store M in alignp and N in *BITPOSP and return true.  Otherwise return false
-   and store BITS_PER_UNIT to *alignp and any bit-offset to *bitposp.
+   store M in alignp and N in *BITPOSP and return true.  Return false if
+   the results are just a conservative approximation.
 
    If EXP is not a pointer, false is returned too.  */
 
   STRIP_NOPS (exp);
 
   if (TREE_CODE (exp) == ADDR_EXPR)
-    return get_object_alignment_1 (TREE_OPERAND (exp, 0), alignp, bitposp);
+    return get_object_alignment_2 (TREE_OPERAND (exp, 0),
+                                  alignp, bitposp, true);
   else if (TREE_CODE (exp) == SSA_NAME
           && POINTER_TYPE_P (TREE_TYPE (exp)))
     {
        {
          *bitposp = ptr_misalign * BITS_PER_UNIT;
          *alignp = ptr_align * BITS_PER_UNIT;
+         /* We cannot really tell whether this result is an approximation.  */
          return true;
        }
       else