[llvm] 3978f37 - [InferAlignment] Create tests for InferAlignment pass

Dhruv Chawla via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 19 23:42:35 PDT 2023


Author: Dhruv Chawla
Date: 2023-09-20T12:03:36+05:30
New Revision: 3978f37c0f1e368849ff594d9d603ec600010f7e

URL: https://github.com/llvm/llvm-project/commit/3978f37c0f1e368849ff594d9d603ec600010f7e
DIFF: https://github.com/llvm/llvm-project/commit/3978f37c0f1e368849ff594d9d603ec600010f7e.diff

LOG: [InferAlignment] Create tests for InferAlignment pass

These tests are in preparation for the InferAlignment pass. They consist
mainly of tests that break when alignment inference is disabled in
LoadInst and StoreInst within InstCombine.

Differential Revision: https://reviews.llvm.org/D158530

Added: 
    llvm/test/Transforms/InferAlignment/alloca.ll
    llvm/test/Transforms/InferAlignment/atomic.ll
    llvm/test/Transforms/InferAlignment/attributes.ll
    llvm/test/Transforms/InferAlignment/gep-2d.ll
    llvm/test/Transforms/InferAlignment/gep-array.ll
    llvm/test/Transforms/InferAlignment/irregular-size.ll
    llvm/test/Transforms/InferAlignment/propagate-assume.ll
    llvm/test/Transforms/InferAlignment/ptrmask.ll
    llvm/test/Transforms/InferAlignment/undef-and-null.ll
    llvm/test/Transforms/InferAlignment/vector.ll
    llvm/test/Transforms/InferAlignment/volatile.ll
    llvm/test/Transforms/InferAlignment/vscale.ll

Modified: 
    

Removed: 
    


################################################################################
diff  --git a/llvm/test/Transforms/InferAlignment/alloca.ll b/llvm/test/Transforms/InferAlignment/alloca.ll
new file mode 100644
index 000000000000000..b64413336d347b0
--- /dev/null
+++ b/llvm/test/Transforms/InferAlignment/alloca.ll
@@ -0,0 +1,59 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt < %s -passes=no-op-function -S | FileCheck %s
+
+; ------------------------------------------------------------------------------
+; Scalar type
+; ------------------------------------------------------------------------------
+
+define void @alloca_local(i8 %x, i32 %y) {
+; CHECK-LABEL: define void @alloca_local
+; CHECK-SAME: (i8 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca i32, align 1
+; CHECK-NEXT:    [[LOAD_I8:%.*]] = load i8, ptr [[ALLOCA]], align 1
+; CHECK-NEXT:    [[LOAD_I32:%.*]] = load i32, ptr [[ALLOCA]], align 1
+; CHECK-NEXT:    store i8 [[X]], ptr [[ALLOCA]], align 1
+; CHECK-NEXT:    store i32 [[Y]], ptr [[ALLOCA]], align 1
+; CHECK-NEXT:    ret void
+;
+  %alloca = alloca i32, align 1
+
+  %load.i8 = load i8, ptr %alloca, align 1
+  %load.i32 = load i32, ptr %alloca, align 1
+
+  store i8 %x, ptr %alloca, align 1
+  store i32 %y, ptr %alloca, align 1
+
+  ret void
+}
+
+; ------------------------------------------------------------------------------
+; Struct type
+; ------------------------------------------------------------------------------
+
+%struct.pair = type { { i32, i32 }, { i32, i32 } }
+
+define void @alloca_struct(i32 %x) {
+; CHECK-LABEL: define void @alloca_struct
+; CHECK-SAME: (i32 [[X:%.*]]) {
+; CHECK-NEXT:    [[ALLOCA_STRUCT:%.*]] = alloca [[STRUCT_PAIR:%.*]], align 8
+; CHECK-NEXT:    [[GEP_0:%.*]] = getelementptr [[STRUCT_PAIR]], ptr [[ALLOCA_STRUCT]], i64 0, i32 1
+; CHECK-NEXT:    [[GEP_1:%.*]] = getelementptr { i32, i32 }, ptr [[GEP_0]], i64 0, i32 1
+; CHECK-NEXT:    [[LOAD_2:%.*]] = load i32, ptr [[GEP_0]], align 1
+; CHECK-NEXT:    store i32 0, ptr [[GEP_0]], align 1
+; CHECK-NEXT:    [[LOAD_1:%.*]] = load i32, ptr [[GEP_1]], align 1
+; CHECK-NEXT:    store i32 0, ptr [[GEP_1]], align 1
+; CHECK-NEXT:    ret void
+;
+  %alloca.struct = alloca %struct.pair
+
+  %gep.0 = getelementptr %struct.pair, ptr %alloca.struct, i64 0, i32 1
+  %gep.1 = getelementptr { i32, i32 }, ptr %gep.0, i64 0, i32 1
+
+  %load.2 = load i32, ptr %gep.0, align 1
+  store i32 0, ptr %gep.0, align 1
+
+  %load.1 = load i32, ptr %gep.1, align 1
+  store i32 0, ptr %gep.1, align 1
+
+  ret void
+}

diff  --git a/llvm/test/Transforms/InferAlignment/atomic.ll b/llvm/test/Transforms/InferAlignment/atomic.ll
new file mode 100644
index 000000000000000..23efc4381fd32fd
--- /dev/null
+++ b/llvm/test/Transforms/InferAlignment/atomic.ll
@@ -0,0 +1,97 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt -S < %s -passes=no-op-function | FileCheck %s
+
+; ------------------------------------------------------------------------------
+; load/store of null
+; ------------------------------------------------------------------------------
+
+define void @load_null() {
+; CHECK-LABEL: define void @load_null() {
+; CHECK-NEXT:    [[X_0:%.*]] = load atomic i32, ptr null unordered, align 4
+; CHECK-NEXT:    [[X_1:%.*]] = load atomic i32, ptr null monotonic, align 4
+; CHECK-NEXT:    [[X_2:%.*]] = load atomic i32, ptr null seq_cst, align 4
+; CHECK-NEXT:    ret void
+;
+  %x.0 = load atomic i32, ptr null unordered, align 4
+  %x.1 = load atomic i32, ptr null monotonic, align 4
+  %x.2 = load atomic i32, ptr null seq_cst, align 4
+  ret void
+}
+
+define void @store_null() {
+; CHECK-LABEL: define void @store_null() {
+; CHECK-NEXT:    store atomic i32 0, ptr null unordered, align 4
+; CHECK-NEXT:    store atomic i32 0, ptr null monotonic, align 4
+; CHECK-NEXT:    store atomic i32 0, ptr null seq_cst, align 4
+; CHECK-NEXT:    ret void
+;
+  store atomic i32 0, ptr null unordered, align 4
+  store atomic i32 0, ptr null monotonic, align 4
+  store atomic i32 0, ptr null seq_cst, align 4
+  ret void
+}
+
+; ------------------------------------------------------------------------------
+; load/store of global
+; ------------------------------------------------------------------------------
+ at c = global i64 42
+
+define void @load_nonnull() {
+; CHECK-LABEL: define void @load_nonnull() {
+; CHECK-NEXT:    [[X_0:%.*]] = load atomic i32, ptr @c unordered, align 4
+; CHECK-NEXT:    [[X_1:%.*]] = load atomic i32, ptr @c monotonic, align 4
+; CHECK-NEXT:    [[X_2:%.*]] = load atomic i32, ptr @c seq_cst, align 4
+; CHECK-NEXT:    ret void
+;
+  %x.0 = load atomic i32, ptr @c unordered, align 4
+  %x.1 = load atomic i32, ptr @c monotonic, align 4
+  %x.2 = load atomic i32, ptr @c seq_cst, align 4
+  ret void
+}
+
+define void @store_nonnull() {
+; CHECK-LABEL: define void @store_nonnull() {
+; CHECK-NEXT:    store atomic i32 0, ptr @c unordered, align 4
+; CHECK-NEXT:    store atomic i32 0, ptr @c monotonic, align 4
+; CHECK-NEXT:    store atomic i32 0, ptr @c seq_cst, align 4
+; CHECK-NEXT:    ret void
+;
+  store atomic i32 0, ptr @c unordered, align 4
+  store atomic i32 0, ptr @c monotonic, align 4
+  store atomic i32 0, ptr @c seq_cst, align 4
+  ret void
+}
+
+; ------------------------------------------------------------------------------
+; load/store of alloca
+; ------------------------------------------------------------------------------
+
+define void @load_alloca() {
+; CHECK-LABEL: define void @load_alloca() {
+; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[X_0:%.*]] = load atomic i32, ptr [[ALLOCA]] unordered, align 1
+; CHECK-NEXT:    [[X_1:%.*]] = load atomic i32, ptr [[ALLOCA]] monotonic, align 1
+; CHECK-NEXT:    [[X_2:%.*]] = load atomic i32, ptr [[ALLOCA]] seq_cst, align 1
+; CHECK-NEXT:    ret void
+;
+  %alloca = alloca i32
+  %x.0 = load atomic i32, ptr %alloca unordered, align 1
+  %x.1 = load atomic i32, ptr %alloca monotonic, align 1
+  %x.2 = load atomic i32, ptr %alloca seq_cst, align 1
+  ret void
+}
+
+define void @store_alloca() {
+; CHECK-LABEL: define void @store_alloca() {
+; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    store atomic i32 0, ptr [[ALLOCA]] unordered, align 1
+; CHECK-NEXT:    store atomic i32 0, ptr [[ALLOCA]] monotonic, align 1
+; CHECK-NEXT:    store atomic i32 0, ptr [[ALLOCA]] seq_cst, align 1
+; CHECK-NEXT:    ret void
+;
+  %alloca = alloca i32
+  store atomic i32 0, ptr %alloca unordered, align 1
+  store atomic i32 0, ptr %alloca monotonic, align 1
+  store atomic i32 0, ptr %alloca seq_cst, align 1
+  ret void
+}

diff  --git a/llvm/test/Transforms/InferAlignment/attributes.ll b/llvm/test/Transforms/InferAlignment/attributes.ll
new file mode 100644
index 000000000000000..6dce9a11d661fcd
--- /dev/null
+++ b/llvm/test/Transforms/InferAlignment/attributes.ll
@@ -0,0 +1,44 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt < %s -passes=no-op-function -S | FileCheck %s
+
+define void @attribute(ptr align 32 %a) {
+; CHECK-LABEL: define void @attribute
+; CHECK-SAME: (ptr align 32 [[A:%.*]]) {
+; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[A]], align 1
+; CHECK-NEXT:    store i32 123, ptr [[A]], align 1
+; CHECK-NEXT:    ret void
+;
+  %load = load i32, ptr %a, align 1
+  store i32 123, ptr %a, align 1
+  ret void
+}
+
+define void @attribute_through_call(ptr align 32 %a) {
+; CHECK-LABEL: define void @attribute_through_call
+; CHECK-SAME: (ptr align 32 [[A:%.*]]) {
+; CHECK-NEXT:    [[RES:%.*]] = call ptr @call(ptr [[A]])
+; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[RES]], align 1
+; CHECK-NEXT:    store i32 123, ptr [[RES]], align 1
+; CHECK-NEXT:    ret void
+;
+  %res = call ptr @call(ptr %a)
+  %load = load i32, ptr %res, align 1
+  store i32 123, ptr %res, align 1
+  ret void
+}
+
+define void @attribute_return_value(ptr %a) {
+; CHECK-LABEL: define void @attribute_return_value
+; CHECK-SAME: (ptr [[A:%.*]]) {
+; CHECK-NEXT:    [[RES:%.*]] = call align 32 ptr @call(ptr [[A]])
+; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[RES]], align 1
+; CHECK-NEXT:    store i32 123, ptr [[RES]], align 1
+; CHECK-NEXT:    ret void
+;
+  %res = call align 32 ptr @call(ptr %a)
+  %load = load i32, ptr %res, align 1
+  store i32 123, ptr %res, align 1
+  ret void
+}
+
+declare ptr @call(ptr returned)

diff  --git a/llvm/test/Transforms/InferAlignment/gep-2d.ll b/llvm/test/Transforms/InferAlignment/gep-2d.ll
new file mode 100644
index 000000000000000..b88a9be988ccf32
--- /dev/null
+++ b/llvm/test/Transforms/InferAlignment/gep-2d.ll
@@ -0,0 +1,73 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt < %s -passes=no-op-function -S | FileCheck %s
+
+; A multi-dimensional array in a nested loop.inner doing vector stores that
+; aren't yet aligned. InferAlignment can understand the addressing in the
+; Nice case to prove 16 byte alignment. In the Awkward case, the inner
+; array dimension is not even, so the stores to it won't always be aligned.
+;
+; InferAlignment should prove alignment in exactly one of the two cases.
+
+ at Nice    = global [1001 x [20000 x double]] zeroinitializer, align 32
+ at Awkward = global [1001 x [20001 x double]] zeroinitializer, align 32
+
+define void @nested_loop() {
+; CHECK-LABEL: define void @nested_loop() {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP_OUTER:%.*]]
+; CHECK:       loop.outer:
+; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP_OUTER_TAIL:%.*]] ]
+; CHECK-NEXT:    br label [[LOOP_INNER:%.*]]
+; CHECK:       loop.inner:
+; CHECK-NEXT:    [[J:%.*]] = phi i64 [ 0, [[LOOP_OUTER]] ], [ [[J_NEXT:%.*]], [[LOOP_INNER_TAIL:%.*]] ]
+; CHECK-NEXT:    [[GEP_1:%.*]] = getelementptr [1001 x [20000 x double]], ptr @Nice, i64 0, i64 [[I]], i64 [[J]]
+; CHECK-NEXT:    store <2 x double> zeroinitializer, ptr [[GEP_1]], align 8
+; CHECK-NEXT:    [[LOAD_1:%.*]] = load <2 x double>, ptr [[GEP_1]], align 8
+; CHECK-NEXT:    [[GEP_2:%.*]] = getelementptr [1001 x [20001 x double]], ptr @Awkward, i64 0, i64 [[I]], i64 [[J]]
+; CHECK-NEXT:    store <2 x double> zeroinitializer, ptr [[GEP_2]], align 8
+; CHECK-NEXT:    [[LOAD_2:%.*]] = load <2 x double>, ptr [[GEP_2]], align 8
+; CHECK-NEXT:    br label [[LOOP_INNER_TAIL]]
+; CHECK:       loop.inner.tail:
+; CHECK-NEXT:    [[J_NEXT]] = add i64 [[J]], 2
+; CHECK-NEXT:    [[J_CMP:%.*]] = icmp eq i64 [[J_NEXT]], 556
+; CHECK-NEXT:    br i1 [[J_CMP]], label [[LOOP_OUTER_TAIL]], label [[LOOP_INNER]]
+; CHECK:       loop.outer.tail:
+; CHECK-NEXT:    [[I_NEXT]] = add i64 [[I]], 1
+; CHECK-NEXT:    [[I_CMP:%.*]] = icmp eq i64 [[I_NEXT]], 991
+; CHECK-NEXT:    br i1 [[I_CMP]], label [[RETURN:%.*]], label [[LOOP_OUTER]]
+; CHECK:       return:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop.outer
+
+loop.outer:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %loop.outer.tail ]
+  br label %loop.inner
+
+loop.inner:
+  %j = phi i64 [ 0, %loop.outer ], [ %j.next, %loop.inner.tail ]
+
+  %gep.1 = getelementptr [1001 x [20000 x double]], ptr @Nice, i64 0, i64 %i, i64 %j
+  store <2 x double><double 0.0, double 0.0>, ptr %gep.1, align 8
+  %load.1 = load <2 x double>, ptr %gep.1, align 8
+
+  %gep.2 = getelementptr [1001 x [20001 x double]], ptr @Awkward, i64 0, i64 %i, i64 %j
+  store <2 x double><double 0.0, double 0.0>, ptr %gep.2, align 8
+  %load.2 = load <2 x double>, ptr %gep.2, align 8
+
+  br label %loop.inner.tail
+
+loop.inner.tail:
+  %j.next = add i64 %j, 2
+  %j.cmp = icmp eq i64 %j.next, 556
+  br i1 %j.cmp, label %loop.outer.tail, label %loop.inner
+
+loop.outer.tail:
+  %i.next = add i64 %i, 1
+  %i.cmp = icmp eq i64 %i.next, 991
+  br i1 %i.cmp, label %return, label %loop.outer
+
+return:
+  ret void
+}

diff  --git a/llvm/test/Transforms/InferAlignment/gep-array.ll b/llvm/test/Transforms/InferAlignment/gep-array.ll
new file mode 100644
index 000000000000000..76ba55eee649ea0
--- /dev/null
+++ b/llvm/test/Transforms/InferAlignment/gep-array.ll
@@ -0,0 +1,72 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt -passes=no-op-function -S < %s | FileCheck %s
+
+; ------------------------------------------------------------------------------
+; Array of pair
+; ------------------------------------------------------------------------------
+
+; Check that we improve the alignment information.
+; The base pointer is 16-byte aligned and we access the field at offsets of 8
+; bytes.
+; Every element in the @array.simple array is 16-byte aligned so any access from
+; the following gep is 8-byte aligned.
+
+%pair.simple = type { ptr, i32 }
+ at array.simple = global [4 x %pair.simple] zeroinitializer, align 16
+
+define void @simple_pair(i64 %idx) {
+; CHECK-LABEL: define void @simple_pair
+; CHECK-SAME: (i64 [[IDX:%.*]]) {
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [4 x %pair.simple], ptr @array.simple, i64 0, i64 [[IDX]], i32 1
+; CHECK-NEXT:    [[RES:%.*]] = load i32, ptr [[GEP]], align 1
+; CHECK-NEXT:    store i32 0, ptr [[GEP]], align 1
+; CHECK-NEXT:    ret void
+;
+  %gep = getelementptr inbounds [4 x %pair.simple], ptr @array.simple, i64 0, i64 %idx, i32 1
+
+  %res = load i32, ptr %gep, align 1
+  store i32 0, ptr %gep, align 1
+
+  ret void
+}
+
+; ------------------------------------------------------------------------------
+; Array of pair of arrays
+; ------------------------------------------------------------------------------
+
+%pair.array = type { [3 x i32], [3 x i32] }
+ at array.array = internal global [3 x %pair.array] zeroinitializer
+
+define void @load_nested() {
+; CHECK-LABEL: define void @load_nested() {
+; CHECK-NEXT:    [[X_0:%.*]] = load i32, ptr @array.array, align 4
+; CHECK-NEXT:    [[X_1:%.*]] = load i32, ptr getelementptr inbounds ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 1), align 4
+; CHECK-NEXT:    [[X_2:%.*]] = load i32, ptr getelementptr inbounds ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 2), align 4
+; CHECK-NEXT:    [[X_3:%.*]] = load i32, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 3), align 4
+; CHECK-NEXT:    [[X_4:%.*]] = load i32, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 4), align 4
+; CHECK-NEXT:    ret void
+;
+  %x.0 =  load i32, ptr @array.array, align 4
+  %x.1 =  load i32, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 1), align 4
+  %x.2 =  load i32, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 2), align 4
+  %x.3 =  load i32, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 3), align 4
+  %x.4 =  load i32, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 4), align 4
+  ret void
+}
+
+define void @store_nested() {
+; CHECK-LABEL: define void @store_nested() {
+; CHECK-NEXT:    store i32 1, ptr @array.array, align 4
+; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 1), align 4
+; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 2), align 4
+; CHECK-NEXT:    store i32 1, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 3), align 4
+; CHECK-NEXT:    store i32 1, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 4), align 4
+; CHECK-NEXT:    ret void
+;
+  store i32 1, ptr @array.array, align 4
+  store i32 1, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 1), align 4
+  store i32 1, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 2), align 4
+  store i32 1, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 3), align 4
+  store i32 1, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 4), align 4
+  ret void
+}

diff  --git a/llvm/test/Transforms/InferAlignment/irregular-size.ll b/llvm/test/Transforms/InferAlignment/irregular-size.ll
new file mode 100644
index 000000000000000..caec3f55b61211e
--- /dev/null
+++ b/llvm/test/Transforms/InferAlignment/irregular-size.ll
@@ -0,0 +1,55 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt < %s -passes=no-op-function -S | FileCheck %s
+
+define void @non_pow2_size(i177 %X) {
+; CHECK-LABEL: define void @non_pow2_size
+; CHECK-SAME: (i177 [[X:%.*]]) {
+; CHECK-NEXT:    [[A:%.*]] = alloca i177, align 1
+; CHECK-NEXT:    [[L1:%.*]] = load i177, ptr [[A]], align 1
+; CHECK-NEXT:    store i177 [[X]], ptr [[A]], align 1
+; CHECK-NEXT:    ret void
+;
+  %A = alloca i177, align 1
+  %L1 = load i177, ptr %A, align 1
+  store i177 %X, ptr %A, align 1
+  ret void
+}
+
+; TODO: For non-byte-sized vectors, current implementation assumes there is
+; padding to the next byte boundary between elements.
+ at vector_i4 = constant [16 x <2 x i4>] zeroinitializer, align 8
+
+define void @load_vector_i4(i4 %X) {
+; CHECK-LABEL: define void @load_vector_i4
+; CHECK-SAME: (i4 [[X:%.*]]) {
+; CHECK-NEXT:    [[PTR_0:%.*]] = getelementptr [16 x <2 x i4>], ptr @vector_i4, i64 0, i64 1
+; CHECK-NEXT:    [[PTR_1:%.*]] = getelementptr [16 x <2 x i4>], ptr @vector_i4, i64 0, i64 2
+; CHECK-NEXT:    [[PTR_2:%.*]] = getelementptr [16 x <2 x i4>], ptr @vector_i4, i64 0, i64 4
+; CHECK-NEXT:    [[PTR_3:%.*]] = getelementptr [16 x <2 x i4>], ptr @vector_i4, i64 0, i64 8
+; CHECK-NEXT:    [[RES_0:%.*]] = load i4, ptr [[PTR_0]], align 1
+; CHECK-NEXT:    [[RES_1:%.*]] = load i4, ptr [[PTR_1]], align 1
+; CHECK-NEXT:    [[RES_2:%.*]] = load i4, ptr [[PTR_2]], align 1
+; CHECK-NEXT:    [[RES_3:%.*]] = load i4, ptr [[PTR_3]], align 1
+; CHECK-NEXT:    store i4 [[X]], ptr [[PTR_0]], align 1
+; CHECK-NEXT:    store i4 [[X]], ptr [[PTR_1]], align 1
+; CHECK-NEXT:    store i4 [[X]], ptr [[PTR_2]], align 1
+; CHECK-NEXT:    store i4 [[X]], ptr [[PTR_3]], align 1
+; CHECK-NEXT:    ret void
+;
+  %ptr.0 = getelementptr [16 x <2 x i4>], ptr @vector_i4, i64 0, i64 1
+  %ptr.1 = getelementptr [16 x <2 x i4>], ptr @vector_i4, i64 0, i64 2
+  %ptr.2 = getelementptr [16 x <2 x i4>], ptr @vector_i4, i64 0, i64 4
+  %ptr.3 = getelementptr [16 x <2 x i4>], ptr @vector_i4, i64 0, i64 8
+
+  %res.0 = load i4, ptr %ptr.0, align 1
+  %res.1 = load i4, ptr %ptr.1, align 1
+  %res.2 = load i4, ptr %ptr.2, align 1
+  %res.3 = load i4, ptr %ptr.3, align 1
+
+  store i4 %X, ptr %ptr.0, align 1
+  store i4 %X, ptr %ptr.1, align 1
+  store i4 %X, ptr %ptr.2, align 1
+  store i4 %X, ptr %ptr.3, align 1
+
+  ret void
+}

diff  --git a/llvm/test/Transforms/InferAlignment/propagate-assume.ll b/llvm/test/Transforms/InferAlignment/propagate-assume.ll
new file mode 100644
index 000000000000000..a5c7afa0393baec
--- /dev/null
+++ b/llvm/test/Transforms/InferAlignment/propagate-assume.ll
@@ -0,0 +1,248 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt < %s -passes=no-op-function -S | FileCheck %s
+
+; ------------------------------------------------------------------------------
+; Simple test
+; ------------------------------------------------------------------------------
+
+define void @simple_forwardpropagate(ptr %a) {
+; CHECK-LABEL: define void @simple_forwardpropagate
+; CHECK-SAME: (ptr [[A:%.*]]) {
+; CHECK-NEXT:    [[PTRINT:%.*]] = ptrtoint ptr [[A]] to i64
+; CHECK-NEXT:    [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31
+; CHECK-NEXT:    [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[MASKCOND]])
+; CHECK-NEXT:    [[LOAD_A:%.*]] = load i32, ptr [[A]], align 4
+; CHECK-NEXT:    store i32 345, ptr [[A]], align 4
+; CHECK-NEXT:    ret void
+;
+  %ptrint = ptrtoint ptr %a to i64
+  %maskedptr = and i64 %ptrint, 31
+  %maskcond = icmp eq i64 %maskedptr, 0
+  tail call void @llvm.assume(i1 %maskcond)
+
+  %load.a = load i32, ptr %a, align 4
+  store i32 345, ptr %a, align 4
+
+  ret void
+}
+
+define void @simple_backpropagate(ptr %a) {
+; CHECK-LABEL: define void @simple_backpropagate
+; CHECK-SAME: (ptr [[A:%.*]]) {
+; CHECK-NEXT:    [[LOAD_A:%.*]] = load i32, ptr [[A]], align 4
+; CHECK-NEXT:    store i32 345, ptr [[A]], align 4
+; CHECK-NEXT:    [[PTRINT:%.*]] = ptrtoint ptr [[A]] to i64
+; CHECK-NEXT:    [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31
+; CHECK-NEXT:    [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[MASKCOND]])
+; CHECK-NEXT:    ret void
+;
+  %load.a = load i32, ptr %a, align 4
+  store i32 345, ptr %a, align 4
+
+  %ptrint = ptrtoint ptr %a to i64
+  %maskedptr = and i64 %ptrint, 31
+  %maskcond = icmp eq i64 %maskedptr, 0
+  tail call void @llvm.assume(i1 %maskcond)
+
+  ret void
+}
+
+define void @simple_forwardpropagate_bundle(ptr %a) {
+; CHECK-LABEL: define void @simple_forwardpropagate_bundle
+; CHECK-SAME: (ptr [[A:%.*]]) {
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i32 32) ]
+; CHECK-NEXT:    [[LOAD_A:%.*]] = load i32, ptr [[A]], align 4
+; CHECK-NEXT:    store i32 345, ptr [[A]], align 4
+; CHECK-NEXT:    ret void
+;
+  call void @llvm.assume(i1 true) ["align"(ptr %a, i32 32)]
+  %load.a = load i32, ptr %a, align 4
+  store i32 345, ptr %a, align 4
+  ret void
+}
+
+define void @simple_backpropagate_bundle(ptr %a) {
+; CHECK-LABEL: define void @simple_backpropagate_bundle
+; CHECK-SAME: (ptr [[A:%.*]]) {
+; CHECK-NEXT:    [[LOAD_A:%.*]] = load i32, ptr [[A]], align 4
+; CHECK-NEXT:    store i32 345, ptr [[A]], align 4
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i32 32) ]
+; CHECK-NEXT:    ret void
+;
+  %load.a = load i32, ptr %a, align 4
+  store i32 345, ptr %a, align 4
+  call void @llvm.assume(i1 true) ["align"(ptr %a, i32 32)]
+  ret void
+}
+
+; ------------------------------------------------------------------------------
+; Complex test
+; ------------------------------------------------------------------------------
+
+define void @loop_forwardpropagate(ptr %a, ptr %b) {
+; CHECK-LABEL: define void @loop_forwardpropagate
+; CHECK-SAME: (ptr [[A:%.*]], ptr [[B:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[PTRINT:%.*]] = ptrtoint ptr [[A]] to i64
+; CHECK-NEXT:    [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 63
+; CHECK-NEXT:    [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[MASKCOND]])
+; CHECK-NEXT:    [[PTRINT2:%.*]] = ptrtoint ptr [[B]] to i64
+; CHECK-NEXT:    [[MASKEDPTR2:%.*]] = and i64 [[PTRINT2]], 63
+; CHECK-NEXT:    [[MASKEDCOND2:%.*]] = icmp eq i64 [[MASKEDPTR2]], 0
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[MASKEDCOND2]])
+; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[FOR_BODY]] ]
+; CHECK-NEXT:    [[GEP_B:%.*]] = getelementptr inbounds i32, ptr [[B]], i64 [[I]]
+; CHECK-NEXT:    [[LOAD_B:%.*]] = load i32, ptr [[GEP_B]], align 4
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[LOAD_B]], 1
+; CHECK-NEXT:    [[GEP_A:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[I]]
+; CHECK-NEXT:    store i32 [[ADD]], ptr [[GEP_A]], align 4
+; CHECK-NEXT:    [[I_NEXT]] = add nuw nsw i64 [[I]], 16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I_NEXT]], 1648
+; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
+; CHECK:       for.end:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %ptrint = ptrtoint ptr %a to i64
+  %maskedptr = and i64 %ptrint, 63
+  %maskcond = icmp eq i64 %maskedptr, 0
+  tail call void @llvm.assume(i1 %maskcond)
+
+  %ptrint2 = ptrtoint ptr %b to i64
+  %maskedptr2 = and i64 %ptrint2, 63
+  %maskedcond2 = icmp eq i64 %maskedptr2, 0
+  tail call void @llvm.assume(i1 %maskedcond2)
+
+  br label %for.body
+
+for.body:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ]
+
+  %gep.b = getelementptr inbounds i32, ptr %b, i64 %i
+  %load.b = load i32, ptr %gep.b, align 4
+  %add = add nsw i32 %load.b, 1
+
+  %gep.a = getelementptr inbounds i32, ptr %a, i64 %i
+  store i32 %add, ptr %gep.a, align 4
+
+  %i.next = add nuw nsw i64 %i, 16
+  %cmp = icmp slt i64 %i.next, 1648
+
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:
+  ret void
+}
+
+define void @loop_forwardpropagate_bundle(ptr %a, ptr %b) {
+; CHECK-LABEL: define void @loop_forwardpropagate_bundle
+; CHECK-SAME: (ptr [[A:%.*]], ptr [[B:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    tail call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i32 64) ]
+; CHECK-NEXT:    tail call void @llvm.assume(i1 true) [ "align"(ptr [[B]], i32 64) ]
+; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[FOR_BODY]] ]
+; CHECK-NEXT:    [[GEP_B:%.*]] = getelementptr inbounds i32, ptr [[B]], i64 [[I]]
+; CHECK-NEXT:    [[LOAD_B:%.*]] = load i32, ptr [[GEP_B]], align 4
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[LOAD_B]], 1
+; CHECK-NEXT:    [[GEP_A:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[I]]
+; CHECK-NEXT:    store i32 [[ADD]], ptr [[GEP_A]], align 4
+; CHECK-NEXT:    [[I_NEXT]] = add nuw nsw i64 [[I]], 16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I_NEXT]], 1648
+; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
+; CHECK:       for.end:
+; CHECK-NEXT:    ret void
+;
+entry:
+  tail call void @llvm.assume(i1 true) ["align"(ptr %a, i32 64)]
+  tail call void @llvm.assume(i1 true) ["align"(ptr %b, i32 64)]
+  br label %for.body
+
+for.body:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ]
+
+  %gep.b = getelementptr inbounds i32, ptr %b, i64 %i
+  %load.b = load i32, ptr %gep.b, align 4
+  %add = add nsw i32 %load.b, 1
+
+  %gep.a = getelementptr inbounds i32, ptr %a, i64 %i
+  store i32 %add, ptr %gep.a, align 4
+
+  %i.next = add nuw nsw i64 %i, 16
+  %cmp = icmp slt i64 %i.next, 1648
+
+  br i1 %cmp, label %for.body, label %for.end
+
+for.end:
+  ret void
+}
+
+; Check that assume is propagated backwards through all
+; operations that are `isGuaranteedToTransferExecutionToSuccessor`
+; (it should reach the load and mark it as `align 32`).
+define void @complex_backpropagate(ptr %a, ptr %b, ptr %c) {
+; CHECK-LABEL: define void @complex_backpropagate
+; CHECK-SAME: (ptr [[A:%.*]], ptr [[B:%.*]], ptr [[C:%.*]]) {
+; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca i64, align 8
+; CHECK-NEXT:    [[LOAD_A:%.*]] = load i32, ptr [[A]], align 4
+; CHECK-NEXT:    [[LOAD_B:%.*]] = load i32, ptr [[B]], align 4
+; CHECK-NEXT:    store i32 [[LOAD_B]], ptr [[A]], align 4
+; CHECK-NEXT:    [[OBJ_SIZE:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[C]], i1 false, i1 false, i1 false)
+; CHECK-NEXT:    store i64 [[OBJ_SIZE]], ptr [[ALLOCA]], align 4
+; CHECK-NEXT:    [[PTRINT:%.*]] = ptrtoint ptr [[A]] to i64
+; CHECK-NEXT:    [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31
+; CHECK-NEXT:    [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[MASKCOND]])
+; CHECK-NEXT:    ret void
+;
+  %alloca = alloca i64
+  %load.a = load i32, ptr %a, align 4
+
+  %load.b = load i32, ptr %b
+  store i32 %load.b, ptr %a
+
+  %obj.size = call i64 @llvm.objectsize.i64.p0(ptr %c, i1 false)
+  store i64 %obj.size, ptr %alloca
+
+  %ptrint = ptrtoint ptr %a to i64
+  %maskedptr = and i64 %ptrint, 31
+  %maskcond = icmp eq i64 %maskedptr, 0
+  tail call void @llvm.assume(i1 %maskcond)
+
+  ret void
+}
+
+define void @complex_backpropagate_bundle(ptr %a, ptr %b, ptr %c) {
+; CHECK-LABEL: define void @complex_backpropagate_bundle
+; CHECK-SAME: (ptr [[A:%.*]], ptr [[B:%.*]], ptr [[C:%.*]]) {
+; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca i64, align 8
+; CHECK-NEXT:    [[LOAD_A:%.*]] = load i32, ptr [[A]], align 4
+; CHECK-NEXT:    [[LOAD_B:%.*]] = load i32, ptr [[B]], align 4
+; CHECK-NEXT:    store i32 [[LOAD_B]], ptr [[A]], align 4
+; CHECK-NEXT:    [[OBJ_SIZE:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[C]], i1 false, i1 false, i1 false)
+; CHECK-NEXT:    store i64 [[OBJ_SIZE]], ptr [[ALLOCA]], align 4
+; CHECK-NEXT:    tail call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i32 32) ]
+; CHECK-NEXT:    ret void
+;
+  %alloca = alloca i64
+  %load.a = load i32, ptr %a, align 4
+
+  %load.b = load i32, ptr %b
+  store i32 %load.b, ptr %a
+
+  %obj.size = call i64 @llvm.objectsize.i64.p0(ptr %c, i1 false)
+  store i64 %obj.size, ptr %alloca
+
+  tail call void @llvm.assume(i1 true) ["align"(ptr %a, i32 32)]
+
+  ret void
+}
+
+declare i64 @llvm.objectsize.i64.p0(ptr, i1)
+declare void @llvm.assume(i1)

diff  --git a/llvm/test/Transforms/InferAlignment/ptrmask.ll b/llvm/test/Transforms/InferAlignment/ptrmask.ll
new file mode 100644
index 000000000000000..1db2d093216484e
--- /dev/null
+++ b/llvm/test/Transforms/InferAlignment/ptrmask.ll
@@ -0,0 +1,77 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt < %s -passes=no-op-function -S | FileCheck %s
+
+; ------------------------------------------------------------------------------
+; load instructions
+; ------------------------------------------------------------------------------
+
+define void @load(ptr align 1 %ptr) {
+; CHECK-LABEL: define void @load
+; CHECK-SAME: (ptr align 1 [[PTR:%.*]]) {
+; CHECK-NEXT:    [[ALIGNED_0:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR]], i64 -2)
+; CHECK-NEXT:    [[ALIGNED_1:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR]], i64 -4)
+; CHECK-NEXT:    [[ALIGNED_2:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR]], i64 -8)
+; CHECK-NEXT:    [[LOAD_0:%.*]] = load <16 x i8>, ptr [[ALIGNED_0]], align 1
+; CHECK-NEXT:    [[LOAD_1:%.*]] = load <16 x i8>, ptr [[ALIGNED_1]], align 1
+; CHECK-NEXT:    [[LOAD_2:%.*]] = load <16 x i8>, ptr [[ALIGNED_2]], align 1
+; CHECK-NEXT:    ret void
+;
+  %aligned.0 = call ptr @llvm.ptrmask.p0.i64(ptr %ptr, i64 -2)
+  %aligned.1 = call ptr @llvm.ptrmask.p0.i64(ptr %ptr, i64 -4)
+  %aligned.2 = call ptr @llvm.ptrmask.p0.i64(ptr %ptr, i64 -8)
+
+  %load.0 = load <16 x i8>, ptr %aligned.0, align 1
+  %load.1 = load <16 x i8>, ptr %aligned.1, align 1
+  %load.2 = load <16 x i8>, ptr %aligned.2, align 1
+
+  ret void
+}
+
+; ------------------------------------------------------------------------------
+; store instructions
+; ------------------------------------------------------------------------------
+
+define void @store(ptr align 1 %ptr) {
+; CHECK-LABEL: define void @store
+; CHECK-SAME: (ptr align 1 [[PTR:%.*]]) {
+; CHECK-NEXT:    [[ALIGNED_0:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR]], i64 -2)
+; CHECK-NEXT:    [[ALIGNED_1:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR]], i64 -4)
+; CHECK-NEXT:    [[ALIGNED_2:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR]], i64 -8)
+; CHECK-NEXT:    store <16 x i8> zeroinitializer, ptr [[ALIGNED_0]], align 1
+; CHECK-NEXT:    store <16 x i8> zeroinitializer, ptr [[ALIGNED_1]], align 1
+; CHECK-NEXT:    store <16 x i8> zeroinitializer, ptr [[ALIGNED_2]], align 1
+; CHECK-NEXT:    ret void
+;
+  %aligned.0 = call ptr @llvm.ptrmask.p0.i64(ptr %ptr, i64 -2)
+  %aligned.1 = call ptr @llvm.ptrmask.p0.i64(ptr %ptr, i64 -4)
+  %aligned.2 = call ptr @llvm.ptrmask.p0.i64(ptr %ptr, i64 -8)
+
+  store <16 x i8> zeroinitializer, ptr %aligned.0, align 1
+  store <16 x i8> zeroinitializer, ptr %aligned.1, align 1
+  store <16 x i8> zeroinitializer, ptr %aligned.2, align 1
+
+  ret void
+}
+
+; ------------------------------------------------------------------------------
+; Overaligned pointer
+; ------------------------------------------------------------------------------
+
+; Underlying alignment greater than alignment forced by ptrmask
+define void @ptrmask_overaligned(ptr align 16 %ptr) {
+; CHECK-LABEL: define void @ptrmask_overaligned
+; CHECK-SAME: (ptr align 16 [[PTR:%.*]]) {
+; CHECK-NEXT:    [[ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR]], i64 -8)
+; CHECK-NEXT:    [[LOAD:%.*]] = load <16 x i8>, ptr [[ALIGNED]], align 1
+; CHECK-NEXT:    store <16 x i8> zeroinitializer, ptr [[ALIGNED]], align 1
+; CHECK-NEXT:    ret void
+;
+  %aligned = call ptr @llvm.ptrmask.p0.i64(ptr %ptr, i64 -8)
+
+  %load = load <16 x i8>, ptr %aligned, align 1
+  store <16 x i8> zeroinitializer, ptr %aligned, align 1
+
+  ret void
+}
+
+declare ptr @llvm.ptrmask.p0.i64(ptr, i64)

diff  --git a/llvm/test/Transforms/InferAlignment/undef-and-null.ll b/llvm/test/Transforms/InferAlignment/undef-and-null.ll
new file mode 100644
index 000000000000000..76b751a4d411f94
--- /dev/null
+++ b/llvm/test/Transforms/InferAlignment/undef-and-null.ll
@@ -0,0 +1,26 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt -passes=no-op-function -S < %s | FileCheck %s
+
+define void @load_undef_null(ptr %P) {
+; CHECK-LABEL: define void @load_undef_null
+; CHECK-SAME: (ptr [[P:%.*]]) {
+; CHECK-NEXT:    [[RET_0:%.*]] = load i32, ptr undef, align 4
+; CHECK-NEXT:    [[RET_1:%.*]] = load i32, ptr null, align 4
+; CHECK-NEXT:    ret void
+;
+  %ret.0 = load i32, ptr undef
+  %ret.1 = load i32, ptr null
+  ret void
+}
+
+define void @store_undef_null(ptr %P) {
+; CHECK-LABEL: define void @store_undef_null
+; CHECK-SAME: (ptr [[P:%.*]]) {
+; CHECK-NEXT:    store i32 123, ptr undef, align 4
+; CHECK-NEXT:    store i32 124, ptr null, align 4
+; CHECK-NEXT:    ret void
+;
+  store i32 123, ptr undef
+  store i32 124, ptr null
+  ret void
+}

diff  --git a/llvm/test/Transforms/InferAlignment/vector.ll b/llvm/test/Transforms/InferAlignment/vector.ll
new file mode 100644
index 000000000000000..1599b583f32445a
--- /dev/null
+++ b/llvm/test/Transforms/InferAlignment/vector.ll
@@ -0,0 +1,111 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt < %s -passes=no-op-function -S | FileCheck %s
+
+; InferAlignment should be able to prove vector alignment in the
+; presence of a few mild address computation tricks.
+
+; ------------------------------------------------------------------------------
+; alloca
+; ------------------------------------------------------------------------------
+
+define void @alloca(<2 x i64> %y) {
+; CHECK-LABEL: define void @alloca
+; CHECK-SAME: (<2 x i64> [[Y:%.*]]) {
+; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca <2 x i64>, align 16
+; CHECK-NEXT:    [[LOAD:%.*]] = load <2 x i64>, ptr [[ALLOCA]], align 1
+; CHECK-NEXT:    store <2 x i64> [[Y]], ptr [[ALLOCA]], align 1
+; CHECK-NEXT:    ret void
+;
+  %alloca = alloca <2 x i64>
+  %load = load <2 x i64>, ptr %alloca, align 1
+  store <2 x i64> %y, ptr %alloca, align 1
+  ret void
+}
+
+; ------------------------------------------------------------------------------
+; global
+; ------------------------------------------------------------------------------
+
+ at x.vector = external global <2 x i64>, align 16
+
+define void @global(<2 x i64> %y) {
+; CHECK-LABEL: define void @global
+; CHECK-SAME: (<2 x i64> [[Y:%.*]]) {
+; CHECK-NEXT:    [[LOAD:%.*]] = load <2 x i64>, ptr @x.vector, align 1
+; CHECK-NEXT:    store <2 x i64> [[Y]], ptr @x.vector, align 1
+; CHECK-NEXT:    ret void
+;
+  %load = load <2 x i64>, ptr @x.vector, align 1
+  store <2 x i64> %y, ptr @x.vector, align 1
+  ret void
+}
+
+; ------------------------------------------------------------------------------
+; getelementptr
+; ------------------------------------------------------------------------------
+
+ at vector = external global <2 x i64>, align 16
+ at vector.arr = external global [13 x <2 x i64>], align 16
+
+; ------------------------------------------------------------------------------
+; 1d access
+; ------------------------------------------------------------------------------
+
+define void @vector_singular(i32 %i, <2 x i64> %y) {
+; CHECK-LABEL: define void @vector_singular
+; CHECK-SAME: (i32 [[I:%.*]], <2 x i64> [[Y:%.*]]) {
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr <2 x i64>, ptr @vector, i32 [[I]]
+; CHECK-NEXT:    [[LOAD:%.*]] = load <2 x i64>, ptr [[GEP]], align 1
+; CHECK-NEXT:    store <2 x i64> [[Y]], ptr [[GEP]], align 1
+; CHECK-NEXT:    ret void
+;
+  %gep = getelementptr <2 x i64>, ptr @vector, i32 %i
+  %load = load <2 x i64>, ptr %gep, align 1
+  store <2 x i64> %y, ptr %gep, align 1
+  ret void
+}
+
+; ------------------------------------------------------------------------------
+; 2d access
+; ------------------------------------------------------------------------------
+
+define void @vector_array(i32 %i, i32 %j, <2 x i64> %y) {
+; CHECK-LABEL: define void @vector_array
+; CHECK-SAME: (i32 [[I:%.*]], i32 [[J:%.*]], <2 x i64> [[Y:%.*]]) {
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr [13 x <2 x i64>], ptr @vector.arr, i32 [[I]], i32 [[J]]
+; CHECK-NEXT:    [[LOAD:%.*]] = load <2 x i64>, ptr [[GEP]], align 1
+; CHECK-NEXT:    store <2 x i64> [[Y]], ptr [[GEP]], align 1
+; CHECK-NEXT:    ret void
+;
+  %gep = getelementptr [13 x <2 x i64>], ptr @vector.arr, i32 %i, i32 %j
+  %load = load <2 x i64>, ptr %gep, align 1
+  store <2 x i64> %y, ptr %gep, align 1
+  ret void
+}
+
+; ------------------------------------------------------------------------------
+; non-vector array type
+; ------------------------------------------------------------------------------
+
+; When we see a unaligned load or store from an insufficiently aligned global or
+; alloca, increase the alignment, turning it into an aligned load or store.
+ at x.array = internal global [4 x i32] zeroinitializer
+
+define void @nonvector_array() {
+; CHECK-LABEL: define void @nonvector_array() {
+; CHECK-NEXT:    [[LOAD_0:%.*]] = load <16 x i8>, ptr @x.array, align 1
+; CHECK-NEXT:    store <16 x i8> zeroinitializer, ptr @x.array, align 1
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr [4 x i32], ptr @x.array, i16 0, i16 2
+; CHECK-NEXT:    [[LOAD_1:%.*]] = load <16 x i8>, ptr [[GEP]], align 1
+; CHECK-NEXT:    store <16 x i8> zeroinitializer, ptr [[GEP]], align 1
+; CHECK-NEXT:    ret void
+;
+  %load.0 = load <16 x i8>, ptr @x.array, align 1
+  store <16 x i8> zeroinitializer, ptr @x.array, align 1
+
+  %gep = getelementptr [4 x i32], ptr @x.array, i16 0, i16 2
+  %load.1 = load <16 x i8>, ptr %gep, align 1
+  store <16 x i8> zeroinitializer, ptr %gep, align 1
+
+  ret void
+}

diff  --git a/llvm/test/Transforms/InferAlignment/volatile.ll b/llvm/test/Transforms/InferAlignment/volatile.ll
new file mode 100644
index 000000000000000..f2991b6fc2d2dbf
--- /dev/null
+++ b/llvm/test/Transforms/InferAlignment/volatile.ll
@@ -0,0 +1,32 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt < %s -passes=no-op-function -S | FileCheck %s
+
+define void @load_volatile() {
+; CHECK-LABEL: define void @load_volatile() {
+; CHECK-NEXT:    [[A:%.*]] = alloca { i32 }, align 8
+; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[LOAD_A:%.*]] = load volatile i32, ptr [[A]], align 4
+; CHECK-NEXT:    [[LOAD_B:%.*]] = load volatile i32, ptr [[B]], align 4
+; CHECK-NEXT:    ret void
+;
+  %a = alloca { i32 }
+  %b = alloca i32
+  %load.a = load volatile i32, ptr %a
+  %load.b = load volatile i32, ptr %b
+  ret void
+}
+
+define void @store_volatile() {
+; CHECK-LABEL: define void @store_volatile() {
+; CHECK-NEXT:    [[A:%.*]] = alloca { i32 }, align 8
+; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    store volatile i32 123, ptr [[A]], align 4
+; CHECK-NEXT:    store volatile i32 123, ptr [[B]], align 4
+; CHECK-NEXT:    ret void
+;
+  %a = alloca { i32 }
+  %b = alloca i32
+  store volatile i32 123, ptr %a
+  store volatile i32 123, ptr %b
+  ret void
+}

diff  --git a/llvm/test/Transforms/InferAlignment/vscale.ll b/llvm/test/Transforms/InferAlignment/vscale.ll
new file mode 100644
index 000000000000000..5152d50a6bb770f
--- /dev/null
+++ b/llvm/test/Transforms/InferAlignment/vscale.ll
@@ -0,0 +1,36 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt -passes=no-op-function -S < %s | FileCheck %s
+
+; <4 x i32> -> 16 byte alignment
+define void @alignment_sustain(ptr align 16 %ptr) {
+; CHECK-LABEL: define void @alignment_sustain
+; CHECK-SAME: (ptr align 16 [[PTR:%.*]]) {
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr <vscale x 4 x i32>, ptr [[PTR]], i32 3
+; CHECK-NEXT:    [[LOAD:%.*]] = load <4 x i32>, ptr [[GEP]], align 16
+; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr [[GEP]], align 16
+; CHECK-NEXT:    ret void
+;
+  %gep = getelementptr <vscale x 4 x i32>, ptr %ptr, i32 3
+
+  %load = load <4 x i32>, ptr %gep, align 16
+  store <4 x i32> zeroinitializer, ptr %gep, align 16
+
+  ret void
+}
+
+; <8 x i32> -> 32 byte alignment
+define void @alignment_increase(ptr align 32 %ptr) {
+; CHECK-LABEL: define void @alignment_increase
+; CHECK-SAME: (ptr align 32 [[PTR:%.*]]) {
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr <vscale x 8 x i32>, ptr [[PTR]], i32 3
+; CHECK-NEXT:    [[LOAD:%.*]] = load <8 x i32>, ptr [[GEP]], align 16
+; CHECK-NEXT:    store <8 x i32> zeroinitializer, ptr [[GEP]], align 16
+; CHECK-NEXT:    ret void
+;
+  %gep = getelementptr <vscale x 8 x i32>, ptr %ptr, i32 3
+
+  %load = load <8 x i32>, ptr %gep, align 16
+  store <8 x i32> zeroinitializer, ptr %gep, align 16
+
+  ret void
+}


        


More information about the llvm-commits mailing list