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 @@ -3432,6 +3432,16 @@ ICmpInst::Predicate NewPred = Pred == ICmpInst::ICMP_EQ ? ICmpInst::ICMP_ULE : ICmpInst::ICMP_UGT; return new ICmpInst(NewPred, II->getArgOperand(0), II->getArgOperand(1)); + } else { + Value *II0 = II->getOperand(0); + Value *II1 = II->getOperand(1); + ICmpInst::Predicate EqPred = + Pred == ICmpInst::ICMP_EQ ? ICmpInst::ICMP_UGE : ICmpInst::ICMP_ULT; + if (match(II1, m_Constant())) + return BinaryOperator::CreateAnd( + Builder.CreateICmp(EqPred, II0, II1), + Builder.CreateICmp(Pred, Builder.CreateSub(II0, II1), + Builder.getInt(C))); } break; } @@ -3657,6 +3667,21 @@ II->getArgOperand(1)); } break; + case Intrinsic::usub_sat: { + Value *II0 = II->getOperand(0); + Value *II1 = II->getOperand(1); + if (match(II1, m_Constant())) { + if (ICmpInst::compare(APInt::getZero(C.getBitWidth()), C, Pred)) + return BinaryOperator::CreateOr( + Builder.CreateICmp(ICmpInst::ICMP_ULT, II0, II1), + Builder.CreateICmp(Pred, Builder.CreateSub(II0, II1), Builder.getInt(C))); + else + return BinaryOperator::CreateAnd( + Builder.CreateICmp(ICmpInst::ICMP_UGE, II0, II1), + Builder.CreateICmp(Pred, Builder.CreateSub(II0, II1), Builder.getInt(C))); + } + break; + } default: break; } diff --git a/llvm/test/Transforms/InstCombine/icmp-usub-sat.ll b/llvm/test/Transforms/InstCombine/icmp-usub-sat.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/icmp-usub-sat.ll @@ -0,0 +1,120 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +; https://github.com/llvm/llvm-project/issues/58342 + +define i1 @icmp_eq(i8 %arg) { +; CHECK-LABEL: define i1 @icmp_eq +; CHECK-SAME: (i8 [[ARG:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[ARG]], 7 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %sub = call i8 @llvm.usub.sat.i8(i8 %arg, i8 2) + %cmp = icmp eq i8 %sub, 5 + ret i1 %cmp +} + +define i1 @icmp_ne(i8 %arg) { +; CHECK-LABEL: define i1 @icmp_ne +; CHECK-SAME: (i8 [[ARG:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i8 [[ARG]], 2 +; CHECK-NEXT: ret i1 [[TMP1]] +; + %sub = call i8 @llvm.usub.sat.i8(i8 %arg, i8 2) + %cmp = icmp ne i8 %sub, 5 + ret i1 %cmp +} + +define i1 @icmp_ule(i8 %arg) { +; CHECK-LABEL: define i1 @icmp_ule +; CHECK-SAME: (i8 [[ARG:%.*]]) { +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[ARG]], 8 +; CHECK-NEXT: ret i1 [[CMP]] +; + %sub = call i8 @llvm.usub.sat.i8(i8 %arg, i8 2) + %cmp = icmp ule i8 %sub, 5 + ret i1 %cmp +} + +define i1 @icmp_ult(i8 %arg) { +; CHECK-LABEL: define i1 @icmp_ult +; CHECK-SAME: (i8 [[ARG:%.*]]) { +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[ARG]], 7 +; CHECK-NEXT: ret i1 [[CMP]] +; + %sub = call i8 @llvm.usub.sat.i8(i8 %arg, i8 2) + %cmp = icmp ult i8 %sub, 5 + ret i1 %cmp +} + +define i1 @icmp_uge(i8 %arg) { +; CHECK-LABEL: define i1 @icmp_uge +; CHECK-SAME: (i8 [[ARG:%.*]]) { +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[ARG]], 6 +; CHECK-NEXT: ret i1 [[CMP]] +; + %sub = call i8 @llvm.usub.sat.i8(i8 %arg, i8 2) + %cmp = icmp uge i8 %sub, 5 + ret i1 %cmp +} + +define i1 @icmp_ugt(i8 %arg) { +; CHECK-LABEL: define i1 @icmp_ugt +; CHECK-SAME: (i8 [[ARG:%.*]]) { +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[ARG]], 7 +; CHECK-NEXT: ret i1 [[CMP]] +; + %sub = call i8 @llvm.usub.sat.i8(i8 %arg, i8 2) + %cmp = icmp ugt i8 %sub, 5 + ret i1 %cmp +} + +define i1 @icmp_sle(i8 %arg) { +; CHECK-LABEL: define i1 @icmp_sle +; CHECK-SAME: (i8 [[ARG:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[ARG]], 126 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[TMP1]], -122 +; CHECK-NEXT: ret i1 [[CMP]] +; + %sub = call i8 @llvm.usub.sat.i8(i8 %arg, i8 2) + %cmp = icmp sle i8 %sub, 5 + ret i1 %cmp +} + +define i1 @icmp_slt(i8 %arg) { +; CHECK-LABEL: define i1 @icmp_slt +; CHECK-SAME: (i8 [[ARG:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[ARG]], 126 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[TMP1]], -123 +; CHECK-NEXT: ret i1 [[CMP]] +; + %sub = call i8 @llvm.usub.sat.i8(i8 %arg, i8 2) + %cmp = icmp slt i8 %sub, 5 + ret i1 %cmp +} + +define i1 @icmp_sge(i8 %arg) { +; CHECK-LABEL: define i1 @icmp_sge +; CHECK-SAME: (i8 [[ARG:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[ARG]], -7 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[TMP1]], 123 +; CHECK-NEXT: ret i1 [[CMP]] +; + %sub = call i8 @llvm.usub.sat.i8(i8 %arg, i8 2) + %cmp = icmp sge i8 %sub, 5 + ret i1 %cmp +} + +define i1 @icmp_sgt(i8 %arg) { +; CHECK-LABEL: define i1 @icmp_sgt +; CHECK-SAME: (i8 [[ARG:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[ARG]], -8 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[TMP1]], 122 +; CHECK-NEXT: ret i1 [[CMP]] +; + %sub = call i8 @llvm.usub.sat.i8(i8 %arg, i8 2) + %cmp = icmp sgt i8 %sub, 5 + ret i1 %cmp +} + +declare i8 @llvm.usub.sat.i8(i8, i8)