diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -1362,6 +1362,51 @@ 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. diff --git a/llvm/test/Analysis/ValueTracking/shift-recurrence-knownbits.ll b/llvm/test/Analysis/ValueTracking/shift-recurrence-knownbits.ll --- a/llvm/test/Analysis/ValueTracking/shift-recurrence-knownbits.ll +++ b/llvm/test/Analysis/ValueTracking/shift-recurrence-knownbits.ll @@ -6,12 +6,9 @@ ; 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 @@ ; 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 @@ ; 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 @@ 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 @@ 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