From 72eb14a268c5ec3e33260ff2b8393b38867cbb21 Mon Sep 17 00:00:00 2001 From: benwu25 Date: Tue, 9 Sep 2025 18:34:46 -0700 Subject: [PATCH 1/6] [InstCombine] New test (#157524) --- llvm/test/Transforms/InstCombine/min-zext.ll | 112 +++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 llvm/test/Transforms/InstCombine/min-zext.ll diff --git a/llvm/test/Transforms/InstCombine/min-zext.ll b/llvm/test/Transforms/InstCombine/min-zext.ll new file mode 100644 index 0000000000000..4e56aebd9fc68 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/min-zext.ll @@ -0,0 +1,112 @@ +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +define i32 @test_smin(i32 %arg0, i32 %arg1) { +; CHECK-LABEL: define i32 @test_smin( +; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) +; CHECK-NEXT: %v1 = add nsw i32 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) +; CHECK-NEXT: %v3 = sub i32 %v2, %v0 +; CHECK-NEXT: ret i32 %v3 +; + %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) + %v1 = add nsw i32 %arg0, 1 + %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) + %v3 = sub i32 %v2, %v0 + ret i32 %v3 +} + +define i32 @test_umin(i32 %arg0, i32 %arg1) { +; CHECK-LABEL: define i32 @test_umin( +; CHECK-NEXT: %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) +; CHECK-NEXT: %v1 = add nuw i32 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 %arg1) +; CHECK-NEXT: %v3 = sub i32 %v2, %v0 +; CHECK-NEXT: ret i32 %v3 +; + %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) + %v1 = add nuw i32 %arg0, 1 + %v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 %arg1) + %v3 = sub i32 %v2, %v0 + ret i32 %v3 +} + +define i1 @test_smin_i1(i1 %arg0, i1 %arg1) { +; CHECK-LABEL: define i1 @test_smin_i1( +; CHECK-NEXT: %v0 = or i1 %arg0, %arg1 +; CHECK-NEXT: %v3 = xor i1 %v0, true +; CHECK-NEXT: ret i1 %v3 +; + %v0 = tail call i1 @llvm.smin.i1(i1 %arg0, i1 %arg1) + %v1 = add nsw i1 %arg0, 1 + %v2 = tail call i1 @llvm.smin.i1(i1 %v1, i1 %arg1) + %v3 = sub i1 %v2, %v0 + ret i1 %v3 +} + +declare void @use(i2) + +define i2 @test_smin_use_operands(i2 %arg0, i2 %arg1) { +; CHECK-LABEL: define i2 @test_smin_use_operands( +; CHECK-NEXT: %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) +; CHECK-NEXT: %v1 = add nsw i2 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) +; CHECK-NEXT: %v3 = sub i2 %v2, %v0 +; CHECK-NEXT: call void @use(i2 %v2) +; CHECK-NEXT: call void @use(i2 %v0) +; CHECK-NEXT: ret i2 %v3 +; + %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) + %v1 = add nsw i2 %arg0, 1 + %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) + %v3 = sub i2 %v2, %v0 + call void @use(i2 %v2) + call void @use(i2 %v0) + ret i2 %v3 +} + +define i2 @test_smin_use_operand(i2 %arg0, i2 %arg1) { +; CHECK-LABEL: define i2 @test_smin_use_operand( +; CHECK-NEXT: %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) +; CHECK-NEXT: %v1 = add nsw i2 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) +; CHECK-NEXT: %v3 = sub i2 %v2, %v0 +; CHECK-NEXT: call void @use(i2 %v2) +; CHECK-NEXT: ret i2 %v3 +; + %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) + %v1 = add nsw i2 %arg0, 1 + %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) + %v3 = sub i2 %v2, %v0 + call void @use(i2 %v2) + ret i2 %v3 +} + +define i32 @test_smin_missing_nsw(i32 %arg0, i32 %arg1) { +; CHECK-LABEL: define i32 @test_smin_missing_nsw( +; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) +; CHECK-NEXT: %v1 = add i32 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) +; CHECK-NEXT: %v3 = sub i32 %v2, %v0 +; CHECK-NEXT: ret i32 %v3 +; + %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) + %v1 = add i32 %arg0, 1 + %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) + %v3 = sub i32 %v2, %v0 + ret i32 %v3 +} + +define i32 @test_umin_missing_nuw(i32 %arg0, i32 %arg1) { +; CHECK-LABEL: define i32 @test_umin_missing_nuw( +; CHECK-NEXT: %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) +; CHECK-NEXT: %v1 = add i32 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 %arg1) +; CHECK-NEXT: %v3 = sub i32 %v2, %v0 +; CHECK-NEXT: ret i32 %v3 +; + %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) + %v1 = add i32 %arg0, 1 + %v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 %arg1) + %v3 = sub i32 %v2, %v0 + ret i32 %v3 +} From b8d16acadffdf1e20f8bb75f953447be2a7feb4d Mon Sep 17 00:00:00 2001 From: benwu25 Date: Tue, 9 Sep 2025 19:28:53 -0700 Subject: [PATCH 2/6] [InstCombine] Fold min(X+1, Y) - min(X, Y) --> zext X < Y (#157524) This fold is invalid for @llvm.smin.i1, since smin(-1, 0) == -1 (take X = Y = 0). Otherwise, if X+1 has the appropriate nsw or nuw, this transform replaces a sub and at least one min with an icmp and a zext. It is also invalid for i1 in general, but it seems that other folds take care of i1. In #157524, this expression was folded to a select, but it seems that select X < Y, 1, 0 can be canonicalized to zext X < Y. --- .../InstCombine/InstCombineAddSub.cpp | 18 ++++ llvm/test/Transforms/InstCombine/min-zext.ll | 84 ++++++++++--------- 2 files changed, 62 insertions(+), 40 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp index d934638c15e75..63c6fc52322d6 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -2719,6 +2719,24 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) { return BinaryOperator::CreateSub(X, Not); } + // min(X+1, Y) - min(X, Y) --> zext X < Y + // Replacing a sub and at least one min with an icmp + // and a zext is a potential improvement. + if (match(Op0, m_c_SMin(m_c_NSWAdd(m_Value(X), m_One()), m_Value(Y))) && + match(Op1, m_c_SMin(m_Value(X), m_Value(Y))) && + I.getType()->getScalarSizeInBits() != 1 && + (Op0->hasOneUse() || Op1->hasOneUse())) { + Value *Cond = Builder.CreateICmpSLT(X, Y); + return new ZExtInst(Cond, I.getType()); + } + if (match(Op0, m_c_UMin(m_c_NUWAdd(m_Value(X), m_One()), m_Value(Y))) && + match(Op1, m_c_UMin(m_Value(X), m_Value(Y))) && + I.getType()->getScalarSizeInBits() != 1 && + (Op0->hasOneUse() || Op1->hasOneUse())) { + Value *Cond = Builder.CreateICmpULT(X, Y); + return new ZExtInst(Cond, I.getType()); + } + // Optimize pointer differences into the same array into a size. Consider: // &A[10] - &A[0]: we should compile this to "10". Value *LHSOp, *RHSOp; diff --git a/llvm/test/Transforms/InstCombine/min-zext.ll b/llvm/test/Transforms/InstCombine/min-zext.ll index 4e56aebd9fc68..43af1f48bcfed 100644 --- a/llvm/test/Transforms/InstCombine/min-zext.ll +++ b/llvm/test/Transforms/InstCombine/min-zext.ll @@ -1,12 +1,12 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s define i32 @test_smin(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_smin( -; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) -; CHECK-NEXT: %v1 = add nsw i32 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) -; CHECK-NEXT: %v3 = sub i32 %v2, %v0 -; CHECK-NEXT: ret i32 %v3 +; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[ARG0]], [[ARG1]] +; CHECK-NEXT: [[V3:%.*]] = zext i1 [[TMP1]] to i32 +; CHECK-NEXT: ret i32 [[V3]] ; %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) %v1 = add nsw i32 %arg0, 1 @@ -17,11 +17,10 @@ define i32 @test_smin(i32 %arg0, i32 %arg1) { define i32 @test_umin(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_umin( -; CHECK-NEXT: %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) -; CHECK-NEXT: %v1 = add nuw i32 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 %arg1) -; CHECK-NEXT: %v3 = sub i32 %v2, %v0 -; CHECK-NEXT: ret i32 %v3 +; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[ARG0]], [[ARG1]] +; CHECK-NEXT: [[V3:%.*]] = zext i1 [[TMP1]] to i32 +; CHECK-NEXT: ret i32 [[V3]] ; %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) %v1 = add nuw i32 %arg0, 1 @@ -32,9 +31,10 @@ define i32 @test_umin(i32 %arg0, i32 %arg1) { define i1 @test_smin_i1(i1 %arg0, i1 %arg1) { ; CHECK-LABEL: define i1 @test_smin_i1( -; CHECK-NEXT: %v0 = or i1 %arg0, %arg1 -; CHECK-NEXT: %v3 = xor i1 %v0, true -; CHECK-NEXT: ret i1 %v3 +; CHECK-SAME: i1 [[ARG0:%.*]], i1 [[ARG1:%.*]]) { +; CHECK-NEXT: [[V0:%.*]] = or i1 [[ARG0]], [[ARG1]] +; CHECK-NEXT: [[V3:%.*]] = xor i1 [[V0]], true +; CHECK-NEXT: ret i1 [[V3]] ; %v0 = tail call i1 @llvm.smin.i1(i1 %arg0, i1 %arg1) %v1 = add nsw i1 %arg0, 1 @@ -47,47 +47,50 @@ declare void @use(i2) define i2 @test_smin_use_operands(i2 %arg0, i2 %arg1) { ; CHECK-LABEL: define i2 @test_smin_use_operands( -; CHECK-NEXT: %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) -; CHECK-NEXT: %v1 = add nsw i2 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) -; CHECK-NEXT: %v3 = sub i2 %v2, %v0 -; CHECK-NEXT: call void @use(i2 %v2) -; CHECK-NEXT: call void @use(i2 %v0) -; CHECK-NEXT: ret i2 %v3 +; CHECK-SAME: i2 [[ARG0:%.*]], i2 [[ARG1:%.*]]) { +; CHECK-NEXT: [[V0:%.*]] = tail call i2 @llvm.smin.i2(i2 [[ARG0]], i2 [[ARG1]]) +; CHECK-NEXT: [[V1:%.*]] = add nsw i2 [[ARG0]], 1 +; CHECK-NEXT: [[V2:%.*]] = tail call i2 @llvm.smin.i2(i2 [[V1]], i2 [[ARG1]]) +; CHECK-NEXT: [[V3:%.*]] = sub i2 [[V2]], [[V0]] +; CHECK-NEXT: call void @use(i2 [[V2]]) +; CHECK-NEXT: call void @use(i2 [[V0]]) +; CHECK-NEXT: ret i2 [[V3]] ; %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) %v1 = add nsw i2 %arg0, 1 %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) - %v3 = sub i2 %v2, %v0 + %v3 = sub i2 %v2, %v0 call void @use(i2 %v2) call void @use(i2 %v0) - ret i2 %v3 + ret i2 %v3 } define i2 @test_smin_use_operand(i2 %arg0, i2 %arg1) { ; CHECK-LABEL: define i2 @test_smin_use_operand( -; CHECK-NEXT: %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) -; CHECK-NEXT: %v1 = add nsw i2 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) -; CHECK-NEXT: %v3 = sub i2 %v2, %v0 -; CHECK-NEXT: call void @use(i2 %v2) -; CHECK-NEXT: ret i2 %v3 +; CHECK-SAME: i2 [[ARG0:%.*]], i2 [[ARG1:%.*]]) { +; CHECK-NEXT: [[V1:%.*]] = add nsw i2 [[ARG0]], 1 +; CHECK-NEXT: [[V2:%.*]] = tail call i2 @llvm.smin.i2(i2 [[V1]], i2 [[ARG1]]) +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i2 [[ARG0]], [[ARG1]] +; CHECK-NEXT: [[V3:%.*]] = zext i1 [[TMP1]] to i2 +; CHECK-NEXT: call void @use(i2 [[V2]]) +; CHECK-NEXT: ret i2 [[V3]] ; %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) %v1 = add nsw i2 %arg0, 1 %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) - %v3 = sub i2 %v2, %v0 + %v3 = sub i2 %v2, %v0 call void @use(i2 %v2) - ret i2 %v3 + ret i2 %v3 } define i32 @test_smin_missing_nsw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_smin_missing_nsw( -; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) -; CHECK-NEXT: %v1 = add i32 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) -; CHECK-NEXT: %v3 = sub i32 %v2, %v0 -; CHECK-NEXT: ret i32 %v3 +; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { +; CHECK-NEXT: [[V0:%.*]] = tail call i32 @llvm.smin.i32(i32 [[ARG0]], i32 [[ARG1]]) +; CHECK-NEXT: [[V1:%.*]] = add i32 [[ARG0]], 1 +; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 [[ARG1]]) +; CHECK-NEXT: [[V3:%.*]] = sub i32 [[V2]], [[V0]] +; CHECK-NEXT: ret i32 [[V3]] ; %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) %v1 = add i32 %arg0, 1 @@ -98,11 +101,12 @@ define i32 @test_smin_missing_nsw(i32 %arg0, i32 %arg1) { define i32 @test_umin_missing_nuw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_umin_missing_nuw( -; CHECK-NEXT: %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) -; CHECK-NEXT: %v1 = add i32 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 %arg1) -; CHECK-NEXT: %v3 = sub i32 %v2, %v0 -; CHECK-NEXT: ret i32 %v3 +; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { +; CHECK-NEXT: [[V0:%.*]] = tail call i32 @llvm.umin.i32(i32 [[ARG0]], i32 [[ARG1]]) +; CHECK-NEXT: [[V1:%.*]] = add i32 [[ARG0]], 1 +; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.umin.i32(i32 [[V1]], i32 [[ARG1]]) +; CHECK-NEXT: [[V3:%.*]] = sub i32 [[V2]], [[V0]] +; CHECK-NEXT: ret i32 [[V3]] ; %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) %v1 = add i32 %arg0, 1 From e6a44697d2d09def667aae2526c5436566073faa Mon Sep 17 00:00:00 2001 From: benwu25 Date: Wed, 10 Sep 2025 12:56:22 -0700 Subject: [PATCH 3/6] [InstCombine] Add mismatched operands test (#157524) In case I misinterpreted, this can be changed to mismatch the arguments of one of the min calls instead. --- llvm/test/Transforms/InstCombine/min-zext.ll | 99 +++++++++++--------- 1 file changed, 55 insertions(+), 44 deletions(-) diff --git a/llvm/test/Transforms/InstCombine/min-zext.ll b/llvm/test/Transforms/InstCombine/min-zext.ll index 43af1f48bcfed..8f44a5f9cc5c4 100644 --- a/llvm/test/Transforms/InstCombine/min-zext.ll +++ b/llvm/test/Transforms/InstCombine/min-zext.ll @@ -1,12 +1,12 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s define i32 @test_smin(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_smin( -; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[ARG0]], [[ARG1]] -; CHECK-NEXT: [[V3:%.*]] = zext i1 [[TMP1]] to i32 -; CHECK-NEXT: ret i32 [[V3]] +; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) +; CHECK-NEXT: %v1 = add nsw i32 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) +; CHECK-NEXT: %v3 = sub i32 %v2, %v0 +; CHECK-NEXT: ret i32 %v3 ; %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) %v1 = add nsw i32 %arg0, 1 @@ -17,10 +17,11 @@ define i32 @test_smin(i32 %arg0, i32 %arg1) { define i32 @test_umin(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_umin( -; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[ARG0]], [[ARG1]] -; CHECK-NEXT: [[V3:%.*]] = zext i1 [[TMP1]] to i32 -; CHECK-NEXT: ret i32 [[V3]] +; CHECK-NEXT: %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) +; CHECK-NEXT: %v1 = add nuw i32 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 %arg1) +; CHECK-NEXT: %v3 = sub i32 %v2, %v0 +; CHECK-NEXT: ret i32 %v3 ; %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) %v1 = add nuw i32 %arg0, 1 @@ -31,10 +32,9 @@ define i32 @test_umin(i32 %arg0, i32 %arg1) { define i1 @test_smin_i1(i1 %arg0, i1 %arg1) { ; CHECK-LABEL: define i1 @test_smin_i1( -; CHECK-SAME: i1 [[ARG0:%.*]], i1 [[ARG1:%.*]]) { -; CHECK-NEXT: [[V0:%.*]] = or i1 [[ARG0]], [[ARG1]] -; CHECK-NEXT: [[V3:%.*]] = xor i1 [[V0]], true -; CHECK-NEXT: ret i1 [[V3]] +; CHECK-NEXT: %v0 = or i1 %arg0, %arg1 +; CHECK-NEXT: %v3 = xor i1 %v0, true +; CHECK-NEXT: ret i1 %v3 ; %v0 = tail call i1 @llvm.smin.i1(i1 %arg0, i1 %arg1) %v1 = add nsw i1 %arg0, 1 @@ -47,50 +47,47 @@ declare void @use(i2) define i2 @test_smin_use_operands(i2 %arg0, i2 %arg1) { ; CHECK-LABEL: define i2 @test_smin_use_operands( -; CHECK-SAME: i2 [[ARG0:%.*]], i2 [[ARG1:%.*]]) { -; CHECK-NEXT: [[V0:%.*]] = tail call i2 @llvm.smin.i2(i2 [[ARG0]], i2 [[ARG1]]) -; CHECK-NEXT: [[V1:%.*]] = add nsw i2 [[ARG0]], 1 -; CHECK-NEXT: [[V2:%.*]] = tail call i2 @llvm.smin.i2(i2 [[V1]], i2 [[ARG1]]) -; CHECK-NEXT: [[V3:%.*]] = sub i2 [[V2]], [[V0]] -; CHECK-NEXT: call void @use(i2 [[V2]]) -; CHECK-NEXT: call void @use(i2 [[V0]]) -; CHECK-NEXT: ret i2 [[V3]] +; CHECK-NEXT: %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) +; CHECK-NEXT: %v1 = add nsw i2 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) +; CHECK-NEXT: %v3 = sub i2 %v2, %v0 +; CHECK-NEXT: call void @use(i2 %v2) +; CHECK-NEXT: call void @use(i2 %v0) +; CHECK-NEXT: ret i2 %v3 ; %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) %v1 = add nsw i2 %arg0, 1 %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) - %v3 = sub i2 %v2, %v0 + %v3 = sub i2 %v2, %v0 call void @use(i2 %v2) call void @use(i2 %v0) - ret i2 %v3 + ret i2 %v3 } define i2 @test_smin_use_operand(i2 %arg0, i2 %arg1) { ; CHECK-LABEL: define i2 @test_smin_use_operand( -; CHECK-SAME: i2 [[ARG0:%.*]], i2 [[ARG1:%.*]]) { -; CHECK-NEXT: [[V1:%.*]] = add nsw i2 [[ARG0]], 1 -; CHECK-NEXT: [[V2:%.*]] = tail call i2 @llvm.smin.i2(i2 [[V1]], i2 [[ARG1]]) -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i2 [[ARG0]], [[ARG1]] -; CHECK-NEXT: [[V3:%.*]] = zext i1 [[TMP1]] to i2 -; CHECK-NEXT: call void @use(i2 [[V2]]) -; CHECK-NEXT: ret i2 [[V3]] +; CHECK-NEXT: %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) +; CHECK-NEXT: %v1 = add nsw i2 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) +; CHECK-NEXT: %v3 = sub i2 %v2, %v0 +; CHECK-NEXT: call void @use(i2 %v2) +; CHECK-NEXT: ret i2 %v3 ; %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) %v1 = add nsw i2 %arg0, 1 %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) - %v3 = sub i2 %v2, %v0 + %v3 = sub i2 %v2, %v0 call void @use(i2 %v2) - ret i2 %v3 + ret i2 %v3 } define i32 @test_smin_missing_nsw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_smin_missing_nsw( -; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { -; CHECK-NEXT: [[V0:%.*]] = tail call i32 @llvm.smin.i32(i32 [[ARG0]], i32 [[ARG1]]) -; CHECK-NEXT: [[V1:%.*]] = add i32 [[ARG0]], 1 -; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 [[ARG1]]) -; CHECK-NEXT: [[V3:%.*]] = sub i32 [[V2]], [[V0]] -; CHECK-NEXT: ret i32 [[V3]] +; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) +; CHECK-NEXT: %v1 = add i32 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) +; CHECK-NEXT: %v3 = sub i32 %v2, %v0 +; CHECK-NEXT: ret i32 %v3 ; %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) %v1 = add i32 %arg0, 1 @@ -101,12 +98,11 @@ define i32 @test_smin_missing_nsw(i32 %arg0, i32 %arg1) { define i32 @test_umin_missing_nuw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_umin_missing_nuw( -; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { -; CHECK-NEXT: [[V0:%.*]] = tail call i32 @llvm.umin.i32(i32 [[ARG0]], i32 [[ARG1]]) -; CHECK-NEXT: [[V1:%.*]] = add i32 [[ARG0]], 1 -; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.umin.i32(i32 [[V1]], i32 [[ARG1]]) -; CHECK-NEXT: [[V3:%.*]] = sub i32 [[V2]], [[V0]] -; CHECK-NEXT: ret i32 [[V3]] +; CHECK-NEXT: %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) +; CHECK-NEXT: %v1 = add i32 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 %arg1) +; CHECK-NEXT: %v3 = sub i32 %v2, %v0 +; CHECK-NEXT: ret i32 %v3 ; %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) %v1 = add i32 %arg0, 1 @@ -114,3 +110,18 @@ define i32 @test_umin_missing_nuw(i32 %arg0, i32 %arg1) { %v3 = sub i32 %v2, %v0 ret i32 %v3 } + +define i32 @test_mismatched_operands(i32 %arg0, i32 %arg1) { +; CHECK-LABEL: define i32 @test_mismatched_operands( +; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) +; CHECK-NEXT: %v1 = add nsw i32 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) +; CHECK-NEXT: %v3 = sub i32 %v0, %v2 +; CHECK-NEXT: ret i32 %v3 +; + %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) + %v1 = add nsw i32 %arg0, 1 + %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) + %v3 = sub i32 %v0, %v2 + ret i32 %v3 +} From fb65223b604c5f1c45ef813391fd97909aef18d3 Mon Sep 17 00:00:00 2001 From: benwu25 Date: Wed, 10 Sep 2025 13:02:32 -0700 Subject: [PATCH 4/6] [InstCombine] Use m_Specific rather than m_Value (#157524) --- .../InstCombine/InstCombineAddSub.cpp | 4 +- llvm/test/Transforms/InstCombine/min-zext.ll | 95 ++++++++++--------- 2 files changed, 52 insertions(+), 47 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp index 63c6fc52322d6..b798d839efa43 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -2723,14 +2723,14 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) { // Replacing a sub and at least one min with an icmp // and a zext is a potential improvement. if (match(Op0, m_c_SMin(m_c_NSWAdd(m_Value(X), m_One()), m_Value(Y))) && - match(Op1, m_c_SMin(m_Value(X), m_Value(Y))) && + match(Op1, m_c_SMin(m_Specific(X), m_Specific(Y))) && I.getType()->getScalarSizeInBits() != 1 && (Op0->hasOneUse() || Op1->hasOneUse())) { Value *Cond = Builder.CreateICmpSLT(X, Y); return new ZExtInst(Cond, I.getType()); } if (match(Op0, m_c_UMin(m_c_NUWAdd(m_Value(X), m_One()), m_Value(Y))) && - match(Op1, m_c_UMin(m_Value(X), m_Value(Y))) && + match(Op1, m_c_UMin(m_Specific(X), m_Specific(Y))) && I.getType()->getScalarSizeInBits() != 1 && (Op0->hasOneUse() || Op1->hasOneUse())) { Value *Cond = Builder.CreateICmpULT(X, Y); diff --git a/llvm/test/Transforms/InstCombine/min-zext.ll b/llvm/test/Transforms/InstCombine/min-zext.ll index 8f44a5f9cc5c4..254ad1ece59d1 100644 --- a/llvm/test/Transforms/InstCombine/min-zext.ll +++ b/llvm/test/Transforms/InstCombine/min-zext.ll @@ -1,12 +1,12 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s define i32 @test_smin(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_smin( -; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) -; CHECK-NEXT: %v1 = add nsw i32 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) -; CHECK-NEXT: %v3 = sub i32 %v2, %v0 -; CHECK-NEXT: ret i32 %v3 +; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[ARG0]], [[ARG1]] +; CHECK-NEXT: [[V3:%.*]] = zext i1 [[TMP1]] to i32 +; CHECK-NEXT: ret i32 [[V3]] ; %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) %v1 = add nsw i32 %arg0, 1 @@ -17,11 +17,10 @@ define i32 @test_smin(i32 %arg0, i32 %arg1) { define i32 @test_umin(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_umin( -; CHECK-NEXT: %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) -; CHECK-NEXT: %v1 = add nuw i32 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 %arg1) -; CHECK-NEXT: %v3 = sub i32 %v2, %v0 -; CHECK-NEXT: ret i32 %v3 +; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[ARG0]], [[ARG1]] +; CHECK-NEXT: [[V3:%.*]] = zext i1 [[TMP1]] to i32 +; CHECK-NEXT: ret i32 [[V3]] ; %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) %v1 = add nuw i32 %arg0, 1 @@ -32,9 +31,10 @@ define i32 @test_umin(i32 %arg0, i32 %arg1) { define i1 @test_smin_i1(i1 %arg0, i1 %arg1) { ; CHECK-LABEL: define i1 @test_smin_i1( -; CHECK-NEXT: %v0 = or i1 %arg0, %arg1 -; CHECK-NEXT: %v3 = xor i1 %v0, true -; CHECK-NEXT: ret i1 %v3 +; CHECK-SAME: i1 [[ARG0:%.*]], i1 [[ARG1:%.*]]) { +; CHECK-NEXT: [[V0:%.*]] = or i1 [[ARG0]], [[ARG1]] +; CHECK-NEXT: [[V3:%.*]] = xor i1 [[V0]], true +; CHECK-NEXT: ret i1 [[V3]] ; %v0 = tail call i1 @llvm.smin.i1(i1 %arg0, i1 %arg1) %v1 = add nsw i1 %arg0, 1 @@ -47,47 +47,50 @@ declare void @use(i2) define i2 @test_smin_use_operands(i2 %arg0, i2 %arg1) { ; CHECK-LABEL: define i2 @test_smin_use_operands( -; CHECK-NEXT: %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) -; CHECK-NEXT: %v1 = add nsw i2 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) -; CHECK-NEXT: %v3 = sub i2 %v2, %v0 -; CHECK-NEXT: call void @use(i2 %v2) -; CHECK-NEXT: call void @use(i2 %v0) -; CHECK-NEXT: ret i2 %v3 +; CHECK-SAME: i2 [[ARG0:%.*]], i2 [[ARG1:%.*]]) { +; CHECK-NEXT: [[V0:%.*]] = tail call i2 @llvm.smin.i2(i2 [[ARG0]], i2 [[ARG1]]) +; CHECK-NEXT: [[V1:%.*]] = add nsw i2 [[ARG0]], 1 +; CHECK-NEXT: [[V2:%.*]] = tail call i2 @llvm.smin.i2(i2 [[V1]], i2 [[ARG1]]) +; CHECK-NEXT: [[V3:%.*]] = sub i2 [[V2]], [[V0]] +; CHECK-NEXT: call void @use(i2 [[V2]]) +; CHECK-NEXT: call void @use(i2 [[V0]]) +; CHECK-NEXT: ret i2 [[V3]] ; %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) %v1 = add nsw i2 %arg0, 1 %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) - %v3 = sub i2 %v2, %v0 + %v3 = sub i2 %v2, %v0 call void @use(i2 %v2) call void @use(i2 %v0) - ret i2 %v3 + ret i2 %v3 } define i2 @test_smin_use_operand(i2 %arg0, i2 %arg1) { ; CHECK-LABEL: define i2 @test_smin_use_operand( -; CHECK-NEXT: %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) -; CHECK-NEXT: %v1 = add nsw i2 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) -; CHECK-NEXT: %v3 = sub i2 %v2, %v0 -; CHECK-NEXT: call void @use(i2 %v2) -; CHECK-NEXT: ret i2 %v3 +; CHECK-SAME: i2 [[ARG0:%.*]], i2 [[ARG1:%.*]]) { +; CHECK-NEXT: [[V1:%.*]] = add nsw i2 [[ARG0]], 1 +; CHECK-NEXT: [[V2:%.*]] = tail call i2 @llvm.smin.i2(i2 [[V1]], i2 [[ARG1]]) +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i2 [[ARG0]], [[ARG1]] +; CHECK-NEXT: [[V3:%.*]] = zext i1 [[TMP1]] to i2 +; CHECK-NEXT: call void @use(i2 [[V2]]) +; CHECK-NEXT: ret i2 [[V3]] ; %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) %v1 = add nsw i2 %arg0, 1 %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) - %v3 = sub i2 %v2, %v0 + %v3 = sub i2 %v2, %v0 call void @use(i2 %v2) - ret i2 %v3 + ret i2 %v3 } define i32 @test_smin_missing_nsw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_smin_missing_nsw( -; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) -; CHECK-NEXT: %v1 = add i32 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) -; CHECK-NEXT: %v3 = sub i32 %v2, %v0 -; CHECK-NEXT: ret i32 %v3 +; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { +; CHECK-NEXT: [[V0:%.*]] = tail call i32 @llvm.smin.i32(i32 [[ARG0]], i32 [[ARG1]]) +; CHECK-NEXT: [[V1:%.*]] = add i32 [[ARG0]], 1 +; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 [[ARG1]]) +; CHECK-NEXT: [[V3:%.*]] = sub i32 [[V2]], [[V0]] +; CHECK-NEXT: ret i32 [[V3]] ; %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) %v1 = add i32 %arg0, 1 @@ -98,11 +101,12 @@ define i32 @test_smin_missing_nsw(i32 %arg0, i32 %arg1) { define i32 @test_umin_missing_nuw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_umin_missing_nuw( -; CHECK-NEXT: %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) -; CHECK-NEXT: %v1 = add i32 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 %arg1) -; CHECK-NEXT: %v3 = sub i32 %v2, %v0 -; CHECK-NEXT: ret i32 %v3 +; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { +; CHECK-NEXT: [[V0:%.*]] = tail call i32 @llvm.umin.i32(i32 [[ARG0]], i32 [[ARG1]]) +; CHECK-NEXT: [[V1:%.*]] = add i32 [[ARG0]], 1 +; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.umin.i32(i32 [[V1]], i32 [[ARG1]]) +; CHECK-NEXT: [[V3:%.*]] = sub i32 [[V2]], [[V0]] +; CHECK-NEXT: ret i32 [[V3]] ; %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) %v1 = add i32 %arg0, 1 @@ -113,11 +117,12 @@ define i32 @test_umin_missing_nuw(i32 %arg0, i32 %arg1) { define i32 @test_mismatched_operands(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_mismatched_operands( -; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) -; CHECK-NEXT: %v1 = add nsw i32 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) -; CHECK-NEXT: %v3 = sub i32 %v0, %v2 -; CHECK-NEXT: ret i32 %v3 +; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { +; CHECK-NEXT: [[V0:%.*]] = tail call i32 @llvm.smin.i32(i32 [[ARG0]], i32 [[ARG1]]) +; CHECK-NEXT: [[V1:%.*]] = add nsw i32 [[ARG0]], 1 +; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 [[ARG1]]) +; CHECK-NEXT: [[V3:%.*]] = sub i32 [[V0]], [[V2]] +; CHECK-NEXT: ret i32 [[V3]] ; %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) %v1 = add nsw i32 %arg0, 1 From cc097ac17fb60d3027a15476a77d82ce3b6604f8 Mon Sep 17 00:00:00 2001 From: benwu25 Date: Thu, 11 Sep 2025 11:33:11 -0700 Subject: [PATCH 5/6] [InstCombine] Update mismatched ops test, add disjoint or test (#157524) --- llvm/test/Transforms/InstCombine/min-zext.ll | 118 +++++++++++-------- 1 file changed, 66 insertions(+), 52 deletions(-) diff --git a/llvm/test/Transforms/InstCombine/min-zext.ll b/llvm/test/Transforms/InstCombine/min-zext.ll index 254ad1ece59d1..8671a2045732b 100644 --- a/llvm/test/Transforms/InstCombine/min-zext.ll +++ b/llvm/test/Transforms/InstCombine/min-zext.ll @@ -1,12 +1,12 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s define i32 @test_smin(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_smin( -; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[ARG0]], [[ARG1]] -; CHECK-NEXT: [[V3:%.*]] = zext i1 [[TMP1]] to i32 -; CHECK-NEXT: ret i32 [[V3]] +; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) +; CHECK-NEXT: %v1 = add nsw i32 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) +; CHECK-NEXT: %v3 = sub i32 %v2, %v0 +; CHECK-NEXT: ret i32 %v3 ; %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) %v1 = add nsw i32 %arg0, 1 @@ -17,10 +17,11 @@ define i32 @test_smin(i32 %arg0, i32 %arg1) { define i32 @test_umin(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_umin( -; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { -; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[ARG0]], [[ARG1]] -; CHECK-NEXT: [[V3:%.*]] = zext i1 [[TMP1]] to i32 -; CHECK-NEXT: ret i32 [[V3]] +; CHECK-NEXT: %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) +; CHECK-NEXT: %v1 = add nuw i32 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 %arg1) +; CHECK-NEXT: %v3 = sub i32 %v2, %v0 +; CHECK-NEXT: ret i32 %v3 ; %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) %v1 = add nuw i32 %arg0, 1 @@ -31,10 +32,9 @@ define i32 @test_umin(i32 %arg0, i32 %arg1) { define i1 @test_smin_i1(i1 %arg0, i1 %arg1) { ; CHECK-LABEL: define i1 @test_smin_i1( -; CHECK-SAME: i1 [[ARG0:%.*]], i1 [[ARG1:%.*]]) { -; CHECK-NEXT: [[V0:%.*]] = or i1 [[ARG0]], [[ARG1]] -; CHECK-NEXT: [[V3:%.*]] = xor i1 [[V0]], true -; CHECK-NEXT: ret i1 [[V3]] +; CHECK-NEXT: %v0 = or i1 %arg0, %arg1 +; CHECK-NEXT: %v3 = xor i1 %v0, true +; CHECK-NEXT: ret i1 %v3 ; %v0 = tail call i1 @llvm.smin.i1(i1 %arg0, i1 %arg1) %v1 = add nsw i1 %arg0, 1 @@ -47,50 +47,47 @@ declare void @use(i2) define i2 @test_smin_use_operands(i2 %arg0, i2 %arg1) { ; CHECK-LABEL: define i2 @test_smin_use_operands( -; CHECK-SAME: i2 [[ARG0:%.*]], i2 [[ARG1:%.*]]) { -; CHECK-NEXT: [[V0:%.*]] = tail call i2 @llvm.smin.i2(i2 [[ARG0]], i2 [[ARG1]]) -; CHECK-NEXT: [[V1:%.*]] = add nsw i2 [[ARG0]], 1 -; CHECK-NEXT: [[V2:%.*]] = tail call i2 @llvm.smin.i2(i2 [[V1]], i2 [[ARG1]]) -; CHECK-NEXT: [[V3:%.*]] = sub i2 [[V2]], [[V0]] -; CHECK-NEXT: call void @use(i2 [[V2]]) -; CHECK-NEXT: call void @use(i2 [[V0]]) -; CHECK-NEXT: ret i2 [[V3]] +; CHECK-NEXT: %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) +; CHECK-NEXT: %v1 = add nsw i2 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) +; CHECK-NEXT: %v3 = sub i2 %v2, %v0 +; CHECK-NEXT: call void @use(i2 %v2) +; CHECK-NEXT: call void @use(i2 %v0) +; CHECK-NEXT: ret i2 %v3 ; %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) %v1 = add nsw i2 %arg0, 1 %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) - %v3 = sub i2 %v2, %v0 + %v3 = sub i2 %v2, %v0 call void @use(i2 %v2) call void @use(i2 %v0) - ret i2 %v3 + ret i2 %v3 } define i2 @test_smin_use_operand(i2 %arg0, i2 %arg1) { ; CHECK-LABEL: define i2 @test_smin_use_operand( -; CHECK-SAME: i2 [[ARG0:%.*]], i2 [[ARG1:%.*]]) { -; CHECK-NEXT: [[V1:%.*]] = add nsw i2 [[ARG0]], 1 -; CHECK-NEXT: [[V2:%.*]] = tail call i2 @llvm.smin.i2(i2 [[V1]], i2 [[ARG1]]) -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i2 [[ARG0]], [[ARG1]] -; CHECK-NEXT: [[V3:%.*]] = zext i1 [[TMP1]] to i2 -; CHECK-NEXT: call void @use(i2 [[V2]]) -; CHECK-NEXT: ret i2 [[V3]] +; CHECK-NEXT: %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) +; CHECK-NEXT: %v1 = add nsw i2 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) +; CHECK-NEXT: %v3 = sub i2 %v2, %v0 +; CHECK-NEXT: call void @use(i2 %v2) +; CHECK-NEXT: ret i2 %v3 ; %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) %v1 = add nsw i2 %arg0, 1 %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) - %v3 = sub i2 %v2, %v0 + %v3 = sub i2 %v2, %v0 call void @use(i2 %v2) - ret i2 %v3 + ret i2 %v3 } define i32 @test_smin_missing_nsw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_smin_missing_nsw( -; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { -; CHECK-NEXT: [[V0:%.*]] = tail call i32 @llvm.smin.i32(i32 [[ARG0]], i32 [[ARG1]]) -; CHECK-NEXT: [[V1:%.*]] = add i32 [[ARG0]], 1 -; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 [[ARG1]]) -; CHECK-NEXT: [[V3:%.*]] = sub i32 [[V2]], [[V0]] -; CHECK-NEXT: ret i32 [[V3]] +; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) +; CHECK-NEXT: %v1 = add i32 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) +; CHECK-NEXT: %v3 = sub i32 %v2, %v0 +; CHECK-NEXT: ret i32 %v3 ; %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) %v1 = add i32 %arg0, 1 @@ -101,12 +98,11 @@ define i32 @test_smin_missing_nsw(i32 %arg0, i32 %arg1) { define i32 @test_umin_missing_nuw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_umin_missing_nuw( -; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { -; CHECK-NEXT: [[V0:%.*]] = tail call i32 @llvm.umin.i32(i32 [[ARG0]], i32 [[ARG1]]) -; CHECK-NEXT: [[V1:%.*]] = add i32 [[ARG0]], 1 -; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.umin.i32(i32 [[V1]], i32 [[ARG1]]) -; CHECK-NEXT: [[V3:%.*]] = sub i32 [[V2]], [[V0]] -; CHECK-NEXT: ret i32 [[V3]] +; CHECK-NEXT: %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) +; CHECK-NEXT: %v1 = add i32 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 %arg1) +; CHECK-NEXT: %v3 = sub i32 %v2, %v0 +; CHECK-NEXT: ret i32 %v3 ; %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) %v1 = add i32 %arg0, 1 @@ -115,18 +111,36 @@ define i32 @test_umin_missing_nuw(i32 %arg0, i32 %arg1) { ret i32 %v3 } +@tmp = external global i32 + define i32 @test_mismatched_operands(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_mismatched_operands( -; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { -; CHECK-NEXT: [[V0:%.*]] = tail call i32 @llvm.smin.i32(i32 [[ARG0]], i32 [[ARG1]]) -; CHECK-NEXT: [[V1:%.*]] = add nsw i32 [[ARG0]], 1 -; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 [[ARG1]]) -; CHECK-NEXT: [[V3:%.*]] = sub i32 [[V0]], [[V2]] -; CHECK-NEXT: ret i32 [[V3]] +; CHECK-NEXT: %tmp = load i32, ptr @tmp, align 4 +; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %tmp) +; CHECK-NEXT: %v1 = add nsw i32 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) +; CHECK-NEXT: %v3 = sub i32 %v0, %v2 +; CHECK-NEXT: ret i32 %v3 ; - %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) + %tmp = load i32, ptr @tmp, align 4 + %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %tmp) %v1 = add nsw i32 %arg0, 1 %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) - %v3 = sub i32 %v0, %v2 + %v3 = sub i32 %v2, %v0 + ret i32 %v3 +} + +define i32 @test_disjoint_or(i32 %arg0, i32 %arg1) { +; CHECK-LABEL: define i32 @test_disjoint_or( +; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) +; CHECK-NEXT: %v1 = or disjoint i32 %arg0, 1 +; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) +; CHECK-NEXT: %v3 = sub i32 %v2, %v0 +; CHECK-NEXT: ret i32 %v3 +; + %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) + %v1 = or disjoint i32 %arg0, 1 + %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) + %v3 = sub i32 %v2, %v0 ret i32 %v3 } From 2ba69409bc92b145356f3c1955603ef95e43e355 Mon Sep 17 00:00:00 2001 From: benwu25 Date: Thu, 11 Sep 2025 11:41:07 -0700 Subject: [PATCH 6/6] [InstCombine] Use m_NSXAddLike rather than m_c_NSXAdd (#157524) --- .../InstCombine/InstCombineAddSub.cpp | 4 +- llvm/test/Transforms/InstCombine/min-zext.ll | 108 +++++++++--------- 2 files changed, 58 insertions(+), 54 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp index cb70040a1a737..71c53e37c7757 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -2734,14 +2734,14 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) { // min(X+1, Y) - min(X, Y) --> zext X < Y // Replacing a sub and at least one min with an icmp // and a zext is a potential improvement. - if (match(Op0, m_c_SMin(m_c_NSWAdd(m_Value(X), m_One()), m_Value(Y))) && + if (match(Op0, m_c_SMin(m_NSWAddLike(m_Value(X), m_One()), m_Value(Y))) && match(Op1, m_c_SMin(m_Specific(X), m_Specific(Y))) && I.getType()->getScalarSizeInBits() != 1 && (Op0->hasOneUse() || Op1->hasOneUse())) { Value *Cond = Builder.CreateICmpSLT(X, Y); return new ZExtInst(Cond, I.getType()); } - if (match(Op0, m_c_UMin(m_c_NUWAdd(m_Value(X), m_One()), m_Value(Y))) && + if (match(Op0, m_c_UMin(m_NUWAddLike(m_Value(X), m_One()), m_Value(Y))) && match(Op1, m_c_UMin(m_Specific(X), m_Specific(Y))) && I.getType()->getScalarSizeInBits() != 1 && (Op0->hasOneUse() || Op1->hasOneUse())) { diff --git a/llvm/test/Transforms/InstCombine/min-zext.ll b/llvm/test/Transforms/InstCombine/min-zext.ll index 8671a2045732b..f016d1a8de524 100644 --- a/llvm/test/Transforms/InstCombine/min-zext.ll +++ b/llvm/test/Transforms/InstCombine/min-zext.ll @@ -1,12 +1,12 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s define i32 @test_smin(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_smin( -; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) -; CHECK-NEXT: %v1 = add nsw i32 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) -; CHECK-NEXT: %v3 = sub i32 %v2, %v0 -; CHECK-NEXT: ret i32 %v3 +; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[ARG0]], [[ARG1]] +; CHECK-NEXT: [[V3:%.*]] = zext i1 [[TMP1]] to i32 +; CHECK-NEXT: ret i32 [[V3]] ; %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) %v1 = add nsw i32 %arg0, 1 @@ -17,11 +17,10 @@ define i32 @test_smin(i32 %arg0, i32 %arg1) { define i32 @test_umin(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_umin( -; CHECK-NEXT: %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) -; CHECK-NEXT: %v1 = add nuw i32 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 %arg1) -; CHECK-NEXT: %v3 = sub i32 %v2, %v0 -; CHECK-NEXT: ret i32 %v3 +; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[ARG0]], [[ARG1]] +; CHECK-NEXT: [[V3:%.*]] = zext i1 [[TMP1]] to i32 +; CHECK-NEXT: ret i32 [[V3]] ; %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) %v1 = add nuw i32 %arg0, 1 @@ -32,9 +31,10 @@ define i32 @test_umin(i32 %arg0, i32 %arg1) { define i1 @test_smin_i1(i1 %arg0, i1 %arg1) { ; CHECK-LABEL: define i1 @test_smin_i1( -; CHECK-NEXT: %v0 = or i1 %arg0, %arg1 -; CHECK-NEXT: %v3 = xor i1 %v0, true -; CHECK-NEXT: ret i1 %v3 +; CHECK-SAME: i1 [[ARG0:%.*]], i1 [[ARG1:%.*]]) { +; CHECK-NEXT: [[V0:%.*]] = or i1 [[ARG0]], [[ARG1]] +; CHECK-NEXT: [[V3:%.*]] = xor i1 [[V0]], true +; CHECK-NEXT: ret i1 [[V3]] ; %v0 = tail call i1 @llvm.smin.i1(i1 %arg0, i1 %arg1) %v1 = add nsw i1 %arg0, 1 @@ -47,47 +47,50 @@ declare void @use(i2) define i2 @test_smin_use_operands(i2 %arg0, i2 %arg1) { ; CHECK-LABEL: define i2 @test_smin_use_operands( -; CHECK-NEXT: %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) -; CHECK-NEXT: %v1 = add nsw i2 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) -; CHECK-NEXT: %v3 = sub i2 %v2, %v0 -; CHECK-NEXT: call void @use(i2 %v2) -; CHECK-NEXT: call void @use(i2 %v0) -; CHECK-NEXT: ret i2 %v3 +; CHECK-SAME: i2 [[ARG0:%.*]], i2 [[ARG1:%.*]]) { +; CHECK-NEXT: [[V0:%.*]] = tail call i2 @llvm.smin.i2(i2 [[ARG0]], i2 [[ARG1]]) +; CHECK-NEXT: [[V1:%.*]] = add nsw i2 [[ARG0]], 1 +; CHECK-NEXT: [[V2:%.*]] = tail call i2 @llvm.smin.i2(i2 [[V1]], i2 [[ARG1]]) +; CHECK-NEXT: [[V3:%.*]] = sub i2 [[V2]], [[V0]] +; CHECK-NEXT: call void @use(i2 [[V2]]) +; CHECK-NEXT: call void @use(i2 [[V0]]) +; CHECK-NEXT: ret i2 [[V3]] ; %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) %v1 = add nsw i2 %arg0, 1 %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) - %v3 = sub i2 %v2, %v0 + %v3 = sub i2 %v2, %v0 call void @use(i2 %v2) call void @use(i2 %v0) - ret i2 %v3 + ret i2 %v3 } define i2 @test_smin_use_operand(i2 %arg0, i2 %arg1) { ; CHECK-LABEL: define i2 @test_smin_use_operand( -; CHECK-NEXT: %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) -; CHECK-NEXT: %v1 = add nsw i2 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) -; CHECK-NEXT: %v3 = sub i2 %v2, %v0 -; CHECK-NEXT: call void @use(i2 %v2) -; CHECK-NEXT: ret i2 %v3 +; CHECK-SAME: i2 [[ARG0:%.*]], i2 [[ARG1:%.*]]) { +; CHECK-NEXT: [[V1:%.*]] = add nsw i2 [[ARG0]], 1 +; CHECK-NEXT: [[V2:%.*]] = tail call i2 @llvm.smin.i2(i2 [[V1]], i2 [[ARG1]]) +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i2 [[ARG0]], [[ARG1]] +; CHECK-NEXT: [[V3:%.*]] = zext i1 [[TMP1]] to i2 +; CHECK-NEXT: call void @use(i2 [[V2]]) +; CHECK-NEXT: ret i2 [[V3]] ; %v0 = tail call i2 @llvm.smin.i2(i2 %arg0, i2 %arg1) %v1 = add nsw i2 %arg0, 1 %v2 = tail call i2 @llvm.smin.i2(i2 %v1, i2 %arg1) - %v3 = sub i2 %v2, %v0 + %v3 = sub i2 %v2, %v0 call void @use(i2 %v2) - ret i2 %v3 + ret i2 %v3 } define i32 @test_smin_missing_nsw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_smin_missing_nsw( -; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) -; CHECK-NEXT: %v1 = add i32 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) -; CHECK-NEXT: %v3 = sub i32 %v2, %v0 -; CHECK-NEXT: ret i32 %v3 +; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { +; CHECK-NEXT: [[V0:%.*]] = tail call i32 @llvm.smin.i32(i32 [[ARG0]], i32 [[ARG1]]) +; CHECK-NEXT: [[V1:%.*]] = add i32 [[ARG0]], 1 +; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 [[ARG1]]) +; CHECK-NEXT: [[V3:%.*]] = sub i32 [[V2]], [[V0]] +; CHECK-NEXT: ret i32 [[V3]] ; %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) %v1 = add i32 %arg0, 1 @@ -98,11 +101,12 @@ define i32 @test_smin_missing_nsw(i32 %arg0, i32 %arg1) { define i32 @test_umin_missing_nuw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_umin_missing_nuw( -; CHECK-NEXT: %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) -; CHECK-NEXT: %v1 = add i32 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i32 @llvm.umin.i32(i32 %v1, i32 %arg1) -; CHECK-NEXT: %v3 = sub i32 %v2, %v0 -; CHECK-NEXT: ret i32 %v3 +; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { +; CHECK-NEXT: [[V0:%.*]] = tail call i32 @llvm.umin.i32(i32 [[ARG0]], i32 [[ARG1]]) +; CHECK-NEXT: [[V1:%.*]] = add i32 [[ARG0]], 1 +; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.umin.i32(i32 [[V1]], i32 [[ARG1]]) +; CHECK-NEXT: [[V3:%.*]] = sub i32 [[V2]], [[V0]] +; CHECK-NEXT: ret i32 [[V3]] ; %v0 = tail call i32 @llvm.umin.i32(i32 %arg0, i32 %arg1) %v1 = add i32 %arg0, 1 @@ -115,28 +119,28 @@ define i32 @test_umin_missing_nuw(i32 %arg0, i32 %arg1) { define i32 @test_mismatched_operands(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_mismatched_operands( -; CHECK-NEXT: %tmp = load i32, ptr @tmp, align 4 -; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %tmp) -; CHECK-NEXT: %v1 = add nsw i32 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) -; CHECK-NEXT: %v3 = sub i32 %v0, %v2 -; CHECK-NEXT: ret i32 %v3 +; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { +; CHECK-NEXT: [[TMP:%.*]] = load i32, ptr @tmp, align 4 +; CHECK-NEXT: [[V0:%.*]] = tail call i32 @llvm.smin.i32(i32 [[ARG0]], i32 [[TMP]]) +; CHECK-NEXT: [[V1:%.*]] = add nsw i32 [[ARG0]], 1 +; CHECK-NEXT: [[V2:%.*]] = tail call i32 @llvm.smin.i32(i32 [[V1]], i32 [[ARG1]]) +; CHECK-NEXT: [[V3:%.*]] = sub i32 [[V2]], [[V0]] +; CHECK-NEXT: ret i32 [[V3]] ; %tmp = load i32, ptr @tmp, align 4 %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %tmp) %v1 = add nsw i32 %arg0, 1 %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) %v3 = sub i32 %v2, %v0 - ret i32 %v3 + ret i32 %v3 } define i32 @test_disjoint_or(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i32 @test_disjoint_or( -; CHECK-NEXT: %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) -; CHECK-NEXT: %v1 = or disjoint i32 %arg0, 1 -; CHECK-NEXT: %v2 = tail call i32 @llvm.smin.i32(i32 %v1, i32 %arg1) -; CHECK-NEXT: %v3 = sub i32 %v2, %v0 -; CHECK-NEXT: ret i32 %v3 +; CHECK-SAME: i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[ARG0]], [[ARG1]] +; CHECK-NEXT: [[V3:%.*]] = zext i1 [[TMP1]] to i32 +; CHECK-NEXT: ret i32 [[V3]] ; %v0 = tail call i32 @llvm.smin.i32(i32 %arg0, i32 %arg1) %v1 = or disjoint i32 %arg0, 1