diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -4975,6 +4975,7 @@ Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); const CmpInst::Predicate Pred = I.getPredicate(); Value *A = nullptr; + bool CheckIs; if (I.isEquality()) { // (A & (A-1)) == 0 --> ctpop(A) < 2 (two commuted variants) // ((A-1) & A) != 0 --> ctpop(A) > 1 (two commuted variants) @@ -4990,14 +4991,28 @@ else if (match(Op1, m_OneUse(m_c_And(m_Neg(m_Specific(Op0)), m_Specific(Op0))))) A = Op0; + + CheckIs = Pred == ICmpInst::ICMP_EQ; + } else if (Pred == ICmpInst::ICMP_UGE || Pred == ICmpInst::ICMP_ULT) { + // (A ^ (A-1)) u>= A --> ctpop(A) < 2 (two commuted variants) + // ((A-1) ^ A) u< A --> ctpop(A) > 1 (two commuted variants) + if (match(Op0, m_OneUse(m_c_Xor(m_Add(m_Specific(Op1), m_AllOnes()), + m_Specific(Op1))))) + A = Op1; + else if (match(Op1, m_OneUse(m_c_Xor(m_Add(m_Specific(Op0), m_AllOnes()), + m_Specific(Op0))))) + A = Op0; + + CheckIs = Pred == ICmpInst::ICMP_UGE; } + if (A) { Type *Ty = A->getType(); CallInst *CtPop = Builder.CreateUnaryIntrinsic(Intrinsic::ctpop, A); - return Pred == ICmpInst::ICMP_EQ ? new ICmpInst(ICmpInst::ICMP_ULT, CtPop, - ConstantInt::get(Ty, 2)) - : new ICmpInst(ICmpInst::ICMP_UGT, CtPop, - ConstantInt::get(Ty, 1)); + return CheckIs ? new ICmpInst(ICmpInst::ICMP_ULT, CtPop, + ConstantInt::get(Ty, 2)) + : new ICmpInst(ICmpInst::ICMP_UGT, CtPop, + ConstantInt::get(Ty, 1)); } return nullptr; diff --git a/llvm/test/Transforms/InstCombine/ispow2.ll b/llvm/test/Transforms/InstCombine/ispow2.ll --- a/llvm/test/Transforms/InstCombine/ispow2.ll +++ b/llvm/test/Transforms/InstCombine/ispow2.ll @@ -1157,9 +1157,8 @@ define i1 @blsmsk_is_p2_or_z(i32 %xx, i32 %yy) { ; CHECK-LABEL: @blsmsk_is_p2_or_z( ; CHECK-NEXT: [[X:%.*]] = or i32 [[XX:%.*]], [[YY:%.*]] -; CHECK-NEXT: [[XM1:%.*]] = add i32 [[X]], -1 -; CHECK-NEXT: [[Y:%.*]] = xor i32 [[X]], [[XM1]] -; CHECK-NEXT: [[R:%.*]] = icmp uge i32 [[X]], [[Y]] +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.ctpop.i32(i32 [[X]]), !range [[RNG0]] +; CHECK-NEXT: [[R:%.*]] = icmp ult i32 [[TMP1]], 2 ; CHECK-NEXT: ret i1 [[R]] ; %x = or i32 %xx, %yy @@ -1171,9 +1170,8 @@ define i1 @blsmsk_isnt_p2_or_z(i32 %x) { ; CHECK-LABEL: @blsmsk_isnt_p2_or_z( -; CHECK-NEXT: [[XM1:%.*]] = add i32 [[X:%.*]], -1 -; CHECK-NEXT: [[Y:%.*]] = xor i32 [[XM1]], [[X]] -; CHECK-NEXT: [[R:%.*]] = icmp ult i32 [[Y]], [[X]] +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.ctpop.i32(i32 [[X:%.*]]), !range [[RNG0]] +; CHECK-NEXT: [[R:%.*]] = icmp ugt i32 [[TMP1]], 1 ; CHECK-NEXT: ret i1 [[R]] ; %xm1 = add i32 %x, -1