From 884ef85b3f95c86bae2d627e600bca63061210e9 Mon Sep 17 00:00:00 2001 From: Philip Reames Date: Wed, 30 Jun 2021 10:18:38 -0700 Subject: [PATCH] [instcombine] umin(x, 1) == zext(x != 0) We already implemented this for the select form, but the intrinsic form was missing. Note that this doesn't change poison behavior as 1 is non-poison, and the optimized form is still poison exactly when x is. --- .../InstCombine/InstCombineCalls.cpp | 11 ++++- .../InstCombine/minmax-intrinsics.ll | 41 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/lib/Transforms/InstCombine/InstCombineCalls.cpp b/lib/Transforms/InstCombine/InstCombineCalls.cpp index 552de8b072e..5060b45ad6b 100644 --- a/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -956,8 +956,17 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) { break; } - case Intrinsic::umax: case Intrinsic::umin: { + Value *I0 = II->getArgOperand(0), *I1 = II->getArgOperand(1); + // umin(x, 1) == zext(x != 0) + if (match(I1, m_One())) { + Value *Zero = Constant::getNullValue(I0->getType()); + Value *Cmp = Builder.CreateICmpNE(I0, Zero); + return CastInst::Create(Instruction::ZExt, Cmp, II->getType()); + } + LLVM_FALLTHROUGH; + } + case Intrinsic::umax: { Value *I0 = II->getArgOperand(0), *I1 = II->getArgOperand(1); Value *X, *Y; if (match(I0, m_ZExt(m_Value(X))) && match(I1, m_ZExt(m_Value(Y))) && diff --git a/test/Transforms/InstCombine/minmax-intrinsics.ll b/test/Transforms/InstCombine/minmax-intrinsics.ll index 3b2279a92bf..0dd429cb589 100644 --- a/test/Transforms/InstCombine/minmax-intrinsics.ll +++ b/test/Transforms/InstCombine/minmax-intrinsics.ll @@ -817,3 +817,44 @@ define i8 @clamp_two_vals_smin_smax_edge(i8 %x) { %r = call i8 @llvm.smax.i8(i8 %m, i8 127) ret i8 %r } + + +define i8 @umin_non_zero_idiom1(i8 %a) { +; CHECK-LABEL: @umin_non_zero_idiom1( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i8 [[A:%.*]], 0 +; CHECK-NEXT: [[RES:%.*]] = zext i1 [[TMP1]] to i8 +; CHECK-NEXT: ret i8 [[RES]] +; + %res = call i8 @llvm.umin.i8(i8 %a, i8 1) + ret i8 %res +} + +define i8 @umin_non_zero_idiom2(i8 %a) { +; CHECK-LABEL: @umin_non_zero_idiom2( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i8 [[A:%.*]], 0 +; CHECK-NEXT: [[RES:%.*]] = zext i1 [[TMP1]] to i8 +; CHECK-NEXT: ret i8 [[RES]] +; + %res = call i8 @llvm.umin.i8(i8 1, i8 %a) + ret i8 %res +} + +define <3 x i8> @umin_non_zero_idiom3(<3 x i8> %a) { +; CHECK-LABEL: @umin_non_zero_idiom3( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <3 x i8> [[A:%.*]], zeroinitializer +; CHECK-NEXT: [[RES:%.*]] = zext <3 x i1> [[TMP1]] to <3 x i8> +; CHECK-NEXT: ret <3 x i8> [[RES]] +; + %res = call <3 x i8> @llvm.umin.v3i8(<3 x i8> %a, <3 x i8> ) + ret <3 x i8> %res +} + +define <3 x i8> @umin_non_zero_idiom4(<3 x i8> %a) { +; CHECK-LABEL: @umin_non_zero_idiom4( +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <3 x i8> [[A:%.*]], zeroinitializer +; CHECK-NEXT: [[RES:%.*]] = zext <3 x i1> [[TMP1]] to <3 x i8> +; CHECK-NEXT: ret <3 x i8> [[RES]] +; + %res = call <3 x i8> @llvm.umin.v3i8(<3 x i8> %a, <3 x i8> ) + ret <3 x i8> %res +}