diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp index 3f2a6f8eb2ea97..5b0a4857f33dbe 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp @@ -899,6 +899,33 @@ Value *InstCombinerImpl::SimplifyMultipleUseDemandedBits( break; } + case Instruction::AShr: { + // Compute the Known bits to simplify things downstream. + computeKnownBits(I, Known, Depth, CxtI); + + // If this user is only demanding bits that we know, return the known + // constant. + if (DemandedMask.isSubsetOf(Known.Zero | Known.One)) + return Constant::getIntegerValue(ITy, Known.One); + + // If the right shift operand 0 is a result of a left shift by the same + // amount, this is probably a zero/sign extension, which may be unnecessary, + // if we do not demand any of the new sign bits. So, return the original + // operand instead. + const APInt *ShiftRC; + const APInt *ShiftLC; + Value *X; + unsigned BitWidth = DemandedMask.getBitWidth(); + if (match(I, + m_AShr(m_Shl(m_Value(X), m_APInt(ShiftLC)), m_APInt(ShiftRC))) && + ShiftLC == ShiftRC && + DemandedMask.isSubsetOf(APInt::getLowBitsSet( + BitWidth, BitWidth - ShiftRC->getZExtValue()))) { + return X; + } + + break; + } default: // Compute the Known bits to simplify things downstream. computeKnownBits(I, Known, Depth, CxtI); diff --git a/llvm/test/Transforms/InstCombine/and.ll b/llvm/test/Transforms/InstCombine/and.ll index ed50ae16350d1a..020dbc483d9de5 100644 --- a/llvm/test/Transforms/InstCombine/and.ll +++ b/llvm/test/Transforms/InstCombine/and.ll @@ -979,7 +979,7 @@ define i32 @lowmask_sext_in_reg(i32 %x) { ; CHECK-NEXT: [[L:%.*]] = shl i32 [[X:%.*]], 20 ; CHECK-NEXT: [[R:%.*]] = ashr exact i32 [[L]], 20 ; CHECK-NEXT: call void @use32(i32 [[R]]) -; CHECK-NEXT: [[AND:%.*]] = and i32 [[R]], 4095 +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], 4095 ; CHECK-NEXT: ret i32 [[AND]] ; %l = shl i32 %x, 20 @@ -989,6 +989,8 @@ define i32 @lowmask_sext_in_reg(i32 %x) { ret i32 %and } +; Negative test - mismatched shift amounts + define i32 @lowmask_not_sext_in_reg(i32 %x) { ; CHECK-LABEL: @lowmask_not_sext_in_reg( ; CHECK-NEXT: [[L:%.*]] = shl i32 [[X:%.*]], 19 @@ -1004,6 +1006,8 @@ define i32 @lowmask_not_sext_in_reg(i32 %x) { ret i32 %and } +; Negative test - too much shift for mask + define i32 @not_lowmask_sext_in_reg(i32 %x) { ; CHECK-LABEL: @not_lowmask_sext_in_reg( ; CHECK-NEXT: [[L:%.*]] = shl i32 [[X:%.*]], 20 @@ -1019,6 +1023,8 @@ define i32 @not_lowmask_sext_in_reg(i32 %x) { ret i32 %and } +; Negative test - too much shift for mask + define i32 @not_lowmask_sext_in_reg2(i32 %x) { ; CHECK-LABEL: @not_lowmask_sext_in_reg2( ; CHECK-NEXT: [[L:%.*]] = shl i32 [[X:%.*]], 21 @@ -1039,7 +1045,7 @@ define <2 x i32> @lowmask_sext_in_reg_splat(<2 x i32> %x, <2 x i32>* %p) { ; CHECK-NEXT: [[L:%.*]] = shl <2 x i32> [[X:%.*]], ; CHECK-NEXT: [[R:%.*]] = ashr exact <2 x i32> [[L]], ; CHECK-NEXT: store <2 x i32> [[R]], <2 x i32>* [[P:%.*]], align 8 -; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> [[R]], +; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> [[X]], ; CHECK-NEXT: ret <2 x i32> [[AND]] ; %l = shl <2 x i32> %x,