Index: llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp @@ -914,6 +914,24 @@ break; } + case Instruction::AShr: { + // 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 the demanded bits are already within original operand. 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); Index: llvm/test/Transforms/InstCombine/and.ll =================================================================== --- llvm/test/Transforms/InstCombine/and.ll +++ llvm/test/Transforms/InstCombine/and.ll @@ -979,7 +979,7 @@ ; 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 @@ 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 @@ 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 @@ 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 @@ ; 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,