diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -688,6 +688,15 @@ return; replaceSubOverflowUses(II, A, B, ToRemove); } + if (II->getIntrinsicID() == Intrinsic::usub_with_overflow) { + // if A >= B usub_with_overflow(a, b) should not overflow and + // can be simplified to a regular sub + Value *A = II->getArgOperand(0); + Value *B = II->getArgOperand(1); + if (!DoesConditionHold(CmpInst::ICMP_UGE, A, B, Info)) + return; + replaceSubOverflowUses(II, A, B, ToRemove); + } } static bool eliminateConstraints(Function &F, DominatorTree &DT) { diff --git a/llvm/test/Transforms/ConstraintElimination/usub-with-overflow.ll b/llvm/test/Transforms/ConstraintElimination/usub-with-overflow.ll --- a/llvm/test/Transforms/ConstraintElimination/usub-with-overflow.ll +++ b/llvm/test/Transforms/ConstraintElimination/usub-with-overflow.ll @@ -9,12 +9,10 @@ ; CHECK-NEXT: [[C_1:%.*]] = icmp uge i8 [[B:%.*]], [[A:%.*]] ; CHECK-NEXT: br i1 [[C_1]], label [[MATH:%.*]], label [[EXIT_FAIL:%.*]] ; CHECK: math: -; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]]) -; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1 -; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] +; CHECK-NEXT: [[TMP0:%.*]] = sub i8 [[B]], [[A]] +; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] ; CHECK: exit.ok: -; CHECK-NEXT: [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0 -; CHECK-NEXT: ret i8 [[RES]] +; CHECK-NEXT: ret i8 [[TMP0]] ; CHECK: exit.fail: ; CHECK-NEXT: ret i8 0 ; @@ -41,12 +39,10 @@ ; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[B:%.*]], [[A:%.*]] ; CHECK-NEXT: br i1 [[C_1]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]] ; CHECK: math: -; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]]) -; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1 -; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] +; CHECK-NEXT: [[TMP0:%.*]] = sub i8 [[B]], [[A]] +; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] ; CHECK: exit.ok: -; CHECK-NEXT: [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0 -; CHECK-NEXT: ret i8 [[RES]] +; CHECK-NEXT: ret i8 [[TMP0]] ; CHECK: exit.fail: ; CHECK-NEXT: ret i8 0 ; @@ -75,13 +71,12 @@ ; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[B:%.*]], [[A:%.*]] ; CHECK-NEXT: br i1 [[C_1]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]] ; CHECK: math: +; CHECK-NEXT: [[TMP0:%.*]] = sub i8 [[B]], [[A]] ; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]]) ; CHECK-NEXT: call void @use_res({ i8, i1 } [[OP]]) -; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1 -; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] +; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] ; CHECK: exit.ok: -; CHECK-NEXT: [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0 -; CHECK-NEXT: ret i8 [[RES]] +; CHECK-NEXT: ret i8 [[TMP0]] ; CHECK: exit.fail: ; CHECK-NEXT: ret i8 0 ; @@ -111,12 +106,10 @@ ; CHECK-NEXT: [[OR:%.*]] = or i1 [[C_2]], [[C_1]] ; CHECK-NEXT: br i1 [[OR]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]] ; CHECK: math: -; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]]) -; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1 -; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] +; CHECK-NEXT: [[TMP0:%.*]] = sub i8 [[B]], [[A]] +; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] ; CHECK: exit.ok: -; CHECK-NEXT: [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0 -; CHECK-NEXT: ret i8 [[RES]] +; CHECK-NEXT: ret i8 [[TMP0]] ; CHECK: exit.fail: ; CHECK-NEXT: ret i8 0 ; @@ -147,9 +140,7 @@ ; CHECK-NEXT: [[OR:%.*]] = or i1 [[C_2]], [[C_1]] ; CHECK-NEXT: br i1 [[OR]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]] ; CHECK: math: -; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]]) -; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1 -; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] +; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] ; CHECK: exit.ok: ; CHECK-NEXT: ret i8 20 ; CHECK: exit.fail: @@ -181,12 +172,10 @@ ; CHECK-NEXT: [[AND:%.*]] = and i1 [[C_2]], [[C_1]] ; CHECK-NEXT: br i1 [[AND]], label [[MATH:%.*]], label [[EXIT_FAIL:%.*]] ; CHECK: math: -; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]]) -; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1 -; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] +; CHECK-NEXT: [[TMP0:%.*]] = sub i8 [[B]], [[A]] +; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] ; CHECK: exit.ok: -; CHECK-NEXT: [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0 -; CHECK-NEXT: ret i8 [[RES]] +; CHECK-NEXT: ret i8 [[TMP0]] ; CHECK: exit.fail: ; CHECK-NEXT: ret i8 0 ;