Skip to content

Commit 952ad47

Browse files
committed
[ValueTracking] Let isGuaranteedNotToBeUndefOrPoison look into branch conditions of dominating blocks' terminators
Summary: ``` br i1 c, BB1, BB2: BB1: use1(c) BB2: use2(c) ``` In BB1 and BB2, c is never undef or poison because otherwise the branch would have triggered UB. Checked with Alive2 Reviewers: xbolva00, spatel, lebedev.ri, reames, jdoerfert, nlopes, sanjoy Reviewed By: reames Subscribers: jdoerfert, hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D75401
1 parent e91e1df commit 952ad47

File tree

4 files changed

+100
-5
lines changed

4 files changed

+100
-5
lines changed

llvm/include/llvm/Analysis/ValueTracking.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,13 @@ class Value;
569569

570570
/// Return true if this function can prove that V is never undef value
571571
/// or poison value.
572-
bool isGuaranteedNotToBeUndefOrPoison(const Value *V);
572+
//
573+
/// If CtxI and DT are specified this method performs flow-sensitive analysis
574+
/// and returns true if it is guaranteed to be never undef or poison
575+
/// immediately before the CtxI.
576+
bool isGuaranteedNotToBeUndefOrPoison(const Value *V,
577+
const Instruction *CtxI = nullptr,
578+
const DominatorTree *DT = nullptr);
573579

574580
/// Specific patterns of select instructions we can match.
575581
enum SelectPatternFlavor {

llvm/lib/Analysis/InstructionSimplify.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5361,16 +5361,17 @@ Value *llvm::SimplifyCall(CallBase *Call, const SimplifyQuery &Q) {
53615361
}
53625362

53635363
/// Given operands for a Freeze, see if we can fold the result.
5364-
static Value *SimplifyFreezeInst(Value *Op0) {
5364+
static Value *SimplifyFreezeInst(Value *Op0, const SimplifyQuery &Q) {
53655365
// Use a utility function defined in ValueTracking.
5366-
if (llvm::isGuaranteedNotToBeUndefOrPoison(Op0))
5366+
if (llvm::isGuaranteedNotToBeUndefOrPoison(Op0, Q.CxtI, Q.DT))
53675367
return Op0;
5368+
53685369
// We have room for improvement.
53695370
return nullptr;
53705371
}
53715372

53725373
Value *llvm::SimplifyFreezeInst(Value *Op0, const SimplifyQuery &Q) {
5373-
return ::SimplifyFreezeInst(Op0);
5374+
return ::SimplifyFreezeInst(Op0, Q);
53745375
}
53755376

53765377
/// See if we can compute a simplified version of this instruction.

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4525,7 +4525,9 @@ bool llvm::isOverflowIntrinsicNoWrap(const WithOverflowInst *WO,
45254525
return llvm::any_of(GuardingBranches, AllUsesGuardedByBranch);
45264526
}
45274527

4528-
bool llvm::isGuaranteedNotToBeUndefOrPoison(const Value *V) {
4528+
bool llvm::isGuaranteedNotToBeUndefOrPoison(const Value *V,
4529+
const Instruction *CtxI,
4530+
const DominatorTree *DT) {
45294531
// If the value is a freeze instruction, then it can never
45304532
// be undef or poison.
45314533
if (isa<FreezeInst>(V))
@@ -4558,6 +4560,29 @@ bool llvm::isGuaranteedNotToBeUndefOrPoison(const Value *V) {
45584560
return true;
45594561
}
45604562

4563+
if (!CtxI || !DT)
4564+
return false;
4565+
4566+
// If V is used as a branch condition before reaching CtxI, V cannot be
4567+
// undef or poison.
4568+
// br V, BB1, BB2
4569+
// BB1:
4570+
// CtxI ; V cannot be undef or poison here
4571+
auto Dominator = DT->getNode(CtxI->getParent())->getIDom();
4572+
while (Dominator) {
4573+
auto *TI = Dominator->getBlock()->getTerminator();
4574+
4575+
if (auto BI = dyn_cast<BranchInst>(TI)) {
4576+
if (BI->isConditional() && BI->getCondition() == V)
4577+
return true;
4578+
} else if (auto SI = dyn_cast<SwitchInst>(TI)) {
4579+
if (SI->getCondition() == V)
4580+
return true;
4581+
}
4582+
4583+
Dominator = Dominator->getIDom();
4584+
}
4585+
45614586
return false;
45624587
}
45634588

llvm/test/Transforms/InstSimplify/freeze.ll

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,66 @@ define i32 @make_const() {
1818
%x = freeze i32 10
1919
ret i32 %x
2020
}
21+
22+
define i1 @brcond(i1 %c, i1 %c2) {
23+
; CHECK-LABEL: @brcond(
24+
; CHECK-NEXT: br i1 [[C:%.*]], label [[A:%.*]], label [[B:%.*]]
25+
; CHECK: A:
26+
; CHECK-NEXT: br i1 [[C2:%.*]], label [[A2:%.*]], label [[B]]
27+
; CHECK: A2:
28+
; CHECK-NEXT: ret i1 [[C]]
29+
; CHECK: B:
30+
; CHECK-NEXT: ret i1 [[C]]
31+
;
32+
br i1 %c, label %A, label %B
33+
A:
34+
br i1 %c2, label %A2, label %B
35+
A2:
36+
%f1 = freeze i1 %c
37+
ret i1 %f1
38+
B:
39+
%f2 = freeze i1 %c
40+
ret i1 %f2
41+
}
42+
43+
define i32 @brcond_switch(i32 %x) {
44+
; CHECK-LABEL: @brcond_switch(
45+
; CHECK-NEXT: switch i32 [[X:%.*]], label [[EXIT:%.*]] [
46+
; CHECK-NEXT: i32 0, label [[A:%.*]]
47+
; CHECK-NEXT: ]
48+
; CHECK: A:
49+
; CHECK-NEXT: ret i32 [[X]]
50+
; CHECK: EXIT:
51+
; CHECK-NEXT: ret i32 [[X]]
52+
;
53+
switch i32 %x, label %EXIT [ i32 0, label %A ]
54+
A:
55+
%fr1 = freeze i32 %x
56+
ret i32 %fr1
57+
EXIT:
58+
%fr2 = freeze i32 %x
59+
ret i32 %fr2
60+
}
61+
62+
define i1 @brcond_noopt(i1 %c, i1 %c2) {
63+
; CHECK-LABEL: @brcond_noopt(
64+
; CHECK-NEXT: [[F:%.*]] = freeze i1 [[C:%.*]]
65+
; CHECK-NEXT: call void @f1(i1 [[F]])
66+
; CHECK-NEXT: call void @f2()
67+
; CHECK-NEXT: br i1 [[C]], label [[A:%.*]], label [[B:%.*]]
68+
; CHECK: A:
69+
; CHECK-NEXT: ret i1 false
70+
; CHECK: B:
71+
; CHECK-NEXT: ret i1 true
72+
;
73+
%f = freeze i1 %c
74+
call void @f1(i1 %f) ; cannot optimize i1 %f to %c
75+
call void @f2() ; .. because if f2() exits, `br %c` cannot be reached
76+
br i1 %c, label %A, label %B
77+
A:
78+
ret i1 0
79+
B:
80+
ret i1 1
81+
}
82+
declare void @f1(i1)
83+
declare void @f2()

0 commit comments

Comments
 (0)