Skip to content

Commit f1e1055

Browse files
authored
[ValueTracking] Compute known bits from recursive select/phi (llvm#113707)
This patch is inspired by llvm#113686. I found that it removes a lot of unnecessary "and X, 1" in some applications that represent boolean values with int.
1 parent 96d2196 commit f1e1055

File tree

2 files changed

+132
-7
lines changed

2 files changed

+132
-7
lines changed

llvm/lib/Analysis/ValueTracking.cpp

+17-7
Original file line numberDiff line numberDiff line change
@@ -1566,6 +1566,22 @@ static void computeKnownBitsFromOperator(const Operator *I,
15661566
// Skip direct self references.
15671567
if (IncValue == P) continue;
15681568

1569+
// Recurse, but cap the recursion to one level, because we don't
1570+
// want to waste time spinning around in loops.
1571+
// TODO: See if we can base recursion limiter on number of incoming phi
1572+
// edges so we don't overly clamp analysis.
1573+
unsigned IncDepth = MaxAnalysisRecursionDepth - 1;
1574+
1575+
// If the Use is a select of this phi, use the knownbit of the other
1576+
// operand to break the recursion.
1577+
if (auto *SI = dyn_cast<SelectInst>(IncValue)) {
1578+
if (SI->getTrueValue() == P || SI->getFalseValue() == P) {
1579+
IncValue = SI->getTrueValue() == P ? SI->getFalseValue()
1580+
: SI->getTrueValue();
1581+
IncDepth = Depth + 1;
1582+
}
1583+
}
1584+
15691585
// Change the context instruction to the "edge" that flows into the
15701586
// phi. This is important because that is where the value is actually
15711587
// "evaluated" even though it is used later somewhere else. (see also
@@ -1574,13 +1590,7 @@ static void computeKnownBitsFromOperator(const Operator *I,
15741590
RecQ.CxtI = P->getIncomingBlock(u)->getTerminator();
15751591

15761592
Known2 = KnownBits(BitWidth);
1577-
1578-
// Recurse, but cap the recursion to one level, because we don't
1579-
// want to waste time spinning around in loops.
1580-
// TODO: See if we can base recursion limiter on number of incoming phi
1581-
// edges so we don't overly clamp analysis.
1582-
computeKnownBits(IncValue, DemandedElts, Known2,
1583-
MaxAnalysisRecursionDepth - 1, RecQ);
1593+
computeKnownBits(IncValue, DemandedElts, Known2, IncDepth, RecQ);
15841594

15851595
// See if we can further use a conditional branch into the phi
15861596
// to help us determine the range of the value.

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

+115
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,118 @@ end:
142142
ret i32 %res
143143
}
144144

145+
define i32 @knownbits_phi_select_test1(ptr %p1, ptr %p2, i8 %x) {
146+
; CHECK-LABEL: @knownbits_phi_select_test1(
147+
; CHECK-NEXT: entry:
148+
; CHECK-NEXT: br label [[LOOP:%.*]]
149+
; CHECK: loop:
150+
; CHECK-NEXT: [[INDVAR1:%.*]] = phi i8 [ [[LOAD2:%.*]], [[BB2:%.*]] ], [ [[X:%.*]], [[ENTRY:%.*]] ]
151+
; CHECK-NEXT: [[INDVAR3:%.*]] = phi ptr [ [[INDVAR3_NEXT:%.*]], [[BB2]] ], [ [[P1:%.*]], [[ENTRY]] ]
152+
; CHECK-NEXT: [[INDVAR4:%.*]] = phi i32 [ [[INDVAR4_NEXT:%.*]], [[BB2]] ], [ 0, [[ENTRY]] ]
153+
; CHECK-NEXT: [[INDVAR5:%.*]] = phi i32 [ [[INDVAR5_NEXT:%.*]], [[BB2]] ], [ 0, [[ENTRY]] ]
154+
; CHECK-NEXT: switch i8 [[INDVAR1]], label [[DEFAULT:%.*]] [
155+
; CHECK-NEXT: i8 0, label [[EXIT:%.*]]
156+
; CHECK-NEXT: i8 59, label [[BB1:%.*]]
157+
; CHECK-NEXT: i8 35, label [[BB1]]
158+
; CHECK-NEXT: ]
159+
; CHECK: default:
160+
; CHECK-NEXT: [[EXT:%.*]] = sext i8 [[INDVAR1]] to i64
161+
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i16, ptr [[P2:%.*]], i64 [[EXT]]
162+
; CHECK-NEXT: [[LOAD1:%.*]] = load i16, ptr [[GEP1]], align 2
163+
; CHECK-NEXT: [[MASK:%.*]] = and i16 [[LOAD1]], 8192
164+
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i16 [[MASK]], 0
165+
; CHECK-NEXT: br i1 [[CMP1]], label [[BB2]], label [[BB1]]
166+
; CHECK: bb1:
167+
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[INDVAR4]], 0
168+
; CHECK-NEXT: [[CMP3:%.*]] = icmp ne i32 [[INDVAR5]], 0
169+
; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[CMP2]], i1 true, i1 [[CMP3]]
170+
; CHECK-NEXT: br i1 [[OR_COND]], label [[BB2]], label [[EXIT]]
171+
; CHECK: bb2:
172+
; CHECK-NEXT: [[CMP4:%.*]] = icmp eq i8 [[INDVAR1]], 39
173+
; CHECK-NEXT: [[EXT2:%.*]] = zext i1 [[CMP4]] to i32
174+
; CHECK-NEXT: [[INDVAR4_NEXT]] = xor i32 [[INDVAR4]], [[EXT2]]
175+
; CHECK-NEXT: [[CMP6:%.*]] = icmp eq i8 [[INDVAR1]], 34
176+
; CHECK-NEXT: [[EXT3:%.*]] = zext i1 [[CMP6]] to i32
177+
; CHECK-NEXT: [[INDVAR5_NEXT]] = xor i32 [[INDVAR5]], [[EXT3]]
178+
; CHECK-NEXT: [[INDVAR3_NEXT]] = getelementptr inbounds i8, ptr [[INDVAR3]], i64 1
179+
; CHECK-NEXT: [[LOAD2]] = load i8, ptr [[INDVAR3_NEXT]], align 1
180+
; CHECK-NEXT: br label [[LOOP]]
181+
; CHECK: exit:
182+
; CHECK-NEXT: ret i32 [[INDVAR5]]
183+
;
184+
entry:
185+
br label %loop
186+
187+
loop:
188+
%indvar1 = phi i8 [ %load2, %bb2 ], [ %x, %entry ]
189+
%indvar2 = phi i64 [ %indvar2.next, %bb2 ], [ 0, %entry ]
190+
%indvar3 = phi ptr [ %indvar3.next, %bb2 ], [ %p1, %entry ]
191+
%indvar4 = phi i32 [ %indvar4.next, %bb2 ], [ 0, %entry ]
192+
%indvar5 = phi i32 [ %indvar5.next, %bb2 ], [ 0, %entry ]
193+
switch i8 %indvar1, label %default [
194+
i8 0, label %exit
195+
i8 59, label %bb1
196+
i8 35, label %bb1
197+
]
198+
199+
default:
200+
%ext = sext i8 %indvar1 to i64
201+
%gep1 = getelementptr inbounds i16, ptr %p2, i64 %ext
202+
%load1 = load i16, ptr %gep1, align 2
203+
%mask = and i16 %load1, 8192
204+
%cmp1 = icmp eq i16 %mask, 0
205+
br i1 %cmp1, label %bb2, label %bb1
206+
207+
bb1:
208+
%cmp2 = icmp ne i32 %indvar4, 0
209+
%cmp3 = icmp ne i32 %indvar5, 0
210+
%or.cond = select i1 %cmp2, i1 true, i1 %cmp3
211+
br i1 %or.cond, label %bb2, label %exit
212+
213+
bb2:
214+
%cmp4 = icmp eq i8 %indvar1, 39
215+
%cmp5 = icmp eq i32 %indvar4, 0
216+
%ext2 = zext i1 %cmp5 to i32
217+
%indvar4.next = select i1 %cmp4, i32 %ext2, i32 %indvar4
218+
%cmp6 = icmp eq i8 %indvar1, 34
219+
%cmp7 = icmp eq i32 %indvar5, 0
220+
%ext3 = zext i1 %cmp7 to i32
221+
%indvar5.next = select i1 %cmp6, i32 %ext3, i32 %indvar5
222+
%indvar3.next = getelementptr inbounds i8, ptr %indvar3, i64 1
223+
%indvar2.next = add i64 %indvar2, 1
224+
%load2 = load i8, ptr %indvar3.next, align 1
225+
br label %loop
226+
227+
exit:
228+
ret i32 %indvar5
229+
}
230+
231+
define i8 @knownbits_phi_select_test2() {
232+
; CHECK-LABEL: @knownbits_phi_select_test2(
233+
; CHECK-NEXT: entry:
234+
; CHECK-NEXT: br label [[LOOP:%.*]]
235+
; CHECK: loop:
236+
; CHECK-NEXT: [[INDVAR:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[CONTAIN:%.*]], [[LOOP]] ]
237+
; CHECK-NEXT: [[COND0:%.*]] = call i1 @cond()
238+
; CHECK-NEXT: [[CONTAIN]] = select i1 [[COND0]], i8 1, i8 [[INDVAR]]
239+
; CHECK-NEXT: [[COND1:%.*]] = call i1 @cond()
240+
; CHECK-NEXT: br i1 [[COND1]], label [[EXIT:%.*]], label [[LOOP]]
241+
; CHECK: exit:
242+
; CHECK-NEXT: ret i8 [[CONTAIN]]
243+
;
244+
entry:
245+
br label %loop
246+
247+
loop:
248+
%indvar = phi i8 [ 0, %entry ], [ %contain, %loop ]
249+
%cond0 = call i1 @cond()
250+
%contain = select i1 %cond0, i8 1, i8 %indvar
251+
%cond1 = call i1 @cond()
252+
br i1 %cond1, label %exit, label %loop
253+
254+
exit:
255+
%bool = and i8 %contain, 1
256+
ret i8 %bool
257+
}
258+
259+
declare i1 @cond()

0 commit comments

Comments
 (0)