From 8fcbce729d0ccd6881e479af9eec694abec61ee5 Mon Sep 17 00:00:00 2001
From: Jakub Jelinek <jakub@redhat.com>
Date: Sat, 8 Feb 2014 10:09:01 +0100
Subject: [PATCH] re PR middle-end/60092 (posix_memalign not recognized to
 derive alias and alignment info)

	PR middle-end/60092
	* tree-ssa-ccp.c (surely_varying_stmt_p): Don't return true
	if TYPE_ATTRIBUTES (gimple_call_fntype ()) contain
	assume_aligned or alloc_align attributes.
	(bit_value_assume_aligned): Add ATTR, PTRVAL and ALLOC_ALIGN
	arguments.  Handle also assume_aligned and alloc_align attributes.
	(evaluate_stmt): Adjust bit_value_assume_aligned caller.
	Handle calls to functions with assume_aligned or alloc_align
	attributes.
	* doc/extend.texi: Document assume_aligned and alloc_align
	attributes.
c-family/
	* c-common.c (handle_alloc_size_attribute): Use tree_fits_uhwi_p
	and tree_to_uhwi.
	(handle_alloc_align_attribute, handle_assume_aligned_attribute): New
	functions.
	(c_common_attribute_table): Add alloc_align and assume_aligned
	attributes.
testsuite/
	* gcc.dg/attr-alloc_align-1.c: New test.
	* gcc.dg/attr-alloc_align-2.c: New test.
	* gcc.dg/attr-alloc_align-3.c: New test.
	* gcc.dg/attr-assume_aligned-1.c: New test.
	* gcc.dg/attr-assume_aligned-2.c: New test.
	* gcc.dg/attr-assume_aligned-3.c: New test.

From-SVN: r207628
---
 gcc/ChangeLog                                |  14 +++
 gcc/c-family/ChangeLog                       |  10 ++
 gcc/c-family/c-common.c                      |  62 ++++++++++-
 gcc/doc/extend.texi                          |  44 +++++++-
 gcc/testsuite/ChangeLog                      |  10 ++
 gcc/testsuite/gcc.dg/attr-alloc_align-1.c    |  39 +++++++
 gcc/testsuite/gcc.dg/attr-alloc_align-2.c    |  10 ++
 gcc/testsuite/gcc.dg/attr-alloc_align-3.c    |  56 ++++++++++
 gcc/testsuite/gcc.dg/attr-assume_aligned-1.c |  39 +++++++
 gcc/testsuite/gcc.dg/attr-assume_aligned-2.c |   8 ++
 gcc/testsuite/gcc.dg/attr-assume_aligned-3.c |  24 ++++
 gcc/tree-ssa-ccp.c                           | 110 +++++++++++++++----
 12 files changed, 398 insertions(+), 28 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/attr-alloc_align-1.c
 create mode 100644 gcc/testsuite/gcc.dg/attr-alloc_align-2.c
 create mode 100644 gcc/testsuite/gcc.dg/attr-alloc_align-3.c
 create mode 100644 gcc/testsuite/gcc.dg/attr-assume_aligned-1.c
 create mode 100644 gcc/testsuite/gcc.dg/attr-assume_aligned-2.c
 create mode 100644 gcc/testsuite/gcc.dg/attr-assume_aligned-3.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a5a83ef3dff5..2b9464a3d6df 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,17 @@
+2014-02-08  Jakub Jelinek  <jakub@redhat.com>
+
+	PR middle-end/60092
+	* tree-ssa-ccp.c (surely_varying_stmt_p): Don't return true
+	if TYPE_ATTRIBUTES (gimple_call_fntype ()) contain
+	assume_aligned or alloc_align attributes.
+	(bit_value_assume_aligned): Add ATTR, PTRVAL and ALLOC_ALIGN
+	arguments.  Handle also assume_aligned and alloc_align attributes.
+	(evaluate_stmt): Adjust bit_value_assume_aligned caller.
+	Handle calls to functions with assume_aligned or alloc_align
+	attributes.
+	* doc/extend.texi: Document assume_aligned and alloc_align
+	attributes.
+
 2014-02-08  Terry Guo  <terry.guo@arm.com>
 
 	* doc/invoke.texi: Document ARM -march=armv7e-m.
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 1e61bc341a7c..ba14b99da074 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,13 @@
+2014-02-08  Jakub Jelinek  <jakub@redhat.com>
+
+	PR middle-end/60092
+	* c-common.c (handle_alloc_size_attribute): Use tree_fits_uhwi_p
+	and tree_to_uhwi.
+	(handle_alloc_align_attribute, handle_assume_aligned_attribute): New
+	functions.
+	(c_common_attribute_table): Add alloc_align and assume_aligned
+	attributes.
+
 2014-02-06  Marek Polacek  <polacek@redhat.com>
 
 	PR c/60087
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 50cc848fe902..5cf285bc5827 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -366,6 +366,8 @@ static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
 static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
 static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
 static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *);
+static tree handle_alloc_align_attribute (tree *, tree, tree, int, bool *);
+static tree handle_assume_aligned_attribute (tree *, tree, tree, int, bool *);
 static tree handle_target_attribute (tree *, tree, tree, int, bool *);
 static tree handle_optimize_attribute (tree *, tree, tree, int, bool *);
 static tree ignore_attribute (tree *, tree, tree, int, bool *);
@@ -766,6 +768,10 @@ const struct attribute_spec c_common_attribute_table[] =
 			      handle_omp_declare_simd_attribute, false },
   { "omp declare target",     0, 0, true, false, false,
 			      handle_omp_declare_target_attribute, false },
+  { "alloc_align",	      1, 1, false, true, true,
+			      handle_alloc_align_attribute, false },
+  { "assume_aligned",	      1, 2, false, true, true,
+			      handle_assume_aligned_attribute, false },
   { NULL,                     0, 0, false, false, false, NULL, false }
 };
 
@@ -8043,10 +8049,9 @@ handle_alloc_size_attribute (tree *node, tree ARG_UNUSED (name), tree args,
 	  && TREE_CODE (position) != FUNCTION_DECL)
 	position = default_conversion (position);
 
-      if (TREE_CODE (position) != INTEGER_CST
-	  || TREE_INT_CST_HIGH (position)
-	  || TREE_INT_CST_LOW (position) < 1
-	  || TREE_INT_CST_LOW (position) > arg_count )
+      if (!tree_fits_uhwi_p (position)
+	  || !arg_count
+	  || !IN_RANGE (tree_to_uhwi (position), 1, arg_count))
 	{
 	  warning (OPT_Wattributes,
 	           "alloc_size parameter outside range");
@@ -8057,6 +8062,55 @@ handle_alloc_size_attribute (tree *node, tree ARG_UNUSED (name), tree args,
   return NULL_TREE;
 }
 
+/* Handle a "alloc_align" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_alloc_align_attribute (tree *node, tree, tree args, int,
+			      bool *no_add_attrs)
+{
+  unsigned arg_count = type_num_arguments (*node);
+  tree position = TREE_VALUE (args);
+  if (position && TREE_CODE (position) != IDENTIFIER_NODE)
+    position = default_conversion (position);
+
+  if (!tree_fits_uhwi_p (position)
+      || !arg_count
+      || !IN_RANGE (tree_to_uhwi (position), 1, arg_count))
+    {
+      warning (OPT_Wattributes,
+	       "alloc_align parameter outside range");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  return NULL_TREE;
+}
+
+/* Handle a "assume_aligned" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_assume_aligned_attribute (tree *, tree, tree args, int,
+				 bool *no_add_attrs)
+{
+  for (; args; args = TREE_CHAIN (args))
+    {
+      tree position = TREE_VALUE (args);
+      if (position && TREE_CODE (position) != IDENTIFIER_NODE
+	  && TREE_CODE (position) != FUNCTION_DECL)
+	position = default_conversion (position);
+
+      if (TREE_CODE (position) != INTEGER_CST)
+	{
+	  warning (OPT_Wattributes,
+		   "assume_aligned parameter not integer constant");
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+    }
+  return NULL_TREE;
+}
+
 /* Handle a "fn spec" attribute; arguments as in
    struct attribute_spec.handler.  */
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index a42e90490c0b..a969fb4939c3 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -2154,8 +2154,8 @@ The keyword @code{__attribute__} allows you to specify special
 attributes when making a declaration.  This keyword is followed by an
 attribute specification inside double parentheses.  The following
 attributes are currently defined for functions on all targets:
-@code{aligned}, @code{alloc_size}, @code{noreturn},
-@code{returns_twice}, @code{noinline}, @code{noclone},
+@code{aligned}, @code{alloc_size}, @code{alloc_align}, @code{assume_aligned},
+@code{noreturn}, @code{returns_twice}, @code{noinline}, @code{noclone},
 @code{always_inline}, @code{flatten}, @code{pure}, @code{const},
 @code{nothrow}, @code{sentinel}, @code{format}, @code{format_arg},
 @code{no_instrument_function}, @code{no_split_stack},
@@ -2249,6 +2249,46 @@ declares that @code{my_calloc} returns memory of the size given by
 the product of parameter 1 and 2 and that @code{my_realloc} returns memory
 of the size given by parameter 2.
 
+@item alloc_align
+@cindex @code{alloc_align} attribute
+The @code{alloc_align} attribute is used to tell the compiler that the
+function return value points to memory, where the returned pointer minimum
+alignment is given by one of the functions parameters.  GCC uses this
+information to improve pointer alignment analysis.
+
+The function parameter denoting the allocated alignment is specified by
+one integer argument, whose number is the argument of the attribute.
+Argument numbering starts at one.
+
+For instance,
+
+@smallexample
+void* my_memalign(size_t, size_t) __attribute__((alloc_align(1)))
+@end smallexample
+
+@noindent
+declares that @code{my_memalign} returns memory with minimum alignment
+given by parameter 1.
+
+@item assume_aligned
+@cindex @code{assume_aligned} attribute
+The @code{assume_aligned} attribute is used to tell the compiler that the
+function return value points to memory, where the returned pointer minimum
+alignment is given by the first argument.
+If the attribute has two arguments, the second argument is misalignment offset.
+
+For instance
+
+@smallexample
+void* my_alloc1(size_t) __attribute__((assume_aligned(16)))
+void* my_alloc2(size_t) __attribute__((assume_aligned(32, 8)))
+@end smallexample
+
+@noindent
+declares that @code{my_alloc1} returns 16-byte aligned pointer and
+that @code{my_alloc2} returns a pointer whose value modulo 32 is equal
+to 8.
+
 @item always_inline
 @cindex @code{always_inline} function attribute
 Generally, functions are not inlined unless optimization is specified.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index feca2e21e3a6..274081191219 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,13 @@
+2014-02-08  Jakub Jelinek  <jakub@redhat.com>
+
+	PR middle-end/60092
+	* gcc.dg/attr-alloc_align-1.c: New test.
+	* gcc.dg/attr-alloc_align-2.c: New test.
+	* gcc.dg/attr-alloc_align-3.c: New test.
+	* gcc.dg/attr-assume_aligned-1.c: New test.
+	* gcc.dg/attr-assume_aligned-2.c: New test.
+	* gcc.dg/attr-assume_aligned-3.c: New test.
+
 2014-02-08  Jakub Jelinek  <jakub@redhat.com>
 
 	PR target/60077
diff --git a/gcc/testsuite/gcc.dg/attr-alloc_align-1.c b/gcc/testsuite/gcc.dg/attr-alloc_align-1.c
new file mode 100644
index 000000000000..45f5ec065e45
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/attr-alloc_align-1.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+
+double *my_alloc1 (int len, int align) __attribute__((__alloc_align__ (2)));
+double *my_alloc2 (int align, int len) __attribute__((alloc_align (1)));
+
+void
+test1 (int len, int align)
+{
+  int i;
+  double *__restrict o1 = my_alloc1 (len, 32);
+  double *__restrict o2 = my_alloc1 (len, 32);
+  double *__restrict o3 = my_alloc1 (len, 32);
+  double *__restrict i1 = my_alloc1 (len, 32);
+  double *__restrict i2 = my_alloc1 (len, align);
+  for (i = 0; i < len; ++i)
+    {
+      o1[i] = i1[i] * i2[i];
+      o2[i] = i1[i] + i2[i];
+      o3[i] = i1[i] - i2[i];
+    }
+}
+
+void
+test2 (int len, int align)
+{
+  int i;
+  double *__restrict o1 = my_alloc2 (32, len);
+  double *__restrict o2 = my_alloc2 (32, len);
+  double *__restrict o3 = my_alloc2 (32, len);
+  double *__restrict i1 = my_alloc2 (32, len);
+  double *__restrict i2 = my_alloc2 (align, len);
+  for (i = 0; i < len; ++i)
+    {
+      o1[i] = i1[i] * i2[i];
+      o2[i] = i1[i] + i2[i];
+      o3[i] = i1[i] - i2[i];
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/attr-alloc_align-2.c b/gcc/testsuite/gcc.dg/attr-alloc_align-2.c
new file mode 100644
index 000000000000..3dc7a219839c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/attr-alloc_align-2.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+
+int i;
+void *f1 (int) __attribute__((alloc_align (1)));
+void *f2 (int, int, int) __attribute__((alloc_align (3)));
+void *f3 (void) __attribute__((alloc_align)); /* { dg-error "wrong number of arguments specified" } */
+void *f4 (int, int) __attribute__((alloc_align (1, 2))); /* { dg-error "wrong number of arguments specified" } */
+void *f5 (void) __attribute__((alloc_align (i))); /* { dg-warning "outside range" } */
+void *f6 (int) __attribute__((alloc_align (0))); /* { dg-warning "outside range" } */
+void *f7 (int) __attribute__((alloc_align (2))); /* { dg-warning "outside range" } */
diff --git a/gcc/testsuite/gcc.dg/attr-alloc_align-3.c b/gcc/testsuite/gcc.dg/attr-alloc_align-3.c
new file mode 100644
index 000000000000..2efe0c0684ab
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/attr-alloc_align-3.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+char *my_alloc1 (int len, int align) __attribute__((__alloc_align__ (2)));
+char *my_alloc2 (int align, int len) __attribute__((alloc_align (1)));
+
+int
+test1 (int len)
+{
+  int i;
+  char *p = my_alloc1 (len, 32);
+  return ((__INTPTR_TYPE__) p) & 31;
+}
+
+int
+test2 (int len)
+{
+  int i;
+  char *p = my_alloc2 (32, len);
+  return ((__INTPTR_TYPE__) p) & 31;
+}
+
+int
+test3 (int len)
+{
+  int i;
+  char *p = my_alloc1 (len, 16);
+  return ((__INTPTR_TYPE__) p) & 15;
+}
+
+int
+test4 (int len)
+{
+  int i;
+  char *p = my_alloc2 (16, len);
+  return ((__INTPTR_TYPE__) p) & 15;
+}
+
+int
+test5 (int len, int align)
+{
+  int i;
+  char *p = my_alloc1 (len, align);
+  return ((__INTPTR_TYPE__) p) & 15;
+}
+
+int
+test6 (int len, int align)
+{
+  int i;
+  char *p = my_alloc2 (align, len);
+  return ((__INTPTR_TYPE__) p) & 15;
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 4 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/attr-assume_aligned-1.c b/gcc/testsuite/gcc.dg/attr-assume_aligned-1.c
new file mode 100644
index 000000000000..9a7d5a1ffe6e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/attr-assume_aligned-1.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+
+double *my_alloc1 (int len) __attribute__((__assume_aligned__ (16)));
+double *my_alloc2 (int len) __attribute__((__assume_aligned__ (32, 16)));
+
+void
+test1 (int len)
+{
+  int i;
+  double *__restrict o1 = my_alloc1 (len);
+  double *__restrict o2 = my_alloc1 (len);
+  double *__restrict o3 = my_alloc1 (len);
+  double *__restrict i1 = my_alloc1 (len);
+  double *__restrict i2 = my_alloc1 (len);
+  for (i = 0; i < len; ++i)
+    {
+      o1[i] = i1[i] * i2[i];
+      o2[i] = i1[i] + i2[i];
+      o3[i] = i1[i] - i2[i];
+    }
+}
+
+void
+test2 (int len)
+{
+  int i;
+  double *__restrict o1 = my_alloc2 (len);
+  double *__restrict o2 = my_alloc2 (len);
+  double *__restrict o3 = my_alloc2 (len);
+  double *__restrict i1 = my_alloc2 (len);
+  double *__restrict i2 = my_alloc2 (len);
+  for (i = 0; i < len; ++i)
+    {
+      o1[i] = i1[i] * i2[i];
+      o2[i] = i1[i] + i2[i];
+      o3[i] = i1[i] - i2[i];
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/attr-assume_aligned-2.c b/gcc/testsuite/gcc.dg/attr-assume_aligned-2.c
new file mode 100644
index 000000000000..9ab558945b37
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/attr-assume_aligned-2.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+
+int i;
+void *f1 (void) __attribute__((assume_aligned (32)));
+void *f2 (void) __attribute__((assume_aligned (16, 4)));
+void *f3 (void) __attribute__((assume_aligned)); /* { dg-error "wrong number of arguments specified" } */
+void *f4 (void) __attribute__((assume_aligned (32, 16, 8))); /* { dg-error "wrong number of arguments specified" } */
+void *f5 (void) __attribute__((assume_aligned (i))); /* { dg-warning "integer constant" } */
diff --git a/gcc/testsuite/gcc.dg/attr-assume_aligned-3.c b/gcc/testsuite/gcc.dg/attr-assume_aligned-3.c
new file mode 100644
index 000000000000..3731aac50eae
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/attr-assume_aligned-3.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+char *my_alloc1 (int len) __attribute__((__assume_aligned__ (32)));
+char *my_alloc2 (int len) __attribute__((assume_aligned (32, 4)));
+
+int
+test1 (int len)
+{
+  int i;
+  char *p = my_alloc1 (len);
+  return ((__INTPTR_TYPE__) p) & 31;
+}
+
+int
+test2 (int len)
+{
+  int i;
+  char *p = my_alloc2 (len);
+  return (((__INTPTR_TYPE__) p) & 31) != 4;
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 2 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index 493bbcb336b9..eeefeaf07240 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -738,13 +738,18 @@ surely_varying_stmt_p (gimple stmt)
     return true;
 
   /* If it is a call and does not return a value or is not a
-     builtin and not an indirect call, it is varying.  */
+     builtin and not an indirect call or a call to function with
+     assume_aligned/alloc_align attribute, it is varying.  */
   if (is_gimple_call (stmt))
     {
-      tree fndecl;
+      tree fndecl, fntype = gimple_call_fntype (stmt);
       if (!gimple_call_lhs (stmt)
 	  || ((fndecl = gimple_call_fndecl (stmt)) != NULL_TREE
-	      && !DECL_BUILT_IN (fndecl)))
+	      && !DECL_BUILT_IN (fndecl)
+	      && !lookup_attribute ("assume_aligned",
+				    TYPE_ATTRIBUTES (fntype))
+	      && !lookup_attribute ("alloc_align",
+				    TYPE_ATTRIBUTES (fntype))))
 	return true;
     }
 
@@ -1476,40 +1481,86 @@ bit_value_binop (enum tree_code code, tree type, tree rhs1, tree rhs2)
   return val;
 }
 
-/* Return the propagation value when applying __builtin_assume_aligned to
-   its arguments.  */
+/* Return the propagation value for __builtin_assume_aligned
+   and functions with assume_aligned or alloc_aligned attribute.
+   For __builtin_assume_aligned, ATTR is NULL_TREE,
+   for assume_aligned attribute ATTR is non-NULL and ALLOC_ALIGNED
+   is false, for alloc_aligned attribute ATTR is non-NULL and
+   ALLOC_ALIGNED is true.  */
 
 static prop_value_t
-bit_value_assume_aligned (gimple stmt)
+bit_value_assume_aligned (gimple stmt, tree attr, prop_value_t ptrval,
+			  bool alloc_aligned)
 {
-  tree ptr = gimple_call_arg (stmt, 0), align, misalign = NULL_TREE;
-  tree type = TREE_TYPE (ptr);
+  tree align, misalign = NULL_TREE, type;
   unsigned HOST_WIDE_INT aligni, misaligni = 0;
-  prop_value_t ptrval = get_value_for_expr (ptr, true);
   prop_value_t alignval;
   double_int value, mask;
   prop_value_t val;
+
+  if (attr == NULL_TREE)
+    {
+      tree ptr = gimple_call_arg (stmt, 0);
+      type = TREE_TYPE (ptr);
+      ptrval = get_value_for_expr (ptr, true);
+    }
+  else
+    {
+      tree lhs = gimple_call_lhs (stmt);
+      type = TREE_TYPE (lhs);
+    }
+
   if (ptrval.lattice_val == UNDEFINED)
     return ptrval;
   gcc_assert ((ptrval.lattice_val == CONSTANT
 	       && TREE_CODE (ptrval.value) == INTEGER_CST)
 	      || ptrval.mask.is_minus_one ());
-  align = gimple_call_arg (stmt, 1);
-  if (!tree_fits_uhwi_p (align))
-    return ptrval;
-  aligni = tree_to_uhwi (align);
-  if (aligni <= 1
-      || (aligni & (aligni - 1)) != 0)
-    return ptrval;
-  if (gimple_call_num_args (stmt) > 2)
+  if (attr == NULL_TREE)
     {
-      misalign = gimple_call_arg (stmt, 2);
-      if (!tree_fits_uhwi_p (misalign))
+      /* Get aligni and misaligni from __builtin_assume_aligned.  */
+      align = gimple_call_arg (stmt, 1);
+      if (!tree_fits_uhwi_p (align))
 	return ptrval;
-      misaligni = tree_to_uhwi (misalign);
-      if (misaligni >= aligni)
+      aligni = tree_to_uhwi (align);
+      if (gimple_call_num_args (stmt) > 2)
+	{
+	  misalign = gimple_call_arg (stmt, 2);
+	  if (!tree_fits_uhwi_p (misalign))
+	    return ptrval;
+	  misaligni = tree_to_uhwi (misalign);
+	}
+    }
+  else
+    {
+      /* Get aligni and misaligni from assume_aligned or
+	 alloc_align attributes.  */
+      if (TREE_VALUE (attr) == NULL_TREE)
+	return ptrval;
+      attr = TREE_VALUE (attr);
+      align = TREE_VALUE (attr);
+      if (!tree_fits_uhwi_p (align))
 	return ptrval;
+      aligni = tree_to_uhwi (align);
+      if (alloc_aligned)
+	{
+	  if (aligni == 0 || aligni > gimple_call_num_args (stmt))
+	    return ptrval;
+	  align = gimple_call_arg (stmt, aligni - 1);
+	  if (!tree_fits_uhwi_p (align))
+	    return ptrval;
+	  aligni = tree_to_uhwi (align);
+	}
+      else if (TREE_CHAIN (attr) && TREE_VALUE (TREE_CHAIN (attr)))
+	{
+	  misalign = TREE_VALUE (TREE_CHAIN (attr));
+	  if (!tree_fits_uhwi_p (misalign))
+	    return ptrval;
+	  misaligni = tree_to_uhwi (misalign);
+	}
     }
+  if (aligni <= 1 || (aligni & (aligni - 1)) != 0 || misaligni >= aligni)
+    return ptrval;
+
   align = build_int_cst_type (type, -aligni);
   alignval = get_value_for_expr (align, true);
   bit_value_binop_1 (BIT_AND_EXPR, type, &value, &mask,
@@ -1708,12 +1759,27 @@ evaluate_stmt (gimple stmt)
 	      break;
 
 	    case BUILT_IN_ASSUME_ALIGNED:
-	      val = bit_value_assume_aligned (stmt);
+	      val = bit_value_assume_aligned (stmt, NULL_TREE, val, false);
 	      break;
 
 	    default:;
 	    }
 	}
+      if (is_gimple_call (stmt) && gimple_call_lhs (stmt))
+	{
+	  tree fntype = gimple_call_fntype (stmt);
+	  if (fntype)
+	    {
+	      tree attrs = lookup_attribute ("assume_aligned",
+					     TYPE_ATTRIBUTES (fntype));
+	      if (attrs)
+		val = bit_value_assume_aligned (stmt, attrs, val, false);
+	      attrs = lookup_attribute ("alloc_align",
+					TYPE_ATTRIBUTES (fntype));
+	      if (attrs)
+		val = bit_value_assume_aligned (stmt, attrs, val, true);
+	    }
+	}
       is_constant = (val.lattice_val == CONSTANT);
     }
 
-- 
GitLab