mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
[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
This commit is contained in:
parent
5c03a3baf7
commit
2bc932f596
@ -1362,6 +1362,51 @@ static void computeKnownBitsFromOperator(const Operator *I,
|
||||
if (!LU)
|
||||
continue;
|
||||
unsigned Opcode = LU->getOpcode();
|
||||
|
||||
|
||||
// If this is a shift recurrence, we know the bits being shifted in.
|
||||
// We can combine that with information about the start value of the
|
||||
// recurrence to conclude facts about the result.
|
||||
if (Opcode == Instruction::LShr ||
|
||||
Opcode == Instruction::AShr ||
|
||||
Opcode == Instruction::Shl) {
|
||||
Value *LL = LU->getOperand(0);
|
||||
Value *LR = LU->getOperand(1);
|
||||
// Find a recurrence.
|
||||
if (LL == I)
|
||||
L = LR;
|
||||
else
|
||||
continue; // Check for recurrence with L and R flipped.
|
||||
|
||||
// We have matched a recurrence of the form:
|
||||
// %iv = [R, %entry], [%iv.next, %backedge]
|
||||
// %iv.next = shift_op %iv, L
|
||||
|
||||
// Recurse with the phi context to avoid concern about whether facts
|
||||
// inferred hold at original context instruction. TODO: It may be
|
||||
// correct to use the original context. IF warranted, explore and
|
||||
// add sufficient tests to cover.
|
||||
Query RecQ = Q;
|
||||
RecQ.CxtI = P;
|
||||
computeKnownBits(R, DemandedElts, Known2, Depth + 1, RecQ);
|
||||
switch (Opcode) {
|
||||
case Instruction::Shl:
|
||||
// A shl recurrence will only increase the tailing zeros
|
||||
Known.Zero.setLowBits(Known2.countMinTrailingZeros());
|
||||
break;
|
||||
case Instruction::LShr:
|
||||
// A lshr recurrence will preserve the leading zeros of the
|
||||
// start value
|
||||
Known.Zero.setHighBits(Known2.countMinLeadingZeros());
|
||||
break;
|
||||
case Instruction::AShr:
|
||||
// An ashr recurrence will extend the initial sign bit
|
||||
Known.Zero.setHighBits(Known2.countMinLeadingZeros());
|
||||
Known.One.setHighBits(Known2.countMinLeadingOnes());
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
// Check for operations that have the property that if
|
||||
// both their operands have low zero bits, the result
|
||||
// will have low zero bits.
|
||||
|
@ -6,12 +6,9 @@ define i64 @test_lshr() {
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||||
; CHECK: loop:
|
||||
; CHECK-NEXT: [[IV_LSHR:%.*]] = phi i64 [ 1023, [[ENTRY:%.*]] ], [ [[IV_LSHR_NEXT:%.*]], [[LOOP]] ]
|
||||
; CHECK-NEXT: [[IV_LSHR_NEXT]] = lshr i64 [[IV_LSHR]], 1
|
||||
; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]]
|
||||
; CHECK: exit:
|
||||
; CHECK-NEXT: [[RES:%.*]] = or i64 [[IV_LSHR]], 1023
|
||||
; CHECK-NEXT: ret i64 [[RES]]
|
||||
; CHECK-NEXT: ret i64 1023
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
@ -29,12 +26,9 @@ define i64 @test_ashr_zeros() {
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||||
; CHECK: loop:
|
||||
; CHECK-NEXT: [[IV_ASHR:%.*]] = phi i64 [ 1023, [[ENTRY:%.*]] ], [ [[IV_ASHR_NEXT:%.*]], [[LOOP]] ]
|
||||
; CHECK-NEXT: [[IV_ASHR_NEXT]] = ashr i64 [[IV_ASHR]], 1
|
||||
; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]]
|
||||
; CHECK: exit:
|
||||
; CHECK-NEXT: [[RES:%.*]] = or i64 [[IV_ASHR]], 1023
|
||||
; CHECK-NEXT: ret i64 [[RES]]
|
||||
; CHECK-NEXT: ret i64 1023
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
@ -52,12 +46,9 @@ define i64 @test_ashr_ones() {
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||||
; CHECK: loop:
|
||||
; CHECK-NEXT: [[IV_ASHR:%.*]] = phi i64 [ -1023, [[ENTRY:%.*]] ], [ [[IV_ASHR_NEXT:%.*]], [[LOOP]] ]
|
||||
; CHECK-NEXT: [[IV_ASHR_NEXT]] = ashr i64 [[IV_ASHR]], 1
|
||||
; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]]
|
||||
; CHECK: exit:
|
||||
; CHECK-NEXT: [[RES:%.*]] = or i64 [[IV_ASHR]], 1023
|
||||
; CHECK-NEXT: ret i64 [[RES]]
|
||||
; CHECK-NEXT: ret i64 -1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
@ -70,6 +61,28 @@ exit:
|
||||
ret i64 %res
|
||||
}
|
||||
|
||||
; Same as previous, but swapped operands to phi
|
||||
define i64 @test_ashr_ones2() {
|
||||
; CHECK-LABEL: @test_ashr_ones2(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||||
; CHECK: loop:
|
||||
; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]]
|
||||
; CHECK: exit:
|
||||
; CHECK-NEXT: ret i64 -1
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
loop:
|
||||
%iv.ashr = phi i64 [%iv.ashr.next, %loop], [-1023, %entry]
|
||||
%iv.ashr.next = ashr i64 %iv.ashr, 1
|
||||
br i1 undef, label %exit, label %loop
|
||||
exit:
|
||||
%res = or i64 %iv.ashr, 1023
|
||||
ret i64 %res
|
||||
}
|
||||
|
||||
|
||||
; negative case for when start is unknown
|
||||
define i64 @test_ashr_unknown(i64 %start) {
|
||||
; CHECK-LABEL: @test_ashr_unknown(
|
||||
@ -94,17 +107,40 @@ exit:
|
||||
ret i64 %res
|
||||
}
|
||||
|
||||
; Negative case where we don't have a (shift) recurrence because the operands
|
||||
; of the ashr are swapped. (This does end up being a divide recurrence.)
|
||||
define i64 @test_ashr_wrong_op(i64 %start) {
|
||||
; CHECK-LABEL: @test_ashr_wrong_op(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||||
; CHECK: loop:
|
||||
; CHECK-NEXT: [[IV_ASHR:%.*]] = phi i64 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_ASHR_NEXT:%.*]], [[LOOP]] ]
|
||||
; CHECK-NEXT: [[IV_ASHR_NEXT]] = lshr i64 1, [[IV_ASHR]]
|
||||
; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]]
|
||||
; CHECK: exit:
|
||||
; CHECK-NEXT: [[RES:%.*]] = or i64 [[IV_ASHR]], 1023
|
||||
; CHECK-NEXT: ret i64 [[RES]]
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
loop:
|
||||
%iv.ashr = phi i64 [%start, %entry], [%iv.ashr.next, %loop]
|
||||
%iv.ashr.next = ashr i64 1, %iv.ashr
|
||||
br i1 undef, label %exit, label %loop
|
||||
exit:
|
||||
%res = or i64 %iv.ashr, 1023
|
||||
ret i64 %res
|
||||
}
|
||||
|
||||
|
||||
define i64 @test_shl() {
|
||||
; CHECK-LABEL: @test_shl(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||||
; CHECK: loop:
|
||||
; CHECK-NEXT: [[IV_SHL:%.*]] = phi i64 [ 8, [[ENTRY:%.*]] ], [ [[IV_SHL_NEXT:%.*]], [[LOOP]] ]
|
||||
; CHECK-NEXT: [[IV_SHL_NEXT]] = shl i64 [[IV_SHL]], 1
|
||||
; CHECK-NEXT: br i1 undef, label [[EXIT:%.*]], label [[LOOP]]
|
||||
; CHECK: exit:
|
||||
; CHECK-NEXT: [[RES:%.*]] = and i64 [[IV_SHL]], 6
|
||||
; CHECK-NEXT: ret i64 [[RES]]
|
||||
; CHECK-NEXT: ret i64 0
|
||||
;
|
||||
entry:
|
||||
br label %loop
|
||||
|
Loading…
x
Reference in New Issue
Block a user