Skip to content

Commit a56ba1f

Browse files
authored
[ValueTracking] Handle recursive select/PHI in ComputeKnownBits (llvm#114689)
Finish porting llvm#114008 to `KnownBits` (Follow up to llvm#113707).
1 parent b1943f4 commit a56ba1f

File tree

5 files changed

+194
-55
lines changed

5 files changed

+194
-55
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,36 @@ static bool cmpExcludesZero(CmpInst::Predicate Pred, const Value *RHS) {
592592
return true;
593593
}
594594

595+
static void breakSelfRecursivePHI(const Use *U, const PHINode *PHI,
596+
Value *&ValOut, Instruction *&CtxIOut) {
597+
ValOut = U->get();
598+
if (ValOut == PHI)
599+
return;
600+
CtxIOut = PHI->getIncomingBlock(*U)->getTerminator();
601+
Value *V;
602+
// If the Use is a select of this phi, compute analysis on other arm to break
603+
// recursion.
604+
// TODO: Min/Max
605+
if (match(ValOut, m_Select(m_Value(), m_Specific(PHI), m_Value(V))) ||
606+
match(ValOut, m_Select(m_Value(), m_Value(V), m_Specific(PHI))))
607+
ValOut = V;
608+
609+
// Same for select, if this phi is 2-operand phi, compute analysis on other
610+
// incoming value to break recursion.
611+
// TODO: We could handle any number of incoming edges as long as we only have
612+
// two unique values.
613+
else if (auto *IncPhi = dyn_cast<PHINode>(ValOut);
614+
IncPhi && IncPhi->getNumIncomingValues() == 2) {
615+
for (int Idx = 0; Idx < 2; ++Idx) {
616+
if (IncPhi->getIncomingValue(Idx) == PHI) {
617+
ValOut = IncPhi->getIncomingValue(1 - Idx);
618+
CtxIOut = IncPhi->getIncomingBlock(1 - Idx)->getTerminator();
619+
break;
620+
}
621+
}
622+
}
623+
}
624+
595625
static bool isKnownNonZeroFromAssume(const Value *V, const SimplifyQuery &Q) {
596626
// Use of assumptions is context-sensitive. If we don't have a context, we
597627
// cannot use them!
@@ -1641,25 +1671,19 @@ static void computeKnownBitsFromOperator(const Operator *I,
16411671

16421672
Known.Zero.setAllBits();
16431673
Known.One.setAllBits();
1644-
for (unsigned u = 0, e = P->getNumIncomingValues(); u < e; ++u) {
1645-
Value *IncValue = P->getIncomingValue(u);
1674+
for (const Use &U : P->operands()) {
1675+
Value *IncValue;
1676+
Instruction *CxtI;
1677+
breakSelfRecursivePHI(&U, P, IncValue, CxtI);
16461678
// Skip direct self references.
1647-
if (IncValue == P) continue;
1648-
1649-
// If the Use is a select of this phi, use the knownbit of the other
1650-
// operand to break the recursion.
1651-
if (auto *SI = dyn_cast<SelectInst>(IncValue)) {
1652-
if (SI->getTrueValue() == P || SI->getFalseValue() == P)
1653-
IncValue = SI->getTrueValue() == P ? SI->getFalseValue()
1654-
: SI->getTrueValue();
1655-
}
1679+
if (IncValue == P)
1680+
continue;
16561681

16571682
// Change the context instruction to the "edge" that flows into the
16581683
// phi. This is important because that is where the value is actually
16591684
// "evaluated" even though it is used later somewhere else. (see also
16601685
// D69571).
1661-
SimplifyQuery RecQ = Q.getWithoutCondContext();
1662-
RecQ.CxtI = P->getIncomingBlock(u)->getTerminator();
1686+
SimplifyQuery RecQ = Q.getWithoutCondContext().getWithInstruction(CxtI);
16631687

16641688
Known2 = KnownBits(BitWidth);
16651689

@@ -6053,30 +6077,13 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
60536077
bool First = true;
60546078

60556079
for (const Use &U : P->operands()) {
6056-
Value *IncValue = U.get();
6080+
Value *IncValue;
6081+
Instruction *CxtI;
6082+
breakSelfRecursivePHI(&U, P, IncValue, CxtI);
60576083
// Skip direct self references.
60586084
if (IncValue == P)
60596085
continue;
60606086

6061-
Instruction *CxtI = P->getIncomingBlock(U)->getTerminator();
6062-
6063-
// If the Use is a select of this phi, use the fp class of the other
6064-
// operand to break the recursion. Same around 2-operand phi nodes
6065-
Value *V;
6066-
if (match(IncValue, m_Select(m_Value(), m_Specific(P), m_Value(V))) ||
6067-
match(IncValue, m_Select(m_Value(), m_Value(V), m_Specific(P)))) {
6068-
IncValue = V;
6069-
} else if (auto *IncPhi = dyn_cast<PHINode>(IncValue);
6070-
IncPhi && IncPhi->getNumIncomingValues() == 2) {
6071-
for (int Idx = 0; Idx < 2; ++Idx) {
6072-
if (IncPhi->getIncomingValue(Idx) == P) {
6073-
IncValue = IncPhi->getIncomingValue(1 - Idx);
6074-
CxtI = IncPhi->getIncomingBlock(1 - Idx)->getTerminator();
6075-
break;
6076-
}
6077-
}
6078-
}
6079-
60806087
KnownFPClass KnownSrc;
60816088
// Recurse, but cap the recursion to two levels, because we don't want
60826089
// to waste time spinning around in loops. We need at least depth 2 to

llvm/test/Analysis/ScalarEvolution/cycled_phis.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ define void @test_01() {
88
; CHECK-LABEL: 'test_01'
99
; CHECK-NEXT: Classifying expressions for: @test_01
1010
; CHECK-NEXT: %phi_1 = phi i32 [ 10, %entry ], [ %phi_2, %loop ]
11-
; CHECK-NEXT: --> %phi_1 U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
11+
; CHECK-NEXT: --> %phi_1 U: [0,31) S: [0,31) Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
1212
; CHECK-NEXT: %phi_2 = phi i32 [ 20, %entry ], [ %phi_1, %loop ]
13-
; CHECK-NEXT: --> %phi_2 U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
13+
; CHECK-NEXT: --> %phi_2 U: [0,31) S: [0,31) Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
1414
; CHECK-NEXT: %cond = call i1 @cond()
1515
; CHECK-NEXT: --> %cond U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
1616
; CHECK-NEXT: Determining loop execution counts for: @test_01

llvm/test/Analysis/ScalarEvolution/unknown_phis.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ define void @merge_values_with_ranges_looped(ptr %a_len_ptr, ptr %b_len_ptr) {
3939
; CHECK-NEXT: %len_b = load i32, ptr %b_len_ptr, align 4, !range !0
4040
; CHECK-NEXT: --> %len_b U: [0,2147483647) S: [0,2147483647)
4141
; CHECK-NEXT: %p1 = phi i32 [ %len_a, %entry ], [ %p2, %loop ]
42-
; CHECK-NEXT: --> %p1 U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
42+
; CHECK-NEXT: --> %p1 U: [0,-2147483648) S: [0,-2147483648) Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
4343
; CHECK-NEXT: %p2 = phi i32 [ %len_b, %entry ], [ %p1, %loop ]
44-
; CHECK-NEXT: --> %p2 U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
44+
; CHECK-NEXT: --> %p2 U: [0,-2147483648) S: [0,-2147483648) Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
4545
; CHECK-NEXT: %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
4646
; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%loop> U: [0,100) S: [0,100) Exits: 99 LoopDispositions: { %loop: Computable }
4747
; CHECK-NEXT: %iv.next = add i32 %iv, 1

llvm/test/Transforms/InstCombine/known-phi-recurse.ll

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,4 +256,142 @@ exit:
256256
ret i8 %bool
257257
}
258258

259+
define i8 @knownbits_umax_select_test() {
260+
; CHECK-LABEL: @knownbits_umax_select_test(
261+
; CHECK-NEXT: entry:
262+
; CHECK-NEXT: br label [[LOOP:%.*]]
263+
; CHECK: loop:
264+
; CHECK-NEXT: [[INDVAR:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[CONTAIN:%.*]], [[LOOP]] ]
265+
; CHECK-NEXT: [[COND0:%.*]] = call i1 @cond()
266+
; CHECK-NEXT: [[CONTAIN]] = call i8 @llvm.umax.i8(i8 [[INDVAR]], i8 1)
267+
; CHECK-NEXT: [[COND1:%.*]] = call i1 @cond()
268+
; CHECK-NEXT: br i1 [[COND1]], label [[EXIT:%.*]], label [[LOOP]]
269+
; CHECK: exit:
270+
; CHECK-NEXT: [[BOOL:%.*]] = and i8 [[CONTAIN]], 1
271+
; CHECK-NEXT: ret i8 [[BOOL]]
272+
;
273+
entry:
274+
br label %loop
275+
276+
loop:
277+
%indvar = phi i8 [ 0, %entry ], [ %contain, %loop ]
278+
%cond0 = call i1 @cond()
279+
%contain = call i8 @llvm.umax.i8(i8 1, i8 %indvar)
280+
%cond1 = call i1 @cond()
281+
br i1 %cond1, label %exit, label %loop
282+
283+
exit:
284+
%bool = and i8 %contain, 1
285+
ret i8 %bool
286+
}
287+
288+
define i8 @knownbits_phi_phi_test() {
289+
; CHECK-LABEL: @knownbits_phi_phi_test(
290+
; CHECK-NEXT: entry:
291+
; CHECK-NEXT: br label [[LOOP:%.*]]
292+
; CHECK: loop:
293+
; CHECK-NEXT: [[INDVAR:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[CONTAIN:%.*]], [[LOOP_BB1:%.*]] ]
294+
; CHECK-NEXT: [[COND0:%.*]] = call i1 @cond()
295+
; CHECK-NEXT: br i1 [[COND0]], label [[LOOP_BB0:%.*]], label [[LOOP_BB1]]
296+
; CHECK: loop.bb0:
297+
; CHECK-NEXT: call void @side.effect()
298+
; CHECK-NEXT: br label [[LOOP_BB1]]
299+
; CHECK: loop.bb1:
300+
; CHECK-NEXT: [[CONTAIN]] = phi i8 [ 1, [[LOOP_BB0]] ], [ [[INDVAR]], [[LOOP]] ]
301+
; CHECK-NEXT: [[COND1:%.*]] = call i1 @cond()
302+
; CHECK-NEXT: br i1 [[COND1]], label [[EXIT:%.*]], label [[LOOP]]
303+
; CHECK: exit:
304+
; CHECK-NEXT: ret i8 [[CONTAIN]]
305+
;
306+
entry:
307+
br label %loop
308+
309+
loop:
310+
%indvar = phi i8 [ 0, %entry ], [ %contain, %loop.bb1 ]
311+
%cond0 = call i1 @cond()
312+
br i1 %cond0, label %loop.bb0, label %loop.bb1
313+
loop.bb0:
314+
call void @side.effect()
315+
br label %loop.bb1
316+
loop.bb1:
317+
%contain = phi i8 [ 1, %loop.bb0 ], [ %indvar, %loop ]
318+
%cond1 = call i1 @cond()
319+
br i1 %cond1, label %exit, label %loop
320+
321+
exit:
322+
%bool = and i8 %contain, 1
323+
ret i8 %bool
324+
}
325+
326+
327+
define i1 @known_non_zero_phi_phi_test() {
328+
; CHECK-LABEL: @known_non_zero_phi_phi_test(
329+
; CHECK-NEXT: entry:
330+
; CHECK-NEXT: br label [[LOOP:%.*]]
331+
; CHECK: loop:
332+
; CHECK-NEXT: [[INDVAR:%.*]] = phi i8 [ 2, [[ENTRY:%.*]] ], [ [[CONTAIN:%.*]], [[LOOP_BB1:%.*]] ]
333+
; CHECK-NEXT: [[COND0:%.*]] = call i1 @cond()
334+
; CHECK-NEXT: br i1 [[COND0]], label [[LOOP_BB0:%.*]], label [[LOOP_BB1]]
335+
; CHECK: loop.bb0:
336+
; CHECK-NEXT: call void @side.effect()
337+
; CHECK-NEXT: br label [[LOOP_BB1]]
338+
; CHECK: loop.bb1:
339+
; CHECK-NEXT: [[CONTAIN]] = phi i8 [ 1, [[LOOP_BB0]] ], [ [[INDVAR]], [[LOOP]] ]
340+
; CHECK-NEXT: [[COND1:%.*]] = call i1 @cond()
341+
; CHECK-NEXT: br i1 [[COND1]], label [[EXIT:%.*]], label [[LOOP]]
342+
; CHECK: exit:
343+
; CHECK-NEXT: [[BOOL:%.*]] = icmp eq i8 [[CONTAIN]], 0
344+
; CHECK-NEXT: ret i1 [[BOOL]]
345+
;
346+
entry:
347+
br label %loop
348+
349+
loop:
350+
%indvar = phi i8 [ 2, %entry ], [ %contain, %loop.bb1 ]
351+
%cond0 = call i1 @cond()
352+
br i1 %cond0, label %loop.bb0, label %loop.bb1
353+
loop.bb0:
354+
call void @side.effect()
355+
br label %loop.bb1
356+
loop.bb1:
357+
%contain = phi i8 [ 1, %loop.bb0 ], [ %indvar, %loop ]
358+
%cond1 = call i1 @cond()
359+
br i1 %cond1, label %exit, label %loop
360+
361+
exit:
362+
%bool = icmp eq i8 %contain, 0
363+
ret i1 %bool
364+
}
365+
366+
define i1 @known_non_zero_phi_select_test() {
367+
; CHECK-LABEL: @known_non_zero_phi_select_test(
368+
; CHECK-NEXT: entry:
369+
; CHECK-NEXT: br label [[LOOP:%.*]]
370+
; CHECK: loop:
371+
; CHECK-NEXT: [[INDVAR:%.*]] = phi i8 [ 2, [[ENTRY:%.*]] ], [ [[CONTAIN:%.*]], [[LOOP]] ]
372+
; CHECK-NEXT: [[COND0:%.*]] = call i1 @cond()
373+
; CHECK-NEXT: [[CONTAIN]] = select i1 [[COND0]], i8 1, i8 [[INDVAR]]
374+
; CHECK-NEXT: [[COND1:%.*]] = call i1 @cond()
375+
; CHECK-NEXT: br i1 [[COND1]], label [[EXIT:%.*]], label [[LOOP]]
376+
; CHECK: exit:
377+
; CHECK-NEXT: [[BOOL:%.*]] = icmp eq i8 [[CONTAIN]], 0
378+
; CHECK-NEXT: ret i1 [[BOOL]]
379+
;
380+
entry:
381+
br label %loop
382+
383+
loop:
384+
%indvar = phi i8 [ 2, %entry ], [ %contain, %loop ]
385+
%cond0 = call i1 @cond()
386+
%contain = select i1 %cond0, i8 1, i8 %indvar
387+
%cond1 = call i1 @cond()
388+
br i1 %cond1, label %exit, label %loop
389+
390+
exit:
391+
%bool = icmp eq i8 %contain, 0
392+
ret i1 %bool
393+
}
394+
259395
declare i1 @cond()
396+
declare void @side.effect()
397+

llvm/test/Transforms/SimplifyCFG/switch-branch-fold-indirectbr-102351.ll

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,29 @@ define i32 @foo.1(i32 %arg, ptr %arg1) {
66
; CHECK-SAME: i32 [[ARG:%.*]], ptr [[ARG1:%.*]]) {
77
; CHECK-NEXT: [[BB:.*]]:
88
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca [2 x ptr], align 16
9-
; CHECK-NEXT: store ptr blockaddress(@foo.1, %[[BB8:.*]]), ptr [[ALLOCA]], align 16
9+
; CHECK-NEXT: store ptr blockaddress(@foo.1, %[[BB2:.*]]), ptr [[ALLOCA]], align 16
1010
; CHECK-NEXT: [[GETELEMENTPTR:%.*]] = getelementptr inbounds [2 x ptr], ptr [[ALLOCA]], i64 0, i64 1
1111
; CHECK-NEXT: store ptr blockaddress(@foo.1, %[[BB16:.*]]), ptr [[GETELEMENTPTR]], align 8
12-
; CHECK-NEXT: br label %[[PREFBB2:.*]]
13-
; CHECK: [[PREFBB2]]:
14-
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 0, %[[BB]] ], [ [[PHI14:%.*]], %[[BB13:.*]] ]
15-
; CHECK-NEXT: [[PHI3:%.*]] = phi i32 [ 0, %[[BB]] ], [ [[PHI15:%.*]], %[[BB13]] ]
16-
; CHECK-NEXT: switch i32 [[PHI]], label %[[BB13]] [
17-
; CHECK-NEXT: i32 0, label %[[PREFBB18:.*]]
18-
; CHECK-NEXT: i32 1, label %[[BB8]]
12+
; CHECK-NEXT: br label %[[BB2]]
13+
; CHECK: [[BB2]]:
14+
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 0, %[[BB]] ], [ 2, %[[BB18:.*]] ]
15+
; CHECK-NEXT: [[PHI3:%.*]] = phi i32 [ 0, %[[BB]] ], [ [[ARG]], %[[BB18]] ]
16+
; CHECK-NEXT: switch i32 [[PHI]], label %[[BB2_UNREACHABLEDEFAULT:.*]] [
17+
; CHECK-NEXT: i32 0, label %[[BB18]]
1918
; CHECK-NEXT: i32 2, label %[[PREFBB11:.*]]
2019
; CHECK-NEXT: ]
21-
; CHECK: [[BB8]]:
22-
; CHECK-NEXT: [[PHI10:%.*]] = phi i32 [ [[ARG]], %[[PREFBB18]] ], [ [[PHI3]], %[[PREFBB2]] ]
23-
; CHECK-NEXT: br label %[[BB13]]
2420
; CHECK: [[PREFBB11]]:
2521
; CHECK-NEXT: [[CALL:%.*]] = call i32 @wombat(i32 noundef [[PHI3]])
2622
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[PHI3]], 1
27-
; CHECK-NEXT: br label %[[PREFBB18]]
28-
; CHECK: [[BB13]]:
29-
; CHECK-NEXT: [[PHI14]] = phi i32 [ [[PHI]], %[[PREFBB2]] ], [ 2, %[[BB8]] ]
30-
; CHECK-NEXT: [[PHI15]] = phi i32 [ [[PHI3]], %[[PREFBB2]] ], [ [[PHI10]], %[[BB8]] ]
31-
; CHECK-NEXT: br label %[[PREFBB2]]
23+
; CHECK-NEXT: br label %[[BB18]]
24+
; CHECK: [[BB2_UNREACHABLEDEFAULT]]:
25+
; CHECK-NEXT: unreachable
3226
; CHECK: [[BB16]]:
3327
; CHECK-NEXT: [[CALL17:%.*]] = call i32 @wombat(i32 noundef [[ARG]])
3428
; CHECK-NEXT: ret i32 0
35-
; CHECK: [[PREFBB18]]:
29+
; CHECK: [[BB18]]:
3630
; CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr [[ARG1]], align 8
37-
; CHECK-NEXT: indirectbr ptr [[LOAD]], [label %[[BB8]], label %bb16]
31+
; CHECK-NEXT: indirectbr ptr [[LOAD]], [label %[[BB2]], label %bb16]
3832
;
3933
bb:
4034
%alloca = alloca [2 x ptr], align 16

0 commit comments

Comments
 (0)