Skip to content

Commit 9b8bc53

Browse files
authored
[FlattenCFG] Fix an Imprecise Usage of AA (#128117)
In current `FlattenCFG`, using `isNoAlias` for two instructions is imprecise. For example, when passing a store instruction and a load instruction directly into `AA->isNoAlias`, it will always return `NoAlias`. This happens because when checking the types of the two Values, the store instruction (which has a `void` type) causes the analysis to return `NoAlias`. For instructions, we should use `getModRefInfo` instead of `isNoAlias`, as aliasing is a concept of memory locations. In this patch, `AAResults::getModRefInfo` is supported to take in two instructions. It will check whether two instructions may access the same memory location or not. And in `FlattenCFG`, we use this new helper function to do the check instead of `isNoAlias`. Unit tests and lit tests are also included to this patch.
1 parent 9bdd9dc commit 9b8bc53

File tree

5 files changed

+183
-2
lines changed

5 files changed

+183
-2
lines changed

llvm/include/llvm/Analysis/AliasAnalysis.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,10 @@ class AAResults {
521521
/// the same memory locations.
522522
ModRefInfo getModRefInfo(const Instruction *I, const CallBase *Call);
523523

524+
/// Return information about whether two instructions may refer to the same
525+
/// memory locations.
526+
ModRefInfo getModRefInfo(const Instruction *I1, const Instruction *I2);
527+
524528
/// Return information about whether a particular call site modifies
525529
/// or reads the specified memory location \p MemLoc before instruction \p I
526530
/// in a BasicBlock.
@@ -600,6 +604,8 @@ class AAResults {
600604
ModRefInfo getModRefInfo(const Instruction *I,
601605
const std::optional<MemoryLocation> &OptLoc,
602606
AAQueryInfo &AAQIP);
607+
ModRefInfo getModRefInfo(const Instruction *I1, const Instruction *I2,
608+
AAQueryInfo &AAQI);
603609
ModRefInfo callCapturesBefore(const Instruction *I,
604610
const MemoryLocation &MemLoc, DominatorTree *DT,
605611
AAQueryInfo &AAQIP);

llvm/lib/Analysis/AliasAnalysis.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,26 @@ ModRefInfo AAResults::getModRefInfo(const CallBase *Call1,
336336
return Result;
337337
}
338338

339+
ModRefInfo AAResults::getModRefInfo(const Instruction *I1,
340+
const Instruction *I2) {
341+
SimpleAAQueryInfo AAQIP(*this);
342+
return getModRefInfo(I1, I2, AAQIP);
343+
}
344+
345+
ModRefInfo AAResults::getModRefInfo(const Instruction *I1,
346+
const Instruction *I2, AAQueryInfo &AAQI) {
347+
// Early-exit if either instruction does not read or write memory.
348+
if (!I1->mayReadOrWriteMemory() || !I2->mayReadOrWriteMemory())
349+
return ModRefInfo::NoModRef;
350+
351+
if (const auto *Call2 = dyn_cast<CallBase>(I2))
352+
return getModRefInfo(I1, Call2, AAQI);
353+
354+
// FIXME: We can have a more precise result.
355+
ModRefInfo MR = getModRefInfo(I1, MemoryLocation::getOrNone(I2), AAQI);
356+
return isModOrRefSet(MR) ? ModRefInfo::ModRef : ModRefInfo::NoModRef;
357+
}
358+
339359
MemoryEffects AAResults::getMemoryEffects(const CallBase *Call,
340360
AAQueryInfo &AAQI) {
341361
MemoryEffects Result = MemoryEffects::unknown();

llvm/lib/Transforms/Utils/FlattenCFG.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,8 +356,8 @@ bool FlattenCFGOpt::CompareIfRegionBlock(BasicBlock *Block1, BasicBlock *Block2,
356356
if (iter1->mayWriteToMemory()) {
357357
for (BasicBlock::iterator BI(PBI2), BE(PTI2); BI != BE; ++BI) {
358358
if (BI->mayReadFromMemory() || BI->mayWriteToMemory()) {
359-
// Check alias with Head2.
360-
if (!AA || !AA->isNoAlias(&*iter1, &*BI))
359+
// Check whether iter1 and BI may access the same memory location.
360+
if (!AA || AA->getModRefInfo(&*iter1, &*BI) != ModRefInfo::NoModRef)
361361
return false;
362362
}
363363
}

llvm/test/Transforms/Util/flatten-cfg.ll

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,3 +309,143 @@ if.then.y:
309309
exit:
310310
ret i1 %cmp.y
311311
}
312+
313+
declare void @foo()
314+
declare void @bar() #1
315+
316+
; Test that two if-regions are not merged when there's potential aliasing
317+
; between a store in the first if-region and a load in the second if-region's header
318+
define i32 @test_alias(i32 %a, i32 %b, ptr %p1, ptr %p2) {
319+
; CHECK-LABEL: define i32 @test_alias
320+
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], ptr [[P1:%.*]], ptr [[P2:%.*]]) {
321+
; CHECK-NEXT: entry:
322+
; CHECK-NEXT: store i32 42, ptr [[P1]], align 4
323+
; CHECK-NEXT: [[COND1:%.*]] = icmp eq i32 [[A]], 0
324+
; CHECK-NEXT: br i1 [[COND1]], label [[IF_THEN1:%.*]], label [[IF_END1:%.*]]
325+
; CHECK: if.then1:
326+
; CHECK-NEXT: store i32 100, ptr [[P2]], align 4
327+
; CHECK-NEXT: br label [[IF_END1]]
328+
; CHECK: if.end1:
329+
; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[P1]], align 4
330+
; CHECK-NEXT: [[COND2:%.*]] = icmp eq i32 [[B]], 0
331+
; CHECK-NEXT: br i1 [[COND2]], label [[IF_THEN2:%.*]], label [[IF_END2:%.*]]
332+
; CHECK: if.then2:
333+
; CHECK-NEXT: store i32 100, ptr [[P2]], align 4
334+
; CHECK-NEXT: br label [[IF_END2]]
335+
; CHECK: if.end2:
336+
; CHECK-NEXT: ret i32 0
337+
;
338+
entry:
339+
store i32 42, ptr %p1
340+
%cond1 = icmp eq i32 %a, 0
341+
br i1 %cond1, label %if.then1, label %if.end1
342+
343+
if.then1:
344+
store i32 100, ptr %p2 ; May alias with the load below
345+
br label %if.end1
346+
347+
if.end1:
348+
%val = load i32, ptr %p1 ; This load prevents merging due to potential alias
349+
%cond2 = icmp eq i32 %b, 0
350+
br i1 %cond2, label %if.then2, label %if.end2
351+
352+
if.then2:
353+
store i32 100, ptr %p2
354+
br label %if.end2
355+
356+
if.end2:
357+
ret i32 0
358+
}
359+
360+
; Test that two if-regions are not merged when there's potential aliasing
361+
; between a store in the first if-region and a function call in the second if-region's header
362+
define i32 @test_alias_2(i32 %a, i32 %b) {
363+
; CHECK-LABEL: define i32 @test_alias_2
364+
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
365+
; CHECK-NEXT: entry:
366+
; CHECK-NEXT: [[P:%.*]] = alloca i32, align 4
367+
; CHECK-NEXT: store i32 42, ptr [[P]], align 4
368+
; CHECK-NEXT: [[COND1:%.*]] = icmp eq i32 [[A]], 0
369+
; CHECK-NEXT: br i1 [[COND1]], label [[IF_THEN1:%.*]], label [[IF_END1:%.*]]
370+
; CHECK: if.then1:
371+
; CHECK-NEXT: store i32 100, ptr @g, align 4
372+
; CHECK-NEXT: br label [[IF_END1]]
373+
; CHECK: if.end1:
374+
; CHECK-NEXT: call void @foo()
375+
; CHECK-NEXT: [[COND2:%.*]] = icmp eq i32 [[B]], 0
376+
; CHECK-NEXT: br i1 [[COND2]], label [[IF_THEN2:%.*]], label [[IF_END2:%.*]]
377+
; CHECK: if.then2:
378+
; CHECK-NEXT: store i32 100, ptr @g, align 4
379+
; CHECK-NEXT: br label [[IF_END2]]
380+
; CHECK: if.end2:
381+
; CHECK-NEXT: ret i32 0
382+
;
383+
entry:
384+
%p = alloca i32
385+
store i32 42, ptr %p
386+
%cond1 = icmp eq i32 %a, 0
387+
br i1 %cond1, label %if.then1, label %if.end1
388+
389+
if.then1:
390+
store i32 100, ptr @g
391+
br label %if.end1
392+
393+
if.end1:
394+
call void @foo()
395+
%cond2 = icmp eq i32 %b, 0
396+
br i1 %cond2, label %if.then2, label %if.end2
397+
398+
if.then2:
399+
store i32 100, ptr @g
400+
br label %if.end2
401+
402+
if.end2:
403+
ret i32 0
404+
}
405+
406+
; Test that two if-regions are merged when there's no potential aliasing
407+
; between a store in the first if-region and a load in the second if-region's header
408+
define i32 @test_no_alias(i32 %a, i32 %b) {
409+
; CHECK-LABEL: define i32 @test_no_alias
410+
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
411+
; CHECK-NEXT: entry:
412+
; CHECK-NEXT: [[P:%.*]] = alloca i32, align 4
413+
; CHECK-NEXT: store i32 42, ptr [[P]], align 4
414+
; CHECK-NEXT: [[COND1:%.*]] = icmp eq i32 [[A]], 0
415+
; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr @g, align 4
416+
; CHECK-NEXT: [[COND2:%.*]] = icmp eq i32 [[B]], 0
417+
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND1]], [[COND2]]
418+
; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN2:%.*]], label [[IF_END2:%.*]]
419+
; CHECK: if.then2:
420+
; CHECK-NEXT: store i32 100, ptr [[P]], align 4
421+
; CHECK-NEXT: call void @bar()
422+
; CHECK-NEXT: br label [[IF_END2]]
423+
; CHECK: if.end2:
424+
; CHECK-NEXT: ret i32 0
425+
;
426+
entry:
427+
%p = alloca i32
428+
store i32 42, ptr %p
429+
%cond1 = icmp eq i32 %a, 0
430+
br i1 %cond1, label %if.then1, label %if.end1
431+
432+
if.then1:
433+
store i32 100, ptr %p ; No alias with the load below
434+
call void @bar() ; No alias with the load below since it's a pure function
435+
br label %if.end1
436+
437+
if.end1:
438+
%val = load i32, ptr @g
439+
%cond2 = icmp eq i32 %b, 0
440+
br i1 %cond2, label %if.then2, label %if.end2
441+
442+
if.then2:
443+
store i32 100, ptr %p
444+
call void @bar()
445+
br label %if.end2
446+
447+
if.end2:
448+
ret i32 0
449+
}
450+
451+
attributes #1 = { readnone willreturn nounwind }

llvm/unittests/Analysis/AliasAnalysisTest.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,14 @@ TEST_F(AliasAnalysisTest, getModRefInfo) {
186186
AtomicRMWInst::Xchg, Addr, ConstantInt::get(IntType, 1), Alignment,
187187
AtomicOrdering::Monotonic, SyncScope::System, BB);
188188

189+
FunctionType *FooBarTy = FunctionType::get(Type::getVoidTy(C), {}, false);
190+
Function::Create(FooBarTy, Function::ExternalLinkage, "foo", &M);
191+
auto *BarF = Function::Create(FooBarTy, Function::ExternalLinkage, "bar", &M);
192+
BarF->setDoesNotAccessMemory();
193+
194+
const Instruction *Foo = CallInst::Create(M.getFunction("foo"), {}, BB);
195+
const Instruction *Bar = CallInst::Create(M.getFunction("bar"), {}, BB);
196+
189197
ReturnInst::Create(C, nullptr, BB);
190198

191199
auto &AA = getAAResults(*F);
@@ -203,6 +211,13 @@ TEST_F(AliasAnalysisTest, getModRefInfo) {
203211
EXPECT_EQ(AA.getModRefInfo(CmpXChg1, std::nullopt), ModRefInfo::ModRef);
204212
EXPECT_EQ(AA.getModRefInfo(AtomicRMW, MemoryLocation()), ModRefInfo::ModRef);
205213
EXPECT_EQ(AA.getModRefInfo(AtomicRMW, std::nullopt), ModRefInfo::ModRef);
214+
EXPECT_EQ(AA.getModRefInfo(Store1, Load1), ModRefInfo::ModRef);
215+
EXPECT_EQ(AA.getModRefInfo(Store1, Store1), ModRefInfo::ModRef);
216+
EXPECT_EQ(AA.getModRefInfo(Store1, Add1), ModRefInfo::NoModRef);
217+
EXPECT_EQ(AA.getModRefInfo(Store1, Foo), ModRefInfo::ModRef);
218+
EXPECT_EQ(AA.getModRefInfo(Store1, Bar), ModRefInfo::NoModRef);
219+
EXPECT_EQ(AA.getModRefInfo(Foo, Bar), ModRefInfo::NoModRef);
220+
EXPECT_EQ(AA.getModRefInfo(Foo, Foo), ModRefInfo::ModRef);
206221
}
207222

208223
static Instruction *getInstructionByName(Function &F, StringRef Name) {

0 commit comments

Comments
 (0)