diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h index 320deb80bb1f8..f9f4f16038619 100644 --- a/llvm/include/llvm/IR/PatternMatch.h +++ b/llvm/include/llvm/IR/PatternMatch.h @@ -589,6 +589,9 @@ struct is_lowbit_mask { inline cst_pred_ty m_LowBitMask() { return cst_pred_ty(); } +inline api_pred_ty m_LowBitMask(const APInt *&V) { + return V; +} struct icmp_pred_with_threshold { ICmpInst::Predicate Pred; diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 59e131bd3b6a2..5b6728e466fc0 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -3949,6 +3949,33 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I, (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULE)) return new ICmpInst(Pred, X, Builder.CreateNot(Op0)); + { + // Similar to above: an unsigned overflow comparison may use offset + mask: + // ((Op1 + C) & C) u< Op1 --> Op1 != 0 + // ((Op1 + C) & C) u>= Op1 --> Op1 == 0 + // Op0 u> ((Op0 + C) & C) --> Op0 != 0 + // Op0 u<= ((Op0 + C) & C) --> Op0 == 0 + BinaryOperator *BO; + const APInt *C; + if ((Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_UGE) && + match(Op0, m_And(m_BinOp(BO), m_LowBitMask(C))) && + match(BO, m_Add(m_Specific(Op1), m_SpecificIntAllowUndef(*C)))) { + CmpInst::Predicate NewPred = + Pred == ICmpInst::ICMP_ULT ? ICmpInst::ICMP_NE : ICmpInst::ICMP_EQ; + Constant *Zero = ConstantInt::getNullValue(Op1->getType()); + return new ICmpInst(NewPred, Op1, Zero); + } + + if ((Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULE) && + match(Op1, m_And(m_BinOp(BO), m_LowBitMask(C))) && + match(BO, m_Add(m_Specific(Op0), m_SpecificIntAllowUndef(*C)))) { + CmpInst::Predicate NewPred = + Pred == ICmpInst::ICMP_UGT ? ICmpInst::ICMP_NE : ICmpInst::ICMP_EQ; + Constant *Zero = ConstantInt::getNullValue(Op1->getType()); + return new ICmpInst(NewPred, Op0, Zero); + } + } + bool NoOp0WrapProblem = false, NoOp1WrapProblem = false; if (BO0 && isa(BO0)) NoOp0WrapProblem = diff --git a/llvm/test/Transforms/InstCombine/unsigned-add-lack-of-overflow-check.ll b/llvm/test/Transforms/InstCombine/unsigned-add-lack-of-overflow-check.ll index 11ec67bd67527..e76fcbad61c82 100644 --- a/llvm/test/Transforms/InstCombine/unsigned-add-lack-of-overflow-check.ll +++ b/llvm/test/Transforms/InstCombine/unsigned-add-lack-of-overflow-check.ll @@ -200,9 +200,7 @@ define i1 @n15_wrong_pred7(i8 %x, i8 %y) { define i1 @low_bitmask_ult(i8 %x) { ; CHECK-LABEL: @low_bitmask_ult( -; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], 31 -; CHECK-NEXT: [[M:%.*]] = and i8 [[A]], 31 -; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[M]], [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[X:%.*]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %a = add i8 %x, 31 @@ -213,9 +211,7 @@ define i1 @low_bitmask_ult(i8 %x) { define <2 x i1> @low_bitmask_uge(<2 x i8> %x) { ; CHECK-LABEL: @low_bitmask_uge( -; CHECK-NEXT: [[A:%.*]] = add <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[M:%.*]] = and <2 x i8> [[A]], -; CHECK-NEXT: [[R:%.*]] = icmp uge <2 x i8> [[M]], [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i8> [[X:%.*]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[R]] ; %a = add <2 x i8> %x, @@ -227,9 +223,7 @@ define <2 x i1> @low_bitmask_uge(<2 x i8> %x) { define i1 @low_bitmask_ugt(i8 %px) { ; CHECK-LABEL: @low_bitmask_ugt( ; CHECK-NEXT: [[X:%.*]] = mul i8 [[PX:%.*]], [[PX]] -; CHECK-NEXT: [[A:%.*]] = add i8 [[X]], 127 -; CHECK-NEXT: [[M:%.*]] = and i8 [[A]], 127 -; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[X]], [[M]] +; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[X]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %x = mul i8 %px, %px @@ -242,9 +236,7 @@ define i1 @low_bitmask_ugt(i8 %px) { define <2 x i1> @low_bitmask_ule(<2 x i8> %px) { ; CHECK-LABEL: @low_bitmask_ule( ; CHECK-NEXT: [[X:%.*]] = mul <2 x i8> [[PX:%.*]], [[PX]] -; CHECK-NEXT: [[A:%.*]] = add <2 x i8> [[X]], -; CHECK-NEXT: [[M:%.*]] = and <2 x i8> [[A]], -; CHECK-NEXT: [[R:%.*]] = icmp ule <2 x i8> [[X]], [[M]] +; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i8> [[X]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[R]] ; %x = mul <2 x i8> %px, %px @@ -259,7 +251,7 @@ define i1 @low_bitmask_ult_use(i8 %x) { ; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], 7 ; CHECK-NEXT: [[M:%.*]] = and i8 [[A]], 7 ; CHECK-NEXT: call void @use8(i8 [[M]]) -; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[M]], [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[X]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %a = add i8 %x, 7 @@ -274,8 +266,7 @@ define i1 @low_bitmask_ugt_use(i8 %px) { ; CHECK-NEXT: [[X:%.*]] = mul i8 [[PX:%.*]], [[PX]] ; CHECK-NEXT: [[A:%.*]] = add i8 [[X]], 3 ; CHECK-NEXT: call void @use8(i8 [[A]]) -; CHECK-NEXT: [[M:%.*]] = and i8 [[A]], 3 -; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[X]], [[M]] +; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[X]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %x = mul i8 %px, %px @@ -286,6 +277,8 @@ define i1 @low_bitmask_ugt_use(i8 %px) { ret i1 %r } +; negative test - need same low bitmask + define i1 @low_bitmask_ult_wrong_mask1(i8 %x) { ; CHECK-LABEL: @low_bitmask_ult_wrong_mask1( ; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], 30 @@ -299,6 +292,8 @@ define i1 @low_bitmask_ult_wrong_mask1(i8 %x) { ret i1 %r } +; negative test - need same low bitmask + define i1 @low_bitmask_uge_wrong_mask2(i8 %x) { ; CHECK-LABEL: @low_bitmask_uge_wrong_mask2( ; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], 31 @@ -312,6 +307,8 @@ define i1 @low_bitmask_uge_wrong_mask2(i8 %x) { ret i1 %r } +; negative test - predicate mandates operand order + define i1 @low_bitmask_ugt_swapped(i8 %x) { ; CHECK-LABEL: @low_bitmask_ugt_swapped( ; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], 127 @@ -325,6 +322,8 @@ define i1 @low_bitmask_ugt_swapped(i8 %x) { ret i1 %r } +; negative test - unsigned preds only + define i1 @low_bitmask_sgt(i8 %px) { ; CHECK-LABEL: @low_bitmask_sgt( ; CHECK-NEXT: [[X:%.*]] = mul i8 [[PX:%.*]], [[PX]] @@ -340,6 +339,8 @@ define i1 @low_bitmask_sgt(i8 %px) { ret i1 %r } +; negative test - specific operand must match + define i1 @low_bitmask_ult_specific_op(i8 %x, i8 %y) { ; CHECK-LABEL: @low_bitmask_ult_specific_op( ; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], 31