diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index 2c2e1bc4686a4..eb94e894b57b0 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1929,6 +1929,15 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) { break; } + case Intrinsic::scmp: { + Value *I0 = II->getArgOperand(0), *I1 = II->getArgOperand(1); + Value *LHS, *RHS; + if (match(I0, m_NSWSub(m_Value(LHS), m_Value(RHS))) && match(I1, m_Zero())) + return replaceInstUsesWith( + CI, + Builder.CreateIntrinsic(II->getType(), Intrinsic::scmp, {LHS, RHS})); + break; + } case Intrinsic::bitreverse: { Value *IIOperand = II->getArgOperand(0); // bitrev (zext i1 X to ?) --> X ? SignBitC : 0 diff --git a/llvm/test/Transforms/InstCombine/scmp.ll b/llvm/test/Transforms/InstCombine/scmp.ll index 7f374c5f9a1d6..a3334599a67f1 100644 --- a/llvm/test/Transforms/InstCombine/scmp.ll +++ b/llvm/test/Transforms/InstCombine/scmp.ll @@ -264,3 +264,54 @@ define i8 @scmp_from_select_ge(i32 %x, i32 %y) { %r = select i1 %ge, i8 %ne, i8 -1 ret i8 %r } + +; Fold scmp(x nsw- y, 0) to scmp(x, y) +define i8 @scmp_of_sub_and_zero(i32 %x, i32 %y) { +; CHECK-LABEL: define i8 @scmp_of_sub_and_zero( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]]) +; CHECK-NEXT: ret i8 [[R]] +; + %diff = sub nsw i32 %x, %y + %r = call i8 @llvm.scmp(i32 %diff, i32 0) + ret i8 %r +} + +; Negative test: no nsw +define i8 @scmp_of_sub_and_zero_neg_1(i32 %x, i32 %y) { +; CHECK-LABEL: define i8 @scmp_of_sub_and_zero_neg_1( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[DIFF:%.*]] = sub i32 [[X]], [[Y]] +; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[DIFF]], i32 0) +; CHECK-NEXT: ret i8 [[R]] +; + %diff = sub i32 %x, %y + %r = call i8 @llvm.scmp(i32 %diff, i32 0) + ret i8 %r +} + +; Negative test: second argument of scmp is not 0 +define i8 @scmp_of_sub_and_zero_neg2(i32 %x, i32 %y) { +; CHECK-LABEL: define i8 @scmp_of_sub_and_zero_neg2( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[DIFF:%.*]] = sub nsw i32 [[X]], [[Y]] +; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[DIFF]], i32 15) +; CHECK-NEXT: ret i8 [[R]] +; + %diff = sub nsw i32 %x, %y + %r = call i8 @llvm.scmp(i32 %diff, i32 15) + ret i8 %r +} + +; Negative test: calling ucmp instead of scmp +define i8 @scmp_of_sub_and_zero_neg3(i32 %x, i32 %y) { +; CHECK-LABEL: define i8 @scmp_of_sub_and_zero_neg3( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[DIFF:%.*]] = sub nsw i32 [[X]], [[Y]] +; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[DIFF]], i32 0) +; CHECK-NEXT: ret i8 [[R]] +; + %diff = sub nsw i32 %x, %y + %r = call i8 @llvm.ucmp(i32 %diff, i32 0) + ret i8 %r +}