[llvm] [InstCombine] Fold sadd.with.overflow check idiom (PR #216581)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 16 10:23:55 PDT 2026
https://github.com/AZero13 created https://github.com/llvm/llvm-project/pull/216581
Alive2: https://alive2.llvm.org/ce/z/7JGCm4
>From 7509da6d2b6a31272ff7db9cce6580c52c3b2ac9 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sun, 16 Aug 2026 13:20:06 -0400
Subject: [PATCH 1/2] [InstCombine] Precommit tests for sadd.with.overflow
idiom
---
.../InstCombine/sadd-with-overflow-pattern.ll | 213 ++++++++++++++++++
1 file changed, 213 insertions(+)
create mode 100644 llvm/test/Transforms/InstCombine/sadd-with-overflow-pattern.ll
diff --git a/llvm/test/Transforms/InstCombine/sadd-with-overflow-pattern.ll b/llvm/test/Transforms/InstCombine/sadd-with-overflow-pattern.ll
new file mode 100644
index 0000000000000..a4a039c17c4cf
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/sadd-with-overflow-pattern.ll
@@ -0,0 +1,213 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i1 @sadd_overflow_i8(i8 %a, i8 %b) {
+; CHECK-LABEL: @sadd_overflow_i8(
+; CHECK-NEXT: [[SUM:%.*]] = add i8 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT: [[XOR0:%.*]] = xor i8 [[B]], [[A]]
+; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt i8 [[XOR0]], -1
+; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[SUM]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 [[XOR1]], 0
+; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP0]], [[CMP1]]
+; CHECK-NEXT: ret i1 [[AND]]
+;
+ %sum = add i8 %b, %a
+ %xor0 = xor i8 %b, %a
+ %cmp0 = icmp sgt i8 %xor0, -1
+ %xor1 = xor i8 %sum, %a
+ %cmp1 = icmp slt i8 %xor1, 0
+ %and = and i1 %cmp0, %cmp1
+ ret i1 %and
+}
+
+define i1 @sadd_overflow_i16(i16 %a, i16 %b) {
+; CHECK-LABEL: @sadd_overflow_i16(
+; CHECK-NEXT: [[SUM:%.*]] = add i16 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT: [[XOR0:%.*]] = xor i16 [[B]], [[A]]
+; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt i16 [[XOR0]], -1
+; CHECK-NEXT: [[XOR1:%.*]] = xor i16 [[SUM]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i16 [[XOR1]], 0
+; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP0]], [[CMP1]]
+; CHECK-NEXT: ret i1 [[AND]]
+;
+ %sum = add i16 %b, %a
+ %xor0 = xor i16 %b, %a
+ %cmp0 = icmp sgt i16 %xor0, -1
+ %xor1 = xor i16 %sum, %a
+ %cmp1 = icmp slt i16 %xor1, 0
+ %and = and i1 %cmp0, %cmp1
+ ret i1 %and
+}
+
+define i1 @sadd_overflow_i32(i32 %a, i32 %b) {
+; CHECK-LABEL: @sadd_overflow_i32(
+; CHECK-NEXT: [[SUM:%.*]] = add i32 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT: [[XOR0:%.*]] = xor i32 [[B]], [[A]]
+; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt i32 [[XOR0]], -1
+; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[SUM]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[XOR1]], 0
+; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP0]], [[CMP1]]
+; CHECK-NEXT: ret i1 [[AND]]
+;
+ %sum = add i32 %b, %a
+ %xor0 = xor i32 %b, %a
+ %cmp0 = icmp sgt i32 %xor0, -1
+ %xor1 = xor i32 %sum, %a
+ %cmp1 = icmp slt i32 %xor1, 0
+ %and = and i1 %cmp0, %cmp1
+ ret i1 %and
+}
+
+define i1 @sadd_overflow_i64(i64 %a, i64 %b) {
+; CHECK-LABEL: @sadd_overflow_i64(
+; CHECK-NEXT: [[SUM:%.*]] = add i64 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT: [[XOR0:%.*]] = xor i64 [[B]], [[A]]
+; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt i64 [[XOR0]], -1
+; CHECK-NEXT: [[XOR1:%.*]] = xor i64 [[SUM]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i64 [[XOR1]], 0
+; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP0]], [[CMP1]]
+; CHECK-NEXT: ret i1 [[AND]]
+;
+ %sum = add i64 %b, %a
+ %xor0 = xor i64 %b, %a
+ %cmp0 = icmp sgt i64 %xor0, -1
+ %xor1 = xor i64 %sum, %a
+ %cmp1 = icmp slt i64 %xor1, 0
+ %and = and i1 %cmp0, %cmp1
+ ret i1 %and
+}
+
+define i1 @sadd_overflow_commute1(i8 %a, i8 %b) {
+; CHECK-LABEL: @sadd_overflow_commute1(
+; CHECK-NEXT: [[SUM:%.*]] = add i8 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[XOR0:%.*]] = xor i8 [[A]], [[B]]
+; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt i8 [[XOR0]], -1
+; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[SUM]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 [[XOR1]], 0
+; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP0]]
+; CHECK-NEXT: ret i1 [[AND]]
+;
+ %sum = add i8 %a, %b
+ %xor0 = xor i8 %a, %b
+ %cmp0 = icmp sgt i8 %xor0, -1
+ %xor1 = xor i8 %sum, %a
+ %cmp1 = icmp slt i8 %xor1, 0
+ %and = and i1 %cmp1, %cmp0
+ ret i1 %and
+}
+
+define i1 @sadd_overflow_commute2(i8 %a, i8 %b) {
+; CHECK-LABEL: @sadd_overflow_commute2(
+; CHECK-NEXT: [[SUM:%.*]] = add i8 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[XOR0:%.*]] = xor i8 [[B]], [[A]]
+; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt i8 [[XOR0]], -1
+; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[A]], [[SUM]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 [[XOR1]], 0
+; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP0]], [[CMP1]]
+; CHECK-NEXT: ret i1 [[AND]]
+;
+ %sum = add i8 %a, %b
+ %xor0 = xor i8 %b, %a
+ %cmp0 = icmp sgt i8 %xor0, -1
+ %xor1 = xor i8 %a, %sum
+ %cmp1 = icmp slt i8 %xor1, 0
+ %and = and i1 %cmp0, %cmp1
+ ret i1 %and
+}
+
+define i1 @sadd_overflow_wrong_xor(i8 %a, i8 %b, i8 %c) {
+; CHECK-LABEL: @sadd_overflow_wrong_xor(
+; CHECK-NEXT: [[SUM:%.*]] = add i8 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT: [[XOR0:%.*]] = xor i8 [[B]], [[A]]
+; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt i8 [[XOR0]], -1
+; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[SUM]], [[C:%.*]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 [[XOR1]], 0
+; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP0]], [[CMP1]]
+; CHECK-NEXT: ret i1 [[AND]]
+;
+ %sum = add i8 %b, %a
+ %xor0 = xor i8 %b, %a
+ %cmp0 = icmp sgt i8 %xor0, -1
+ %xor1 = xor i8 %sum, %c
+ %cmp1 = icmp slt i8 %xor1, 0
+ %and = and i1 %cmp0, %cmp1
+ ret i1 %and
+}
+
+define i1 @sadd_overflow_wrong_pred1(i8 %a, i8 %b) {
+; CHECK-LABEL: @sadd_overflow_wrong_pred1(
+; CHECK-NEXT: [[SUM:%.*]] = add i8 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT: [[XOR0:%.*]] = xor i8 [[B]], [[A]]
+; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt i8 [[XOR0]], -2
+; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[SUM]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 [[XOR1]], 0
+; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP0]], [[CMP1]]
+; CHECK-NEXT: ret i1 [[AND]]
+;
+ %sum = add i8 %b, %a
+ %xor0 = xor i8 %b, %a
+ %cmp0 = icmp sge i8 %xor0, -1
+ %xor1 = xor i8 %sum, %a
+ %cmp1 = icmp slt i8 %xor1, 0
+ %and = and i1 %cmp0, %cmp1
+ ret i1 %and
+}
+
+define i1 @sadd_overflow_wrong_pred2(i8 %a, i8 %b) {
+; CHECK-LABEL: @sadd_overflow_wrong_pred2(
+; CHECK-NEXT: [[SUM:%.*]] = add i8 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT: [[XOR0:%.*]] = xor i8 [[B]], [[A]]
+; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt i8 [[XOR0]], -1
+; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[SUM]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 [[XOR1]], 1
+; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP0]], [[CMP1]]
+; CHECK-NEXT: ret i1 [[AND]]
+;
+ %sum = add i8 %b, %a
+ %xor0 = xor i8 %b, %a
+ %cmp0 = icmp sgt i8 %xor0, -1
+ %xor1 = xor i8 %sum, %a
+ %cmp1 = icmp sle i8 %xor1, 0
+ %and = and i1 %cmp0, %cmp1
+ ret i1 %and
+}
+
+define <4 x i1> @sadd_overflow_vec(<4 x i32> %a, <4 x i32> %b) {
+; CHECK-LABEL: @sadd_overflow_vec(
+; CHECK-NEXT: [[SUM:%.*]] = add <4 x i32> [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT: [[XOR0:%.*]] = xor <4 x i32> [[B]], [[A]]
+; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt <4 x i32> [[XOR0]], splat (i32 -1)
+; CHECK-NEXT: [[XOR1:%.*]] = xor <4 x i32> [[SUM]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt <4 x i32> [[XOR1]], zeroinitializer
+; CHECK-NEXT: [[AND:%.*]] = and <4 x i1> [[CMP0]], [[CMP1]]
+; CHECK-NEXT: ret <4 x i1> [[AND]]
+;
+ %sum = add <4 x i32> %b, %a
+ %xor0 = xor <4 x i32> %b, %a
+ %cmp0 = icmp sgt <4 x i32> %xor0, <i32 -1, i32 -1, i32 -1, i32 -1>
+ %xor1 = xor <4 x i32> %sum, %a
+ %cmp1 = icmp slt <4 x i32> %xor1, zeroinitializer
+ %and = and <4 x i1> %cmp0, %cmp1
+ ret <4 x i1> %and
+}
+
+define i1 @sadd_overflow_multi_use(i8 %a, i8 %b, ptr %p) {
+; CHECK-LABEL: @sadd_overflow_multi_use(
+; CHECK-NEXT: [[SUM:%.*]] = add i8 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT: [[XOR0:%.*]] = xor i8 [[B]], [[A]]
+; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt i8 [[XOR0]], -1
+; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[SUM]], [[A]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 [[XOR1]], 0
+; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP0]], [[CMP1]]
+; CHECK-NEXT: store i8 [[SUM]], ptr [[P:%.*]], align 1
+; CHECK-NEXT: ret i1 [[AND]]
+;
+ %sum = add i8 %b, %a
+ %xor0 = xor i8 %b, %a
+ %cmp0 = icmp sgt i8 %xor0, -1
+ %xor1 = xor i8 %sum, %a
+ %cmp1 = icmp slt i8 %xor1, 0
+ %and = and i1 %cmp0, %cmp1
+ store i8 %sum, ptr %p
+ ret i1 %and
+}
>From 649930955ae37513c42d84ee263907e4614320e5 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sun, 16 Aug 2026 13:21:52 -0400
Subject: [PATCH 2/2] [InstCombine] Fold sadd.with.overflow check idiom
Alive2: https://alive2.llvm.org/ce/z/7JGCm4
---
.../InstCombine/InstCombineAndOrXor.cpp | 51 +++++++++++++++++
.../InstCombine/sadd-with-overflow-pattern.ll | 55 +++++--------------
2 files changed, 65 insertions(+), 41 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index b6f4a55c07e8a..bb628f672b6a0 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3372,12 +3372,63 @@ static Value *foldAndOrOfICmpEqConstantAndICmp(ICmpInst *LHS, ICmpInst *RHS,
Other);
}
+static Value *foldSignedAddOverflowCheck(ICmpInst *Cmp0, ICmpInst *Cmp1,
+ bool IsAnd,
+ InstCombiner::BuilderTy &Builder) {
+ if (!IsAnd)
+ return nullptr;
+
+ auto IsSignBitCheck = [](ICmpInst *Cmp, bool Expected) {
+ const APInt *C;
+ if (!match(Cmp->getOperand(1), m_APInt(C)))
+ return false;
+ bool TrueIfSigned;
+ if (!isSignBitCheck(Cmp->getPredicate(), *C, TrueIfSigned))
+ return false;
+ return TrueIfSigned == Expected;
+ };
+
+ ICmpInst *SignEqCmp = nullptr;
+ ICmpInst *SignDiffCmp = nullptr;
+ if (IsSignBitCheck(Cmp0, false) && IsSignBitCheck(Cmp1, true)) {
+ SignEqCmp = Cmp0;
+ SignDiffCmp = Cmp1;
+ } else if (IsSignBitCheck(Cmp0, true) && IsSignBitCheck(Cmp1, false)) {
+ SignEqCmp = Cmp1;
+ SignDiffCmp = Cmp0;
+ } else {
+ return nullptr;
+ }
+
+ Value *A, *B;
+ if (!match(SignEqCmp->getOperand(0), m_c_Xor(m_Value(A), m_Value(B))))
+ return nullptr;
+
+ Value *Sum, *AOrB;
+ if (!match(SignDiffCmp->getOperand(0), m_c_Xor(m_Value(Sum), m_Value(AOrB))))
+ return nullptr;
+
+ if (AOrB != A && AOrB != B)
+ return nullptr;
+
+ if (!match(Sum, m_c_Add(m_Specific(A), m_Specific(B))))
+ return nullptr;
+
+ Function *F = Intrinsic::getOrInsertDeclaration(
+ Cmp0->getModule(), Intrinsic::sadd_with_overflow, A->getType());
+ Value *Call = Builder.CreateCall(F, {A, B});
+ return Builder.CreateExtractValue(Call, 1);
+}
+
/// Fold (icmp)&(icmp) or (icmp)|(icmp) if possible.
/// If IsLogical is true, then the and/or is in select form and the transform
/// must be poison-safe.
Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
Instruction &I, bool IsAnd,
bool IsLogical) {
+ if (Value *V = foldSignedAddOverflowCheck(LHS, RHS, IsAnd, Builder))
+ return V;
+
const SimplifyQuery Q = SQ.getWithInstruction(&I);
ICmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate();
diff --git a/llvm/test/Transforms/InstCombine/sadd-with-overflow-pattern.ll b/llvm/test/Transforms/InstCombine/sadd-with-overflow-pattern.ll
index a4a039c17c4cf..50c849a10bc92 100644
--- a/llvm/test/Transforms/InstCombine/sadd-with-overflow-pattern.ll
+++ b/llvm/test/Transforms/InstCombine/sadd-with-overflow-pattern.ll
@@ -3,12 +3,8 @@
define i1 @sadd_overflow_i8(i8 %a, i8 %b) {
; CHECK-LABEL: @sadd_overflow_i8(
-; CHECK-NEXT: [[SUM:%.*]] = add i8 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[XOR0:%.*]] = xor i8 [[B]], [[A]]
-; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt i8 [[XOR0]], -1
-; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[SUM]], [[A]]
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 [[XOR1]], 0
-; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP0]], [[CMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[B:%.*]], i8 [[A:%.*]])
+; CHECK-NEXT: [[AND:%.*]] = extractvalue { i8, i1 } [[TMP1]], 1
; CHECK-NEXT: ret i1 [[AND]]
;
%sum = add i8 %b, %a
@@ -22,12 +18,8 @@ define i1 @sadd_overflow_i8(i8 %a, i8 %b) {
define i1 @sadd_overflow_i16(i16 %a, i16 %b) {
; CHECK-LABEL: @sadd_overflow_i16(
-; CHECK-NEXT: [[SUM:%.*]] = add i16 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[XOR0:%.*]] = xor i16 [[B]], [[A]]
-; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt i16 [[XOR0]], -1
-; CHECK-NEXT: [[XOR1:%.*]] = xor i16 [[SUM]], [[A]]
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i16 [[XOR1]], 0
-; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP0]], [[CMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = call { i16, i1 } @llvm.sadd.with.overflow.i16(i16 [[B:%.*]], i16 [[A:%.*]])
+; CHECK-NEXT: [[AND:%.*]] = extractvalue { i16, i1 } [[TMP1]], 1
; CHECK-NEXT: ret i1 [[AND]]
;
%sum = add i16 %b, %a
@@ -41,12 +33,8 @@ define i1 @sadd_overflow_i16(i16 %a, i16 %b) {
define i1 @sadd_overflow_i32(i32 %a, i32 %b) {
; CHECK-LABEL: @sadd_overflow_i32(
-; CHECK-NEXT: [[SUM:%.*]] = add i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[XOR0:%.*]] = xor i32 [[B]], [[A]]
-; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt i32 [[XOR0]], -1
-; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[SUM]], [[A]]
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[XOR1]], 0
-; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP0]], [[CMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[B:%.*]], i32 [[A:%.*]])
+; CHECK-NEXT: [[AND:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
; CHECK-NEXT: ret i1 [[AND]]
;
%sum = add i32 %b, %a
@@ -60,12 +48,8 @@ define i1 @sadd_overflow_i32(i32 %a, i32 %b) {
define i1 @sadd_overflow_i64(i64 %a, i64 %b) {
; CHECK-LABEL: @sadd_overflow_i64(
-; CHECK-NEXT: [[SUM:%.*]] = add i64 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[XOR0:%.*]] = xor i64 [[B]], [[A]]
-; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt i64 [[XOR0]], -1
-; CHECK-NEXT: [[XOR1:%.*]] = xor i64 [[SUM]], [[A]]
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i64 [[XOR1]], 0
-; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP0]], [[CMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[B:%.*]], i64 [[A:%.*]])
+; CHECK-NEXT: [[AND:%.*]] = extractvalue { i64, i1 } [[TMP1]], 1
; CHECK-NEXT: ret i1 [[AND]]
;
%sum = add i64 %b, %a
@@ -79,12 +63,8 @@ define i1 @sadd_overflow_i64(i64 %a, i64 %b) {
define i1 @sadd_overflow_commute1(i8 %a, i8 %b) {
; CHECK-LABEL: @sadd_overflow_commute1(
-; CHECK-NEXT: [[SUM:%.*]] = add i8 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[XOR0:%.*]] = xor i8 [[A]], [[B]]
-; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt i8 [[XOR0]], -1
-; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[SUM]], [[A]]
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 [[XOR1]], 0
-; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP0]]
+; CHECK-NEXT: [[TMP1:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A:%.*]], i8 [[B:%.*]])
+; CHECK-NEXT: [[AND:%.*]] = extractvalue { i8, i1 } [[TMP1]], 1
; CHECK-NEXT: ret i1 [[AND]]
;
%sum = add i8 %a, %b
@@ -174,12 +154,8 @@ define i1 @sadd_overflow_wrong_pred2(i8 %a, i8 %b) {
define <4 x i1> @sadd_overflow_vec(<4 x i32> %a, <4 x i32> %b) {
; CHECK-LABEL: @sadd_overflow_vec(
-; CHECK-NEXT: [[SUM:%.*]] = add <4 x i32> [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[XOR0:%.*]] = xor <4 x i32> [[B]], [[A]]
-; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt <4 x i32> [[XOR0]], splat (i32 -1)
-; CHECK-NEXT: [[XOR1:%.*]] = xor <4 x i32> [[SUM]], [[A]]
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt <4 x i32> [[XOR1]], zeroinitializer
-; CHECK-NEXT: [[AND:%.*]] = and <4 x i1> [[CMP0]], [[CMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = call { <4 x i32>, <4 x i1> } @llvm.sadd.with.overflow.v4i32(<4 x i32> [[B:%.*]], <4 x i32> [[A:%.*]])
+; CHECK-NEXT: [[AND:%.*]] = extractvalue { <4 x i32>, <4 x i1> } [[TMP1]], 1
; CHECK-NEXT: ret <4 x i1> [[AND]]
;
%sum = add <4 x i32> %b, %a
@@ -194,11 +170,8 @@ define <4 x i1> @sadd_overflow_vec(<4 x i32> %a, <4 x i32> %b) {
define i1 @sadd_overflow_multi_use(i8 %a, i8 %b, ptr %p) {
; CHECK-LABEL: @sadd_overflow_multi_use(
; CHECK-NEXT: [[SUM:%.*]] = add i8 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[XOR0:%.*]] = xor i8 [[B]], [[A]]
-; CHECK-NEXT: [[CMP0:%.*]] = icmp sgt i8 [[XOR0]], -1
-; CHECK-NEXT: [[XOR1:%.*]] = xor i8 [[SUM]], [[A]]
-; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 [[XOR1]], 0
-; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP0]], [[CMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[B]], i8 [[A]])
+; CHECK-NEXT: [[AND:%.*]] = extractvalue { i8, i1 } [[TMP1]], 1
; CHECK-NEXT: store i8 [[SUM]], ptr [[P:%.*]], align 1
; CHECK-NEXT: ret i1 [[AND]]
;
More information about the llvm-commits
mailing list