(with { tree algn = wide_int_to_tree (TREE_TYPE (@0), ~wi::to_wide (@1)); }
(bit_and @0 { algn; })))
+/* Also match cases in which a constant is applied:
+
+ (1) tem = (sizetype) ptr; ---> tem = (sizetype) (ptr + CST);
+ (2) tem = -tem ---> tem = CST - tem;
+
+ and where "& align" masks only trailing zeros of CST. (1) then has no
+ effect, whereas (2) adds CST to the result. */
+(simplify
+ (pointer_plus @0 (negate (bit_and (convert (pointer_plus @0 INTEGER_CST@1))
+ INTEGER_CST@2)))
+ (if (tree_int_cst_min_precision (@2, UNSIGNED) <= tree_ctz (@1))
+ (with { tree algn = wide_int_to_tree (TREE_TYPE (@0), ~wi::to_wide (@2)); }
+ (bit_and @0 { algn; }))))
+(simplify
+ (pointer_plus @0 (minus:s INTEGER_CST@1 (bit_and (convert @0) INTEGER_CST@2)))
+ (if (tree_int_cst_min_precision (@2, UNSIGNED) <= tree_ctz (@1))
+ (with { tree algn = wide_int_to_tree (TREE_TYPE (@0), ~wi::to_wide (@2)); }
+ (pointer_plus (bit_and @0 { algn; }) @1))))
+(simplify
+ (pointer_plus @0 (minus:s INTEGER_CST@1
+ (bit_and (convert (pointer_plus @0 INTEGER_CST@2))
+ INTEGER_CST@3)))
+ (with { auto mask_width = tree_int_cst_min_precision (@3, UNSIGNED); }
+ (if (mask_width <= tree_ctz (@1) && mask_width <= tree_ctz (@2))
+ (with { tree algn = wide_int_to_tree (TREE_TYPE (@0), ~wi::to_wide (@3)); }
+ (pointer_plus (bit_and @0 { algn; }) @1)))))
+
/* Try folding difference of addresses. */
(simplify
(minus (convert ADDR_EXPR@0) (convert (pointer_plus @1 @2)))
--- /dev/null
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* { dg-final { scan-tree-dump-times { & -16B?;} 4 "optimized" { target lp64 } } } */
+/* { dg-final { scan-tree-dump-times { \+ 16;} 3 "optimized" } } */
+/* { dg-final { scan-tree-dump-not { & 15;} "optimized" } } */
+/* { dg-final { scan-tree-dump-not { \+ 96;} "optimized" } } */
+
+typedef __UINTPTR_TYPE__ uintptr_t;
+
+char *
+f1 (char *x)
+{
+ char *y = x + 32;
+ x += -((uintptr_t) y & 15);
+ return x;
+}
+
+char *
+f2 (char *x)
+{
+ x += 16 - ((uintptr_t) x & 15);
+ return x;
+}
+
+char *
+f3 (char *x)
+{
+ char *y = x + 32;
+ x += 16 - ((uintptr_t) y & 15);
+ return x;
+}
+
+char *
+f4 (char *x)
+{
+ char *y = x + 16;
+ x += 16 - ((uintptr_t) y & 15);
+ return x;
+}
--- /dev/null
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* { dg-final { scan-tree-dump-not { & -16B?;} "optimized" } } */
+/* { dg-final { scan-tree-dump-times { & 15;} 10 "optimized" } } */
+
+typedef __UINTPTR_TYPE__ uintptr_t;
+
+char *
+f1 (char *x)
+{
+ char *y = x + 97;
+ x += -((uintptr_t) y & 15);
+ return x;
+}
+
+char *
+f2 (char *x)
+{
+ char *y = x + 98;
+ x += -((uintptr_t) y & 15);
+ return x;
+}
+
+char *
+f3 (char *x)
+{
+ char *y = x + 100;
+ x += -((uintptr_t) y & 15);
+ return x;
+}
+
+char *
+f4 (char *x)
+{
+ char *y = x + 104;
+ x += -((uintptr_t) y & 15);
+ return x;
+}
+
+char *
+f5 (char *x)
+{
+ x += 1 - ((uintptr_t) x & 15);
+ return x;
+}
+
+char *
+f6 (char *x)
+{
+ x += 2 - ((uintptr_t) x & 15);
+ return x;
+}
+
+char *
+f7 (char *x)
+{
+ x += 4 - ((uintptr_t) x & 15);
+ return x;
+}
+
+char *
+f8 (char *x)
+{
+ x += 8 - ((uintptr_t) x & 15);
+ return x;
+}
+
+char *
+f9 (char *x)
+{
+ char *y = x + 8;
+ x += 16 - ((uintptr_t) y & 15);
+ return x;
+}
+
+char *
+f10 (char *x)
+{
+ char *y = x + 16;
+ x += 8 - ((uintptr_t) y & 15);
+ return x;
+}