[InstCombine] Fix known bits handling in SimplifyDemandedUseBits

Fixes a regression from D75801. SimplifyDemandedUseBits() is also
supposed to compute the known bits (of the demanded subset) of the
instruction. For unknown instructions it does so by directly calling
computeKnownBits(). For known instructions it will compute known
bits itself. However, for instructions where only some cases are
handled directly (e.g. a constant shift amount) the known bits
invocation for the unhandled case is sometimes missing. This patch
adds the missing calls and thus removes the main discrepancy with
ExpensiveCombines mode.

Differential Revision: https://reviews.llvm.org/D75804
This commit is contained in:
Nikita Popov 2020-03-07 12:18:05 +01:00
parent a4e71f01c0
commit 51a466a61f
3 changed files with 36 additions and 72 deletions

View File

@ -521,6 +521,8 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
// low bits known zero. // low bits known zero.
if (ShiftAmt) if (ShiftAmt)
Known.Zero.setLowBits(ShiftAmt); Known.Zero.setLowBits(ShiftAmt);
} else {
computeKnownBits(I, Known, Depth, CxtI);
} }
break; break;
} }
@ -544,6 +546,8 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
Known.One.lshrInPlace(ShiftAmt); Known.One.lshrInPlace(ShiftAmt);
if (ShiftAmt) if (ShiftAmt)
Known.Zero.setHighBits(ShiftAmt); // high bits known zero. Known.Zero.setHighBits(ShiftAmt); // high bits known zero.
} else {
computeKnownBits(I, Known, Depth, CxtI);
} }
break; break;
} }
@ -604,6 +608,8 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
} else if (Known.One[BitWidth-ShiftAmt-1]) { // New bits are known one. } else if (Known.One[BitWidth-ShiftAmt-1]) { // New bits are known one.
Known.One |= HighBits; Known.One |= HighBits;
} }
} else {
computeKnownBits(I, Known, Depth, CxtI);
} }
break; break;
} }
@ -625,6 +631,8 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
// Propagate zero bits from the input. // Propagate zero bits from the input.
Known.Zero.setHighBits(std::min( Known.Zero.setHighBits(std::min(
BitWidth, LHSKnown.Zero.countLeadingOnes() + RHSTrailingZeros)); BitWidth, LHSKnown.Zero.countLeadingOnes() + RHSTrailingZeros));
} else {
computeKnownBits(I, Known, Depth, CxtI);
} }
break; break;
} }
@ -683,7 +691,8 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
Known.Zero = APInt::getHighBitsSet(BitWidth, Leaders) & DemandedMask; Known.Zero = APInt::getHighBitsSet(BitWidth, Leaders) & DemandedMask;
break; break;
} }
case Instruction::Call: case Instruction::Call: {
bool KnownBitsComputed = false;
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) { if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
switch (II->getIntrinsicID()) { switch (II->getIntrinsicID()) {
default: break; default: break;
@ -715,8 +724,6 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
NewVal->takeName(I); NewVal->takeName(I);
return InsertNewInstWith(NewVal, *I); return InsertNewInstWith(NewVal, *I);
} }
// TODO: Could compute known zero/one bits based on the input.
break; break;
} }
case Intrinsic::fshr: case Intrinsic::fshr:
@ -741,6 +748,7 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
RHSKnown.Zero.lshr(BitWidth - ShiftAmt); RHSKnown.Zero.lshr(BitWidth - ShiftAmt);
Known.One = LHSKnown.One.shl(ShiftAmt) | Known.One = LHSKnown.One.shl(ShiftAmt) |
RHSKnown.One.lshr(BitWidth - ShiftAmt); RHSKnown.One.lshr(BitWidth - ShiftAmt);
KnownBitsComputed = true;
break; break;
} }
case Intrinsic::x86_mmx_pmovmskb: case Intrinsic::x86_mmx_pmovmskb:
@ -769,16 +777,21 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
// We know that the upper bits are set to zero. // We know that the upper bits are set to zero.
Known.Zero.setBitsFrom(ArgWidth); Known.Zero.setBitsFrom(ArgWidth);
return nullptr; KnownBitsComputed = true;
break;
} }
case Intrinsic::x86_sse42_crc32_64_64: case Intrinsic::x86_sse42_crc32_64_64:
Known.Zero.setBitsFrom(32); Known.Zero.setBitsFrom(32);
return nullptr; KnownBitsComputed = true;
break;
} }
} }
computeKnownBits(V, Known, Depth, CxtI);
if (!KnownBitsComputed)
computeKnownBits(V, Known, Depth, CxtI);
break; break;
} }
}
// If the client is only demanding bits that we know, return the known // If the client is only demanding bits that we know, return the known
// constant. // constant.

View File

@ -13,33 +13,11 @@ target triple = "powerpc64-unknown-linux-gnu"
; ((2072 >> (L == 0)) >> 7) & 1 ; ((2072 >> (L == 0)) >> 7) & 1
; is always zero. ; is always zero.
define signext i32 @main() #1 { define signext i32 @main() #1 {
; EXPENSIVE-OFF-LABEL: @main( ; CHECK-LABEL: @main(
; EXPENSIVE-OFF-NEXT: entry: ; CHECK-NEXT: entry:
; EXPENSIVE-OFF-NEXT: [[TMP0:%.*]] = load i32*, i32** @b, align 8 ; CHECK-NEXT: [[TMP0:%.*]] = load i32*, i32** @b, align 8
; EXPENSIVE-OFF-NEXT: [[TMP1:%.*]] = load i32, i32* @a, align 4 ; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP0]], align 4
; EXPENSIVE-OFF-NEXT: [[LNOT:%.*]] = icmp eq i32 [[TMP1]], 0 ; CHECK-NEXT: ret i32 [[TMP1]]
; EXPENSIVE-OFF-NEXT: [[LNOT_EXT:%.*]] = zext i1 [[LNOT]] to i32
; EXPENSIVE-OFF-NEXT: [[SHR_I:%.*]] = lshr i32 2072, [[LNOT_EXT]]
; EXPENSIVE-OFF-NEXT: [[CALL_LOBIT:%.*]] = lshr i32 [[SHR_I]], 7
; EXPENSIVE-OFF-NEXT: [[TMP2:%.*]] = and i32 [[CALL_LOBIT]], 1
; EXPENSIVE-OFF-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP0]], align 4
; EXPENSIVE-OFF-NEXT: [[OR:%.*]] = or i32 [[TMP2]], [[TMP3]]
; EXPENSIVE-OFF-NEXT: store i32 [[OR]], i32* [[TMP0]], align 4
; EXPENSIVE-OFF-NEXT: [[TMP4:%.*]] = load i32, i32* @a, align 4
; EXPENSIVE-OFF-NEXT: [[LNOT_1:%.*]] = icmp eq i32 [[TMP4]], 0
; EXPENSIVE-OFF-NEXT: [[LNOT_EXT_1:%.*]] = zext i1 [[LNOT_1]] to i32
; EXPENSIVE-OFF-NEXT: [[SHR_I_1:%.*]] = lshr i32 2072, [[LNOT_EXT_1]]
; EXPENSIVE-OFF-NEXT: [[CALL_LOBIT_1:%.*]] = lshr i32 [[SHR_I_1]], 7
; EXPENSIVE-OFF-NEXT: [[TMP5:%.*]] = and i32 [[CALL_LOBIT_1]], 1
; EXPENSIVE-OFF-NEXT: [[OR_1:%.*]] = or i32 [[TMP5]], [[TMP3]]
; EXPENSIVE-OFF-NEXT: store i32 [[OR_1]], i32* [[TMP0]], align 4
; EXPENSIVE-OFF-NEXT: ret i32 [[OR_1]]
;
; EXPENSIVE-ON-LABEL: @main(
; EXPENSIVE-ON-NEXT: entry:
; EXPENSIVE-ON-NEXT: [[TMP0:%.*]] = load i32*, i32** @b, align 8
; EXPENSIVE-ON-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP0]], align 4
; EXPENSIVE-ON-NEXT: ret i32 [[TMP1]]
; ;
entry: entry:
%0 = load i32*, i32** @b, align 8 %0 = load i32*, i32** @b, align 8

View File

@ -3,16 +3,9 @@
; RUN: opt -S -instcombine -expensive-combines=1 < %s | FileCheck %s --check-prefixes=CHECK,EXPENSIVE-ON ; RUN: opt -S -instcombine -expensive-combines=1 < %s | FileCheck %s --check-prefixes=CHECK,EXPENSIVE-ON
define void @test_shl(i1 %x) { define void @test_shl(i1 %x) {
; EXPENSIVE-OFF-LABEL: @test_shl( ; CHECK-LABEL: @test_shl(
; EXPENSIVE-OFF-NEXT: [[Y:%.*]] = zext i1 [[X:%.*]] to i8 ; CHECK-NEXT: call void @sink(i8 0)
; EXPENSIVE-OFF-NEXT: [[Z:%.*]] = shl i8 64, [[Y]] ; CHECK-NEXT: ret void
; EXPENSIVE-OFF-NEXT: [[A:%.*]] = and i8 [[Z]], 1
; EXPENSIVE-OFF-NEXT: call void @sink(i8 [[A]])
; EXPENSIVE-OFF-NEXT: ret void
;
; EXPENSIVE-ON-LABEL: @test_shl(
; EXPENSIVE-ON-NEXT: call void @sink(i8 0)
; EXPENSIVE-ON-NEXT: ret void
; ;
%y = zext i1 %x to i8 %y = zext i1 %x to i8
%z = shl i8 64, %y %z = shl i8 64, %y
@ -22,16 +15,9 @@ define void @test_shl(i1 %x) {
} }
define void @test_lshr(i1 %x) { define void @test_lshr(i1 %x) {
; EXPENSIVE-OFF-LABEL: @test_lshr( ; CHECK-LABEL: @test_lshr(
; EXPENSIVE-OFF-NEXT: [[Y:%.*]] = zext i1 [[X:%.*]] to i8 ; CHECK-NEXT: call void @sink(i8 0)
; EXPENSIVE-OFF-NEXT: [[Z:%.*]] = lshr i8 64, [[Y]] ; CHECK-NEXT: ret void
; EXPENSIVE-OFF-NEXT: [[A:%.*]] = and i8 [[Z]], 1
; EXPENSIVE-OFF-NEXT: call void @sink(i8 [[A]])
; EXPENSIVE-OFF-NEXT: ret void
;
; EXPENSIVE-ON-LABEL: @test_lshr(
; EXPENSIVE-ON-NEXT: call void @sink(i8 0)
; EXPENSIVE-ON-NEXT: ret void
; ;
%y = zext i1 %x to i8 %y = zext i1 %x to i8
%z = lshr i8 64, %y %z = lshr i8 64, %y
@ -41,16 +27,9 @@ define void @test_lshr(i1 %x) {
} }
define void @test_ashr(i1 %x) { define void @test_ashr(i1 %x) {
; EXPENSIVE-OFF-LABEL: @test_ashr( ; CHECK-LABEL: @test_ashr(
; EXPENSIVE-OFF-NEXT: [[Y:%.*]] = zext i1 [[X:%.*]] to i8 ; CHECK-NEXT: call void @sink(i8 0)
; EXPENSIVE-OFF-NEXT: [[Z:%.*]] = ashr i8 -16, [[Y]] ; CHECK-NEXT: ret void
; EXPENSIVE-OFF-NEXT: [[A:%.*]] = and i8 [[Z]], 3
; EXPENSIVE-OFF-NEXT: call void @sink(i8 [[A]])
; EXPENSIVE-OFF-NEXT: ret void
;
; EXPENSIVE-ON-LABEL: @test_ashr(
; EXPENSIVE-ON-NEXT: call void @sink(i8 0)
; EXPENSIVE-ON-NEXT: ret void
; ;
%y = zext i1 %x to i8 %y = zext i1 %x to i8
%z = ashr i8 -16, %y %z = ashr i8 -16, %y
@ -60,15 +39,9 @@ define void @test_ashr(i1 %x) {
} }
define void @test_udiv(i8 %x) { define void @test_udiv(i8 %x) {
; EXPENSIVE-OFF-LABEL: @test_udiv( ; CHECK-LABEL: @test_udiv(
; EXPENSIVE-OFF-NEXT: [[Y:%.*]] = udiv i8 10, [[X:%.*]] ; CHECK-NEXT: call void @sink(i8 0)
; EXPENSIVE-OFF-NEXT: [[Z:%.*]] = and i8 [[Y]], 64 ; CHECK-NEXT: ret void
; EXPENSIVE-OFF-NEXT: call void @sink(i8 [[Z]])
; EXPENSIVE-OFF-NEXT: ret void
;
; EXPENSIVE-ON-LABEL: @test_udiv(
; EXPENSIVE-ON-NEXT: call void @sink(i8 0)
; EXPENSIVE-ON-NEXT: ret void
; ;
%y = udiv i8 10, %x %y = udiv i8 10, %x
%z = and i8 %y, 64 %z = and i8 %y, 64