[llvm] be7d08c - [InstCombine] Fold `sext(A < B) + zext(A > B)` into `ucmp/scmp(A, B)` (#103833)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 21 15:15:28 PDT 2024
Author: Volodymyr Vasylkun
Date: 2024-08-21T23:15:24+01:00
New Revision: be7d08cd59b0f23eea88e791b2413b44301949d3
URL: https://github.com/llvm/llvm-project/commit/be7d08cd59b0f23eea88e791b2413b44301949d3
DIFF: https://github.com/llvm/llvm-project/commit/be7d08cd59b0f23eea88e791b2413b44301949d3.diff
LOG: [InstCombine] Fold `sext(A < B) + zext(A > B)` into `ucmp/scmp(A, B)` (#103833)
This change also covers the fold of `zext(A > B) - zext(A < B)` since it
is already being canonicalized into the aforementioned pattern.
Proof: https://alive2.llvm.org/ce/z/AgnfMn
Added:
llvm/test/Transforms/InstCombine/sext-a-lt-b-plus-zext-a-gt-b-to-uscmp.ll
Modified:
llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
llvm/test/Transforms/InstCombine/add.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index dd4a64050f878a..d7758b5fbf1786 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -1626,6 +1626,26 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
A->getType()->isIntOrIntVectorTy(1))
return replaceInstUsesWith(I, Constant::getNullValue(I.getType()));
+ // sext(A < B) + zext(A > B) => ucmp/scmp(A, B)
+ ICmpInst::Predicate LTPred, GTPred;
+ if (match(&I,
+ m_c_Add(m_SExt(m_c_ICmp(LTPred, m_Value(A), m_Value(B))),
+ m_ZExt(m_c_ICmp(GTPred, m_Deferred(A), m_Deferred(B))))) &&
+ A->getType()->isIntOrIntVectorTy()) {
+ if (ICmpInst::isGT(LTPred)) {
+ std::swap(LTPred, GTPred);
+ std::swap(A, B);
+ }
+
+ if (ICmpInst::isLT(LTPred) && ICmpInst::isGT(GTPred) &&
+ ICmpInst::isSigned(LTPred) == ICmpInst::isSigned(GTPred))
+ return replaceInstUsesWith(
+ I, Builder.CreateIntrinsic(
+ Ty,
+ ICmpInst::isSigned(LTPred) ? Intrinsic::scmp : Intrinsic::ucmp,
+ {A, B}));
+ }
+
// A+B --> A|B iff A and B have no bits set in common.
WithCache<const Value *> LHSCache(LHS), RHSCache(RHS);
if (haveNoCommonBitsSet(LHSCache, RHSCache, SQ.getWithInstruction(&I)))
diff --git a/llvm/test/Transforms/InstCombine/add.ll b/llvm/test/Transforms/InstCombine/add.ll
index 36da56d8441bf7..417c3a950d7805 100644
--- a/llvm/test/Transforms/InstCombine/add.ll
+++ b/llvm/test/Transforms/InstCombine/add.ll
@@ -1315,8 +1315,8 @@ define <2 x i8> @ashr_add_commute(<2 x i1> %x, <2 x i1> %y) {
define i32 @cmp_math(i32 %x, i32 %y) {
; CHECK-LABEL: @cmp_math(
-; CHECK-NEXT: [[LT:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[R:%.*]] = zext i1 [[LT]] to i32
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[R:%.*]] = zext i1 [[TMP1]] to i32
; CHECK-NEXT: ret i32 [[R]]
;
%gt = icmp ugt i32 %x, %y
diff --git a/llvm/test/Transforms/InstCombine/sext-a-lt-b-plus-zext-a-gt-b-to-uscmp.ll b/llvm/test/Transforms/InstCombine/sext-a-lt-b-plus-zext-a-gt-b-to-uscmp.ll
new file mode 100644
index 00000000000000..02ae7ce82f13ce
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/sext-a-lt-b-plus-zext-a-gt-b-to-uscmp.ll
@@ -0,0 +1,184 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+; sext(A s< B) + zext(A s> B) => scmp(A, B)
+define i8 @signed_add(i32 %a, i32 %b) {
+; CHECK-LABEL: define i8 @signed_add(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[A]], i32 [[B]])
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %lt = icmp slt i32 %a, %b
+ %lt8 = sext i1 %lt to i8
+ %gt = icmp sgt i32 %a, %b
+ %gt8 = zext i1 %gt to i8
+ %r = add i8 %lt8, %gt8
+ ret i8 %r
+}
+
+; Unsigned version
+define i8 @unsigned_add(i32 %a, i32 %b) {
+; CHECK-LABEL: define i8 @unsigned_add(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A]], i32 [[B]])
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %lt = icmp ult i32 %a, %b
+ %lt8 = sext i1 %lt to i8
+ %gt = icmp ugt i32 %a, %b
+ %gt8 = zext i1 %gt to i8
+ %r = add i8 %lt8, %gt8
+ ret i8 %r
+}
+
+; Commuted operands
+define i8 @signed_add_commuted1(i32 %a, i32 %b) {
+; CHECK-LABEL: define i8 @signed_add_commuted1(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[B]], i32 [[A]])
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %lt = icmp slt i32 %a, %b
+ %lt8 = zext i1 %lt to i8
+ %gt = icmp sgt i32 %a, %b
+ %gt8 = sext i1 %gt to i8
+ %r = add i8 %lt8, %gt8
+ ret i8 %r
+}
+
+define i8 @signed_add_commuted2(i32 %a, i32 %b) {
+; CHECK-LABEL: define i8 @signed_add_commuted2(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[A]], i32 [[B]])
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %lt = icmp sgt i32 %b, %a
+ %lt8 = sext i1 %lt to i8
+ %gt = icmp sgt i32 %a, %b
+ %gt8 = zext i1 %gt to i8
+ %r = add i8 %lt8, %gt8
+ ret i8 %r
+}
+
+; zext(A s> B) - zext(A s< B) => scmp(A, B)
+define i8 @signed_sub(i32 %a, i32 %b) {
+; CHECK-LABEL: define i8 @signed_sub(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[A]], i32 [[B]])
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %lt = icmp slt i32 %a, %b
+ %lt8 = zext i1 %lt to i8
+ %gt = icmp sgt i32 %a, %b
+ %gt8 = zext i1 %gt to i8
+ %r = sub i8 %gt8, %lt8
+ ret i8 %r
+}
+
+; Unsigned version
+define i8 @unsigned_sub(i32 %a, i32 %b) {
+; CHECK-LABEL: define i8 @unsigned_sub(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A]], i32 [[B]])
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %lt = icmp ult i32 %a, %b
+ %lt8 = zext i1 %lt to i8
+ %gt = icmp ugt i32 %a, %b
+ %gt8 = zext i1 %gt to i8
+ %r = sub i8 %gt8, %lt8
+ ret i8 %r
+}
+
+; Negative test: incorrect predicates
+define i8 @signed_add_neg1(i32 %a, i32 %b) {
+; CHECK-LABEL: define i8 @signed_add_neg1(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[LT:%.*]] = icmp sgt i32 [[A]], [[B]]
+; CHECK-NEXT: [[LT8:%.*]] = sext i1 [[LT]] to i8
+; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[A]], [[B]]
+; CHECK-NEXT: [[GT8:%.*]] = zext i1 [[GT]] to i8
+; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LT8]], [[GT8]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %lt = icmp sgt i32 %a, %b
+ %lt8 = sext i1 %lt to i8
+ %gt = icmp sgt i32 %a, %b
+ %gt8 = zext i1 %gt to i8
+ %r = add i8 %lt8, %gt8
+ ret i8 %r
+}
+
+define i8 @signed_add_neg2(i32 %a, i32 %b) {
+; CHECK-LABEL: define i8 @signed_add_neg2(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[A]], [[B]]
+; CHECK-NEXT: [[LT8:%.*]] = sext i1 [[LT]] to i8
+; CHECK-NEXT: [[GT:%.*]] = icmp ne i32 [[A]], [[B]]
+; CHECK-NEXT: [[GT8:%.*]] = zext i1 [[GT]] to i8
+; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LT8]], [[GT8]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %lt = icmp slt i32 %a, %b
+ %lt8 = sext i1 %lt to i8
+ %gt = icmp ne i32 %a, %b
+ %gt8 = zext i1 %gt to i8
+ %r = add i8 %lt8, %gt8
+ ret i8 %r
+}
+
+; Negative test: mismatched signedness of predicates
+define i8 @signed_add_neg3(i32 %a, i32 %b) {
+; CHECK-LABEL: define i8 @signed_add_neg3(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[A]], [[B]]
+; CHECK-NEXT: [[LT8:%.*]] = sext i1 [[LT]] to i8
+; CHECK-NEXT: [[GT:%.*]] = icmp ugt i32 [[A]], [[B]]
+; CHECK-NEXT: [[GT8:%.*]] = zext i1 [[GT]] to i8
+; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LT8]], [[GT8]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %lt = icmp slt i32 %a, %b
+ %lt8 = sext i1 %lt to i8
+ %gt = icmp ugt i32 %a, %b
+ %gt8 = zext i1 %gt to i8
+ %r = add i8 %lt8, %gt8
+ ret i8 %r
+}
+
+; Negative test: zext instead of sext or vice-versa (NOT commuted operands)
+define i8 @signed_add_neg4(i32 %a, i32 %b) {
+; CHECK-LABEL: define i8 @signed_add_neg4(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[A]], [[B]]
+; CHECK-NEXT: [[LT8:%.*]] = sext i1 [[LT]] to i8
+; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[A]], [[B]]
+; CHECK-NEXT: [[GT8:%.*]] = sext i1 [[GT]] to i8
+; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LT8]], [[GT8]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %lt = icmp slt i32 %a, %b
+ %lt8 = sext i1 %lt to i8
+ %gt = icmp sgt i32 %a, %b
+ %gt8 = sext i1 %gt to i8
+ %r = add i8 %lt8, %gt8
+ ret i8 %r
+}
+
+define i8 @signed_add_neg5(i32 %a, i32 %b) {
+; CHECK-LABEL: define i8 @signed_add_neg5(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[A]], [[B]]
+; CHECK-NEXT: [[LT8:%.*]] = zext i1 [[LT]] to i8
+; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[A]], [[B]]
+; CHECK-NEXT: [[GT8:%.*]] = zext i1 [[GT]] to i8
+; CHECK-NEXT: [[R:%.*]] = add nuw nsw i8 [[LT8]], [[GT8]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %lt = icmp slt i32 %a, %b
+ %lt8 = zext i1 %lt to i8
+ %gt = icmp sgt i32 %a, %b
+ %gt8 = zext i1 %gt to i8
+ %r = add i8 %lt8, %gt8
+ ret i8 %r
+}
More information about the llvm-commits
mailing list