[llvm] b7b3d17 - [InstSimplify] Implement simple folds for `ucmp`/`scmp` intrinsics (#95601)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Jun 16 22:11:00 PDT 2024
Author: Poseydon42
Date: 2024-06-17T13:10:57+08:00
New Revision: b7b3d1798db98c0f7071e4557e860a6fd5847602
URL: https://github.com/llvm/llvm-project/commit/b7b3d1798db98c0f7071e4557e860a6fd5847602
DIFF: https://github.com/llvm/llvm-project/commit/b7b3d1798db98c0f7071e4557e860a6fd5847602.diff
LOG: [InstSimplify] Implement simple folds for `ucmp`/`scmp` intrinsics (#95601)
This patch adds folds for the cases where both operands are the same or
where it can be established that the first operand is less than, equal
to, or greater than the second operand.
Added:
Modified:
llvm/lib/Analysis/InstructionSimplify.cpp
llvm/test/Transforms/InstSimplify/uscmp.ll
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 1fb3b28444e4a..132dd1cc7396e 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -6504,6 +6504,25 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
break;
}
+ case Intrinsic::scmp:
+ case Intrinsic::ucmp: {
+ // Fold to a constant if the relationship between operands can be
+ // established with certainty
+ if (isICmpTrue(CmpInst::ICMP_EQ, Op0, Op1, Q, RecursionLimit))
+ return Constant::getNullValue(ReturnType);
+
+ ICmpInst::Predicate PredGT =
+ IID == Intrinsic::scmp ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT;
+ if (isICmpTrue(PredGT, Op0, Op1, Q, RecursionLimit))
+ return ConstantInt::get(ReturnType, 1);
+
+ ICmpInst::Predicate PredLT =
+ IID == Intrinsic::scmp ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT;
+ if (isICmpTrue(PredLT, Op0, Op1, Q, RecursionLimit))
+ return ConstantInt::getSigned(ReturnType, -1);
+
+ break;
+ }
case Intrinsic::usub_with_overflow:
case Intrinsic::ssub_with_overflow:
// X - X -> { 0, false }
diff --git a/llvm/test/Transforms/InstSimplify/uscmp.ll b/llvm/test/Transforms/InstSimplify/uscmp.ll
index adfcc313eff9e..db96aa39192d6 100644
--- a/llvm/test/Transforms/InstSimplify/uscmp.ll
+++ b/llvm/test/Transforms/InstSimplify/uscmp.ll
@@ -96,3 +96,209 @@ define <4 x i8> @scmp_nonsplat() {
%1 = call <4 x i8> @llvm.scmp(<4 x i32> <i32 0, i32 1, i32 2, i32 3>, <4 x i32> <i32 -1, i32 1, i32 -2, i32 4>)
ret <4 x i8> %1
}
+
+define i8 @scmp_with_itself(i32 %x) {
+; CHECK-LABEL: define i8 @scmp_with_itself(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: ret i8 0
+;
+ %1 = call i8 @llvm.scmp(i32 %x, i32 %x)
+ ret i8 %1
+}
+
+define <4 x i8> @ucmp_vec_with_itself(<4 x i32> %x) {
+; CHECK-LABEL: define <4 x i8> @ucmp_vec_with_itself(
+; CHECK-SAME: <4 x i32> [[X:%.*]]) {
+; CHECK-NEXT: ret <4 x i8> zeroinitializer
+;
+ %1 = call <4 x i8> @llvm.scmp(<4 x i32> %x, <4 x i32> %x)
+ ret <4 x i8> %1
+}
+
+define i8 @scmp_known_gt(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @scmp_known_gt(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[X]], [[Y]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]])
+; CHECK-NEXT: ret i8 1
+;
+ %1 = icmp sgt i32 %x, %y
+ call void @llvm.assume(i1 %1)
+
+ %2 = call i8 @llvm.scmp(i32 %x, i32 %y)
+ ret i8 %2
+}
+
+define i8 @scmp_known_eq(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @scmp_known_eq(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X]], [[Y]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]])
+; CHECK-NEXT: ret i8 0
+;
+ %1 = icmp eq i32 %x, %y
+ call void @llvm.assume(i1 %1)
+
+ %2 = call i8 @llvm.scmp(i32 %x, i32 %y)
+ ret i8 %2
+}
+
+define i8 @scmp_known_lt(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @scmp_known_lt(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X]], [[Y]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]])
+; CHECK-NEXT: ret i8 -1
+;
+ %1 = icmp slt i32 %x, %y
+ call void @llvm.assume(i1 %1)
+
+ %2 = call i8 @llvm.scmp(i32 %x, i32 %y)
+ ret i8 %2
+}
+
+define i8 @ucmp_known_gt(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_known_gt(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[X]], [[Y]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]])
+; CHECK-NEXT: ret i8 1
+;
+ %1 = icmp ugt i32 %x, %y
+ call void @llvm.assume(i1 %1)
+
+ %2 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+ ret i8 %2
+}
+
+define i8 @ucmp_known_eq(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_known_eq(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X]], [[Y]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]])
+; CHECK-NEXT: ret i8 0
+;
+ %1 = icmp eq i32 %x, %y
+ call void @llvm.assume(i1 %1)
+
+ %2 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+ ret i8 %2
+}
+
+define i8 @ucmp_known_lt(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_known_lt(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[X]], [[Y]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]])
+; CHECK-NEXT: ret i8 -1
+;
+ %1 = icmp ult i32 %x, %y
+ call void @llvm.assume(i1 %1)
+
+ %2 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+ ret i8 %2
+}
+
+define i8 @ucmp_with_addition(i32 %x) {
+; CHECK-LABEL: define i8 @ucmp_with_addition(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: ret i8 -1
+;
+ %1 = add nuw i32 %x, 1
+ %2 = call i8 @llvm.ucmp(i32 %x, i32 %1)
+ ret i8 %2
+}
+
+define i8 @ucmp_with_addition2(i32 %x) {
+; CHECK-LABEL: define i8 @ucmp_with_addition2(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: ret i8 1
+;
+ %1 = add nuw i32 %x, 1
+ %2 = call i8 @llvm.ucmp(i32 %1, i32 %x)
+ ret i8 %2
+}
+
+define <4 x i8> @ucmp_with_addition_vec(<4 x i32> %x) {
+; CHECK-LABEL: define <4 x i8> @ucmp_with_addition_vec(
+; CHECK-SAME: <4 x i32> [[X:%.*]]) {
+; CHECK-NEXT: ret <4 x i8> <i8 -1, i8 -1, i8 -1, i8 -1>
+;
+ %1 = add nuw <4 x i32> %x, splat(i32 1)
+ %2 = call <4 x i8> @llvm.ucmp(<4 x i32> %x, <4 x i32> %1)
+ ret <4 x i8> %2
+}
+
+; Negative case: mismatched signedness of predicates
+define i8 @scmp_known_ugt(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @scmp_known_ugt(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[X]], [[Y]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]])
+; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT: ret i8 [[TMP2]]
+;
+ %1 = icmp ugt i32 %x, %y
+ call void @llvm.assume(i1 %1)
+
+ %2 = call i8 @llvm.scmp(i32 %x, i32 %y)
+ ret i8 %2
+}
+
+define i8 @scmp_known_ult(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @scmp_known_ult(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[X]], [[Y]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]])
+; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT: ret i8 [[TMP2]]
+;
+ %1 = icmp ult i32 %x, %y
+ call void @llvm.assume(i1 %1)
+
+ %2 = call i8 @llvm.scmp(i32 %x, i32 %y)
+ ret i8 %2
+}
+
+define i8 @ucmp_known_sgt(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_known_sgt(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[X]], [[Y]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]])
+; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT: ret i8 [[TMP2]]
+;
+ %1 = icmp sgt i32 %x, %y
+ call void @llvm.assume(i1 %1)
+
+ %2 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+ ret i8 %2
+}
+
+define i8 @ucmp_known_slt(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_known_slt(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X]], [[Y]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]])
+; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT: ret i8 [[TMP2]]
+;
+ %1 = icmp slt i32 %x, %y
+ call void @llvm.assume(i1 %1)
+
+ %2 = call i8 @llvm.ucmp(i32 %x, i32 %y)
+ ret i8 %2
+}
+
+; Negative case: no nuw flag
+define i8 @ucmp_with_addition_no_nuw(i32 %x) {
+; CHECK-LABEL: define i8 @ucmp_with_addition_no_nuw(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X]], 1
+; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[TMP1]])
+; CHECK-NEXT: ret i8 [[TMP2]]
+;
+ %1 = add i32 %x, 1
+ %2 = call i8 @llvm.ucmp(i32 %x, i32 %1)
+ ret i8 %2
+}
More information about the llvm-commits
mailing list