Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2035,6 +2035,18 @@ ConstantInt::getNullValue(Ty)); } + // If all bits affected by a sub are included in a high-bit-mask, do the + // mask op before the adjusted sub. Example: + // (0x0f - X) & 0xf8 --> 0x08 - (X & 0xf8) + const APInt *SubC; + if (C->isNegatedPowerOf2() && + match(Op0, m_OneUse(m_Sub(m_APInt(SubC), m_Value(X)))) && + (~*C).isSubsetOf(*SubC)) { + Value *NewAnd = Builder.CreateAnd(X, *C); + Constant *NewSubC = ConstantInt::get(Ty, *C & *SubC); + return BinaryOperator::CreateSub(NewSubC, NewAnd); + } + Constant *C1, *C2; const APInt *C3 = C; Value *X; Index: llvm/test/Transforms/InstCombine/sub.ll =================================================================== --- llvm/test/Transforms/InstCombine/sub.ll +++ llvm/test/Transforms/InstCombine/sub.ll @@ -2253,9 +2253,8 @@ ; ((C2 + C3) & ((C2 & C3) - 1)) == ((C2 & C3) - 1) define i10 @sub_to_and_negpow2(i10 %x) { ; CHECK-LABEL: @sub_to_and_negpow2( -; CHECK-NEXT: [[SUB:%.*]] = sub i10 71, [[X:%.*]] -; CHECK-NEXT: [[AND:%.*]] = and i10 [[SUB]], -8 -; CHECK-NEXT: [[R:%.*]] = sub i10 33, [[AND]] +; CHECK-NEXT: [[TMP1:%.*]] = and i10 [[X:%.*]], -8 +; CHECK-NEXT: [[R:%.*]] = add i10 [[TMP1]], -31 ; CHECK-NEXT: ret i10 [[R]] ; %sub = sub i10 71, %x