diff --git a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index da5384a86aa..4a0edf378c4 100644 --- a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1331,6 +1331,21 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { if (Value *V = FoldLogicalPlusAnd(Op0LHS, Op0RHS, AndRHS, true, I)) return BinaryOperator::CreateAnd(V, AndRHS); + // ((C1-zext(X)) & C2) -> zext((C1-X) & C2) if C2 fits in the bitwidth + // of X. + if (auto *ZI = dyn_cast(Op0RHS)) { + auto *X = ZI->getOperand(0); + ConstantInt *C1; + if (match(Op0LHS, m_ConstantInt(C1)) && + AndRHSMask.isIntN(X->getType()->getScalarSizeInBits())) { + auto *TruncC1 = ConstantExpr::getTrunc(C1, X->getType()); + auto *Sub = Builder->CreateSub(TruncC1, X); + auto *TruncC2 = ConstantExpr::getTrunc(AndRHS, X->getType()); + auto *And = Builder->CreateAnd(Sub, TruncC2); + return new ZExtInst(And, I.getType()); + } + } + // -x & 1 -> x & 1 if (AndRHSMask == 1 && match(Op0LHS, m_Zero())) return BinaryOperator::CreateAnd(Op0RHS, AndRHS); diff --git a/test/Transforms/InstCombine/and.ll b/test/Transforms/InstCombine/and.ll index e45012878ed..ee1dfbbe12e 100644 --- a/test/Transforms/InstCombine/and.ll +++ b/test/Transforms/InstCombine/and.ll @@ -425,3 +425,14 @@ define <2 x i32> @PR24942(<2 x i32> %x) { ret <2 x i32> %and } +define i64 @test35(i32 %X) { +; CHECK-LABEL: @test35( +; CHECK-NEXT: %[[sub:.*]] = sub i32 0, %X +; CHECK-NEXT: %[[and:.*]] = and i32 %[[sub]], 240 +; CHECK-NEXT: %[[cst:.*]] = zext i32 %[[and]] to i64 +; CHECK-NEXT: ret i64 %[[cst]] + %zext = zext i32 %X to i64 + %zsub = sub i64 0, %zext + %res = and i64 %zsub, 240 + ret i64 %res +}