Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2564,6 +2564,21 @@ A->getType()->isIntOrIntVectorTy(1)) return SelectInst::Create(A, Constant::getNullValue(Ty), Op0); + // (-1 + zext(A)) & Op1 --> A ? 0 : Op1 + // Op0 & (-1 + zext(A)) --> A ? 0 : Op0 + if (match(Op0, m_NSWAdd(m_ZExt(m_Value(A)), m_AllOnes())) && + (A->getType()->isIntOrIntVectorTy(1) || + (~computeKnownBits(A, 0, dyn_cast(Op0)).Zero) == 1)) + return SelectInst::Create( + Builder.CreateTrunc(A, A->getType()->getWithNewBitWidth(1)), + Constant::getNullValue(Ty), Op1); + if (match(Op1, m_NSWAdd(m_ZExt(m_Value(A)), m_AllOnes())) && + (A->getType()->isIntOrIntVectorTy(1) || + (~computeKnownBits(A, 0, dyn_cast(Op1)).Zero) == 1)) + return SelectInst::Create( + Builder.CreateTrunc(A, A->getType()->getWithNewBitWidth(1)), + Constant::getNullValue(Ty), Op0); + // (iN X s>> (N-1)) & Y --> (X s< 0) ? Y : 0 -- with optional sext if (match(&I, m_c_And(m_OneUse(m_SExtOrSelf( m_AShr(m_Value(X), m_APIntAllowUndef(C)))), Index: llvm/test/Transforms/InstCombine/binop-cast.ll =================================================================== --- llvm/test/Transforms/InstCombine/binop-cast.ll +++ llvm/test/Transforms/InstCombine/binop-cast.ll @@ -257,3 +257,17 @@ %r = xor i32 %sext, 42 ret i32 %r } + +define i64 @PR63321(ptr %ptr, i64 %c) { +; CHECK-LABEL: @PR63321( +; CHECK-NEXT: [[VAL:%.*]] = load i8, ptr [[PTR:%.*]], align 1, !range [[RNG0:![0-9]+]] +; CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i8 [[VAL]], 0 +; CHECK-NEXT: [[RES:%.*]] = select i1 [[DOTNOT]], i64 [[C:%.*]], i64 0 +; CHECK-NEXT: ret i64 [[RES]] +; + %val = load i8, ptr %ptr, align 1, !range !{i8 0, i8 2} + %rhs = zext i8 %val to i64 + %mask = add i64 -1, %rhs + %res = and i64 %mask, %c + ret i64 %res +}