Skip to content

Commit

Permalink
[InferAlignment] Create tests for InferAlignment pass
Browse files Browse the repository at this point in the history
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
  • Loading branch information
dc03 committed Sep 20, 2023
1 parent cb97761 commit 3978f37
Show file tree
Hide file tree
Showing 12 changed files with 930 additions and 0 deletions.
59 changes: 59 additions & 0 deletions llvm/test/Transforms/InferAlignment/alloca.ll
Original file line number Diff line number Diff line change
@@ -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
}
97 changes: 97 additions & 0 deletions llvm/test/Transforms/InferAlignment/atomic.ll
Original file line number Diff line number Diff line change
@@ -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
; ------------------------------------------------------------------------------
@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
}
44 changes: 44 additions & 0 deletions llvm/test/Transforms/InferAlignment/attributes.ll
Original file line number Diff line number Diff line change
@@ -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)
73 changes: 73 additions & 0 deletions llvm/test/Transforms/InferAlignment/gep-2d.ll
Original file line number Diff line number Diff line change
@@ -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.

@Nice = global [1001 x [20000 x double]] zeroinitializer, align 32
@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
}
72 changes: 72 additions & 0 deletions llvm/test/Transforms/InferAlignment/gep-array.ll
Original file line number Diff line number Diff line change
@@ -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 }
@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] }
@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
}

0 comments on commit 3978f37

Please sign in to comment.