|
7 | 7 | //===----------------------------------------------------------------------===//
|
8 | 8 |
|
9 | 9 | #include "llvm/Analysis/Loads.h"
|
| 10 | +#include "llvm/Analysis/AssumptionCache.h" |
| 11 | +#include "llvm/Analysis/LoopInfo.h" |
| 12 | +#include "llvm/Analysis/ScalarEvolution.h" |
| 13 | +#include "llvm/Analysis/TargetLibraryInfo.h" |
10 | 14 | #include "llvm/AsmParser/Parser.h"
|
11 | 15 | #include "llvm/IR/Constants.h"
|
| 16 | +#include "llvm/IR/Dominators.h" |
12 | 17 | #include "llvm/IR/Instructions.h"
|
13 | 18 | #include "llvm/IR/LLVMContext.h"
|
14 | 19 | #include "llvm/IR/Module.h"
|
@@ -114,3 +119,85 @@ define void @f(i32* %p1, i32* %p2, i64 %i) {
|
114 | 119 | EXPECT_TRUE(canReplacePointersInUseIfEqual(PtrToIntUse, P2, DL));
|
115 | 120 | EXPECT_TRUE(canReplacePointersInUseIfEqual(IcmpUse, P2, DL));
|
116 | 121 | }
|
| 122 | + |
| 123 | +TEST(LoadsTest, IsDerefReadOnlyLoop) { |
| 124 | + LLVMContext C; |
| 125 | + std::unique_ptr<Module> M = parseIR(C, |
| 126 | + R"IR( |
| 127 | +define i64 @f1() { |
| 128 | +entry: |
| 129 | + %p1 = alloca [1024 x i8] |
| 130 | + %p2 = alloca [1024 x i8] |
| 131 | + br label %loop |
| 132 | +
|
| 133 | +loop: |
| 134 | + %index = phi i64 [ %index.next, %loop.inc ], [ 3, %entry ] |
| 135 | + %arrayidx = getelementptr inbounds i8, ptr %p1, i64 %index |
| 136 | + %ld1 = load i8, ptr %arrayidx, align 1 |
| 137 | + %arrayidx1 = getelementptr inbounds i8, ptr %p2, i64 %index |
| 138 | + %ld2 = load i8, ptr %arrayidx1, align 1 |
| 139 | + %cmp3 = icmp eq i8 %ld1, %ld2 |
| 140 | + br i1 %cmp3, label %loop.inc, label %loop.end |
| 141 | +
|
| 142 | +loop.inc: |
| 143 | + %index.next = add i64 %index, 1 |
| 144 | + %exitcond = icmp ne i64 %index.next, 67 |
| 145 | + br i1 %exitcond, label %loop, label %loop.end |
| 146 | +
|
| 147 | +loop.end: |
| 148 | + %retval = phi i64 [ %index, %loop ], [ 67, %loop.inc ] |
| 149 | + ret i64 %retval |
| 150 | +} |
| 151 | +
|
| 152 | +define i64 @f2(ptr %p1) { |
| 153 | +entry: |
| 154 | + %p2 = alloca [1024 x i8] |
| 155 | + br label %loop |
| 156 | +
|
| 157 | +loop: |
| 158 | + %index = phi i64 [ %index.next, %loop.inc ], [ 3, %entry ] |
| 159 | + %arrayidx = getelementptr inbounds i8, ptr %p1, i64 %index |
| 160 | + %ld1 = load i8, ptr %arrayidx, align 1 |
| 161 | + %arrayidx1 = getelementptr inbounds i8, ptr %p2, i64 %index |
| 162 | + %ld2 = load i8, ptr %arrayidx1, align 1 |
| 163 | + %cmp3 = icmp eq i8 %ld1, %ld2 |
| 164 | + br i1 %cmp3, label %loop.inc, label %loop.end |
| 165 | +
|
| 166 | +loop.inc: |
| 167 | + %index.next = add i64 %index, 1 |
| 168 | + %exitcond = icmp ne i64 %index.next, 67 |
| 169 | + br i1 %exitcond, label %loop, label %loop.end |
| 170 | +
|
| 171 | +loop.end: |
| 172 | + %retval = phi i64 [ %index, %loop ], [ 67, %loop.inc ] |
| 173 | + ret i64 %retval |
| 174 | +} |
| 175 | +)IR"); |
| 176 | + auto *GV1 = M->getNamedValue("f1"); |
| 177 | + auto *GV2 = M->getNamedValue("f2"); |
| 178 | + ASSERT_TRUE(GV1 && GV2); |
| 179 | + auto *F1 = dyn_cast<Function>(GV1); |
| 180 | + auto *F2 = dyn_cast<Function>(GV2); |
| 181 | + ASSERT_TRUE(F1 && F2); |
| 182 | + |
| 183 | + TargetLibraryInfoImpl TLII; |
| 184 | + TargetLibraryInfo TLI(TLII); |
| 185 | + |
| 186 | + auto IsDerefReadOnlyLoop = [&TLI](Function *F) -> bool { |
| 187 | + AssumptionCache AC(*F); |
| 188 | + DominatorTree DT(*F); |
| 189 | + LoopInfo LI(DT); |
| 190 | + ScalarEvolution SE(*F, TLI, AC, DT, LI); |
| 191 | + |
| 192 | + Function::iterator FI = F->begin(); |
| 193 | + // First basic block is entry - skip it. |
| 194 | + BasicBlock *Header = &*(++FI); |
| 195 | + assert(Header->getName() == "loop"); |
| 196 | + Loop *L = LI.getLoopFor(Header); |
| 197 | + |
| 198 | + return isDereferenceableReadOnlyLoop(L, &SE, &DT, &AC); |
| 199 | + }; |
| 200 | + |
| 201 | + ASSERT_TRUE(IsDerefReadOnlyLoop(F1)); |
| 202 | + ASSERT_FALSE(IsDerefReadOnlyLoop(F2)); |
| 203 | +} |
0 commit comments