[llvm] [ConstraintElim] Fold sadd.with.overflow with a constant op. (PR #223239)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 13 07:45:59 PDT 2026


https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/223239

>From fc2ce067df6534634e5facfd63d3cdfc259c86e9 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Wed, 9 Sep 2026 12:32:04 +0100
Subject: [PATCH 1/2] [ConstraintElim] Add tests for folding sadd.with.overflow
 (NFC).

Pre-commit tests for folding sadd.with.overflow with a constant addend via the
constraint solver: the SMIN/SMAX boundary constants, off-by-one bounds that must
not fold, a bound only known in the unsigned system, a variable addend and an
escaping aggregate.
---
 .../sadd-with-overflow.ll                     | 226 ++++++++++++++++++
 1 file changed, 226 insertions(+)

diff --git a/llvm/test/Transforms/ConstraintElimination/sadd-with-overflow.ll b/llvm/test/Transforms/ConstraintElimination/sadd-with-overflow.ll
index 7dbbf29b5a9d3c..3f559e0cda8259 100644
--- a/llvm/test/Transforms/ConstraintElimination/sadd-with-overflow.ll
+++ b/llvm/test/Transforms/ConstraintElimination/sadd-with-overflow.ll
@@ -2,6 +2,7 @@
 ; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
 
 declare void @use(i1)
+declare void @use.agg({ i8, i1 })
 
 ; A is in [0, 100), so A + 1 does not signed-overflow (A s<= SMAX - 1).
 define i8 @sadd_no_overflow_pos_const(i8 %a) {
@@ -103,3 +104,228 @@ then:
 else:
   ret i8 0
 }
+
+; C == SMIN, so A + C does not signed-overflow iff A s>= 0.
+define i8 @sadd_c_smin(i8 %a) {
+; CHECK-LABEL: define i8 @sadd_c_smin(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[LO:%.*]] = icmp sge i8 [[A]], 0
+; CHECK-NEXT:    br i1 [[LO]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK:       [[THEN]]:
+; CHECK-NEXT:    [[S:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 -128)
+; CHECK-NEXT:    [[V:%.*]] = extractvalue { i8, i1 } [[S]], 0
+; CHECK-NEXT:    [[O:%.*]] = extractvalue { i8, i1 } [[S]], 1
+; CHECK-NEXT:    call void @use(i1 [[O]])
+; CHECK-NEXT:    ret i8 [[V]]
+; CHECK:       [[ELSE]]:
+; CHECK-NEXT:    ret i8 0
+;
+entry:
+  %lo = icmp sge i8 %a, 0
+  br i1 %lo, label %then, label %else
+
+then:
+  %s = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %a, i8 -128)
+  %v = extractvalue { i8, i1 } %s, 0
+  %o = extractvalue { i8, i1 } %s, 1
+  call void @use(i1 %o)
+  ret i8 %v
+
+else:
+  ret i8 0
+}
+
+; C == SMAX, so A + C does not signed-overflow iff A s<= 0.
+define i8 @sadd_c_smax(i8 %a) {
+; CHECK-LABEL: define i8 @sadd_c_smax(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[HI:%.*]] = icmp sle i8 [[A]], 0
+; CHECK-NEXT:    br i1 [[HI]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK:       [[THEN]]:
+; CHECK-NEXT:    [[S:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 127)
+; CHECK-NEXT:    [[V:%.*]] = extractvalue { i8, i1 } [[S]], 0
+; CHECK-NEXT:    [[O:%.*]] = extractvalue { i8, i1 } [[S]], 1
+; CHECK-NEXT:    call void @use(i1 [[O]])
+; CHECK-NEXT:    ret i8 [[V]]
+; CHECK:       [[ELSE]]:
+; CHECK-NEXT:    ret i8 0
+;
+entry:
+  %hi = icmp sle i8 %a, 0
+  br i1 %hi, label %then, label %else
+
+then:
+  %s = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %a, i8 127)
+  %v = extractvalue { i8, i1 } %s, 0
+  %o = extractvalue { i8, i1 } %s, 1
+  call void @use(i1 %o)
+  ret i8 %v
+
+else:
+  ret i8 0
+}
+
+; The upper bound is one too large.
+define i8 @sadd_pos_const_bound_too_large(i8 %a) {
+; CHECK-LABEL: define i8 @sadd_pos_const_bound_too_large(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[HI:%.*]] = icmp sle i8 [[A]], 127
+; CHECK-NEXT:    br i1 [[HI]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK:       [[THEN]]:
+; CHECK-NEXT:    [[S:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 1)
+; CHECK-NEXT:    [[V:%.*]] = extractvalue { i8, i1 } [[S]], 0
+; CHECK-NEXT:    [[O:%.*]] = extractvalue { i8, i1 } [[S]], 1
+; CHECK-NEXT:    call void @use(i1 [[O]])
+; CHECK-NEXT:    ret i8 [[V]]
+; CHECK:       [[ELSE]]:
+; CHECK-NEXT:    ret i8 0
+;
+entry:
+  %hi = icmp sle i8 %a, 127
+  br i1 %hi, label %then, label %else
+
+then:
+  %s = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %a, i8 1)
+  %v = extractvalue { i8, i1 } %s, 0
+  %o = extractvalue { i8, i1 } %s, 1
+  call void @use(i1 %o)
+  ret i8 %v
+
+else:
+  ret i8 0
+}
+
+; The lower bound is one too small.
+define i8 @sadd_neg_const_bound_too_small(i8 %a) {
+; CHECK-LABEL: define i8 @sadd_neg_const_bound_too_small(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[LO:%.*]] = icmp sge i8 [[A]], -128
+; CHECK-NEXT:    br i1 [[LO]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK:       [[THEN]]:
+; CHECK-NEXT:    [[S:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 -1)
+; CHECK-NEXT:    [[V:%.*]] = extractvalue { i8, i1 } [[S]], 0
+; CHECK-NEXT:    [[O:%.*]] = extractvalue { i8, i1 } [[S]], 1
+; CHECK-NEXT:    call void @use(i1 [[O]])
+; CHECK-NEXT:    ret i8 [[V]]
+; CHECK:       [[ELSE]]:
+; CHECK-NEXT:    ret i8 0
+;
+entry:
+  %lo = icmp sge i8 %a, -128
+  br i1 %lo, label %then, label %else
+
+then:
+  %s = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %a, i8 -1)
+  %v = extractvalue { i8, i1 } %s, 0
+  %o = extractvalue { i8, i1 } %s, 1
+  call void @use(i1 %o)
+  ret i8 %v
+
+else:
+  ret i8 0
+}
+
+define i8 @sadd_unsigned_bound(i8 %a) {
+; CHECK-LABEL: define i8 @sadd_unsigned_bound(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[HI:%.*]] = icmp ult i8 [[A]], 100
+; CHECK-NEXT:    br i1 [[HI]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK:       [[THEN]]:
+; CHECK-NEXT:    [[S:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 1)
+; CHECK-NEXT:    [[V:%.*]] = extractvalue { i8, i1 } [[S]], 0
+; CHECK-NEXT:    [[O:%.*]] = extractvalue { i8, i1 } [[S]], 1
+; CHECK-NEXT:    call void @use(i1 [[O]])
+; CHECK-NEXT:    ret i8 [[V]]
+; CHECK:       [[ELSE]]:
+; CHECK-NEXT:    ret i8 0
+;
+entry:
+  %hi = icmp ult i8 %a, 100
+  br i1 %hi, label %then, label %else
+
+then:
+  %s = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %a, i8 1)
+  %v = extractvalue { i8, i1 } %s, 0
+  %o = extractvalue { i8, i1 } %s, 1
+  call void @use(i1 %o)
+  ret i8 %v
+
+else:
+  ret i8 0
+}
+
+; The second operand is not a constant.
+define i8 @sadd_variable_ops(i8 %a, i8 %b) {
+; CHECK-LABEL: define i8 @sadd_variable_ops(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[LO:%.*]] = icmp sge i8 [[A]], 0
+; CHECK-NEXT:    [[HI:%.*]] = icmp slt i8 [[A]], 100
+; CHECK-NEXT:    [[OK:%.*]] = and i1 [[LO]], [[HI]]
+; CHECK-NEXT:    br i1 [[OK]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK:       [[THEN]]:
+; CHECK-NEXT:    [[S:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 [[B]])
+; CHECK-NEXT:    [[V:%.*]] = extractvalue { i8, i1 } [[S]], 0
+; CHECK-NEXT:    [[O:%.*]] = extractvalue { i8, i1 } [[S]], 1
+; CHECK-NEXT:    call void @use(i1 [[O]])
+; CHECK-NEXT:    ret i8 [[V]]
+; CHECK:       [[ELSE]]:
+; CHECK-NEXT:    ret i8 0
+;
+entry:
+  %lo = icmp sge i8 %a, 0
+  %hi = icmp slt i8 %a, 100
+  %ok = and i1 %lo, %hi
+  br i1 %ok, label %then, label %else
+
+then:
+  %s = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %a, i8 %b)
+  %v = extractvalue { i8, i1 } %s, 0
+  %o = extractvalue { i8, i1 } %s, 1
+  call void @use(i1 %o)
+  ret i8 %v
+
+else:
+  ret i8 0
+}
+
+define i8 @sadd_aggregate_escapes(i8 %a) {
+; CHECK-LABEL: define i8 @sadd_aggregate_escapes(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[LO:%.*]] = icmp sge i8 [[A]], 0
+; CHECK-NEXT:    [[HI:%.*]] = icmp slt i8 [[A]], 100
+; CHECK-NEXT:    [[OK:%.*]] = and i1 [[LO]], [[HI]]
+; CHECK-NEXT:    br i1 [[OK]], label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK:       [[THEN]]:
+; CHECK-NEXT:    [[S:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 1)
+; CHECK-NEXT:    [[V:%.*]] = extractvalue { i8, i1 } [[S]], 0
+; CHECK-NEXT:    [[O:%.*]] = extractvalue { i8, i1 } [[S]], 1
+; CHECK-NEXT:    call void @use.agg({ i8, i1 } [[S]])
+; CHECK-NEXT:    call void @use(i1 [[O]])
+; CHECK-NEXT:    ret i8 [[V]]
+; CHECK:       [[ELSE]]:
+; CHECK-NEXT:    ret i8 0
+;
+entry:
+  %lo = icmp sge i8 %a, 0
+  %hi = icmp slt i8 %a, 100
+  %ok = and i1 %lo, %hi
+  br i1 %ok, label %then, label %else
+
+then:
+  %s = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %a, i8 1)
+  %v = extractvalue { i8, i1 } %s, 0
+  %o = extractvalue { i8, i1 } %s, 1
+  call void @use.agg({ i8, i1 } %s)
+  call void @use(i1 %o)
+  ret i8 %v
+
+else:
+  ret i8 0
+}

>From 61f79c941dca11d7229156c4bdab1e8563d27dbc Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Wed, 9 Sep 2026 12:37:29 +0100
Subject: [PATCH 2/2] [ConstraintElim] Fold sadd.with.overflow with a constant
 op.

Generalize the overflow-math simplification to also allow simplifying
sadd.with.overflow if the second operand is constant, using
makeGuaranteedNoWrapRegion.

Note that this partially overlaps with the flag strengthening logic.
I'll share a patch soon to try to unify the code more.

No improvements in llvm-opt-benchmarks-nightly. It improves end-to-end
optimizations for Swift (which emits a lot of checked arithmetic) and
also Clang + UBsan.

An end-to-end improvement with overflow intrinsics is
https://llvm.godbolt.org/z/6nrj7aodd.
---
 .../Scalar/ConstraintElimination.cpp          | 43 ++++++++++++++-----
 .../sadd-with-overflow.ll                     | 35 ++++++---------
 2 files changed, 44 insertions(+), 34 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index ed95686e9e5d9c..da2d61e1c6e27b 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1544,7 +1544,8 @@ void State::addInfoFor(BasicBlock &BB) {
       }
       break;
     }
-    // Enqueue ssub_with_overflow for simplification.
+    // Enqueue intrinsics for simplification.
+    case Intrinsic::sadd_with_overflow:
     case Intrinsic::ssub_with_overflow:
     case Intrinsic::ucmp:
     case Intrinsic::scmp:
@@ -2217,16 +2218,21 @@ void ConstraintInfo::addFactImpl(CmpInst::Predicate Pred, Value *A, Value *B,
   }
 }
 
-static bool replaceSubOverflowUses(IntrinsicInst *II, Value *A, Value *B,
-                                   SmallVectorImpl<Instruction *> &ToRemove) {
+/// Replace the uses of the overflow intrinsic \p II, which has been proven not
+/// to signed-overflow, by (Opcode A, B).
+static bool replaceOverflowUses(IntrinsicInst *II,
+                                Instruction::BinaryOps Opcode, Value *A,
+                                Value *B,
+                                SmallVectorImpl<Instruction *> &ToRemove) {
   bool Changed = false;
   IRBuilder<> Builder(II->getParent(), II->getIterator());
-  Value *Sub = nullptr;
+  Value *Res = nullptr;
   for (User *U : make_early_inc_range(II->users())) {
     if (match(U, m_ExtractValue<0>(m_Value()))) {
-      if (!Sub)
-        Sub = Builder.CreateNSWSub(A, B);
-      U->replaceAllUsesWith(Sub);
+      if (!Res)
+        Res = Builder.CreateNoWrapBinOp(Opcode, A, B, /*IsNUW=*/false,
+                                        /*IsNSW=*/true);
+      U->replaceAllUsesWith(Res);
       Changed = true;
     } else if (match(U, m_ExtractValue<1>(m_Value()))) {
       U->replaceAllUsesWith(Builder.getFalse());
@@ -2267,8 +2273,8 @@ tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
     return CSToUse.isConditionImpliedInSubSystem(R.Coefficients);
   };
 
-  bool Changed = false;
-  if (II->getIntrinsicID() == Intrinsic::ssub_with_overflow) {
+  switch (II->getIntrinsicID()) {
+  case Intrinsic::ssub_with_overflow: {
     // If A s>= B && B s>= 0, ssub.with.overflow(a, b) should not overflow and
     // can be simplified to a regular sub.
     Value *A = II->getArgOperand(0);
@@ -2277,9 +2283,24 @@ tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
         !DoesConditionHold(CmpInst::ICMP_SGE, B,
                            ConstantInt::get(A->getType(), 0), Info))
       return false;
-    Changed = replaceSubOverflowUses(II, A, B, ToRemove);
+    return replaceOverflowUses(II, Instruction::Sub, A, B, ToRemove);
+  }
+  case Intrinsic::sadd_with_overflow: {
+    Value *A = II->getArgOperand(0);
+    Value *B = II->getArgOperand(1);
+    auto *C = dyn_cast<ConstantInt>(B);
+    if (!C ||
+        !doesHoldInRange(Info, A,
+                         ConstantRange::makeGuaranteedNoWrapRegion(
+                             Instruction::Add, ConstantRange(C->getValue()),
+                             OverflowingBinaryOperator::NoSignedWrap),
+                         /*Signed=*/true))
+      return false;
+    return replaceOverflowUses(II, Instruction::Add, A, B, ToRemove);
+  }
+  default:
+    return false;
   }
-  return Changed;
 }
 
 static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
diff --git a/llvm/test/Transforms/ConstraintElimination/sadd-with-overflow.ll b/llvm/test/Transforms/ConstraintElimination/sadd-with-overflow.ll
index 3f559e0cda8259..4194797fa5ea05 100644
--- a/llvm/test/Transforms/ConstraintElimination/sadd-with-overflow.ll
+++ b/llvm/test/Transforms/ConstraintElimination/sadd-with-overflow.ll
@@ -14,10 +14,8 @@ define i8 @sadd_no_overflow_pos_const(i8 %a) {
 ; CHECK-NEXT:    [[OK:%.*]] = and i1 [[LO]], [[HI]]
 ; CHECK-NEXT:    br i1 [[OK]], label %[[THEN:.*]], label %[[ELSE:.*]]
 ; CHECK:       [[THEN]]:
-; CHECK-NEXT:    [[S:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 1)
-; CHECK-NEXT:    [[V:%.*]] = extractvalue { i8, i1 } [[S]], 0
-; CHECK-NEXT:    [[O:%.*]] = extractvalue { i8, i1 } [[S]], 1
-; CHECK-NEXT:    call void @use(i1 [[O]])
+; CHECK-NEXT:    [[V:%.*]] = add nsw i8 [[A]], 1
+; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    ret i8 [[V]]
 ; CHECK:       [[ELSE]]:
 ; CHECK-NEXT:    ret i8 0
@@ -49,10 +47,8 @@ define i8 @sadd_no_overflow_neg_const(i8 %a) {
 ; CHECK-NEXT:    [[OK:%.*]] = and i1 [[LO]], [[HI]]
 ; CHECK-NEXT:    br i1 [[OK]], label %[[THEN:.*]], label %[[ELSE:.*]]
 ; CHECK:       [[THEN]]:
-; CHECK-NEXT:    [[S:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 -1)
-; CHECK-NEXT:    [[V:%.*]] = extractvalue { i8, i1 } [[S]], 0
-; CHECK-NEXT:    [[O:%.*]] = extractvalue { i8, i1 } [[S]], 1
-; CHECK-NEXT:    call void @use(i1 [[O]])
+; CHECK-NEXT:    [[V:%.*]] = add nsw i8 [[A]], -1
+; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    ret i8 [[V]]
 ; CHECK:       [[ELSE]]:
 ; CHECK-NEXT:    ret i8 0
@@ -113,10 +109,8 @@ define i8 @sadd_c_smin(i8 %a) {
 ; CHECK-NEXT:    [[LO:%.*]] = icmp sge i8 [[A]], 0
 ; CHECK-NEXT:    br i1 [[LO]], label %[[THEN:.*]], label %[[ELSE:.*]]
 ; CHECK:       [[THEN]]:
-; CHECK-NEXT:    [[S:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 -128)
-; CHECK-NEXT:    [[V:%.*]] = extractvalue { i8, i1 } [[S]], 0
-; CHECK-NEXT:    [[O:%.*]] = extractvalue { i8, i1 } [[S]], 1
-; CHECK-NEXT:    call void @use(i1 [[O]])
+; CHECK-NEXT:    [[V:%.*]] = add nsw i8 [[A]], -128
+; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    ret i8 [[V]]
 ; CHECK:       [[ELSE]]:
 ; CHECK-NEXT:    ret i8 0
@@ -144,10 +138,8 @@ define i8 @sadd_c_smax(i8 %a) {
 ; CHECK-NEXT:    [[HI:%.*]] = icmp sle i8 [[A]], 0
 ; CHECK-NEXT:    br i1 [[HI]], label %[[THEN:.*]], label %[[ELSE:.*]]
 ; CHECK:       [[THEN]]:
-; CHECK-NEXT:    [[S:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 127)
-; CHECK-NEXT:    [[V:%.*]] = extractvalue { i8, i1 } [[S]], 0
-; CHECK-NEXT:    [[O:%.*]] = extractvalue { i8, i1 } [[S]], 1
-; CHECK-NEXT:    call void @use(i1 [[O]])
+; CHECK-NEXT:    [[V:%.*]] = add nsw i8 [[A]], 127
+; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    ret i8 [[V]]
 ; CHECK:       [[ELSE]]:
 ; CHECK-NEXT:    ret i8 0
@@ -236,10 +228,8 @@ define i8 @sadd_unsigned_bound(i8 %a) {
 ; CHECK-NEXT:    [[HI:%.*]] = icmp ult i8 [[A]], 100
 ; CHECK-NEXT:    br i1 [[HI]], label %[[THEN:.*]], label %[[ELSE:.*]]
 ; CHECK:       [[THEN]]:
-; CHECK-NEXT:    [[S:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 1)
-; CHECK-NEXT:    [[V:%.*]] = extractvalue { i8, i1 } [[S]], 0
-; CHECK-NEXT:    [[O:%.*]] = extractvalue { i8, i1 } [[S]], 1
-; CHECK-NEXT:    call void @use(i1 [[O]])
+; CHECK-NEXT:    [[V:%.*]] = add nsw i8 [[A]], 1
+; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    ret i8 [[V]]
 ; CHECK:       [[ELSE]]:
 ; CHECK-NEXT:    ret i8 0
@@ -303,11 +293,10 @@ define i8 @sadd_aggregate_escapes(i8 %a) {
 ; CHECK-NEXT:    [[OK:%.*]] = and i1 [[LO]], [[HI]]
 ; CHECK-NEXT:    br i1 [[OK]], label %[[THEN:.*]], label %[[ELSE:.*]]
 ; CHECK:       [[THEN]]:
+; CHECK-NEXT:    [[V:%.*]] = add nsw i8 [[A]], 1
 ; CHECK-NEXT:    [[S:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 1)
-; CHECK-NEXT:    [[V:%.*]] = extractvalue { i8, i1 } [[S]], 0
-; CHECK-NEXT:    [[O:%.*]] = extractvalue { i8, i1 } [[S]], 1
 ; CHECK-NEXT:    call void @use.agg({ i8, i1 } [[S]])
-; CHECK-NEXT:    call void @use(i1 [[O]])
+; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    ret i8 [[V]]
 ; CHECK:       [[ELSE]]:
 ; CHECK-NEXT:    ret i8 0



More information about the llvm-commits mailing list