llvm.org GIT mirror llvm / 89c6743
[ADT] Enable reverse iteration for DenseMap Reviewers: mehdi_amini, dexonsmith, dblaikie, davide, chandlerc, davidxl, echristo, efriedma Reviewed By: dblaikie Subscribers: rsmith, mgorny, emaste, llvm-commits Differential Revision: https://reviews.llvm.org/D35043 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@311730 91177308-0d34-0410-b5e6-96231b3b80d8 Mandeep Singh Grang 2 years ago
11 changed file(s) with 228 addition(s) and 799 deletion(s). Raw diff Collapse all Expand all
1818 #include "llvm/Support/AlignOf.h"
1919 #include "llvm/Support/Compiler.h"
2020 #include "llvm/Support/MathExtras.h"
21 #include "llvm/Support/ReverseIteration.h"
2122 #include "llvm/Support/type_traits.h"
2223 #include
2324 #include
6667 DenseMapIterator;
6768
6869 inline iterator begin() {
69 // When the map is empty, avoid the overhead of AdvancePastEmptyBuckets().
70 return empty() ? end() : iterator(getBuckets(), getBucketsEnd(), *this);
70 // When the map is empty, avoid the overhead of advancing/retreating past
71 // empty buckets.
72 if (empty())
73 return end();
74 if (shouldReverseIterate())
75 return makeIterator(getBucketsEnd() - 1, getBuckets(), *this);
76 return makeIterator(getBuckets(), getBucketsEnd(), *this);
7177 }
7278 inline iterator end() {
73 return iterator(getBucketsEnd(), getBucketsEnd(), *this, true);
79 return makeIterator(getBucketsEnd(), getBucketsEnd(), *this, true);
7480 }
7581 inline const_iterator begin() const {
76 return empty() ? end()
77 : const_iterator(getBuckets(), getBucketsEnd(), *this);
82 if (empty())
83 return end();
84 if (shouldReverseIterate())
85 return makeConstIterator(getBucketsEnd() - 1, getBuckets(), *this);
86 return makeConstIterator(getBuckets(), getBucketsEnd(), *this);
7887 }
7988 inline const_iterator end() const {
80 return const_iterator(getBucketsEnd(), getBucketsEnd(), *this, true);
89 return makeConstIterator(getBucketsEnd(), getBucketsEnd(), *this, true);
8190 }
8291
8392 LLVM_NODISCARD bool empty() const {
136145 iterator find(const_arg_type_t Val) {
137146 BucketT *TheBucket;
138147 if (LookupBucketFor(Val, TheBucket))
139 return iterator(TheBucket, getBucketsEnd(), *this, true);
148 return makeIterator(TheBucket, getBucketsEnd(), *this, true);
140149 return end();
141150 }
142151 const_iterator find(const_arg_type_t Val) const {
143152 const BucketT *TheBucket;
144153 if (LookupBucketFor(Val, TheBucket))
145 return const_iterator(TheBucket, getBucketsEnd(), *this, true);
154 return makeConstIterator(TheBucket, getBucketsEnd(), *this, true);
146155 return end();
147156 }
148157
155164 iterator find_as(const LookupKeyT &Val) {
156165 BucketT *TheBucket;
157166 if (LookupBucketFor(Val, TheBucket))
158 return iterator(TheBucket, getBucketsEnd(), *this, true);
167 return makeIterator(TheBucket, getBucketsEnd(), *this, true);
159168 return end();
160169 }
161170 template
162171 const_iterator find_as(const LookupKeyT &Val) const {
163172 const BucketT *TheBucket;
164173 if (LookupBucketFor(Val, TheBucket))
165 return const_iterator(TheBucket, getBucketsEnd(), *this, true);
174 return makeConstIterator(TheBucket, getBucketsEnd(), *this, true);
166175 return end();
167176 }
168177
196205 std::pair try_emplace(KeyT &&Key, Ts &&... Args) {
197206 BucketT *TheBucket;
198207 if (LookupBucketFor(Key, TheBucket))
199 return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
200 false); // Already in map.
208 return std::make_pair(
209 makeIterator(TheBucket, getBucketsEnd(), *this, true),
210 false); // Already in map.
201211
202212 // Otherwise, insert the new element.
203213 TheBucket =
204214 InsertIntoBucket(TheBucket, std::move(Key), std::forward(Args)...);
205 return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
206 true);
215 return std::make_pair(
216 makeIterator(TheBucket, getBucketsEnd(), *this, true),
217 true);
207218 }
208219
209220 // Inserts key,value pair into the map if the key isn't already in the map.
213224 std::pair try_emplace(const KeyT &Key, Ts &&... Args) {
214225 BucketT *TheBucket;
215226 if (LookupBucketFor(Key, TheBucket))
216 return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
217 false); // Already in map.
227 return std::make_pair(
228 makeIterator(TheBucket, getBucketsEnd(), *this, true),
229 false); // Already in map.
218230
219231 // Otherwise, insert the new element.
220232 TheBucket = InsertIntoBucket(TheBucket, Key, std::forward(Args)...);
221 return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
222 true);
233 return std::make_pair(
234 makeIterator(TheBucket, getBucketsEnd(), *this, true),
235 true);
223236 }
224237
225238 /// Alternate version of insert() which allows a different, and possibly
232245 const LookupKeyT &Val) {
233246 BucketT *TheBucket;
234247 if (LookupBucketFor(Val, TheBucket))
235 return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
236 false); // Already in map.
248 return std::make_pair(
249 makeIterator(TheBucket, getBucketsEnd(), *this, true),
250 false); // Already in map.
237251
238252 // Otherwise, insert the new element.
239253 TheBucket = InsertIntoBucketWithLookup(TheBucket, std::move(KV.first),
240254 std::move(KV.second), Val);
241 return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
242 true);
255 return std::make_pair(
256 makeIterator(TheBucket, getBucketsEnd(), *this, true),
257 true);
243258 }
244259
245260 /// insert - Range insertion of pairs.
410425 }
411426
412427 private:
428 iterator makeIterator(BucketT *P, BucketT *E,
429 DebugEpochBase &Epoch,
430 bool NoAdvance=false) {
431 if (shouldReverseIterate()) {
432 BucketT *B = P == getBucketsEnd() ? getBuckets() : P + 1;
433 return iterator(B, E, Epoch, NoAdvance);
434 }
435 return iterator(P, E, Epoch, NoAdvance);
436 }
437
438 const_iterator makeConstIterator(const BucketT *P, const BucketT *E,
439 const DebugEpochBase &Epoch,
440 const bool NoAdvance=false) const {
441 if (shouldReverseIterate()) {
442 const BucketT *B = P == getBucketsEnd() ? getBuckets() : P + 1;
443 return const_iterator(B, E, Epoch, NoAdvance);
444 }
445 return const_iterator(P, E, Epoch, NoAdvance);
446 }
447
413448 unsigned getNumEntries() const {
414449 return static_cast(this)->getNumEntries();
415450 }
10941129 bool NoAdvance = false)
10951130 : DebugEpochBase::HandleBase(&Epoch), Ptr(Pos), End(E) {
10961131 assert(isHandleInSync() && "invalid construction!");
1097 if (!NoAdvance) AdvancePastEmptyBuckets();
1132
1133 if (NoAdvance) return;
1134 if (shouldReverseIterate()) {
1135 RetreatPastEmptyBuckets();
1136 return;
1137 }
1138 AdvancePastEmptyBuckets();
10981139 }
10991140
11001141 // Converting ctor from non-const iterators to const iterators. SFINAE'd out
11081149
11091150 reference operator*() const {
11101151 assert(isHandleInSync() && "invalid iterator access!");
1152 if (shouldReverseIterate())
1153 return Ptr[-1];
11111154 return *Ptr;
11121155 }
11131156 pointer operator->() const {
11141157 assert(isHandleInSync() && "invalid iterator access!");
1158 if (shouldReverseIterate())
1159 return &(Ptr[-1]);
11151160 return Ptr;
11161161 }
11171162
11321177
11331178 inline DenseMapIterator& operator++() { // Preincrement
11341179 assert(isHandleInSync() && "invalid iterator access!");
1180 if (shouldReverseIterate()) {
1181 --Ptr;
1182 RetreatPastEmptyBuckets();
1183 return *this;
1184 }
11351185 ++Ptr;
11361186 AdvancePastEmptyBuckets();
11371187 return *this;
11431193
11441194 private:
11451195 void AdvancePastEmptyBuckets() {
1196 assert(Ptr <= End);
11461197 const KeyT Empty = KeyInfoT::getEmptyKey();
11471198 const KeyT Tombstone = KeyInfoT::getTombstoneKey();
11481199
11491200 while (Ptr != End && (KeyInfoT::isEqual(Ptr->getFirst(), Empty) ||
11501201 KeyInfoT::isEqual(Ptr->getFirst(), Tombstone)))
11511202 ++Ptr;
1203 }
1204
1205 void RetreatPastEmptyBuckets() {
1206 assert(Ptr >= End);
1207 const KeyT Empty = KeyInfoT::getEmptyKey();
1208 const KeyT Tombstone = KeyInfoT::getTombstoneKey();
1209
1210 while (Ptr != End && (KeyInfoT::isEqual(Ptr[-1].getFirst(), Empty) ||
1211 KeyInfoT::isEqual(Ptr[-1].getFirst(), Tombstone)))
1212 --Ptr;
11521213 }
11531214 };
11541215
1515 #define LLVM_ADT_SMALLPTRSET_H
1616
1717 #include "llvm/Support/Compiler.h"
18 #include "llvm/Support/PointerLikeTypeTraits.h"
1918 #include "llvm/Support/ReverseIteration.h"
2019 #include "llvm/Support/type_traits.h"
2120 #include
223222 public:
224223 explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E)
225224 : Bucket(BP), End(E) {
226 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
227 if (ReverseIterate::value) {
225 if (shouldReverseIterate()) {
228226 RetreatIfNotValid();
229227 return;
230228 }
231 #endif
232229 AdvanceIfNotValid();
233230 }
234231
250247 *Bucket == SmallPtrSetImplBase::getTombstoneMarker()))
251248 ++Bucket;
252249 }
253 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
254250 void RetreatIfNotValid() {
255251 assert(Bucket >= End);
256252 while (Bucket != End &&
259255 --Bucket;
260256 }
261257 }
262 #endif
263258 };
264259
265260 /// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
280275 // Most methods provided by baseclass.
281276
282277 const PtrTy operator*() const {
283 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
284 if (ReverseIterate::value) {
278 if (shouldReverseIterate()) {
285279 assert(Bucket > End);
286280 return PtrTraits::getFromVoidPointer(const_cast(Bucket[-1]));
287281 }
288 #endif
289282 assert(Bucket < End);
290283 return PtrTraits::getFromVoidPointer(const_cast(*Bucket));
291284 }
292285
293286 inline SmallPtrSetIterator& operator++() { // Preincrement
294 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
295 if (ReverseIterate::value) {
287 if (shouldReverseIterate()) {
296288 --Bucket;
297289 RetreatIfNotValid();
298290 return *this;
299291 }
300 #endif
301292 ++Bucket;
302293 AdvanceIfNotValid();
303294 return *this;
395386 }
396387
397388 iterator begin() const {
398 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
399 if (ReverseIterate::value)
389 if (shouldReverseIterate())
400390 return makeIterator(EndPointer() - 1);
401 #endif
402391 return makeIterator(CurArray);
403392 }
404393 iterator end() const { return makeIterator(EndPointer()); }
406395 private:
407396 /// Create an iterator that dereferences to same place as the given pointer.
408397 iterator makeIterator(const void *const *P) const {
409 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
410 if (ReverseIterate::value)
398 if (shouldReverseIterate())
411399 return iterator(P == EndPointer() ? CurArray : P + 1, CurArray);
412 #endif
413400 return iterator(P, EndPointer());
414401 }
415402 };
2929 struct ConstantLog2
3030 : std::integral_constant::value + 1> {};
3131 template <> struct ConstantLog2<1> : std::integral_constant {};
32 }
32
33 // Provide a trait to check if T is pointer-like.
34 template struct HasPointerLikeTypeTraits {
35 static const bool value = false;
36 };
37
38 // sizeof(T) is valid only for a complete T.
39 template struct HasPointerLikeTypeTraits<
40 T, decltype((sizeof(PointerLikeTypeTraits) + sizeof(T)), void())> {
41 static const bool value = true;
42 };
43
44 template struct IsPointerLike {
45 static const bool value = HasPointerLikeTypeTraits::value;
46 };
47
48 template struct IsPointerLike {
49 static const bool value = true;
50 };
51 } // namespace detail
3352
3453 // Provide PointerLikeTypeTraits for non-cvr pointers.
3554 template struct PointerLikeTypeTraits {
11 #define LLVM_SUPPORT_REVERSEITERATION_H
22
33 #include "llvm/Config/abi-breaking.h"
4 #include "llvm/Support/PointerLikeTypeTraits.h"
45
56 namespace llvm {
6 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
7 template struct ReverseIterate { static bool value; };
7
8 template
9 bool shouldReverseIterate() {
810 #if LLVM_ENABLE_REVERSE_ITERATION
9 template bool ReverseIterate::value = true;
11 return detail::IsPointerLike::value;
1012 #else
11 template bool ReverseIterate::value = false;
12 #endif
13 return false;
1314 #endif
1415 }
1516
17 }
1618 #endif
4444 using namespace cl;
4545
4646 #define DEBUG_TYPE "commandline"
47
48 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
49 namespace llvm {
50 // If LLVM_ENABLE_ABI_BREAKING_CHECKS is set the flag -mllvm -reverse-iterate
51 // can be used to toggle forward/reverse iteration of unordered containers.
52 // This will help uncover differences in codegen caused due to undefined
53 // iteration order.
54 static cl::opt ReverseIteration("reverse-iterate",
55 cl::location(ReverseIterate::value));
56 }
57 #endif
5847
5948 //===----------------------------------------------------------------------===//
6049 // Template instantiations and anchors.
+0
-474
test/Transforms/Util/PredicateInfo/condprop2.ll less more
None ; REQUIRES: abi-breaking-checks
1 ; NOTE: The flag -reverse-iterate is present only in a +Asserts build.
2 ; Hence, this test has been split from condprop.ll to test with -reverse-iterate.
3 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
4 ; RUN: opt -print-predicateinfo -analyze -reverse-iterate < %s 2>&1 | FileCheck %s
5
6 @a = external global i32 ; [#uses=7]
7
8 define i32 @test1() nounwind {
9 ; CHECK-LABEL: @test1(
10 ; CHECK-NEXT: entry:
11 ; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* @a, align 4
12 ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 4
13 ; CHECK-NEXT: br i1 [[TMP1]], label [[BB:%.*]], label [[BB1:%.*]]
14 ; CHECK: bb:
15 ; CHECK-NEXT: br label [[BB8:%.*]]
16 ; CHECK: bb1:
17 ; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* @a, align 4
18 ; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 5
19 ; CHECK-NEXT: br i1 [[TMP3]], label [[BB2:%.*]], label [[BB3:%.*]]
20 ; CHECK: bb2:
21 ; CHECK-NEXT: br label [[BB8]]
22 ; CHECK: bb3:
23 ; CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* @a, align 4
24 ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 4
25 ; CHECK-NEXT: br i1 [[TMP5]], label [[BB4:%.*]], label [[BB5:%.*]]
26 ; CHECK: bb4:
27 ; CHECK-NEXT: [[TMP6:%.*]] = load i32, i32* @a, align 4
28 ; CHECK-NEXT: [[TMP7:%.*]] = add i32 [[TMP6]], 5
29 ; CHECK-NEXT: br label [[BB8]]
30 ; CHECK: bb5:
31 ; CHECK-NEXT: [[TMP8:%.*]] = load i32, i32* @a, align 4
32 ; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 5
33 ; CHECK-NEXT: br i1 [[TMP9]], label [[BB6:%.*]], label [[BB7:%.*]]
34 ; CHECK: bb6:
35 ; CHECK-NEXT: [[TMP10:%.*]] = load i32, i32* @a, align 4
36 ; CHECK-NEXT: [[TMP11:%.*]] = add i32 [[TMP10]], 4
37 ; CHECK-NEXT: br label [[BB8]]
38 ; CHECK: bb7:
39 ; CHECK-NEXT: [[TMP12:%.*]] = load i32, i32* @a, align 4
40 ; CHECK-NEXT: br label [[BB8]]
41 ; CHECK: bb8:
42 ; CHECK-NEXT: [[DOT0:%.*]] = phi i32 [ [[TMP12]], [[BB7]] ], [ [[TMP11]], [[BB6]] ], [ [[TMP7]], [[BB4]] ], [ 4, [[BB2]] ], [ 5, [[BB]] ]
43 ; CHECK-NEXT: br label [[RETURN:%.*]]
44 ; CHECK: return:
45 ; CHECK-NEXT: ret i32 [[DOT0]]
46 ;
47 entry:
48 %0 = load i32, i32* @a, align 4
49 %1 = icmp eq i32 %0, 4
50 br i1 %1, label %bb, label %bb1
51
52 bb: ; preds = %entry
53 br label %bb8
54
55 bb1: ; preds = %entry
56 %2 = load i32, i32* @a, align 4
57 %3 = icmp eq i32 %2, 5
58 br i1 %3, label %bb2, label %bb3
59
60 bb2: ; preds = %bb1
61 br label %bb8
62
63 bb3: ; preds = %bb1
64 %4 = load i32, i32* @a, align 4
65 %5 = icmp eq i32 %4, 4
66 br i1 %5, label %bb4, label %bb5
67
68 bb4: ; preds = %bb3
69 %6 = load i32, i32* @a, align 4
70 %7 = add i32 %6, 5
71 br label %bb8
72
73 bb5: ; preds = %bb3
74 %8 = load i32, i32* @a, align 4
75 %9 = icmp eq i32 %8, 5
76 br i1 %9, label %bb6, label %bb7
77
78 bb6: ; preds = %bb5
79 %10 = load i32, i32* @a, align 4
80 %11 = add i32 %10, 4
81 br label %bb8
82
83 bb7: ; preds = %bb5
84 %12 = load i32, i32* @a, align 4
85 br label %bb8
86
87 bb8: ; preds = %bb7, %bb6, %bb4, %bb2, %bb
88 %.0 = phi i32 [ %12, %bb7 ], [ %11, %bb6 ], [ %7, %bb4 ], [ 4, %bb2 ], [ 5, %bb ]
89 br label %return
90
91 return: ; preds = %bb8
92 ret i32 %.0
93 }
94
95 declare void @foo(i1)
96 declare void @bar(i32)
97
98 define void @test3(i32 %x, i32 %y) {
99 ; CHECK-LABEL: @test3(
100 ; CHECK-NEXT: [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
101 ; CHECK-NEXT: [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
102 ; CHECK-NEXT: [[Z:%.*]] = and i1 [[XZ]], [[YZ]]
103 ; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
104 ; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
105 ; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])
106 ; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])
107 ; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]])
108 ; CHECK-NEXT: br i1 [[Z]], label [[BOTH_ZERO:%.*]], label [[NOPE:%.*]]
109 ; CHECK: both_zero:
110 ; CHECK-NEXT: call void @foo(i1 [[XZ_0]])
111 ; CHECK-NEXT: call void @foo(i1 [[YZ_0]])
112 ; CHECK-NEXT: call void @bar(i32 [[X_0]])
113 ; CHECK-NEXT: call void @bar(i32 [[Y_0]])
114 ; CHECK-NEXT: ret void
115 ; CHECK: nope:
116 ; CHECK-NEXT: call void @foo(i1 [[Z_0]])
117 ; CHECK-NEXT: ret void
118 ;
119 %xz = icmp eq i32 %x, 0
120 %yz = icmp eq i32 %y, 0
121 %z = and i1 %xz, %yz
122 br i1 %z, label %both_zero, label %nope
123 both_zero:
124 call void @foo(i1 %xz)
125 call void @foo(i1 %yz)
126 call void @bar(i32 %x)
127 call void @bar(i32 %y)
128 ret void
129 nope:
130 call void @foo(i1 %z)
131 ret void
132 }
133
134 define void @test4(i1 %b, i32 %x) {
135 ; CHECK-LABEL: @test4(
136 ; CHECK-NEXT: br i1 [[B:%.*]], label [[SW:%.*]], label [[CASE3:%.*]]
137 ; CHECK: sw:
138 ; CHECK: i32 0, label [[CASE0:%.*]]
139 ; CHECK-NEXT: i32 1, label [[CASE1:%.*]]
140 ; CHECK-NEXT: i32 2, label [[CASE0]]
141 ; CHECK-NEXT: i32 3, label [[CASE3]]
142 ; CHECK-NEXT: i32 4, label [[DEFAULT:%.*]]
143 ; CHECK-NEXT: ] Edge: [label [[SW]],label %case1] }
144 ; CHECK-NEXT: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X:%.*]])
145 ; CHECK-NEXT: switch i32 [[X]], label [[DEFAULT]] [
146 ; CHECK-NEXT: i32 0, label [[CASE0]]
147 ; CHECK-NEXT: i32 1, label [[CASE1]]
148 ; CHECK-NEXT: i32 2, label [[CASE0]]
149 ; CHECK-NEXT: i32 3, label [[CASE3]]
150 ; CHECK-NEXT: i32 4, label [[DEFAULT]]
151 ; CHECK-NEXT: ]
152 ; CHECK: default:
153 ; CHECK-NEXT: call void @bar(i32 [[X]])
154 ; CHECK-NEXT: ret void
155 ; CHECK: case0:
156 ; CHECK-NEXT: call void @bar(i32 [[X]])
157 ; CHECK-NEXT: ret void
158 ; CHECK: case1:
159 ; CHECK-NEXT: call void @bar(i32 [[X_0]])
160 ; CHECK-NEXT: ret void
161 ; CHECK: case3:
162 ; CHECK-NEXT: call void @bar(i32 [[X]])
163 ; CHECK-NEXT: ret void
164 ;
165 br i1 %b, label %sw, label %case3
166 sw:
167 switch i32 %x, label %default [
168 i32 0, label %case0
169 i32 1, label %case1
170 i32 2, label %case0
171 i32 3, label %case3
172 i32 4, label %default
173 ]
174 default:
175 call void @bar(i32 %x)
176 ret void
177 case0:
178 call void @bar(i32 %x)
179 ret void
180 case1:
181 call void @bar(i32 %x)
182 ret void
183 case3:
184 call void @bar(i32 %x)
185 ret void
186 }
187
188 define i1 @test5(i32 %x, i32 %y) {
189 ; CHECK-LABEL: @test5(
190 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
191 ; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
192 ; CHECK: [[X_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
193 ; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
194 ; CHECK: [[Y_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
195 ; CHECK-NEXT: br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]
196 ; CHECK: same:
197 ; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[X_0]], [[Y_0]]
198 ; CHECK-NEXT: ret i1 [[CMP2]]
199 ; CHECK: different:
200 ; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i32 [[X_1]], [[Y_1]]
201 ; CHECK-NEXT: ret i1 [[CMP3]]
202 ;
203 %cmp = icmp eq i32 %x, %y
204 br i1 %cmp, label %same, label %different
205
206 same:
207 %cmp2 = icmp ne i32 %x, %y
208 ret i1 %cmp2
209
210 different:
211 %cmp3 = icmp eq i32 %x, %y
212 ret i1 %cmp3
213 }
214
215 define i1 @test6(i32 %x, i32 %y) {
216 ; CHECK-LABEL: @test6(
217 ; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[X:%.*]], [[Y:%.*]]
218 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X]], [[Y]]
219 ; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i32 [[X]], [[Y]]
220 ; CHECK-NEXT: br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]
221 ; CHECK: same:
222 ; CHECK-NEXT: ret i1 [[CMP2]]
223 ; CHECK: different:
224 ; CHECK-NEXT: ret i1 [[CMP3]]
225 ;
226 %cmp2 = icmp ne i32 %x, %y
227 %cmp = icmp eq i32 %x, %y
228 %cmp3 = icmp eq i32 %x, %y
229 br i1 %cmp, label %same, label %different
230
231 same:
232 ret i1 %cmp2
233
234 different:
235 ret i1 %cmp3
236 }
237
238 define i1 @test6_fp(float %x, float %y) {
239 ; CHECK-LABEL: @test6_fp(
240 ; CHECK-NEXT: [[CMP2:%.*]] = fcmp une float [[X:%.*]], [[Y:%.*]]
241 ; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq float [[X]], [[Y]]
242 ; CHECK-NEXT: [[CMP3:%.*]] = fcmp oeq float [[X]], [[Y]]
243 ; CHECK-NEXT: br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]
244 ; CHECK: same:
245 ; CHECK-NEXT: ret i1 [[CMP2]]
246 ; CHECK: different:
247 ; CHECK-NEXT: ret i1 [[CMP3]]
248 ;
249 %cmp2 = fcmp une float %x, %y
250 %cmp = fcmp oeq float %x, %y
251 %cmp3 = fcmp oeq float %x, %y
252 br i1 %cmp, label %same, label %different
253
254 same:
255 ret i1 %cmp2
256
257 different:
258 ret i1 %cmp3
259 }
260
261 define i1 @test7(i32 %x, i32 %y) {
262 ; CHECK-LABEL: @test7(
263 ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
264 ; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
265 ; CHECK: [[X_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
266 ; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
267 ; CHECK: [[Y_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
268 ; CHECK-NEXT: br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]
269 ; CHECK: same:
270 ; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i32 [[X_0]], [[Y_0]]
271 ; CHECK-NEXT: ret i1 [[CMP2]]
272 ; CHECK: different:
273 ; CHECK-NEXT: [[CMP3:%.*]] = icmp sgt i32 [[X_1]], [[Y_1]]
274 ; CHECK-NEXT: ret i1 [[CMP3]]
275 ;
276 %cmp = icmp sgt i32 %x, %y
277 br i1 %cmp, label %same, label %different
278
279 same:
280 %cmp2 = icmp sle i32 %x, %y
281 ret i1 %cmp2
282
283 different:
284 %cmp3 = icmp sgt i32 %x, %y
285 ret i1 %cmp3
286 }
287
288 define i1 @test7_fp(float %x, float %y) {
289 ; CHECK-LABEL: @test7_fp(
290 ; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt float [[X:%.*]], [[Y:%.*]]
291 ; CHECK: [[X_0:%.*]] = call float @llvm.ssa.copy.f32(float [[X]])
292 ; CHECK: [[X_1:%.*]] = call float @llvm.ssa.copy.f32(float [[X]])
293 ; CHECK: [[Y_0:%.*]] = call float @llvm.ssa.copy.f32(float [[Y]])
294 ; CHECK: [[Y_1:%.*]] = call float @llvm.ssa.copy.f32(float [[Y]])
295 ; CHECK-NEXT: br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]
296 ; CHECK: same:
297 ; CHECK-NEXT: [[CMP2:%.*]] = fcmp ule float [[X_0]], [[Y_0]]
298 ; CHECK-NEXT: ret i1 [[CMP2]]
299 ; CHECK: different:
300 ; CHECK-NEXT: [[CMP3:%.*]] = fcmp ogt float [[X_1]], [[Y_1]]
301 ; CHECK-NEXT: ret i1 [[CMP3]]
302 ;
303 %cmp = fcmp ogt float %x, %y
304 br i1 %cmp, label %same, label %different
305
306 same:
307 %cmp2 = fcmp ule float %x, %y
308 ret i1 %cmp2
309
310 different:
311 %cmp3 = fcmp ogt float %x, %y
312 ret i1 %cmp3
313 }
314
315 define i1 @test8(i32 %x, i32 %y) {
316 ; CHECK-LABEL: @test8(
317 ; CHECK-NEXT: [[CMP2:%.*]] = icmp sle i32 [[X:%.*]], [[Y:%.*]]
318 ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X]], [[Y]]
319 ; CHECK-NEXT: [[CMP3:%.*]] = icmp sgt i32 [[X]], [[Y]]
320 ; CHECK-NEXT: br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]
321 ; CHECK: same:
322 ; CHECK-NEXT: ret i1 [[CMP2]]
323 ; CHECK: different:
324 ; CHECK-NEXT: ret i1 [[CMP3]]
325 ;
326 %cmp2 = icmp sle i32 %x, %y
327 %cmp = icmp sgt i32 %x, %y
328 %cmp3 = icmp sgt i32 %x, %y
329 br i1 %cmp, label %same, label %different
330
331 same:
332 ret i1 %cmp2
333
334 different:
335 ret i1 %cmp3
336 }
337
338 define i1 @test8_fp(float %x, float %y) {
339 ; CHECK-LABEL: @test8_fp(
340 ; CHECK-NEXT: [[CMP2:%.*]] = fcmp ule float [[X:%.*]], [[Y:%.*]]
341 ; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt float [[X]], [[Y]]
342 ; CHECK-NEXT: [[CMP3:%.*]] = fcmp ogt float [[X]], [[Y]]
343 ; CHECK-NEXT: br i1 [[CMP]], label [[SAME:%.*]], label [[DIFFERENT:%.*]]
344 ; CHECK: same:
345 ; CHECK-NEXT: ret i1 [[CMP2]]
346 ; CHECK: different:
347 ; CHECK-NEXT: ret i1 [[CMP3]]
348 ;
349 %cmp2 = fcmp ule float %x, %y
350 %cmp = fcmp ogt float %x, %y
351 %cmp3 = fcmp ogt float %x, %y
352 br i1 %cmp, label %same, label %different
353
354 same:
355 ret i1 %cmp2
356
357 different:
358 ret i1 %cmp3
359 }
360
361 define i32 @test9(i32 %i, i32 %j) {
362 ; CHECK-LABEL: @test9(
363 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], [[J:%.*]]
364 ; CHECK: [[I_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[I]])
365 ; CHECK: [[J_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[J]])
366 ; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[RET:%.*]]
367 ; CHECK: cond_true:
368 ; CHECK-NEXT: [[DIFF:%.*]] = sub i32 [[I_0]], [[J_0]]
369 ; CHECK-NEXT: ret i32 [[DIFF]]
370 ; CHECK: ret:
371 ; CHECK-NEXT: ret i32 5
372 ;
373 %cmp = icmp eq i32 %i, %j
374 br i1 %cmp, label %cond_true, label %ret
375
376 cond_true:
377 %diff = sub i32 %i, %j
378 ret i32 %diff
379
380 ret:
381 ret i32 5
382 }
383
384 define i32 @test10(i32 %j, i32 %i) {
385 ; CHECK-LABEL: @test10(
386 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], [[J:%.*]]
387 ; CHECK: [[J_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[J]])
388 ; CHECK: [[I_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[I]])
389 ; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[RET:%.*]]
390 ; CHECK: cond_true:
391 ; CHECK-NEXT: [[DIFF:%.*]] = sub i32 [[I_0]], [[J_0]]
392 ; CHECK-NEXT: ret i32 [[DIFF]]
393 ; CHECK: ret:
394 ; CHECK-NEXT: ret i32 5
395 ;
396 %cmp = icmp eq i32 %i, %j
397 br i1 %cmp, label %cond_true, label %ret
398
399 cond_true:
400 %diff = sub i32 %i, %j
401 ret i32 %diff
402
403 ret:
404 ret i32 5
405 }
406
407 declare i32 @yogibar()
408
409 define i32 @test11(i32 %x) {
410 ; CHECK-LABEL: @test11(
411 ; CHECK-NEXT: [[V0:%.*]] = call i32 @yogibar()
412 ; CHECK-NEXT: [[V1:%.*]] = call i32 @yogibar()
413 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[V0]], [[V1]]
414 ; CHECK: [[V0_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[V0]])
415 ; CHECK: [[V1_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[V1]])
416 ; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[NEXT:%.*]]
417 ; CHECK: cond_true:
418 ; CHECK-NEXT: ret i32 [[V1_0]]
419 ; CHECK: next:
420 ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[X:%.*]], [[V0_0]]
421 ; CHECK: [[V0_0_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[V0_0]])
422 ; CHECK-NEXT: br i1 [[CMP2]], label [[COND_TRUE2:%.*]], label [[NEXT2:%.*]]
423 ; CHECK: cond_true2:
424 ; CHECK-NEXT: ret i32 [[V0_0_1]]
425 ; CHECK: next2:
426 ; CHECK-NEXT: ret i32 0
427 ;
428 %v0 = call i32 @yogibar()
429 %v1 = call i32 @yogibar()
430 %cmp = icmp eq i32 %v0, %v1
431 br i1 %cmp, label %cond_true, label %next
432
433 cond_true:
434 ret i32 %v1
435
436 next:
437 %cmp2 = icmp eq i32 %x, %v0
438 br i1 %cmp2, label %cond_true2, label %next2
439
440 cond_true2:
441 ret i32 %v0
442
443 next2:
444 ret i32 0
445 }
446
447 define i32 @test12(i32 %x) {
448 ; CHECK-LABEL: @test12(
449 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
450 ; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
451 ; CHECK: [[X_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
452 ; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
453 ; CHECK: cond_true:
454 ; CHECK-NEXT: br label [[RET:%.*]]
455 ; CHECK: cond_false:
456 ; CHECK-NEXT: br label [[RET]]
457 ; CHECK: ret:
458 ; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[X_0]], [[COND_TRUE]] ], [ [[X_1]], [[COND_FALSE]] ]
459 ; CHECK-NEXT: ret i32 [[RES]]
460 ;
461 %cmp = icmp eq i32 %x, 0
462 br i1 %cmp, label %cond_true, label %cond_false
463
464 cond_true:
465 br label %ret
466
467 cond_false:
468 br label %ret
469
470 ret:
471 %res = phi i32 [ %x, %cond_true ], [ %x, %cond_false ]
472 ret i32 %res
473 }
+0
-214
test/Transforms/Util/PredicateInfo/testandor2.ll less more
None ; REQUIRES: abi-breaking-checks
1 ; NOTE: The flag -reverse-iterate is present only in a +Asserts build.
2 ; Hence, this test has been split from testandor.ll to test with -reverse-iterate.
3 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
4 ; RUN: opt -print-predicateinfo -reverse-iterate < %s 2>&1 | FileCheck %s
5
6 declare void @foo(i1)
7 declare void @bar(i32)
8 declare void @llvm.assume(i1)
9
10 define void @testor(i32 %x, i32 %y) {
11 ; CHECK-LABEL: @testor(
12 ; CHECK-NEXT: [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
13 ; CHECK-NEXT: [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
14 ; CHECK-NEXT: [[Z:%.*]] = or i1 [[XZ]], [[YZ]]
15 ; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
16 ; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
17 ; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])
18 ; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])
19 ; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]])
20 ; CHECK-NEXT: br i1 [[Z]], label [[ONEOF:%.*]], label [[NEITHER:%.*]]
21 ; CHECK: oneof:
22 ; CHECK-NEXT: call void @foo(i1 [[XZ]])
23 ; CHECK-NEXT: call void @foo(i1 [[YZ]])
24 ; CHECK-NEXT: call void @bar(i32 [[X]])
25 ; CHECK-NEXT: call void @bar(i32 [[Y]])
26 ; CHECK-NEXT: ret void
27 ; CHECK: neither:
28 ; CHECK-NEXT: call void @foo(i1 [[XZ_0]])
29 ; CHECK-NEXT: call void @foo(i1 [[YZ_0]])
30 ; CHECK-NEXT: call void @bar(i32 [[X_0]])
31 ; CHECK-NEXT: call void @bar(i32 [[Y_0]])
32 ; CHECK-NEXT: call void @foo(i1 [[Z_0]])
33 ; CHECK-NEXT: ret void
34 ;
35 %xz = icmp eq i32 %x, 0
36 %yz = icmp eq i32 %y, 0
37 %z = or i1 %xz, %yz
38 br i1 %z, label %oneof, label %neither
39 oneof:
40 ;; Should not insert on the true edge for or
41 call void @foo(i1 %xz)
42 call void @foo(i1 %yz)
43 call void @bar(i32 %x)
44 call void @bar(i32 %y)
45 ret void
46 neither:
47 call void @foo(i1 %xz)
48 call void @foo(i1 %yz)
49 call void @bar(i32 %x)
50 call void @bar(i32 %y)
51 call void @foo(i1 %z)
52 ret void
53 }
54 define void @testand(i32 %x, i32 %y) {
55 ; CHECK-LABEL: @testand(
56 ; CHECK-NEXT: [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
57 ; CHECK-NEXT: [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
58 ; CHECK-NEXT: [[Z:%.*]] = and i1 [[XZ]], [[YZ]]
59 ; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
60 ; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
61 ; CHECK: [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])
62 ; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])
63 ; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]])
64 ; CHECK-NEXT: br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
65 ; CHECK: both:
66 ; CHECK-NEXT: call void @foo(i1 [[XZ_0]])
67 ; CHECK-NEXT: call void @foo(i1 [[YZ_0]])
68 ; CHECK-NEXT: call void @bar(i32 [[X_0]])
69 ; CHECK-NEXT: call void @bar(i32 [[Y_0]])
70 ; CHECK-NEXT: ret void
71 ; CHECK: nope:
72 ; CHECK-NEXT: call void @foo(i1 [[XZ]])
73 ; CHECK-NEXT: call void @foo(i1 [[YZ]])
74 ; CHECK-NEXT: call void @bar(i32 [[X]])
75 ; CHECK-NEXT: call void @bar(i32 [[Y]])
76 ; CHECK-NEXT: call void @foo(i1 [[Z_0]])
77 ; CHECK-NEXT: ret void
78 ;
79 %xz = icmp eq i32 %x, 0
80 %yz = icmp eq i32 %y, 0
81 %z = and i1 %xz, %yz
82 br i1 %z, label %both, label %nope
83 both:
84 call void @foo(i1 %xz)
85 call void @foo(i1 %yz)
86 call void @bar(i32 %x)
87 call void @bar(i32 %y)
88 ret void
89 nope:
90 ;; Should not insert on the false edge for and
91 call void @foo(i1 %xz)
92 call void @foo(i1 %yz)
93 call void @bar(i32 %x)
94 call void @bar(i32 %y)
95 call void @foo(i1 %z)
96 ret void
97 }
98 define void @testandsame(i32 %x, i32 %y) {
99 ; CHECK-LABEL: @testandsame(
100 ; CHECK-NEXT: [[XGT:%.*]] = icmp sgt i32 [[X:%.*]], 0
101 ; CHECK-NEXT: [[XLT:%.*]] = icmp slt i32 [[X]], 100
102 ; CHECK-NEXT: [[Z:%.*]] = and i1 [[XGT]], [[XLT]]
103 ; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
104 ; CHECK: [[X_0_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X_0]])
105 ; CHECK: [[XGT_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XGT]])
106 ; CHECK: [[XLT_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XLT]])
107 ; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]])
108 ; CHECK-NEXT: br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
109 ; CHECK: both:
110 ; CHECK-NEXT: call void @foo(i1 [[XGT_0]])
111 ; CHECK-NEXT: call void @foo(i1 [[XLT_0]])
112 ; CHECK-NEXT: call void @bar(i32 [[X_0_1]])
113 ; CHECK-NEXT: ret void
114 ; CHECK: nope:
115 ; CHECK-NEXT: call void @foo(i1 [[XGT]])
116 ; CHECK-NEXT: call void @foo(i1 [[XLT]])
117 ; CHECK-NEXT: call void @foo(i1 [[Z_0]])
118 ; CHECK-NEXT: ret void
119 ;
120 %xgt = icmp sgt i32 %x, 0
121 %xlt = icmp slt i32 %x, 100
122 %z = and i1 %xgt, %xlt
123 br i1 %z, label %both, label %nope
124 both:
125 call void @foo(i1 %xgt)
126 call void @foo(i1 %xlt)
127 call void @bar(i32 %x)
128 ret void
129 nope:
130 call void @foo(i1 %xgt)
131 call void @foo(i1 %xlt)
132 call void @foo(i1 %z)
133 ret void
134 }
135
136 define void @testandassume(i32 %x, i32 %y) {
137 ; CHECK-LABEL: @testandassume(
138 ; CHECK-NEXT: [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
139 ; CHECK-NEXT: [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
140 ; CHECK-NEXT: [[Z:%.*]] = and i1 [[XZ]], [[YZ]]
141 ; CHECK: [[TMP1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]])
142 ; CHECK: [[TMP2:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]])
143 ; CHECK: [[TMP3:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XZ]])
144 ; CHECK: [[TMP4:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]])
145 ; CHECK: [[TMP5:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]])
146 ; CHECK-NEXT: call void @llvm.assume(i1 [[TMP5]])
147 ; CHECK: [[DOT0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[TMP1]])
148 ; CHECK: [[DOT01:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[TMP2]])
149 ; CHECK: [[DOT02:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[TMP3]])
150 ; CHECK: [[DOT03:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[TMP4]])
151 ; CHECK: [[DOT04:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[TMP5]])
152 ; CHECK-NEXT: br i1 [[TMP5]], label [[BOTH:%.*]], label [[NOPE:%.*]]
153 ; CHECK: both:
154 ; CHECK-NEXT: call void @foo(i1 [[DOT02]])
155 ; CHECK-NEXT: call void @foo(i1 [[DOT03]])
156 ; CHECK-NEXT: call void @bar(i32 [[DOT0]])
157 ; CHECK-NEXT: call void @bar(i32 [[DOT01]])
158 ; CHECK-NEXT: ret void
159 ; CHECK: nope:
160 ; CHECK-NEXT: call void @foo(i1 [[DOT04]])
161 ; CHECK-NEXT: ret void
162 ;
163 %xz = icmp eq i32 %x, 0
164 %yz = icmp eq i32 %y, 0
165 %z = and i1 %xz, %yz
166 call void @llvm.assume(i1 %z)
167 br i1 %z, label %both, label %nope
168 both:
169 call void @foo(i1 %xz)
170 call void @foo(i1 %yz)
171 call void @bar(i32 %x)
172 call void @bar(i32 %y)
173 ret void
174 nope:
175 call void @foo(i1 %z)
176 ret void
177 }
178
179 ;; Unlike and/or for branches, assume is *always* true, so we only match and for it
180 define void @testorassume(i32 %x, i32 %y) {
181 ;
182 ; CHECK-LABEL: @testorassume(
183 ; CHECK-NEXT: [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
184 ; CHECK-NEXT: [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
185 ; CHECK-NEXT: [[Z:%.*]] = or i1 [[XZ]], [[YZ]]
186 ; CHECK-NEXT: call void @llvm.assume(i1 [[Z]])
187 ; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]])
188 ; CHECK-NEXT: br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
189 ; CHECK: both:
190 ; CHECK-NEXT: call void @foo(i1 [[XZ]])
191 ; CHECK-NEXT: call void @foo(i1 [[YZ]])
192 ; CHECK-NEXT: call void @bar(i32 [[X]])
193 ; CHECK-NEXT: call void @bar(i32 [[Y]])
194 ; CHECK-NEXT: ret void
195 ; CHECK: nope:
196 ; CHECK-NEXT: call void @foo(i1 [[Z_0]])
197 ; CHECK-NEXT: ret void
198 ;
199 %xz = icmp eq i32 %x, 0
200 %yz = icmp eq i32 %y, 0
201 %z = or i1 %xz, %yz
202 call void @llvm.assume(i1 %z)
203 br i1 %z, label %both, label %nope
204 both:
205 call void @foo(i1 %xz)
206 call void @foo(i1 %yz)
207 call void @bar(i32 %x)
208 call void @bar(i32 %y)
209 ret void
210 nope:
211 call void @foo(i1 %z)
212 ret void
213 }
4141 PostOrderIteratorTest.cpp
4242 PriorityWorklistTest.cpp
4343 RangeAdapterTest.cpp
44 ReverseIterationTest.cpp
4544 SCCIteratorTest.cpp
4645 STLExtrasTest.cpp
4746 ScopeExitTest.cpp
+0
-52
unittests/ADT/ReverseIterationTest.cpp less more
None //===- llvm/unittest/ADT/ReverseIterationTest.cpp ------------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // ReverseIteration unit tests.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "llvm/ADT/SmallPtrSet.h"
14 #include "gtest/gtest.h"
15
16 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
17 using namespace llvm;
18
19 TEST(ReverseIterationTest, SmallPtrSetTest) {
20
21 SmallPtrSet Set;
22 void *Ptrs[] = { (void*)0x1, (void*)0x2, (void*)0x3, (void*)0x4 };
23 void *ReversePtrs[] = { (void*)0x4, (void*)0x3, (void*)0x2, (void*)0x1 };
24
25 for (auto *Ptr: Ptrs)
26 Set.insert(Ptr);
27
28 // Check forward iteration.
29 ReverseIterate::value = false;
30 for (const auto &Tuple : zip(Set, Ptrs))
31 ASSERT_EQ(std::get<0>(Tuple), std::get<1>(Tuple));
32
33 // Check operator++ (post-increment) in forward iteration.
34 int i = 0;
35 for (auto begin = Set.begin(), end = Set.end();
36 begin != end; i++)
37 ASSERT_EQ(*begin++, Ptrs[i]);
38
39 // Check reverse iteration.
40 ReverseIterate::value = true;
41 for (const auto &Tuple : zip(Set, ReversePtrs))
42 ASSERT_EQ(std::get<0>(Tuple), std::get<1>(Tuple));
43
44 // Check operator++ (post-increment) in reverse iteration.
45 i = 0;
46 for (auto begin = Set.begin(), end = Set.end();
47 begin != end; i++)
48 ASSERT_EQ(*begin++, ReversePtrs[i]);
49
50 }
51 #endif
4141 ProcessTest.cpp
4242 ProgramTest.cpp
4343 RegexTest.cpp
44 ReverseIterationTest.cpp
4445 ReplaceFileTest.cpp
4546 ScaledNumberTest.cpp
4647 SourceMgrTest.cpp
0 //===- llvm/unittest/Support/ReverseIterationTest.cpp ---------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===---------------------------------------------------------------------===//
8 //
9 // Reverse Iteration unit tests.
10 //
11 //===---------------------------------------------------------------------===//
12
13 #include "llvm/ADT/DenseMap.h"
14 #include "llvm/ADT/SmallPtrSet.h"
15 #include "llvm/Support/ReverseIteration.h"
16 #include "gtest/gtest.h"
17
18 using namespace llvm;
19
20 TEST(ReverseIterationTest, DenseMapTest1) {
21 static_assert(detail::IsPointerLike::value,
22 "int * is pointer-like");
23 static_assert(detail::IsPointerLike::value,
24 "uintptr_t is pointer-like");
25 struct IncompleteType;
26 static_assert(detail::IsPointerLike::value,
27 "incomplete * is pointer-like");
28
29 // Test reverse iteration for a DenseMap with pointer-like keys.
30 // DenseMap should reverse iterate if its keys are pointer-like.
31 DenseMap Map;
32 int a = 1, b = 2, c = 3, d = 4;
33 int *Keys[] = { &a, &b, &c, &d };
34
35 // Insert keys into the DenseMap.
36 for (auto *Key: Keys)
37 Map[Key] = 0;
38
39 // Note: This is the observed order of keys in the DenseMap.
40 // If there is any change in the behavior of the DenseMap, this order would
41 // need to be adjusted accordingly.
42 int *IterKeys[] = { &a, &b, &c, &d };
43 if (shouldReverseIterate())
44 std::reverse(&IterKeys[0], &IterKeys[4]);
45
46 // Check that the DenseMap is iterated in the expected order.
47 for (const auto &Tuple : zip(Map, IterKeys))
48 ASSERT_EQ(*(std::get<0>(Tuple).first), *(std::get<1>(Tuple)));
49
50 // Check operator++ (post-increment).
51 int i = 0;
52 for (auto iter = Map.begin(), end = Map.end(); iter != end; iter++, ++i)
53 ASSERT_EQ(iter->first, IterKeys[i]);
54 }
55
56 TEST(ReverseIterationTest, DenseMapTest2) {
57 static_assert(!detail::IsPointerLike::value,
58 "int is not pointer-like");
59
60 // For a DenseMap with non-pointer-like keys, forward iteration equals
61 // reverse iteration.
62 DenseMap Map;
63 int Keys[] = { 1, 2, 3, 4 };
64
65 // Insert keys into the DenseMap.
66 for (auto Key: Keys)
67 Map[Key] = 0;
68
69 // Note: This is the observed order of keys in the DenseMap.
70 // If there is any change in the behavior of the DenseMap, this order
71 // would need to be adjusted accordingly.
72 int IterKeys[] = { 2, 4, 1, 3 };
73
74 // Check that the DenseMap is iterated in the expected order.
75 for (const auto &Tuple : zip(Map, IterKeys))
76 ASSERT_EQ(std::get<0>(Tuple).first, std::get<1>(Tuple));
77
78 // Check operator++ (post-increment).
79 int i = 0;
80 for (auto iter = Map.begin(), end = Map.end(); iter != end; iter++, ++i)
81 ASSERT_EQ(iter->first, IterKeys[i]);
82 }
83
84 TEST(ReverseIterationTest, SmallPtrSetTest) {
85 static_assert(detail::IsPointerLike::value,
86 "void * is pointer-like");
87
88 SmallPtrSet Set;
89 int a = 1, b = 2, c = 3, d = 4;
90 int *Ptrs[] = { &a, &b, &c, &d };
91
92 for (auto *Ptr: Ptrs)
93 Set.insert(Ptr);
94
95 // Note: This is the observed order of keys in the SmallPtrSet.
96 // If there is any change in the behavior of the SmallPtrSet, this order
97 // would need to be adjusted accordingly.
98 int *IterPtrs[] = { &a, &b, &c, &d };
99 if (shouldReverseIterate())
100 std::reverse(&IterPtrs[0], &IterPtrs[4]);
101
102 // Check that the SmallPtrSet is iterated in the expected order.
103 for (const auto &Tuple : zip(Set, IterPtrs))
104 ASSERT_EQ(std::get<0>(Tuple), std::get<1>(Tuple));
105
106 // Check operator++ (post-increment).
107 int i = 0;
108 for (auto iter = Set.begin(), end = Set.end(); iter != end; iter++, ++i)
109 ASSERT_EQ(*iter, IterPtrs[i]);
110 }