Skip to content

Commit 1ea2fc8

Browse files
author
David Goldblatt
committed
[BasicAA] Guess reasonable contexts for separate storage hints
The definition of the pointer of the memory location being queried is always one such context. Even this conservative guess can be better than no guess at all in some cases. Fixes #64666
1 parent b49e0eb commit 1ea2fc8

File tree

4 files changed

+79
-10
lines changed

4 files changed

+79
-10
lines changed

llvm/include/llvm/Analysis/ValueTracking.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -810,9 +810,14 @@ bool isAssumeLikeIntrinsic(const Instruction *I);
810810

811811
/// Return true if it is valid to use the assumptions provided by an
812812
/// assume intrinsic, I, at the point in the control-flow identified by the
813-
/// context instruction, CxtI.
813+
/// context instruction, CxtI. By default, ephemeral values of the assumption
814+
/// are treated as an invalid context, to prevent the assumption from being used
815+
/// to optimize away its argument. If the caller can ensure that this won't
816+
/// happen, it can call with AllowEphemerals set to true to get more valid
817+
/// assumptions.
814818
bool isValidAssumeForContext(const Instruction *I, const Instruction *CxtI,
815-
const DominatorTree *DT = nullptr);
819+
const DominatorTree *DT = nullptr,
820+
bool AllowEphemerals = false);
816821

817822
enum class OverflowResult {
818823
/// Always overflows in the direction of signed/unsigned min value.

llvm/lib/Analysis/BasicAliasAnalysis.cpp

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,7 +1543,7 @@ AliasResult BasicAAResult::aliasCheck(const Value *V1, LocationSize V1Size,
15431543
TLI, NullIsValidLocation)))
15441544
return AliasResult::NoAlias;
15451545

1546-
if (CtxI && EnableSeparateStorageAnalysis) {
1546+
if (EnableSeparateStorageAnalysis) {
15471547
for (AssumptionCache::ResultElem &Elem : AC.assumptionsFor(O1)) {
15481548
if (!Elem || Elem.Index == AssumptionCache::ExprResultIdx)
15491549
continue;
@@ -1559,10 +1559,30 @@ AliasResult BasicAAResult::aliasCheck(const Value *V1, LocationSize V1Size,
15591559
const Value *HintO1 = getUnderlyingObject(Hint1);
15601560
const Value *HintO2 = getUnderlyingObject(Hint2);
15611561

1562-
if (((O1 == HintO1 && O2 == HintO2) ||
1563-
(O1 == HintO2 && O2 == HintO1)) &&
1564-
isValidAssumeForContext(Assume, CtxI, DT))
1565-
return AliasResult::NoAlias;
1562+
auto ValidAssumeForPtrContext = [&](const Value *Ptr) {
1563+
if (const Instruction *PtrI = dyn_cast<Instruction>(Ptr)) {
1564+
return isValidAssumeForContext(Assume, PtrI, DT,
1565+
/* AllowEphemerals */ true);
1566+
}
1567+
if (const Argument *PtrA = dyn_cast<Argument>(Ptr)) {
1568+
const Instruction *FirstI =
1569+
&*PtrA->getParent()->getEntryBlock().begin();
1570+
return isValidAssumeForContext(Assume, FirstI, DT,
1571+
/* AllowEphemerals */ true);
1572+
}
1573+
return false;
1574+
};
1575+
1576+
if ((O1 == HintO1 && O2 == HintO2) || (O1 == HintO2 && O2 == HintO1)) {
1577+
// Note that we go back to V1 and V2 for the
1578+
// ValidAssumeForPtrContext checks; they're dominated by O1 and O2,
1579+
// so strictly more assumptions are valid for them.
1580+
if ((CtxI && isValidAssumeForContext(Assume, CtxI, DT,
1581+
/* AllowEphemerals */ true)) ||
1582+
ValidAssumeForPtrContext(V1) || ValidAssumeForPtrContext(V2)) {
1583+
return AliasResult::NoAlias;
1584+
}
1585+
}
15661586
}
15671587
}
15681588
}

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,8 @@ bool llvm::isAssumeLikeIntrinsic(const Instruction *I) {
485485

486486
bool llvm::isValidAssumeForContext(const Instruction *Inv,
487487
const Instruction *CxtI,
488-
const DominatorTree *DT) {
488+
const DominatorTree *DT,
489+
bool AllowEphemerals) {
489490
// There are two restrictions on the use of an assume:
490491
// 1. The assume must dominate the context (or the control flow must
491492
// reach the assume whenever it reaches the context).
@@ -503,7 +504,7 @@ bool llvm::isValidAssumeForContext(const Instruction *Inv,
503504
// Don't let an assume affect itself - this would cause the problems
504505
// `isEphemeralValueOf` is trying to prevent, and it would also make
505506
// the loop below go out of bounds.
506-
if (Inv == CxtI)
507+
if (!AllowEphemerals && Inv == CxtI)
507508
return false;
508509

509510
// The context comes first, but they're both in the same block.
@@ -516,7 +517,7 @@ bool llvm::isValidAssumeForContext(const Instruction *Inv,
516517
if (!isGuaranteedToTransferExecutionToSuccessor(Range, 15))
517518
return false;
518519

519-
return !isEphemeralValueOf(Inv, CxtI);
520+
return AllowEphemerals || !isEphemeralValueOf(Inv, CxtI);
520521
}
521522

522523
// Inv and CxtI are in different blocks.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
; We want BasicAA to make a reasonable conservative guess as to context for
2+
; separate storage hints. This lets alias analysis users (such as the alias set
3+
; tracker) who can't be context-sensitive still get the benefits of hints.
4+
5+
; RUN: opt < %s -basic-aa-separate-storage -S -passes=print-alias-sets 2>&1 | FileCheck %s
6+
7+
declare void @llvm.assume(i1)
8+
9+
; CHECK-LABEL: Alias sets for function 'arg_arg'
10+
; CHECK: AliasSet[{{.*}}, 1] must alias, Ref Pointers: (ptr %a1, LocationSize::precise(1))
11+
; CHECK: AliasSet[{{.*}}, 1] must alias, Ref Pointers: (ptr %a2, LocationSize::precise(1))
12+
define void @arg_arg(ptr %a1, ptr %a2) {
13+
entry:
14+
call void @llvm.assume(i1 true) [ "separate_storage"(ptr %a1, ptr %a2) ]
15+
%0 = load i8, ptr %a1
16+
%1 = load i8, ptr %a2
17+
ret void
18+
}
19+
20+
; CHECK-LABEL: Alias sets for function 'arg_inst'
21+
; CHECK: AliasSet[{{.*}}, 1] must alias, Ref Pointers: (ptr %a1, LocationSize::precise(1))
22+
; CHECK: AliasSet[{{.*}}, 1] must alias, Ref Pointers: (ptr %0, LocationSize::precise(1))
23+
define void @arg_inst(ptr %a1, ptr %a2) {
24+
entry:
25+
%0 = getelementptr inbounds i8, ptr %a2, i64 20
26+
call void @llvm.assume(i1 true) [ "separate_storage"(ptr %a1, ptr %0) ]
27+
%1 = load i8, ptr %a1
28+
%2 = load i8, ptr %0
29+
ret void
30+
}
31+
32+
; CHECK-LABEL: Alias sets for function 'inst_inst'
33+
; CHECK: AliasSet[{{.*}}, 1] must alias, Ref Pointers: (ptr %0, LocationSize::precise(1))
34+
; CHECK: AliasSet[{{.*}}, 1] must alias, Ref Pointers: (ptr %1, LocationSize::precise(1))
35+
define void @inst_inst(ptr %a1, ptr %a2) {
36+
entry:
37+
%0 = getelementptr inbounds i8, ptr %a1, i64 20
38+
%1 = getelementptr inbounds i8, ptr %a2, i64 20
39+
call void @llvm.assume(i1 true) [ "separate_storage"(ptr %0, ptr %1) ]
40+
%2 = load i8, ptr %0
41+
%3 = load i8, ptr %1
42+
ret void
43+
}

0 commit comments

Comments
 (0)