Index: lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCompares.cpp +++ lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -5062,6 +5062,30 @@ if (Instruction *R = processUMulZExtIdiom(I, Op1, Op0, *this)) return R; } + + // extract(uadd.with.overflow(A, B), 0) ult A + // -> extract(uadd.with.overflow(A, B), 1) + auto UAddOverflowPat = + m_Intrinsic(m_Value(A), m_Value(B)); + if (auto *EVI = dyn_cast(Op0)) { + if (EVI->getNumIndices() == 1 && *EVI->idx_begin() == 0 && + match(EVI->getAggregateOperand(), UAddOverflowPat)) { + // Additional special cases for ult 1 to eq 0 and + // ult MAX to ne MAX canonicalization. + if ((Pred == ICmpInst::ICMP_ULT && (Op1 == A || Op1 == B)) || + (Pred == ICmpInst::ICMP_EQ && match(Op1, m_ZeroInt()) && + (match(A, m_One()) || match(B, m_One()))) || + (Pred == ICmpInst::ICMP_NE && match(Op1, m_AllOnes()) && + (match(A, m_AllOnes()) || match(B, m_AllOnes())))) + return ExtractValueInst::Create(EVI->getAggregateOperand(), 1); + } + } + if (auto *EVI = dyn_cast(Op1)) { + if (EVI->getNumIndices() == 1 && *EVI->idx_begin() == 0 && + match(EVI->getAggregateOperand(), UAddOverflowPat) && + Pred == ICmpInst::ICMP_UGT && (Op0 == A || Op0 == B)) + return ExtractValueInst::Create(EVI->getAggregateOperand(), 1); + } } if (Instruction *Res = foldICmpEquality(I)) Index: test/Transforms/InstCombine/with_overflow.ll =================================================================== --- test/Transforms/InstCombine/with_overflow.ll +++ test/Transforms/InstCombine/with_overflow.ll @@ -351,8 +351,7 @@ ; CHECK-NEXT: [[A:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 [[Y:%.*]]) ; CHECK-NEXT: [[B:%.*]] = extractvalue { i32, i1 } [[A]], 1 ; CHECK-NEXT: store i1 [[B]], i1* [[P:%.*]], align 1 -; CHECK-NEXT: [[C:%.*]] = extractvalue { i32, i1 } [[A]], 0 -; CHECK-NEXT: [[D:%.*]] = icmp ult i32 [[C]], [[X]] +; CHECK-NEXT: [[D:%.*]] = extractvalue { i32, i1 } [[A]], 1 ; CHECK-NEXT: ret i1 [[D]] ; %a = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %x, i32 %y) @@ -368,8 +367,7 @@ ; CHECK-NEXT: [[A:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 [[Y:%.*]]) ; CHECK-NEXT: [[B:%.*]] = extractvalue { i32, i1 } [[A]], 1 ; CHECK-NEXT: store i1 [[B]], i1* [[P:%.*]], align 1 -; CHECK-NEXT: [[C:%.*]] = extractvalue { i32, i1 } [[A]], 0 -; CHECK-NEXT: [[D:%.*]] = icmp ult i32 [[C]], [[Y]] +; CHECK-NEXT: [[D:%.*]] = extractvalue { i32, i1 } [[A]], 1 ; CHECK-NEXT: ret i1 [[D]] ; %a = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %x, i32 %y) @@ -386,8 +384,7 @@ ; CHECK-NEXT: [[A:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X]], i32 [[Y:%.*]]) ; CHECK-NEXT: [[B:%.*]] = extractvalue { i32, i1 } [[A]], 1 ; CHECK-NEXT: store i1 [[B]], i1* [[P:%.*]], align 1 -; CHECK-NEXT: [[C:%.*]] = extractvalue { i32, i1 } [[A]], 0 -; CHECK-NEXT: [[D:%.*]] = icmp ugt i32 [[X]], [[C]] +; CHECK-NEXT: [[D:%.*]] = extractvalue { i32, i1 } [[A]], 1 ; CHECK-NEXT: ret i1 [[D]] ; %x = urem i32 42, %xx ; Thwart complexity-based canonicalization @@ -405,8 +402,7 @@ ; CHECK-NEXT: [[A:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 [[Y]]) ; CHECK-NEXT: [[B:%.*]] = extractvalue { i32, i1 } [[A]], 1 ; CHECK-NEXT: store i1 [[B]], i1* [[P:%.*]], align 1 -; CHECK-NEXT: [[C:%.*]] = extractvalue { i32, i1 } [[A]], 0 -; CHECK-NEXT: [[D:%.*]] = icmp ugt i32 [[Y]], [[C]] +; CHECK-NEXT: [[D:%.*]] = extractvalue { i32, i1 } [[A]], 1 ; CHECK-NEXT: ret i1 [[D]] ; %y = urem i32 42, %yy ; Thwart complexity-based canonicalization @@ -423,8 +419,7 @@ ; CHECK-NEXT: [[A:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 42) ; CHECK-NEXT: [[B:%.*]] = extractvalue { i32, i1 } [[A]], 1 ; CHECK-NEXT: store i1 [[B]], i1* [[P:%.*]], align 1 -; CHECK-NEXT: [[C:%.*]] = extractvalue { i32, i1 } [[A]], 0 -; CHECK-NEXT: [[D:%.*]] = icmp ult i32 [[C]], 42 +; CHECK-NEXT: [[D:%.*]] = extractvalue { i32, i1 } [[A]], 1 ; CHECK-NEXT: ret i1 [[D]] ; %a = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %x, i32 42) @@ -440,8 +435,7 @@ ; CHECK-NEXT: [[A:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 1) ; CHECK-NEXT: [[B:%.*]] = extractvalue { i32, i1 } [[A]], 1 ; CHECK-NEXT: store i1 [[B]], i1* [[P:%.*]], align 1 -; CHECK-NEXT: [[C:%.*]] = extractvalue { i32, i1 } [[A]], 0 -; CHECK-NEXT: [[D:%.*]] = icmp eq i32 [[C]], 0 +; CHECK-NEXT: [[D:%.*]] = extractvalue { i32, i1 } [[A]], 1 ; CHECK-NEXT: ret i1 [[D]] ; %a = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %x, i32 1) @@ -457,8 +451,7 @@ ; CHECK-NEXT: [[A:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X:%.*]], i32 -1) ; CHECK-NEXT: [[B:%.*]] = extractvalue { i32, i1 } [[A]], 1 ; CHECK-NEXT: store i1 [[B]], i1* [[P:%.*]], align 1 -; CHECK-NEXT: [[C:%.*]] = extractvalue { i32, i1 } [[A]], 0 -; CHECK-NEXT: [[D:%.*]] = icmp ne i32 [[C]], -1 +; CHECK-NEXT: [[D:%.*]] = extractvalue { i32, i1 } [[A]], 1 ; CHECK-NEXT: ret i1 [[D]] ; %a = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %x, i32 -1)