Skip to content

Commit 8ef4b96

Browse files
committed
[knownbits] Preserve known bits for small shift recurrences
The motivation for this is that I'm looking at an example that uses shifts as induction variables. There's lots of other omissions, but one of the first I noticed is that we can't compute tight known bits. (This indirectly causes SCEV's range analysis to produce very poor results as well.) Differential Revision: https://reviews.llvm.org/D96440
1 parent ac2be2b commit 8ef4b96

File tree

2 files changed

+97
-16
lines changed

2 files changed

+97
-16
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,6 +1362,51 @@ static void computeKnownBitsFromOperator(const Operator *I,
13621362
if (!LU)
13631363
continue;
13641364
unsigned Opcode = LU->getOpcode();
1365+
1366+
1367+
// If this is a shift recurrence, we know the bits being shifted in.
1368+
// We can combine that with information about the start value of the
1369+
// recurrence to conclude facts about the result.
1370+
if (Opcode == Instruction::LShr ||
1371+
Opcode == Instruction::AShr ||
1372+
Opcode == Instruction::Shl) {
1373+
Value *LL = LU->getOperand(0);
1374+
Value *LR = LU->getOperand(1);
1375+
// Find a recurrence.
1376+
if (LL == I)
1377+
L = LR;
1378+
else
1379+
continue; // Check for recurrence with L and R flipped.
1380+
1381+
// We have matched a recurrence of the form:
1382+
// %iv = [R, %entry], [%iv.next, %backedge]
1383+
// %iv.next = shift_op %iv, L
1384+
1385+
// Recurse with the phi context to avoid concern about whether facts
1386+
// inferred hold at original context instruction. TODO: It may be
1387+
// correct to use the original context. IF warranted, explore and
1388+
// add sufficient tests to cover.
1389+
Query RecQ = Q;
1390+
RecQ.CxtI = P;
1391+
computeKnownBits(R, DemandedElts, Known2, Depth + 1, RecQ);
1392+
switch (Opcode) {
1393+
case Instruction::Shl:
1394+
// A shl recurrence will only increase the tailing zeros
1395+
Known.Zero.setLowBits(Known2.countMinTrailingZeros());
1396+
break;
1397+
case Instruction::LShr:
1398+
// A lshr recurrence will preserve the leading zeros of the
1399+
// start value
1400+
Known.Zero.setHighBits(Known2.countMinLeadingZeros());
1401+
break;
1402+
case Instruction::AShr:
1403+
// An ashr recurrence will extend the initial sign bit
1404+
Known.Zero.setHighBits(Known2.countMinLeadingZeros());
1405+
Known.One.setHighBits(Known2.countMinLeadingOnes());
1406+
break;
1407+
};
1408+
}
1409+
13651410
// Check for operations that have the property that if
13661411
// both their operands have low zero bits, the result
13671412
// will have low zero bits.

llvm/test/Analysis/ValueTracking/shift-recurrence-knownbits.ll

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,9 @@ define i64 @test_lshr() {
66
; CHECK-NEXT: entry:
77
; CHECK-NEXT: br label [[LOOP:%.*]]
88
; CHECK: loop:
9-
; CHECK-NEXT: [[IV_LSHR:%.*]] = phi i64 [ 1023, [[ENTRY:%.*]] ], [ [[IV_LSHR_NEXT:%.*]], [[LOOP]] ]
10-
; CHECK-NEXT: [[IV_LSHR_NEXT]] = lshr i64 [[IV_LSHR]], 1
119
; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]]
1210
; CHECK: exit:
13-
; CHECK-NEXT: [[RES:%.*]] = or i64 [[IV_LSHR]], 1023
14-
; CHECK-NEXT: ret i64 [[RES]]
11+
; CHECK-NEXT: ret i64 1023
1512
;
1613
entry:
1714
br label %loop
@@ -29,12 +26,9 @@ define i64 @test_ashr_zeros() {
2926
; CHECK-NEXT: entry:
3027
; CHECK-NEXT: br label [[LOOP:%.*]]
3128
; CHECK: loop:
32-
; CHECK-NEXT: [[IV_ASHR:%.*]] = phi i64 [ 1023, [[ENTRY:%.*]] ], [ [[IV_ASHR_NEXT:%.*]], [[LOOP]] ]
33-
; CHECK-NEXT: [[IV_ASHR_NEXT]] = ashr i64 [[IV_ASHR]], 1
3429
; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]]
3530
; CHECK: exit:
36-
; CHECK-NEXT: [[RES:%.*]] = or i64 [[IV_ASHR]], 1023
37-
; CHECK-NEXT: ret i64 [[RES]]
31+
; CHECK-NEXT: ret i64 1023
3832
;
3933
entry:
4034
br label %loop
@@ -52,12 +46,9 @@ define i64 @test_ashr_ones() {
5246
; CHECK-NEXT: entry:
5347
; CHECK-NEXT: br label [[LOOP:%.*]]
5448
; CHECK: loop:
55-
; CHECK-NEXT: [[IV_ASHR:%.*]] = phi i64 [ -1023, [[ENTRY:%.*]] ], [ [[IV_ASHR_NEXT:%.*]], [[LOOP]] ]
56-
; CHECK-NEXT: [[IV_ASHR_NEXT]] = ashr i64 [[IV_ASHR]], 1
5749
; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]]
5850
; CHECK: exit:
59-
; CHECK-NEXT: [[RES:%.*]] = or i64 [[IV_ASHR]], 1023
60-
; CHECK-NEXT: ret i64 [[RES]]
51+
; CHECK-NEXT: ret i64 -1
6152
;
6253
entry:
6354
br label %loop
@@ -70,6 +61,28 @@ exit:
7061
ret i64 %res
7162
}
7263

64+
; Same as previous, but swapped operands to phi
65+
define i64 @test_ashr_ones2() {
66+
; CHECK-LABEL: @test_ashr_ones2(
67+
; CHECK-NEXT: entry:
68+
; CHECK-NEXT: br label [[LOOP:%.*]]
69+
; CHECK: loop:
70+
; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]]
71+
; CHECK: exit:
72+
; CHECK-NEXT: ret i64 -1
73+
;
74+
entry:
75+
br label %loop
76+
loop:
77+
%iv.ashr = phi i64 [%iv.ashr.next, %loop], [-1023, %entry]
78+
%iv.ashr.next = ashr i64 %iv.ashr, 1
79+
br i1 undef, label %exit, label %loop
80+
exit:
81+
%res = or i64 %iv.ashr, 1023
82+
ret i64 %res
83+
}
84+
85+
7386
; negative case for when start is unknown
7487
define i64 @test_ashr_unknown(i64 %start) {
7588
; CHECK-LABEL: @test_ashr_unknown(
@@ -94,17 +107,40 @@ exit:
94107
ret i64 %res
95108
}
96109

110+
; Negative case where we don't have a (shift) recurrence because the operands
111+
; of the ashr are swapped. (This does end up being a divide recurrence.)
112+
define i64 @test_ashr_wrong_op(i64 %start) {
113+
; CHECK-LABEL: @test_ashr_wrong_op(
114+
; CHECK-NEXT: entry:
115+
; CHECK-NEXT: br label [[LOOP:%.*]]
116+
; CHECK: loop:
117+
; CHECK-NEXT: [[IV_ASHR:%.*]] = phi i64 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_ASHR_NEXT:%.*]], [[LOOP]] ]
118+
; CHECK-NEXT: [[IV_ASHR_NEXT]] = lshr i64 1, [[IV_ASHR]]
119+
; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]]
120+
; CHECK: exit:
121+
; CHECK-NEXT: [[RES:%.*]] = or i64 [[IV_ASHR]], 1023
122+
; CHECK-NEXT: ret i64 [[RES]]
123+
;
124+
entry:
125+
br label %loop
126+
loop:
127+
%iv.ashr = phi i64 [%start, %entry], [%iv.ashr.next, %loop]
128+
%iv.ashr.next = ashr i64 1, %iv.ashr
129+
br i1 undef, label %exit, label %loop
130+
exit:
131+
%res = or i64 %iv.ashr, 1023
132+
ret i64 %res
133+
}
134+
135+
97136
define i64 @test_shl() {
98137
; CHECK-LABEL: @test_shl(
99138
; CHECK-NEXT: entry:
100139
; CHECK-NEXT: br label [[LOOP:%.*]]
101140
; CHECK: loop:
102-
; CHECK-NEXT: [[IV_SHL:%.*]] = phi i64 [ 8, [[ENTRY:%.*]] ], [ [[IV_SHL_NEXT:%.*]], [[LOOP]] ]
103-
; CHECK-NEXT: [[IV_SHL_NEXT]] = shl i64 [[IV_SHL]], 1
104141
; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]]
105142
; CHECK: exit:
106-
; CHECK-NEXT: [[RES:%.*]] = and i64 [[IV_SHL]], 6
107-
; CHECK-NEXT: ret i64 [[RES]]
143+
; CHECK-NEXT: ret i64 0
108144
;
109145
entry:
110146
br label %loop

0 commit comments

Comments
 (0)