1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -passes='gvn' -basic-aa-separate-storage -S | FileCheck %s
4 declare void @llvm.assume(i1)
8 define i8 @simple_no(ptr %p1, ptr %p2) {
9 ; CHECK-LABEL: @simple_no(
11 ; CHECK-NEXT: store i8 0, ptr [[P1:%.*]], align 1
12 ; CHECK-NEXT: store i8 1, ptr [[P2:%.*]], align 1
13 ; CHECK-NEXT: [[LOADOFSTORE:%.*]] = load i8, ptr [[P1]], align 1
14 ; CHECK-NEXT: ret i8 [[LOADOFSTORE]]
19 %loadofstore = load i8, ptr %p1
23 define i8 @simple_yes(ptr %p1, ptr %p2) {
24 ; CHECK-LABEL: @simple_yes(
26 ; CHECK-NEXT: call void @llvm.assume(i1 true) [ "separate_storage"(ptr [[P1:%.*]], ptr [[P2:%.*]]) ]
27 ; CHECK-NEXT: store i8 0, ptr [[P1]], align 1
28 ; CHECK-NEXT: store i8 1, ptr [[P2]], align 1
29 ; CHECK-NEXT: ret i8 0
32 call void @llvm.assume(i1 1) ["separate_storage"(ptr %p1, ptr %p2)]
35 %loadofstore = load i8, ptr %p1
39 define i8 @ptr_to_ptr_no(ptr %pp) {
40 ; CHECK-LABEL: @ptr_to_ptr_no(
42 ; CHECK-NEXT: [[P_BASE:%.*]] = load ptr, ptr [[PP:%.*]], align 8
43 ; CHECK-NEXT: store i8 0, ptr [[P_BASE]], align 1
44 ; CHECK-NEXT: [[P_BASE2:%.*]] = load ptr, ptr [[PP]], align 8
45 ; CHECK-NEXT: [[LOADOFSTORE:%.*]] = load i8, ptr [[P_BASE2]], align 1
46 ; CHECK-NEXT: ret i8 [[LOADOFSTORE]]
49 %p_base = load ptr, ptr %pp
50 store i8 0, ptr %p_base
51 %p_base2 = load ptr, ptr %pp
52 %loadofstore = load i8, ptr %p_base2
56 define i8 @ptr_to_ptr_yes(ptr %pp) {
57 ; CHECK-LABEL: @ptr_to_ptr_yes(
59 ; CHECK-NEXT: [[P_BASE:%.*]] = load ptr, ptr [[PP:%.*]], align 8
60 ; CHECK-NEXT: call void @llvm.assume(i1 true) [ "separate_storage"(ptr [[P_BASE]], ptr [[PP]]) ]
61 ; CHECK-NEXT: store i8 0, ptr [[P_BASE]], align 1
62 ; CHECK-NEXT: ret i8 0
65 %p_base = load ptr, ptr %pp
66 call void @llvm.assume(i1 1) ["separate_storage"(ptr %p_base, ptr %pp)]
67 store i8 0, ptr %p_base
68 %p_base2 = load ptr, ptr %pp
69 %loadofstore = load i8, ptr %p_base2
73 ; The analysis should only kick in if executed (or will be executed) at the
74 ; given program point.
76 define i8 @flow_sensitive(ptr %p1, ptr %p2, i1 %cond) {
77 ; CHECK-LABEL: @flow_sensitive(
79 ; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BRANCH:%.*]], label [[FALSE_BRANCH:%.*]]
81 ; CHECK-NEXT: store i8 11, ptr [[P1:%.*]], align 1
82 ; CHECK-NEXT: store i8 22, ptr [[P2:%.*]], align 1
83 ; CHECK-NEXT: [[LOADOFSTORE_TRUE:%.*]] = load i8, ptr [[P1]], align 1
84 ; CHECK-NEXT: br label [[ENDIF:%.*]]
85 ; CHECK: false_branch:
86 ; CHECK-NEXT: call void @llvm.assume(i1 true) [ "separate_storage"(ptr [[P1]], ptr [[P2]]) ]
87 ; CHECK-NEXT: store i8 33, ptr [[P1]], align 1
88 ; CHECK-NEXT: store i8 44, ptr [[P2]], align 1
89 ; CHECK-NEXT: br label [[ENDIF]]
91 ; CHECK-NEXT: [[LOADOFSTORE:%.*]] = phi i8 [ [[LOADOFSTORE_TRUE]], [[TRUE_BRANCH]] ], [ 33, [[FALSE_BRANCH]] ]
92 ; CHECK-NEXT: ret i8 [[LOADOFSTORE]]
95 br i1 %cond, label %true_branch, label %false_branch
100 %loadofstore_true = load i8, ptr %p1
104 call void @llvm.assume(i1 1) ["separate_storage"(ptr %p1, ptr %p2)]
107 %loadofstore_false = load i8, ptr %p1
111 %loadofstore = phi i8 [ %loadofstore_true, %true_branch ], [ %loadofstore_false, %false_branch ]
115 define i8 @flow_sensitive_with_dominator(ptr %p1, ptr %p2, i1 %cond) {
116 ; CHECK-LABEL: @flow_sensitive_with_dominator(
118 ; CHECK-NEXT: call void @llvm.assume(i1 true) [ "separate_storage"(ptr [[P1:%.*]], ptr [[P2:%.*]]) ]
119 ; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BRANCH:%.*]], label [[FALSE_BRANCH:%.*]]
120 ; CHECK: true_branch:
121 ; CHECK-NEXT: store i8 11, ptr [[P1]], align 1
122 ; CHECK-NEXT: store i8 22, ptr [[P2]], align 1
123 ; CHECK-NEXT: br label [[ENDIF:%.*]]
124 ; CHECK: false_branch:
125 ; CHECK-NEXT: store i8 33, ptr [[P1]], align 1
126 ; CHECK-NEXT: store i8 44, ptr [[P2]], align 1
127 ; CHECK-NEXT: br label [[ENDIF]]
129 ; CHECK-NEXT: [[LOADOFSTORE:%.*]] = phi i8 [ 11, [[TRUE_BRANCH]] ], [ 33, [[FALSE_BRANCH]] ]
130 ; CHECK-NEXT: ret i8 [[LOADOFSTORE]]
133 call void @llvm.assume(i1 1) ["separate_storage"(ptr %p1, ptr %p2)]
134 br i1 %cond, label %true_branch, label %false_branch
139 %loadofstore_true = load i8, ptr %p1
145 %loadofstore_false = load i8, ptr %p1
149 %loadofstore = phi i8 [ %loadofstore_true, %true_branch ], [ %loadofstore_false, %false_branch ]
153 ; Hints are relative to entire regions of storage, not particular pointers
154 ; inside them. We should know that the whole ranges are disjoint given hints at
157 define i8 @offset_agnostic(ptr %p1, ptr %p2) {
158 ; CHECK-LABEL: @offset_agnostic(
159 ; CHECK-NEXT: [[ACCESS1:%.*]] = getelementptr inbounds i8, ptr [[P1:%.*]], i64 12
160 ; CHECK-NEXT: [[ACCESS2:%.*]] = getelementptr inbounds i8, ptr [[P2:%.*]], i64 34
161 ; CHECK-NEXT: [[HINT1:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 56
162 ; CHECK-NEXT: [[HINT2:%.*]] = getelementptr inbounds i8, ptr [[P2]], i64 78
163 ; CHECK-NEXT: call void @llvm.assume(i1 true) [ "separate_storage"(ptr [[HINT1]], ptr [[HINT2]]) ]
164 ; CHECK-NEXT: store i8 0, ptr [[ACCESS1]], align 1
165 ; CHECK-NEXT: store i8 1, ptr [[ACCESS2]], align 1
166 ; CHECK-NEXT: ret i8 0
168 %access1 = getelementptr inbounds i8, ptr %p1, i64 12
169 %access2 = getelementptr inbounds i8, ptr %p2, i64 34
171 %hint1 = getelementptr inbounds i8, ptr %p1, i64 56
172 %hint2 = getelementptr inbounds i8, ptr %p2, i64 78
173 call void @llvm.assume(i1 1) ["separate_storage"(ptr %hint1, ptr %hint2)]
175 store i8 0, ptr %access1
176 store i8 1, ptr %access2
177 %loadofstore = load i8, ptr %access1