[llvm] fa360c3 - [ConstraintElim] Simplify all overflow intrinsics using isKnownNoWrap. (#224848)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 20 08:49:44 PDT 2026
Author: Florian Hahn
Date: 2026-09-20T15:49:38Z
New Revision: fa360c3b8dbfd8a449364b7a6e454878bcf00eb9
URL: https://github.com/llvm/llvm-project/commit/fa360c3b8dbfd8a449364b7a6e454878bcf00eb9
DIFF: https://github.com/llvm/llvm-project/commit/fa360c3b8dbfd8a449364b7a6e454878bcf00eb9.diff
LOG: [ConstraintElim] Simplify all overflow intrinsics using isKnownNoWrap. (#224848)
Use isKnownNoWrap overload added in
https://github.com/llvm/llvm-project/pull/224758 to simplify all
supported overflowing math intrinsics.
Enables additional simplifications in a few more cases in
https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/1368.
And more simplifications in Swift, which uses overflow intrinsics
extensively.
Compile-time impact in the noise:
https://llvm-compile-time-tracker.com/compare.php?from=7a02bcc9189b467efbb071ab25d99273fefc54da&to=9a224fd59f971aa94b0e3509dcceae3bffb7ec81&stat=instructions:u
PR: https://github.com/llvm/llvm-project/pull/224848
Added:
llvm/test/Transforms/ConstraintElimination/mul-with-overflow.ll
llvm/test/Transforms/ConstraintElimination/uadd-with-overflow.ll
Modified:
llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
llvm/test/Transforms/ConstraintElimination/usub-with-overflow.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 918d1facc0bb8..daf8167224628 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -577,6 +577,10 @@ static bool isKnownNoWrap(Value *V, const ConstraintInfo &Info, bool Signed) {
if (match(V, m_DisjointOr(m_Value(), m_Value())))
return true;
+ if (auto *WO = dyn_cast<WithOverflowInst>(V))
+ return isKnownNoWrap(WO->getBinaryOp(), WO->getLHS(), WO->getRHS(),
+ /*NoWrapFlags=*/0, Info, Signed);
+
if (auto *Trunc = dyn_cast<TruncInst>(V)) {
if (Signed)
return Trunc->hasNoSignedWrap();
@@ -1505,8 +1509,12 @@ void State::addInfoFor(BasicBlock &BB) {
break;
}
// Enqueue intrinsics for simplification.
+ case Intrinsic::uadd_with_overflow:
case Intrinsic::sadd_with_overflow:
+ case Intrinsic::usub_with_overflow:
case Intrinsic::ssub_with_overflow:
+ case Intrinsic::umul_with_overflow:
+ case Intrinsic::smul_with_overflow:
case Intrinsic::ucmp:
case Intrinsic::scmp:
WorkList.push_back(
@@ -2178,11 +2186,9 @@ void ConstraintInfo::addFactImpl(CmpInst::Predicate Pred, Value *A, Value *B,
}
}
-/// 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,
+/// Replace the uses of \p II, which is known not to overflow, by the
+/// corresponding plain binary operation and a false overflow flag.
+static bool replaceOverflowUses(WithOverflowInst *II,
SmallVectorImpl<Instruction *> &ToRemove) {
bool Changed = false;
IRBuilder<> Builder(II->getParent(), II->getIterator());
@@ -2190,8 +2196,10 @@ static bool replaceOverflowUses(IntrinsicInst *II,
for (User *U : make_early_inc_range(II->users())) {
if (match(U, m_ExtractValue<0>(m_Value()))) {
if (!Res)
- Res = Builder.CreateNoWrapBinOp(Opcode, A, B, /*IsNUW=*/false,
- /*IsNSW=*/true);
+ Res = Builder.CreateNoWrapBinOp(II->getBinaryOp(), II->getLHS(),
+ II->getRHS(),
+ /*IsNUW=*/!II->isSigned(),
+ /*IsNSW=*/II->isSigned());
U->replaceAllUsesWith(Res);
Changed = true;
} else if (match(U, m_ExtractValue<1>(m_Value()))) {
@@ -2219,35 +2227,11 @@ static bool replaceOverflowUses(IntrinsicInst *II,
}
static bool
-tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
+tryToSimplifyOverflowMath(WithOverflowInst *II, ConstraintInfo &Info,
SmallVectorImpl<Instruction *> &ToRemove) {
- 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);
- Value *B = II->getArgOperand(1);
- if (!Info.doesHold(CmpInst::ICMP_SGE, A, B) ||
- !Info.doesHold(CmpInst::ICMP_SGE, B, ConstantInt::get(A->getType(), 0)))
- return false;
- 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:
+ if (!isKnownNoWrap(II, Info, II->isSigned()))
return false;
- }
+ return replaceOverflowUses(II, ToRemove);
}
static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
diff --git a/llvm/test/Transforms/ConstraintElimination/mul-with-overflow.ll b/llvm/test/Transforms/ConstraintElimination/mul-with-overflow.ll
new file mode 100644
index 0000000000000..bd4f976133f4a
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/mul-with-overflow.ll
@@ -0,0 +1,96 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
+
+declare void @use(i1)
+
+; A u<= 25, so A * 10 does not unsigned-overflow (A * 10 u<= UMAX).
+define i8 @umul_no_overflow_upper_bound(i8 %a) {
+; CHECK-LABEL: define i8 @umul_no_overflow_upper_bound(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[HI:%.*]] = icmp ule i8 [[A]], 25
+; CHECK-NEXT: call void @llvm.assume(i1 [[HI]])
+; CHECK-NEXT: [[V:%.*]] = mul nuw i8 [[A]], 10
+; CHECK-NEXT: call void @use(i1 false)
+; CHECK-NEXT: ret i8 [[V]]
+;
+entry:
+ %hi = icmp ule i8 %a, 25
+ call void @llvm.assume(i1 %hi)
+ %s = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 %a, i8 10)
+ %v = extractvalue { i8, i1 } %s, 0
+ %o = extractvalue { i8, i1 } %s, 1
+ call void @use(i1 %o)
+ ret i8 %v
+}
+
+; The upper bound is one too large.
+define i8 @umul_upper_bound_too_large(i8 %a) {
+; CHECK-LABEL: define i8 @umul_upper_bound_too_large(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[HI:%.*]] = icmp ule i8 [[A]], 26
+; CHECK-NEXT: call void @llvm.assume(i1 [[HI]])
+; CHECK-NEXT: [[S:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[A]], i8 10)
+; 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]]
+;
+entry:
+ %hi = icmp ule i8 %a, 26
+ call void @llvm.assume(i1 %hi)
+ %s = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 %a, i8 10)
+ %v = extractvalue { i8, i1 } %s, 0
+ %o = extractvalue { i8, i1 } %s, 1
+ call void @use(i1 %o)
+ ret i8 %v
+}
+
+; -12 s<= A s<= 12, so A * 10 stays in the signed range.
+define i8 @smul_no_overflow_both_bounds(i8 %a) {
+; CHECK-LABEL: define i8 @smul_no_overflow_both_bounds(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[LO:%.*]] = icmp sge i8 [[A]], -12
+; CHECK-NEXT: call void @llvm.assume(i1 [[LO]])
+; CHECK-NEXT: [[HI:%.*]] = icmp sle i8 [[A]], 12
+; CHECK-NEXT: call void @llvm.assume(i1 [[HI]])
+; CHECK-NEXT: [[V:%.*]] = mul nsw i8 [[A]], 10
+; CHECK-NEXT: call void @use(i1 false)
+; CHECK-NEXT: ret i8 [[V]]
+;
+entry:
+ %lo = icmp sge i8 %a, -12
+ call void @llvm.assume(i1 %lo)
+ %hi = icmp sle i8 %a, 12
+ call void @llvm.assume(i1 %hi)
+ %s = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %a, i8 10)
+ %v = extractvalue { i8, i1 } %s, 0
+ %o = extractvalue { i8, i1 } %s, 1
+ call void @use(i1 %o)
+ ret i8 %v
+}
+
+; Both bounds are needed, the product may underflow without a lower bound.
+define i8 @smul_missing_lower_bound(i8 %a) {
+; CHECK-LABEL: define i8 @smul_missing_lower_bound(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[HI:%.*]] = icmp sle i8 [[A]], 12
+; CHECK-NEXT: call void @llvm.assume(i1 [[HI]])
+; CHECK-NEXT: [[S:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[A]], i8 10)
+; 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]]
+;
+entry:
+ %hi = icmp sle i8 %a, 12
+ call void @llvm.assume(i1 %hi)
+ %s = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %a, i8 10)
+ %v = extractvalue { i8, i1 } %s, 0
+ %o = extractvalue { i8, i1 } %s, 1
+ call void @use(i1 %o)
+ ret i8 %v
+}
diff --git a/llvm/test/Transforms/ConstraintElimination/uadd-with-overflow.ll b/llvm/test/Transforms/ConstraintElimination/uadd-with-overflow.ll
new file mode 100644
index 0000000000000..843c48c88ea7a
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/uadd-with-overflow.ll
@@ -0,0 +1,71 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
+
+declare void @use(i1)
+
+; A u<= 155, so A + 100 does not unsigned-overflow (A u<= UMAX - 100).
+define i8 @uadd_no_overflow_upper_bound(i8 %a) {
+; CHECK-LABEL: define i8 @uadd_no_overflow_upper_bound(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[HI:%.*]] = icmp ule i8 [[A]], -101
+; CHECK-NEXT: call void @llvm.assume(i1 [[HI]])
+; CHECK-NEXT: [[V:%.*]] = add nuw i8 [[A]], 100
+; CHECK-NEXT: call void @use(i1 false)
+; CHECK-NEXT: ret i8 [[V]]
+;
+entry:
+ %hi = icmp ule i8 %a, 155
+ call void @llvm.assume(i1 %hi)
+ %s = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %a, i8 100)
+ %v = extractvalue { i8, i1 } %s, 0
+ %o = extractvalue { i8, i1 } %s, 1
+ call void @use(i1 %o)
+ ret i8 %v
+}
+
+; The upper bound is one too large.
+define i8 @uadd_upper_bound_too_large(i8 %a) {
+; CHECK-LABEL: define i8 @uadd_upper_bound_too_large(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[HI:%.*]] = icmp ule i8 [[A]], -100
+; CHECK-NEXT: call void @llvm.assume(i1 [[HI]])
+; CHECK-NEXT: [[S:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[A]], i8 100)
+; 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]]
+;
+entry:
+ %hi = icmp ule i8 %a, 156
+ call void @llvm.assume(i1 %hi)
+ %s = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %a, i8 100)
+ %v = extractvalue { i8, i1 } %s, 0
+ %o = extractvalue { i8, i1 } %s, 1
+ call void @use(i1 %o)
+ ret i8 %v
+}
+
+; The second operand is not a constant, so the bound on A proves nothing.
+define i8 @uadd_variable_ops(i8 %a, i8 %b) {
+; CHECK-LABEL: define i8 @uadd_variable_ops(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[HI:%.*]] = icmp ule i8 [[A]], -101
+; CHECK-NEXT: call void @llvm.assume(i1 [[HI]])
+; CHECK-NEXT: [[S:%.*]] = call { i8, i1 } @llvm.uadd.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]]
+;
+entry:
+ %hi = icmp ule i8 %a, 155
+ call void @llvm.assume(i1 %hi)
+ %s = call { i8, i1 } @llvm.uadd.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
+}
diff --git a/llvm/test/Transforms/ConstraintElimination/usub-with-overflow.ll b/llvm/test/Transforms/ConstraintElimination/usub-with-overflow.ll
index 06bfd8269d97d..b4b3fcce2d31a 100644
--- a/llvm/test/Transforms/ConstraintElimination/usub-with-overflow.ll
+++ b/llvm/test/Transforms/ConstraintElimination/usub-with-overflow.ll
@@ -9,11 +9,9 @@ define i8 @usub_no_overflow_due_to_cmp_condition(i8 %a, i8 %b) {
; CHECK-NEXT: [[C_1:%.*]] = icmp uge i8 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: br i1 [[C_1]], label [[MATH:%.*]], label [[EXIT_FAIL:%.*]]
; CHECK: math:
-; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]])
-; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
-; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
+; CHECK-NEXT: [[RES:%.*]] = sub nuw i8 [[B]], [[A]]
+; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
; CHECK: exit.ok:
-; CHECK-NEXT: [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: exit.fail:
; CHECK-NEXT: ret i8 0
@@ -41,11 +39,9 @@ define i8 @usub_no_overflow_due_to_cmp_condition2(i8 %a, i8 %b) {
; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: br i1 [[C_1]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]]
; CHECK: math:
-; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]])
-; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
-; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
+; CHECK-NEXT: [[RES:%.*]] = sub nuw i8 [[B]], [[A]]
+; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
; CHECK: exit.ok:
-; CHECK-NEXT: [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: exit.fail:
; CHECK-NEXT: ret i8 0
@@ -75,12 +71,11 @@ define i8 @sub_no_overflow_due_to_cmp_condition_result_used(i8 %a, i8 %b) {
; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: br i1 [[C_1]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]]
; CHECK: math:
+; CHECK-NEXT: [[RES:%.*]] = sub nuw i8 [[B]], [[A]]
; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]])
; CHECK-NEXT: call void @use_res({ i8, i1 } [[OP]])
-; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
-; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
+; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
; CHECK: exit.ok:
-; CHECK-NEXT: [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: exit.fail:
; CHECK-NEXT: ret i8 0
@@ -111,11 +106,9 @@ define i8 @usub_no_overflow_due_to_or_conds(i8 %a, i8 %b) {
; CHECK-NEXT: [[OR:%.*]] = or i1 [[C_2]], [[C_1]]
; CHECK-NEXT: br i1 [[OR]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]]
; CHECK: math:
-; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]])
-; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
-; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
+; CHECK-NEXT: [[RES:%.*]] = sub nuw i8 [[B]], [[A]]
+; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
; CHECK: exit.ok:
-; CHECK-NEXT: [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: exit.fail:
; CHECK-NEXT: ret i8 0
@@ -147,9 +140,7 @@ define i8 @usub_no_overflow_due_to_or_conds_sub_result_not_used(i8 %a, i8 %b) {
; CHECK-NEXT: [[OR:%.*]] = or i1 [[C_2]], [[C_1]]
; CHECK-NEXT: br i1 [[OR]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]]
; CHECK: math:
-; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]])
-; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
-; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
+; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
; CHECK: exit.ok:
; CHECK-NEXT: ret i8 20
; CHECK: exit.fail:
@@ -181,11 +172,9 @@ define i8 @usub_no_overflow_due_to_and_conds(i8 %a, i8 %b) {
; CHECK-NEXT: [[AND:%.*]] = and i1 [[C_2]], [[C_1]]
; CHECK-NEXT: br i1 [[AND]], label [[MATH:%.*]], label [[EXIT_FAIL:%.*]]
; CHECK: math:
-; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]])
-; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
-; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
+; CHECK-NEXT: [[RES:%.*]] = sub nuw i8 [[B]], [[A]]
+; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
; CHECK: exit.ok:
-; CHECK-NEXT: [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0
; CHECK-NEXT: ret i8 [[RES]]
; CHECK: exit.fail:
; CHECK-NEXT: ret i8 0
More information about the llvm-commits
mailing list