Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1817,9 +1817,9 @@ return BinaryOperator::Create(BinOp, NewLHS, Y); } } - const APInt *ShiftC; + const APInt *ShiftC, *ShiftC2; + unsigned Width = Ty->getScalarSizeInBits(); if (match(Op0, m_OneUse(m_SExt(m_AShr(m_Value(X), m_APInt(ShiftC)))))) { - unsigned Width = Ty->getScalarSizeInBits(); if (*C == APInt::getLowBitsSet(Width, Width - ShiftC->getZExtValue())) { // We are clearing high bits that were potentially set by sext+ashr: // and (sext (ashr X, ShiftC)), C --> lshr (sext X), ShiftC @@ -1828,6 +1828,12 @@ return BinaryOperator::CreateLShr(Sext, ShAmtC); } } + // Peek through masking off the low bits of a sign-extend-in-register: + // and (ashr (shl X, ShiftC), ShiftC), C --> and X, C + if (match(Op0, + m_AShr(m_Shl(m_Value(X), m_APInt(ShiftC)), m_APInt(ShiftC2))) && + ShiftC == ShiftC2 && (Width - ShiftC->getZExtValue()) > C->logBase2()) + return BinaryOperator::CreateAnd(X, Op1); } ConstantInt *AndRHS; 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,