diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index 63f2fd0a733ce..12dd4cec85f59 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1554,7 +1554,11 @@ static bool leftDistributesOverRight(Instruction::BinaryOps LOp, bool HasNUW, switch (ROp) { case Intrinsic::umax: case Intrinsic::umin: - return HasNUW && LOp == Instruction::Add; + if (HasNUW && LOp == Instruction::Add) + return true; + if (HasNUW && LOp == Instruction::Shl) + return true; + return false; case Intrinsic::smax: case Intrinsic::smin: return HasNSW && LOp == Instruction::Add; @@ -1592,29 +1596,37 @@ foldIntrinsicUsingDistributiveLaws(IntrinsicInst *II, if (!leftDistributesOverRight(InnerOpcode, HasNUW, HasNSW, TopLevelOpcode)) return nullptr; - assert(II->isCommutative() && Op0->isCommutative() && - "Only inner and outer commutative op codes are supported."); - Value *A = Op0->getOperand(0); Value *B = Op0->getOperand(1); Value *C = Op1->getOperand(0); Value *D = Op1->getOperand(1); - // Attempts to swap variables such that A always equals C - if (A != C && A != D) - std::swap(A, B); - if (A == C || A == D) { - if (A != C) + // Attempts to swap variables such that A equals C or B equals D, + // if the inner operation is commutative. + if (Op0->isCommutative() && A != C && B != D) { + if (A == D || B == C) std::swap(C, D); + else + return nullptr; + } + + BinaryOperator *NewBinop; + if (A == C) { Value *NewIntrinsic = Builder.CreateBinaryIntrinsic(TopLevelOpcode, B, D); - BinaryOperator *NewBinop = - cast(Builder.CreateBinOp(InnerOpcode, NewIntrinsic, A)); - NewBinop->setHasNoSignedWrap(HasNSW); - NewBinop->setHasNoUnsignedWrap(HasNUW); - return NewBinop; + NewBinop = + cast(Builder.CreateBinOp(InnerOpcode, A, NewIntrinsic)); + } else if (B == D) { + Value *NewIntrinsic = Builder.CreateBinaryIntrinsic(TopLevelOpcode, A, C); + NewBinop = + cast(Builder.CreateBinOp(InnerOpcode, NewIntrinsic, B)); + } else { + return nullptr; } - return nullptr; + NewBinop->setHasNoUnsignedWrap(HasNUW); + NewBinop->setHasNoSignedWrap(HasNSW); + + return NewBinop; } /// CallInst simplification. This mostly only handles folding of intrinsic @@ -1887,6 +1899,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) { if (Instruction *I = foldMaxMulShift(I1, I0)) return I; } + // If both operands of unsigned min/max are sign-extended, it is still ok // to narrow the operation. [[fallthrough]]; diff --git a/llvm/test/Transforms/InstCombine/div-shift.ll b/llvm/test/Transforms/InstCombine/div-shift.ll index af83f37011ba0..fd857b983a788 100644 --- a/llvm/test/Transforms/InstCombine/div-shift.ll +++ b/llvm/test/Transforms/InstCombine/div-shift.ll @@ -144,11 +144,9 @@ define i8 @udiv_umin_(i8 %x, i8 %y, i8 %z) { ; Negative test, extra use define i8 @udiv_umin_extra_use(i8 %x, i8 %y, i8 %z) { ; CHECK-LABEL: @udiv_umin_extra_use( -; CHECK-NEXT: [[Y2:%.*]] = shl nuw i8 1, [[Y:%.*]] -; CHECK-NEXT: [[Z2:%.*]] = shl nuw i8 1, [[Z:%.*]] -; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[Y2]], i8 [[Z2]]) +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[Y:%.*]], i8 [[Z:%.*]]) +; CHECK-NEXT: [[M:%.*]] = shl nuw i8 1, [[TMP1]] ; CHECK-NEXT: call void @use(i8 [[M]]) -; CHECK-NEXT: [[TMP1:%.*]] = call range(i8 0, 9) i8 @llvm.cttz.i8(i8 [[M]], i1 true) ; CHECK-NEXT: [[D:%.*]] = lshr i8 [[X:%.*]], [[TMP1]] ; CHECK-NEXT: ret i8 [[D]] ; diff --git a/llvm/test/Transforms/InstCombine/intrinsic-distributive.ll b/llvm/test/Transforms/InstCombine/intrinsic-distributive.ll index 2284e3f6c174b..630d4ee4d4221 100644 --- a/llvm/test/Transforms/InstCombine/intrinsic-distributive.ll +++ b/llvm/test/Transforms/InstCombine/intrinsic-distributive.ll @@ -2,8 +2,8 @@ ; RUN: opt -S -passes=instcombine < %s 2>&1 | FileCheck %s -define i8 @umax_of_add_nuw(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @umax_of_add_nuw( +define i8 @umax_of_add_nuw_r(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @umax_of_add_nuw_r( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[B]], i8 [[C]]) ; CHECK-NEXT: [[MAX:%.*]] = add nuw i8 [[TMP1]], [[A]] @@ -15,6 +15,19 @@ define i8 @umax_of_add_nuw(i8 %a, i8 %b, i8 %c) { ret i8 %max } +define i8 @umax_of_add_nuw_l(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @umax_of_add_nuw_l( +; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[B]], i8 [[C]]) +; CHECK-NEXT: [[MAX:%.*]] = add nuw i8 [[A]], [[TMP1]] +; CHECK-NEXT: ret i8 [[MAX]] +; + %add1 = add nuw i8 %a, %b + %add2 = add nuw i8 %a, %c + %max = call i8 @llvm.umax.i8(i8 %add1, i8 %add2) + ret i8 %max +} + define i8 @umax_of_add_nuw_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-LABEL: define i8 @umax_of_add_nuw_comm( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { @@ -22,14 +35,14 @@ define i8 @umax_of_add_nuw_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-NEXT: [[MAX:%.*]] = add nuw i8 [[TMP1]], [[A]] ; CHECK-NEXT: ret i8 [[MAX]] ; - %add1 = add nuw i8 %a, %b + %add1 = add nuw i8 %b, %a %add2 = add nuw i8 %a, %c %max = call i8 @llvm.umax.i8(i8 %add1, i8 %add2) ret i8 %max } -define i8 @umax_of_add_nuw_nsw_lhs(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @umax_of_add_nuw_nsw_lhs( +define i8 @umax_of_add_nuw_nsw_lhs_r(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @umax_of_add_nuw_nsw_lhs_r( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[B]], i8 [[C]]) ; CHECK-NEXT: [[MAX:%.*]] = add nuw i8 [[TMP1]], [[A]] @@ -41,21 +54,34 @@ define i8 @umax_of_add_nuw_nsw_lhs(i8 %a, i8 %b, i8 %c) { ret i8 %max } +define i8 @umax_of_add_nuw_nsw_lhs_l(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @umax_of_add_nuw_nsw_lhs_l( +; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[B]], i8 [[C]]) +; CHECK-NEXT: [[MAX:%.*]] = add nuw i8 [[A]], [[TMP1]] +; CHECK-NEXT: ret i8 [[MAX]] +; + %add1 = add nuw nsw i8 %a, %b + %add2 = add nuw i8 %a, %c + %max = call i8 @llvm.umax.i8(i8 %add1, i8 %add2) + ret i8 %max +} + define i8 @umax_of_add_nuw_nsw_lhs_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-LABEL: define i8 @umax_of_add_nuw_nsw_lhs_comm( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[B]], i8 [[C]]) -; CHECK-NEXT: [[MAX:%.*]] = add nuw i8 [[TMP1]], [[A]] +; CHECK-NEXT: [[MAX:%.*]] = add nuw i8 [[A]], [[TMP1]] ; CHECK-NEXT: ret i8 [[MAX]] ; %add1 = add nuw nsw i8 %a, %b - %add2 = add nuw i8 %a, %c + %add2 = add nuw i8 %c, %a %max = call i8 @llvm.umax.i8(i8 %add1, i8 %add2) ret i8 %max } -define i8 @umax_of_add_nuw_nsw_rhs(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @umax_of_add_nuw_nsw_rhs( +define i8 @umax_of_add_nuw_nsw_rhs_r(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @umax_of_add_nuw_nsw_rhs_r( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[B]], i8 [[C]]) ; CHECK-NEXT: [[MAX:%.*]] = add nuw i8 [[TMP1]], [[A]] @@ -67,6 +93,19 @@ define i8 @umax_of_add_nuw_nsw_rhs(i8 %a, i8 %b, i8 %c) { ret i8 %max } +define i8 @umax_of_add_nuw_nsw_rhs_l(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @umax_of_add_nuw_nsw_rhs_l( +; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[B]], i8 [[C]]) +; CHECK-NEXT: [[MAX:%.*]] = add nuw i8 [[A]], [[TMP1]] +; CHECK-NEXT: ret i8 [[MAX]] +; + %add1 = add nuw i8 %a, %b + %add2 = add nuw nsw i8 %a, %c + %max = call i8 @llvm.umax.i8(i8 %add1, i8 %add2) + ret i8 %max +} + define i8 @umax_of_add_nuw_nsw_rhs_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-LABEL: define i8 @umax_of_add_nuw_nsw_rhs_comm( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { @@ -74,14 +113,14 @@ define i8 @umax_of_add_nuw_nsw_rhs_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-NEXT: [[MAX:%.*]] = add nuw i8 [[TMP1]], [[A]] ; CHECK-NEXT: ret i8 [[MAX]] ; - %add1 = add nuw i8 %a, %b + %add1 = add nuw i8 %b, %a %add2 = add nuw nsw i8 %a, %c %max = call i8 @llvm.umax.i8(i8 %add1, i8 %add2) ret i8 %max } -define i8 @umax_of_add_nuw_nsw(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @umax_of_add_nuw_nsw( +define i8 @umax_of_add_nuw_nsw_r(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @umax_of_add_nuw_nsw_r( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[B]], i8 [[C]]) ; CHECK-NEXT: [[MAX:%.*]] = add nuw nsw i8 [[TMP1]], [[A]] @@ -93,15 +132,28 @@ define i8 @umax_of_add_nuw_nsw(i8 %a, i8 %b, i8 %c) { ret i8 %max } +define i8 @umax_of_add_nuw_nsw_l(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @umax_of_add_nuw_nsw_l( +; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[B]], i8 [[C]]) +; CHECK-NEXT: [[MAX:%.*]] = add nuw nsw i8 [[A]], [[TMP1]] +; CHECK-NEXT: ret i8 [[MAX]] +; + %add1 = add nuw nsw i8 %a, %b + %add2 = add nuw nsw i8 %a, %c + %max = call i8 @llvm.umax.i8(i8 %add1, i8 %add2) + ret i8 %max +} + define i8 @umax_of_add_nuw_nsw_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-LABEL: define i8 @umax_of_add_nuw_nsw_comm( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[B]], i8 [[C]]) -; CHECK-NEXT: [[MAX:%.*]] = add nuw nsw i8 [[TMP1]], [[A]] +; CHECK-NEXT: [[MAX:%.*]] = add nuw nsw i8 [[A]], [[TMP1]] ; CHECK-NEXT: ret i8 [[MAX]] ; %add1 = add nuw nsw i8 %a, %b - %add2 = add nuw nsw i8 %a, %c + %add2 = add nuw nsw i8 %c, %a %max = call i8 @llvm.umax.i8(i8 %add1, i8 %add2) ret i8 %max } @@ -136,8 +188,8 @@ define i8 @umax_of_add(i8 %a, i8 %b, i8 %c) { ret i8 %max } -define i8 @umin_of_add_nuw(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @umin_of_add_nuw( +define i8 @umin_of_add_nuw_r(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @umin_of_add_nuw_r( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[B]], i8 [[C]]) ; CHECK-NEXT: [[MIN:%.*]] = add nuw i8 [[TMP1]], [[A]] @@ -149,6 +201,19 @@ define i8 @umin_of_add_nuw(i8 %a, i8 %b, i8 %c) { ret i8 %min } +define i8 @umin_of_add_nuw_l(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @umin_of_add_nuw_l( +; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[B]], i8 [[C]]) +; CHECK-NEXT: [[MIN:%.*]] = add nuw i8 [[A]], [[TMP1]] +; CHECK-NEXT: ret i8 [[MIN]] +; + %add1 = add nuw i8 %a, %b + %add2 = add nuw i8 %a, %c + %min = call i8 @llvm.umin.i8(i8 %add1, i8 %add2) + ret i8 %min +} + define i8 @umin_of_add_nuw_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-LABEL: define i8 @umin_of_add_nuw_comm( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { @@ -156,14 +221,14 @@ define i8 @umin_of_add_nuw_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-NEXT: [[MIN:%.*]] = add nuw i8 [[TMP1]], [[A]] ; CHECK-NEXT: ret i8 [[MIN]] ; - %add1 = add nuw i8 %a, %b + %add1 = add nuw i8 %b, %a %add2 = add nuw i8 %a, %c %min = call i8 @llvm.umin.i8(i8 %add1, i8 %add2) ret i8 %min } -define i8 @umin_of_add_nuw_nsw_lhs(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @umin_of_add_nuw_nsw_lhs( +define i8 @umin_of_add_nuw_nsw_lhs_r(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @umin_of_add_nuw_nsw_lhs_r( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[B]], i8 [[C]]) ; CHECK-NEXT: [[MIN:%.*]] = add nuw i8 [[TMP1]], [[A]] @@ -175,21 +240,34 @@ define i8 @umin_of_add_nuw_nsw_lhs(i8 %a, i8 %b, i8 %c) { ret i8 %min } +define i8 @umin_of_add_nuw_nsw_lhs_l(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @umin_of_add_nuw_nsw_lhs_l( +; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[B]], i8 [[C]]) +; CHECK-NEXT: [[MIN:%.*]] = add nuw i8 [[A]], [[TMP1]] +; CHECK-NEXT: ret i8 [[MIN]] +; + %add1 = add nuw nsw i8 %a, %b + %add2 = add nuw i8 %a, %c + %min = call i8 @llvm.umin.i8(i8 %add1, i8 %add2) + ret i8 %min +} + define i8 @umin_of_add_nuw_nsw_lhs_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-LABEL: define i8 @umin_of_add_nuw_nsw_lhs_comm( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[B]], i8 [[C]]) -; CHECK-NEXT: [[MIN:%.*]] = add nuw i8 [[TMP1]], [[A]] +; CHECK-NEXT: [[MIN:%.*]] = add nuw i8 [[A]], [[TMP1]] ; CHECK-NEXT: ret i8 [[MIN]] ; %add1 = add nuw nsw i8 %a, %b - %add2 = add nuw i8 %a, %c + %add2 = add nuw i8 %c, %a %min = call i8 @llvm.umin.i8(i8 %add1, i8 %add2) ret i8 %min } -define i8 @umin_of_add_nuw_nsw_rhs(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @umin_of_add_nuw_nsw_rhs( +define i8 @umin_of_add_nuw_nsw_rhs_r(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @umin_of_add_nuw_nsw_rhs_r( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[B]], i8 [[C]]) ; CHECK-NEXT: [[MIN:%.*]] = add nuw i8 [[TMP1]], [[A]] @@ -201,6 +279,19 @@ define i8 @umin_of_add_nuw_nsw_rhs(i8 %a, i8 %b, i8 %c) { ret i8 %min } +define i8 @umin_of_add_nuw_nsw_rhs_l(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @umin_of_add_nuw_nsw_rhs_l( +; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[B]], i8 [[C]]) +; CHECK-NEXT: [[MIN:%.*]] = add nuw i8 [[A]], [[TMP1]] +; CHECK-NEXT: ret i8 [[MIN]] +; + %add1 = add nuw i8 %a, %b + %add2 = add nuw nsw i8 %a, %c + %min = call i8 @llvm.umin.i8(i8 %add1, i8 %add2) + ret i8 %min +} + define i8 @umin_of_add_nuw_nsw_rhs_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-LABEL: define i8 @umin_of_add_nuw_nsw_rhs_comm( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { @@ -208,14 +299,14 @@ define i8 @umin_of_add_nuw_nsw_rhs_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-NEXT: [[MIN:%.*]] = add nuw i8 [[TMP1]], [[A]] ; CHECK-NEXT: ret i8 [[MIN]] ; - %add1 = add nuw i8 %a, %b + %add1 = add nuw i8 %b, %a %add2 = add nuw nsw i8 %a, %c %min = call i8 @llvm.umin.i8(i8 %add1, i8 %add2) ret i8 %min } -define i8 @umin_of_add_nuw_nsw(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @umin_of_add_nuw_nsw( +define i8 @umin_of_add_nuw_nsw_r(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @umin_of_add_nuw_nsw_r( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[B]], i8 [[C]]) ; CHECK-NEXT: [[MIN:%.*]] = add nuw nsw i8 [[TMP1]], [[A]] @@ -227,15 +318,28 @@ define i8 @umin_of_add_nuw_nsw(i8 %a, i8 %b, i8 %c) { ret i8 %min } +define i8 @umin_of_add_nuw_nsw_l(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @umin_of_add_nuw_nsw_l( +; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[B]], i8 [[C]]) +; CHECK-NEXT: [[MIN:%.*]] = add nuw nsw i8 [[A]], [[TMP1]] +; CHECK-NEXT: ret i8 [[MIN]] +; + %add1 = add nuw nsw i8 %a, %b + %add2 = add nuw nsw i8 %a, %c + %min = call i8 @llvm.umin.i8(i8 %add1, i8 %add2) + ret i8 %min +} + define i8 @umin_of_add_nuw_nsw_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-LABEL: define i8 @umin_of_add_nuw_nsw_comm( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[B]], i8 [[C]]) -; CHECK-NEXT: [[MIN:%.*]] = add nuw nsw i8 [[TMP1]], [[A]] +; CHECK-NEXT: [[MIN:%.*]] = add nuw nsw i8 [[A]], [[TMP1]] ; CHECK-NEXT: ret i8 [[MIN]] ; %add1 = add nuw nsw i8 %a, %b - %add2 = add nuw nsw i8 %a, %c + %add2 = add nuw nsw i8 %c, %a %min = call i8 @llvm.umin.i8(i8 %add1, i8 %add2) ret i8 %min } @@ -285,8 +389,8 @@ define i8 @smax_of_add_nuw(i8 %a, i8 %b, i8 %c) { ret i8 %max } -define i8 @smax_of_add_nsw(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @smax_of_add_nsw( +define i8 @smax_of_add_nsw_r(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smax_of_add_nsw_r( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[B]], i8 [[C]]) ; CHECK-NEXT: [[MAX:%.*]] = add nsw i8 [[TMP1]], [[A]] @@ -298,6 +402,19 @@ define i8 @smax_of_add_nsw(i8 %a, i8 %b, i8 %c) { ret i8 %max } +define i8 @smax_of_add_nsw_l(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smax_of_add_nsw_l( +; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[B]], i8 [[C]]) +; CHECK-NEXT: [[MAX:%.*]] = add nsw i8 [[A]], [[TMP1]] +; CHECK-NEXT: ret i8 [[MAX]] +; + %add1 = add nsw i8 %a, %b + %add2 = add nsw i8 %a, %c + %max = call i8 @llvm.smax.i8(i8 %add1, i8 %add2) + ret i8 %max +} + define i8 @smax_of_add_nsw_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-LABEL: define i8 @smax_of_add_nsw_comm( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { @@ -305,14 +422,14 @@ define i8 @smax_of_add_nsw_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-NEXT: [[MAX:%.*]] = add nsw i8 [[TMP1]], [[A]] ; CHECK-NEXT: ret i8 [[MAX]] ; - %add1 = add nsw i8 %a, %b + %add1 = add nsw i8 %b, %a %add2 = add nsw i8 %a, %c %max = call i8 @llvm.smax.i8(i8 %add1, i8 %add2) ret i8 %max } -define i8 @smax_of_add_nsw_nuw_lhs(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @smax_of_add_nsw_nuw_lhs( +define i8 @smax_of_add_nsw_nuw_lhs_r(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smax_of_add_nsw_nuw_lhs_r( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[B]], i8 [[C]]) ; CHECK-NEXT: [[MAX:%.*]] = add nsw i8 [[TMP1]], [[A]] @@ -324,11 +441,11 @@ define i8 @smax_of_add_nsw_nuw_lhs(i8 %a, i8 %b, i8 %c) { ret i8 %max } -define i8 @smax_of_add_nsw_nuw_lhs_comm(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @smax_of_add_nsw_nuw_lhs_comm( +define i8 @smax_of_add_nsw_nuw_lhs_l(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smax_of_add_nsw_nuw_lhs_l( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[B]], i8 [[C]]) -; CHECK-NEXT: [[MAX:%.*]] = add nsw i8 [[TMP1]], [[A]] +; CHECK-NEXT: [[MAX:%.*]] = add nsw i8 [[A]], [[TMP1]] ; CHECK-NEXT: ret i8 [[MAX]] ; %add1 = add nsw nuw i8 %a, %b @@ -337,8 +454,21 @@ define i8 @smax_of_add_nsw_nuw_lhs_comm(i8 %a, i8 %b, i8 %c) { ret i8 %max } -define i8 @smax_of_add_nsw_nuw_rhs(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @smax_of_add_nsw_nuw_rhs( +define i8 @smax_of_add_nsw_nuw_lhs_comm(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smax_of_add_nsw_nuw_lhs_comm( +; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[B]], i8 [[C]]) +; CHECK-NEXT: [[MAX:%.*]] = add nsw i8 [[A]], [[TMP1]] +; CHECK-NEXT: ret i8 [[MAX]] +; + %add1 = add nuw nsw i8 %a, %b + %add2 = add nsw i8 %c, %a + %max = call i8 @llvm.smax.i8(i8 %add1, i8 %add2) + ret i8 %max +} + +define i8 @smax_of_add_nsw_nuw_rhs_r(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smax_of_add_nsw_nuw_rhs_r( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[B]], i8 [[C]]) ; CHECK-NEXT: [[MAX:%.*]] = add nsw i8 [[TMP1]], [[A]] @@ -350,6 +480,19 @@ define i8 @smax_of_add_nsw_nuw_rhs(i8 %a, i8 %b, i8 %c) { ret i8 %max } +define i8 @smax_of_add_nsw_nuw_rhs_l(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smax_of_add_nsw_nuw_rhs_l( +; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[B]], i8 [[C]]) +; CHECK-NEXT: [[MAX:%.*]] = add nsw i8 [[A]], [[TMP1]] +; CHECK-NEXT: ret i8 [[MAX]] +; + %add1 = add nsw i8 %a, %b + %add2 = add nsw nuw i8 %a, %c + %max = call i8 @llvm.smax.i8(i8 %add1, i8 %add2) + ret i8 %max +} + define i8 @smax_of_add_nsw_nuw_rhs_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-LABEL: define i8 @smax_of_add_nsw_nuw_rhs_comm( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { @@ -357,14 +500,14 @@ define i8 @smax_of_add_nsw_nuw_rhs_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-NEXT: [[MAX:%.*]] = add nsw i8 [[TMP1]], [[A]] ; CHECK-NEXT: ret i8 [[MAX]] ; - %add1 = add nsw i8 %a, %b + %add1 = add nsw i8 %b, %a %add2 = add nsw nuw i8 %a, %c %max = call i8 @llvm.smax.i8(i8 %add1, i8 %add2) ret i8 %max } -define i8 @smax_of_add_nsw_nuw(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @smax_of_add_nsw_nuw( +define i8 @smax_of_add_nsw_nuw_r(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smax_of_add_nsw_nuw_r( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[B]], i8 [[C]]) ; CHECK-NEXT: [[MAX:%.*]] = add nuw nsw i8 [[TMP1]], [[A]] @@ -376,15 +519,28 @@ define i8 @smax_of_add_nsw_nuw(i8 %a, i8 %b, i8 %c) { ret i8 %max } +define i8 @smax_of_add_nsw_nuw_l(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smax_of_add_nsw_nuw_l( +; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[B]], i8 [[C]]) +; CHECK-NEXT: [[MAX:%.*]] = add nuw nsw i8 [[A]], [[TMP1]] +; CHECK-NEXT: ret i8 [[MAX]] +; + %add1 = add nsw nuw i8 %a, %b + %add2 = add nsw nuw i8 %a, %c + %max = call i8 @llvm.smax.i8(i8 %add1, i8 %add2) + ret i8 %max +} + define i8 @smax_of_add_nsw_nuw_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-LABEL: define i8 @smax_of_add_nsw_nuw_comm( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[B]], i8 [[C]]) -; CHECK-NEXT: [[MAX:%.*]] = add nuw nsw i8 [[TMP1]], [[A]] +; CHECK-NEXT: [[MAX:%.*]] = add nuw nsw i8 [[A]], [[TMP1]] ; CHECK-NEXT: ret i8 [[MAX]] ; %add1 = add nsw nuw i8 %a, %b - %add2 = add nsw nuw i8 %a, %c + %add2 = add nsw nuw i8 %c, %a %max = call i8 @llvm.smax.i8(i8 %add1, i8 %add2) ret i8 %max } @@ -419,8 +575,8 @@ define i8 @smin_of_add_nuw(i8 %a, i8 %b, i8 %c) { ret i8 %min } -define i8 @smin_of_add_nsw(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @smin_of_add_nsw( +define i8 @smin_of_add_nsw_r(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smin_of_add_nsw_r( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[B]], i8 [[C]]) ; CHECK-NEXT: [[MIN:%.*]] = add nsw i8 [[TMP1]], [[A]] @@ -432,6 +588,19 @@ define i8 @smin_of_add_nsw(i8 %a, i8 %b, i8 %c) { ret i8 %min } +define i8 @smin_of_add_nsw_l(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smin_of_add_nsw_l( +; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[B]], i8 [[C]]) +; CHECK-NEXT: [[MIN:%.*]] = add nsw i8 [[A]], [[TMP1]] +; CHECK-NEXT: ret i8 [[MIN]] +; + %add1 = add nsw i8 %a, %b + %add2 = add nsw i8 %a, %c + %min = call i8 @llvm.smin.i8(i8 %add1, i8 %add2) + ret i8 %min +} + define i8 @smin_of_add_nsw_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-LABEL: define i8 @smin_of_add_nsw_comm( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { @@ -439,14 +608,14 @@ define i8 @smin_of_add_nsw_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-NEXT: [[MIN:%.*]] = add nsw i8 [[TMP1]], [[A]] ; CHECK-NEXT: ret i8 [[MIN]] ; - %add1 = add nsw i8 %a, %b + %add1 = add nsw i8 %b, %a %add2 = add nsw i8 %a, %c %min = call i8 @llvm.smin.i8(i8 %add1, i8 %add2) ret i8 %min } -define i8 @smin_of_add_nsw_nuw_lhs(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @smin_of_add_nsw_nuw_lhs( +define i8 @smin_of_add_nsw_nuw_lhs_r(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smin_of_add_nsw_nuw_lhs_r( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[B]], i8 [[C]]) ; CHECK-NEXT: [[MIN:%.*]] = add nsw i8 [[TMP1]], [[A]] @@ -458,11 +627,11 @@ define i8 @smin_of_add_nsw_nuw_lhs(i8 %a, i8 %b, i8 %c) { ret i8 %min } -define i8 @smin_of_add_nsw_nuw_lhs_comm(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @smin_of_add_nsw_nuw_lhs_comm( +define i8 @smin_of_add_nsw_nuw_lhs_l(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smin_of_add_nsw_nuw_lhs_l( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[B]], i8 [[C]]) -; CHECK-NEXT: [[MIN:%.*]] = add nsw i8 [[TMP1]], [[A]] +; CHECK-NEXT: [[MIN:%.*]] = add nsw i8 [[A]], [[TMP1]] ; CHECK-NEXT: ret i8 [[MIN]] ; %add1 = add nsw nuw i8 %a, %b @@ -471,8 +640,22 @@ define i8 @smin_of_add_nsw_nuw_lhs_comm(i8 %a, i8 %b, i8 %c) { ret i8 %min } -define i8 @smin_of_add_nsw_nuw_rhs(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @smin_of_add_nsw_nuw_rhs( +define i8 @smin_of_add_nsw_nuw_lhs_comm(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smin_of_add_nsw_nuw_lhs_comm( +; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { +; CHECK-NEXT: [[ADD1:%.*]] = add nuw nsw i8 [[A]], [[B]] +; CHECK-NEXT: [[ADD2:%.*]] = add nuw i8 [[C]], [[A]] +; CHECK-NEXT: [[MIN:%.*]] = call i8 @llvm.smin.i8(i8 [[ADD1]], i8 [[ADD2]]) +; CHECK-NEXT: ret i8 [[MIN]] +; + %add1 = add nsw nuw i8 %a, %b + %add2 = add nuw i8 %c, %a + %min = call i8 @llvm.smin.i8(i8 %add1, i8 %add2) + ret i8 %min +} + +define i8 @smin_of_add_nsw_nuw_rhs_r(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smin_of_add_nsw_nuw_rhs_r( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[B]], i8 [[C]]) ; CHECK-NEXT: [[MIN:%.*]] = add nsw i8 [[TMP1]], [[A]] @@ -484,6 +667,19 @@ define i8 @smin_of_add_nsw_nuw_rhs(i8 %a, i8 %b, i8 %c) { ret i8 %min } +define i8 @smin_of_add_nsw_nuw_rhs_l(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smin_of_add_nsw_nuw_rhs_l( +; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[B]], i8 [[C]]) +; CHECK-NEXT: [[MIN:%.*]] = add nsw i8 [[A]], [[TMP1]] +; CHECK-NEXT: ret i8 [[MIN]] +; + %add1 = add nsw i8 %a, %b + %add2 = add nsw nuw i8 %a, %c + %min = call i8 @llvm.smin.i8(i8 %add1, i8 %add2) + ret i8 %min +} + define i8 @smin_of_add_nsw_nuw_rhs_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-LABEL: define i8 @smin_of_add_nsw_nuw_rhs_comm( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { @@ -491,14 +687,15 @@ define i8 @smin_of_add_nsw_nuw_rhs_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-NEXT: [[MIN:%.*]] = add nsw i8 [[TMP1]], [[A]] ; CHECK-NEXT: ret i8 [[MIN]] ; - %add1 = add nsw i8 %a, %b + %add1 = add nsw i8 %b, %a %add2 = add nsw nuw i8 %a, %c %min = call i8 @llvm.smin.i8(i8 %add1, i8 %add2) ret i8 %min } -define i8 @smin_of_add_nsw_nuw(i8 %a, i8 %b, i8 %c) { -; CHECK-LABEL: define i8 @smin_of_add_nsw_nuw( + +define i8 @smin_of_add_nsw_nuw_r(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smin_of_add_nsw_nuw_r( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[B]], i8 [[C]]) ; CHECK-NEXT: [[MIN:%.*]] = add nuw nsw i8 [[TMP1]], [[A]] @@ -510,15 +707,28 @@ define i8 @smin_of_add_nsw_nuw(i8 %a, i8 %b, i8 %c) { ret i8 %min } +define i8 @smin_of_add_nsw_nuw_l(i8 %a, i8 %b, i8 %c) { +; CHECK-LABEL: define i8 @smin_of_add_nsw_nuw_l( +; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[B]], i8 [[C]]) +; CHECK-NEXT: [[MIN:%.*]] = add nuw nsw i8 [[A]], [[TMP1]] +; CHECK-NEXT: ret i8 [[MIN]] +; + %add1 = add nsw nuw i8 %a, %b + %add2 = add nsw nuw i8 %a, %c + %min = call i8 @llvm.smin.i8(i8 %add1, i8 %add2) + ret i8 %min +} + define i8 @smin_of_add_nsw_nuw_comm(i8 %a, i8 %b, i8 %c) { ; CHECK-LABEL: define i8 @smin_of_add_nsw_nuw_comm( ; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]], i8 [[C:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[B]], i8 [[C]]) -; CHECK-NEXT: [[MIN:%.*]] = add nuw nsw i8 [[TMP1]], [[A]] +; CHECK-NEXT: [[MIN:%.*]] = add nuw nsw i8 [[A]], [[TMP1]] ; CHECK-NEXT: ret i8 [[MIN]] ; %add1 = add nsw nuw i8 %a, %b - %add2 = add nsw nuw i8 %a, %c + %add2 = add nsw nuw i8 %c, %a %min = call i8 @llvm.smin.i8(i8 %add1, i8 %add2) ret i8 %min } diff --git a/llvm/test/Transforms/InstCombine/shift-uminmax.ll b/llvm/test/Transforms/InstCombine/shift-uminmax.ll new file mode 100644 index 0000000000000..21f8ac9f34674 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/shift-uminmax.ll @@ -0,0 +1,418 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +; For the following patterns: +; umax(nuw_shl(z, x), nuw_shl(z, y)) -> nuw_shl(z, umax(x, y)) +; umin(nuw_shl(z, x), nuw_shl(z, y)) -> nuw_shl(z, umin(x, y)) +; umax(nuw_shl(x, z), nuw_shl(y, z)) -> nuw_shl(umax(x, y), z) +; umin(nuw_shl(x, z), nuw_shl(y, z)) -> nuw_shl(umin(x, y), z) + +define i32 @umax_shl_common_lhs(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: define i32 @umax_shl_common_lhs( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[X]], i32 [[Y]]) +; CHECK-NEXT: [[MAX:%.*]] = shl nuw i32 [[Z]], [[TMP1]] +; CHECK-NEXT: ret i32 [[MAX]] +; + %shl_x = shl nuw i32 %z, %x + %shl_y = shl nuw i32 %z, %y + %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) + ret i32 %max +} + +define i32 @umax_shl_common_rhs(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: define i32 @umax_shl_common_rhs( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[X]], i32 [[Y]]) +; CHECK-NEXT: [[MAX:%.*]] = shl nuw i32 [[TMP1]], [[Z]] +; CHECK-NEXT: ret i32 [[MAX]] +; + %shl_x = shl nuw i32 %x, %z + %shl_y = shl nuw i32 %y, %z + %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) + ret i32 %max +} + +define i32 @umin_shl_common_lhs(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: define i32 @umin_shl_common_lhs( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 [[Y]]) +; CHECK-NEXT: [[MIN:%.*]] = shl nuw i32 [[Z]], [[TMP1]] +; CHECK-NEXT: ret i32 [[MIN]] +; + %shl_x = shl nuw i32 %z, %x + %shl_y = shl nuw i32 %z, %y + %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) + ret i32 %min +} + +define i32 @umin_shl_common_rhs(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: define i32 @umin_shl_common_rhs( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 [[Y]]) +; CHECK-NEXT: [[MIN:%.*]] = shl nuw i32 [[TMP1]], [[Z]] +; CHECK-NEXT: ret i32 [[MIN]] +; + %shl_x = shl nuw i32 %x, %z + %shl_y = shl nuw i32 %y, %z + %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) + ret i32 %min +} + +define i32 @umax_shl_common_lhs_const1(i32 %x, i32 %y) { +; CHECK-LABEL: define i32 @umax_shl_common_lhs_const1( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[X]], i32 [[Y]]) +; CHECK-NEXT: [[MAX:%.*]] = shl nuw i32 1, [[TMP1]] +; CHECK-NEXT: ret i32 [[MAX]] +; + %shl_x = shl nuw i32 1, %x + %shl_y = shl nuw i32 1, %y + %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) + ret i32 %max +} + +define i32 @umax_shl_common_rhs_const1(i32 %x, i32 %y) { +; CHECK-LABEL: define i32 @umax_shl_common_rhs_const1( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[X]], i32 [[Y]]) +; CHECK-NEXT: [[MAX:%.*]] = shl nuw i32 [[TMP1]], 1 +; CHECK-NEXT: ret i32 [[MAX]] +; + %shl_x = shl nuw i32 %x, 1 + %shl_y = shl nuw i32 %y, 1 + %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) + ret i32 %max +} + +define i32 @umin_shl_common_lhs_const1(i32 %x, i32 %y) { +; CHECK-LABEL: define i32 @umin_shl_common_lhs_const1( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 [[Y]]) +; CHECK-NEXT: [[MIN:%.*]] = shl nuw i32 1, [[TMP1]] +; CHECK-NEXT: ret i32 [[MIN]] +; + %shl_x = shl nuw i32 1, %x + %shl_y = shl nuw i32 1, %y + %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) + ret i32 %min +} + +define i32 @umin_shl_common_rhs_const1(i32 %x, i32 %y) { +; CHECK-LABEL: define i32 @umin_shl_common_rhs_const1( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 [[Y]]) +; CHECK-NEXT: [[MIN:%.*]] = shl nuw i32 [[TMP1]], 1 +; CHECK-NEXT: ret i32 [[MIN]] +; + %shl_x = shl nuw i32 %x, 1 + %shl_y = shl nuw i32 %y, 1 + %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) + ret i32 %min +} + +declare void @use(i8) + +define i32 @umax_shl_common_lhs_multi_use(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: define i32 @umax_shl_common_lhs_multi_use( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { +; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[Z]], [[X]] +; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Z]], [[Y]] +; CHECK-NEXT: call void @use(i32 [[SHL_X]]) +; CHECK-NEXT: call void @use(i32 [[SHL_Y]]) +; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) +; CHECK-NEXT: ret i32 [[MAX]] +; + %shl_x = shl nuw i32 %z, %x + %shl_y = shl nuw i32 %z, %y + call void @use(i32 %shl_x) + call void @use(i32 %shl_y) + %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) + ret i32 %max +} + +define i32 @umax_shl_common_rhs_multi_use(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: define i32 @umax_shl_common_rhs_multi_use( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { +; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[X]], [[Z]] +; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Y]], [[Z]] +; CHECK-NEXT: call void @use(i32 [[SHL_X]]) +; CHECK-NEXT: call void @use(i32 [[SHL_Y]]) +; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) +; CHECK-NEXT: ret i32 [[MAX]] +; + %shl_x = shl nuw i32 %x, %z + %shl_y = shl nuw i32 %y, %z + call void @use(i32 %shl_x) + call void @use(i32 %shl_y) + %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) + ret i32 %max +} + +define i32 @umin_shl_common_lhs_multi_use(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: define i32 @umin_shl_common_lhs_multi_use( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { +; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[Z]], [[X]] +; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Z]], [[Y]] +; CHECK-NEXT: call void @use(i32 [[SHL_X]]) +; CHECK-NEXT: call void @use(i32 [[SHL_Y]]) +; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.umin.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) +; CHECK-NEXT: ret i32 [[MIN]] +; + %shl_x = shl nuw i32 %z, %x + %shl_y = shl nuw i32 %z, %y + call void @use(i32 %shl_x) + call void @use(i32 %shl_y) + %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) + ret i32 %min +} + +define i32 @umin_shl_common_rhs_multi_use(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: define i32 @umin_shl_common_rhs_multi_use( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { +; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[X]], [[Z]] +; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Y]], [[Z]] +; CHECK-NEXT: call void @use(i32 [[SHL_X]]) +; CHECK-NEXT: call void @use(i32 [[SHL_Y]]) +; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.umin.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) +; CHECK-NEXT: ret i32 [[MIN]] +; + %shl_x = shl nuw i32 %x, %z + %shl_y = shl nuw i32 %y, %z + call void @use(i32 %shl_x) + call void @use(i32 %shl_y) + %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) + ret i32 %min +} + +define i32 @umax_shl_common_lhs_commuted(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: define i32 @umax_shl_common_lhs_commuted( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[Y]], i32 [[X]]) +; CHECK-NEXT: [[MAX:%.*]] = shl nuw i32 [[Z]], [[TMP1]] +; CHECK-NEXT: ret i32 [[MAX]] +; + %shl_x = shl nuw i32 %z, %x + %shl_y = shl nuw i32 %z, %y + %max = call i32 @llvm.umax.i32(i32 %shl_y, i32 %shl_x) + ret i32 %max +} + +define i32 @umax_shl_common_rhs_commuted(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: define i32 @umax_shl_common_rhs_commuted( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[Y]], i32 [[X]]) +; CHECK-NEXT: [[MAX:%.*]] = shl nuw i32 [[TMP1]], [[Z]] +; CHECK-NEXT: ret i32 [[MAX]] +; + %shl_x = shl nuw i32 %x, %z + %shl_y = shl nuw i32 %y, %z + %max = call i32 @llvm.umax.i32(i32 %shl_y, i32 %shl_x) + ret i32 %max +} + +define i32 @umin_shl_common_lhs_commuted(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: define i32 @umin_shl_common_lhs_commuted( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[Y]], i32 [[X]]) +; CHECK-NEXT: [[MIN:%.*]] = shl nuw i32 [[Z]], [[TMP1]] +; CHECK-NEXT: ret i32 [[MIN]] +; + %shl_x = shl nuw i32 %z, %x + %shl_y = shl nuw i32 %z, %y + %min = call i32 @llvm.umin.i32(i32 %shl_y, i32 %shl_x) + ret i32 %min +} + +define i32 @umin_shl_common_rhs_commuted(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: define i32 @umin_shl_common_rhs_commuted( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[Y]], i32 [[X]]) +; CHECK-NEXT: [[MIN:%.*]] = shl nuw i32 [[TMP1]], [[Z]] +; CHECK-NEXT: ret i32 [[MIN]] +; + %shl_x = shl nuw i32 %x, %z + %shl_y = shl nuw i32 %y, %z + %min = call i32 @llvm.umin.i32(i32 %shl_y, i32 %shl_x) + ret i32 %min +} + +define <2 x i32> @umax_shl_common_lhs_vector(<2 x i32> %z, <2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: define <2 x i32> @umax_shl_common_lhs_vector( +; CHECK-SAME: <2 x i32> [[Z:%.*]], <2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @llvm.umax.v2i32(<2 x i32> [[X]], <2 x i32> [[Y]]) +; CHECK-NEXT: [[MAX:%.*]] = shl nuw <2 x i32> [[Z]], [[TMP1]] +; CHECK-NEXT: ret <2 x i32> [[MAX]] +; + %shl_x = shl nuw <2 x i32> %z, %x + %shl_y = shl nuw <2 x i32> %z, %y + %max = call <2 x i32> @llvm.umax.v2i32(<2 x i32> %shl_x, <2 x i32> %shl_y) + ret <2 x i32> %max +} + +define <2 x i32> @umax_shl_common_rhs_vector(<2 x i32> %z, <2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: define <2 x i32> @umax_shl_common_rhs_vector( +; CHECK-SAME: <2 x i32> [[Z:%.*]], <2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @llvm.umax.v2i32(<2 x i32> [[X]], <2 x i32> [[Y]]) +; CHECK-NEXT: [[MAX:%.*]] = shl nuw <2 x i32> [[TMP1]], [[Z]] +; CHECK-NEXT: ret <2 x i32> [[MAX]] +; + %shl_x = shl nuw <2 x i32> %x, %z + %shl_y = shl nuw <2 x i32> %y, %z + %max = call <2 x i32> @llvm.umax.v2i32(<2 x i32> %shl_x, <2 x i32> %shl_y) + ret <2 x i32> %max +} + + +define <2 x i32> @umin_shl_common_lhs_vector(<2 x i32> %z, <2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: define <2 x i32> @umin_shl_common_lhs_vector( +; CHECK-SAME: <2 x i32> [[Z:%.*]], <2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @llvm.umin.v2i32(<2 x i32> [[X]], <2 x i32> [[Y]]) +; CHECK-NEXT: [[MIN:%.*]] = shl nuw <2 x i32> [[Z]], [[TMP1]] +; CHECK-NEXT: ret <2 x i32> [[MIN]] +; + %shl_x = shl nuw <2 x i32> %z, %x + %shl_y = shl nuw <2 x i32> %z, %y + %min = call <2 x i32> @llvm.umin.v2i32(<2 x i32> %shl_x, <2 x i32> %shl_y) + ret <2 x i32> %min +} + +define <2 x i32> @umin_shl_common_rhs_vector(<2 x i32> %z, <2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: define <2 x i32> @umin_shl_common_rhs_vector( +; CHECK-SAME: <2 x i32> [[Z:%.*]], <2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @llvm.umin.v2i32(<2 x i32> [[X]], <2 x i32> [[Y]]) +; CHECK-NEXT: [[MIN:%.*]] = shl nuw <2 x i32> [[TMP1]], [[Z]] +; CHECK-NEXT: ret <2 x i32> [[MIN]] +; + %shl_x = shl nuw <2 x i32> %x, %z + %shl_y = shl nuw <2 x i32> %y, %z + %min = call <2 x i32> @llvm.umin.v2i32(<2 x i32> %shl_x, <2 x i32> %shl_y) + ret <2 x i32> %min +} + +; Negative tests + +define i32 @umax_shl_different_lhs(i32 %z1, i32 %z2, i32 %x, i32 %y) { +; CHECK-LABEL: define i32 @umax_shl_different_lhs( +; CHECK-SAME: i32 [[Z1:%.*]], i32 [[Z2:%.*]], i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[Z1]], [[X]] +; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Z2]], [[Y]] +; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) +; CHECK-NEXT: ret i32 [[MAX]] +; + %shl_x = shl nuw i32 %z1, %x + %shl_y = shl nuw i32 %z2, %y + %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) + ret i32 %max +} + +define i32 @umax_shl_different_rhs(i32 %z1, i32 %z2, i32 %x, i32 %y) { +; CHECK-LABEL: define i32 @umax_shl_different_rhs( +; CHECK-SAME: i32 [[Z1:%.*]], i32 [[Z2:%.*]], i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[X]], [[Z1]] +; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Y]], [[Z2]] +; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) +; CHECK-NEXT: ret i32 [[MAX]] +; + %shl_x = shl nuw i32 %x, %z1 + %shl_y = shl nuw i32 %y, %z2 + %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) + ret i32 %max +} + +define i32 @umin_shl_different_lhs(i32 %z1, i32 %z2, i32 %x, i32 %y) { +; CHECK-LABEL: define i32 @umin_shl_different_lhs( +; CHECK-SAME: i32 [[Z1:%.*]], i32 [[Z2:%.*]], i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[Z1]], [[X]] +; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Z2]], [[Y]] +; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.umin.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) +; CHECK-NEXT: ret i32 [[MIN]] +; + %shl_x = shl nuw i32 %z1, %x + %shl_y = shl nuw i32 %z2, %y + %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) + ret i32 %min +} + +define i32 @umin_shl_different_rhs(i32 %z1, i32 %z2, i32 %x, i32 %y) { +; CHECK-LABEL: define i32 @umin_shl_different_rhs( +; CHECK-SAME: i32 [[Z1:%.*]], i32 [[Z2:%.*]], i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[X]], [[Z1]] +; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Y]], [[Z2]] +; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.umin.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) +; CHECK-NEXT: ret i32 [[MIN]] +; + %shl_x = shl nuw i32 %x, %z1 + %shl_y = shl nuw i32 %y, %z2 + %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) + ret i32 %min +} + +define i32 @umax_shl_does_not_commute(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: define i32 @umax_shl_does_not_commute( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { +; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[X]], [[Y]] +; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Y]], [[Z]] +; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) +; CHECK-NEXT: ret i32 [[MAX]] +; + %shl_x = shl nuw i32 %x, %y + %shl_y = shl nuw i32 %y, %z + %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) + ret i32 %max +} + +define i32 @umin_shl_does_not_commute(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: define i32 @umin_shl_does_not_commute( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { +; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[X]], [[Y]] +; CHECK-NEXT: [[SHL_Y:%.*]] = shl nuw i32 [[Y]], [[Z]] +; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.umin.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) +; CHECK-NEXT: ret i32 [[MIN]] +; + %shl_x = shl nuw i32 %x, %y + %shl_y = shl nuw i32 %y, %z + %min = call i32 @llvm.umin.i32(i32 %shl_x, i32 %shl_y) + ret i32 %min +} + +define i32 @umax_shl_common_lhs_no_nuw_flag(i32 %x, i32 %y) { +; CHECK-LABEL: define i32 @umax_shl_common_lhs_no_nuw_flag( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[SHL_X:%.*]] = shl i32 2, [[X]] +; CHECK-NEXT: [[SHL_Y:%.*]] = shl i32 2, [[Y]] +; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) +; CHECK-NEXT: ret i32 [[MAX]] +; + %shl_x = shl i32 2, %x + %shl_y = shl i32 2, %y + %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) + ret i32 %max +} + +define i32 @umax_shl_common_rhs_no_nuw_flag(i32 %x, i32 %y) { +; CHECK-LABEL: define i32 @umax_shl_common_rhs_no_nuw_flag( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[SHL_X:%.*]] = shl nuw i32 [[X]], 2 +; CHECK-NEXT: [[SHL_Y:%.*]] = shl i32 [[Y]], 2 +; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[SHL_X]], i32 [[SHL_Y]]) +; CHECK-NEXT: ret i32 [[MAX]] +; + %shl_x = shl nuw i32 %x, 2 + %shl_y = shl i32 %y, 2 + %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) + ret i32 %max +} + +define i32 @umax_shl_common_lhs_preserve_nsw(i32 %x, i32 %y, i32 %z) { +; CHECK-LABEL: define i32 @umax_shl_common_lhs_preserve_nsw( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umax.i32(i32 [[X]], i32 [[Y]]) +; CHECK-NEXT: [[MAX:%.*]] = shl nuw nsw i32 [[Z]], [[TMP1]] +; CHECK-NEXT: ret i32 [[MAX]] +; + %shl_x = shl nuw nsw i32 %z, %x + %shl_y = shl nuw nsw i32 %z, %y + %max = call i32 @llvm.umax.i32(i32 %shl_x, i32 %shl_y) + ret i32 %max +}