; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 ; RUN: opt -passes=instcombine %s -S | FileCheck %s declare void @use_i32(i32) define i8 @umin_mul3_clamp(i8 %x) { ; CHECK-LABEL: define i8 @umin_mul3_clamp( ; CHECK-SAME: i8 [[X:%.*]]) { ; CHECK-NEXT: [[Z:%.*]] = zext i8 [[X]] to i16 ; CHECK-NEXT: [[M:%.*]] = mul nuw nsw i16 [[Z]], 3 ; CHECK-NEXT: [[U:%.*]] = call i16 @llvm.umin.i16(i16 [[M]], i16 255) ; CHECK-NEXT: [[T:%.*]] = trunc nuw i16 [[U]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %z = zext i8 %x to i32 %m = mul nuw nsw i32 %z, 3 %u = call i32 @llvm.umin.i32(i32 %m, i32 255) %t = trunc i32 %u to i8 ret i8 %t } define i8 @umin_add_two_zexts(i8 %x, i8 %y) { ; CHECK-LABEL: define i8 @umin_add_two_zexts( ; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) { ; CHECK-NEXT: [[ZX:%.*]] = zext i8 [[X]] to i16 ; CHECK-NEXT: [[ZY:%.*]] = zext i8 [[Y]] to i16 ; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i16 [[ZX]], [[ZY]] ; CHECK-NEXT: [[U:%.*]] = call i16 @llvm.umin.i16(i16 [[ADD]], i16 200) ; CHECK-NEXT: [[T:%.*]] = trunc nuw i16 [[U]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %zx = zext i8 %x to i32 %zy = zext i8 %y to i32 %add = add nuw i32 %zx, %zy %u = call i32 @llvm.umin.i32(i32 %add, i32 200) %t = trunc i32 %u to i8 ret i8 %t } define i8 @umax_add_two_zexts(i8 %x, i8 %y) { ; CHECK-LABEL: define i8 @umax_add_two_zexts( ; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) { ; CHECK-NEXT: [[ZX:%.*]] = zext i8 [[X]] to i16 ; CHECK-NEXT: [[ZY:%.*]] = zext i8 [[Y]] to i16 ; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i16 [[ZX]], [[ZY]] ; CHECK-NEXT: [[U:%.*]] = call i16 @llvm.umax.i16(i16 [[ADD]], i16 50) ; CHECK-NEXT: [[T:%.*]] = trunc i16 [[U]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %zx = zext i8 %x to i32 %zy = zext i8 %y to i32 %add = add nuw i32 %zx, %zy %u = call i32 @llvm.umax.i32(i32 %add, i32 50) %t = trunc i32 %u to i8 ret i8 %t } define i8 @umin_of_umax_chain(i8 %x) { ; CHECK-LABEL: define i8 @umin_of_umax_chain( ; CHECK-SAME: i8 [[X:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 10) ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.umin.i8(i8 [[TMP1]], i8 -56) ; CHECK-NEXT: ret i8 [[TMP2]] ; %z = zext i8 %x to i32 %u1 = call i32 @llvm.umax.i32(i32 %z, i32 10) %u2 = call i32 @llvm.umin.i32(i32 %u1, i32 200) %t = trunc i32 %u2 to i8 ret i8 %t } define i8 @umax_boundary_max(i8 %x) { ; CHECK-LABEL: define i8 @umax_boundary_max( ; CHECK-SAME: i8 [[X:%.*]]) { ; CHECK-NEXT: ret i8 -1 ; %z = zext i8 %x to i32 %u = call i32 @llvm.umax.i32(i32 %z, i32 255) %t = trunc i32 %u to i8 ret i8 %t } define i8 @umin_mul_two_zexts_too_wide(i8 %x, i8 %y) { ; CHECK-LABEL: define i8 @umin_mul_two_zexts_too_wide( ; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) { ; CHECK-NEXT: [[ZX:%.*]] = zext i8 [[X]] to i16 ; CHECK-NEXT: [[ZY:%.*]] = zext i8 [[Y]] to i16 ; CHECK-NEXT: [[M:%.*]] = mul nuw i16 [[ZX]], [[ZY]] ; CHECK-NEXT: [[U:%.*]] = call i16 @llvm.umin.i16(i16 [[M]], i16 200) ; CHECK-NEXT: [[T:%.*]] = trunc nuw i16 [[U]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %zx = zext i8 %x to i32 %zy = zext i8 %y to i32 %m = mul nuw nsw i32 %zx, %zy %u = call i32 @llvm.umin.i32(i32 %m, i32 200) %t = trunc i32 %u to i8 ret i8 %t } define i8 @umin_unknown_operand(i32 %x) { ; CHECK-LABEL: define i8 @umin_unknown_operand( ; CHECK-SAME: i32 [[X:%.*]]) { ; CHECK-NEXT: [[U:%.*]] = call i32 @llvm.umin.i32(i32 [[X]], i32 100) ; CHECK-NEXT: [[T:%.*]] = trunc nuw nsw i32 [[U]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %u = call i32 @llvm.umin.i32(i32 %x, i32 100) %t = trunc i32 %u to i8 ret i8 %t } ; Constant 256 has bit 8 set, so it does not fit in the i8 narrow type. ; Narrowing to i16 should still succeed because both operands fit there. define i8 @umin_const_above_i8_max(i8 %x) { ; CHECK-LABEL: define i8 @umin_const_above_i8_max( ; CHECK-SAME: i8 [[X:%.*]]) { ; CHECK-NEXT: [[Z:%.*]] = zext i8 [[X]] to i16 ; CHECK-NEXT: [[M:%.*]] = mul nuw nsw i16 [[Z]], 3 ; CHECK-NEXT: [[U:%.*]] = call i16 @llvm.umin.i16(i16 [[M]], i16 256) ; CHECK-NEXT: [[T:%.*]] = trunc i16 [[U]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %z = zext i8 %x to i32 %m = mul nuw nsw i32 %z, 3 %u = call i32 @llvm.umin.i32(i32 %m, i32 256) %t = trunc i32 %u to i8 ret i8 %t } ; Constant 65536 has bit 16 set, so it does not fit in i8 nor i16. The ; %a operand can also exceed 65535, so the umin does not simplify away ; and the narrowing must be skipped at every width. define i8 @umin_const_above_i16_max(i32 %y) { ; CHECK-LABEL: define i8 @umin_const_above_i16_max( ; CHECK-SAME: i32 [[Y:%.*]]) { ; CHECK-NEXT: [[A:%.*]] = and i32 [[Y]], 131071 ; CHECK-NEXT: [[U:%.*]] = call i32 @llvm.umin.i32(i32 [[A]], i32 65536) ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[U]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %a = and i32 %y, 131071 %u = call i32 @llvm.umin.i32(i32 %a, i32 65536) %t = trunc i32 %u to i8 ret i8 %t } ; Constant 200 is positive but outside signed i8 range [-128, 127], so it ; does not have enough sign bits for the i8 narrowing. define i8 @smax_const_above_i8_smax(i8 %x, i8 %y) { ; CHECK-LABEL: define i8 @smax_const_above_i8_smax( ; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) { ; CHECK-NEXT: [[SX:%.*]] = sext i8 [[X]] to i16 ; CHECK-NEXT: [[SY:%.*]] = sext i8 [[Y]] to i16 ; CHECK-NEXT: [[ADD:%.*]] = add nsw i16 [[SX]], [[SY]] ; CHECK-NEXT: [[U:%.*]] = call i16 @llvm.smax.i16(i16 [[ADD]], i16 200) ; CHECK-NEXT: [[T:%.*]] = trunc i16 [[U]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %sx = sext i8 %x to i32 %sy = sext i8 %y to i32 %add = add nsw i32 %sx, %sy %u = call i32 @llvm.smax.i32(i32 %add, i32 200) %t = trunc i32 %u to i8 ret i8 %t } ; Constant -200 is negative but outside signed i8 range [-128, 127]. define i8 @smin_const_below_i8_smin(i8 %x, i8 %y) { ; CHECK-LABEL: define i8 @smin_const_below_i8_smin( ; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) { ; CHECK-NEXT: [[SX:%.*]] = sext i8 [[X]] to i16 ; CHECK-NEXT: [[SY:%.*]] = sext i8 [[Y]] to i16 ; CHECK-NEXT: [[ADD:%.*]] = add nsw i16 [[SX]], [[SY]] ; CHECK-NEXT: [[U:%.*]] = call i16 @llvm.smin.i16(i16 [[ADD]], i16 -200) ; CHECK-NEXT: [[T:%.*]] = trunc i16 [[U]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %sx = sext i8 %x to i32 %sy = sext i8 %y to i32 %add = add nsw i32 %sx, %sy %u = call i32 @llvm.smin.i32(i32 %add, i32 -200) %t = trunc i32 %u to i8 ret i8 %t } define i8 @umin_chain_multi_use(i8 %x) { ; CHECK-LABEL: define i8 @umin_chain_multi_use( ; CHECK-SAME: i8 [[X:%.*]]) { ; CHECK-NEXT: [[Z:%.*]] = zext i8 [[X]] to i32 ; CHECK-NEXT: [[M:%.*]] = mul nuw nsw i32 [[Z]], 3 ; CHECK-NEXT: [[U:%.*]] = call i32 @llvm.umin.i32(i32 [[M]], i32 255) ; CHECK-NEXT: call void @use_i32(i32 [[U]]) ; CHECK-NEXT: [[T:%.*]] = trunc nuw i32 [[U]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %z = zext i8 %x to i32 %m = mul nuw nsw i32 %z, 3 %u = call i32 @llvm.umin.i32(i32 %m, i32 255) call void @use_i32(i32 %u) %t = trunc i32 %u to i8 ret i8 %t } declare void @use_i8(i8) define i8 @umin_trunc_multi_use(i8 %x) { ; CHECK-LABEL: define i8 @umin_trunc_multi_use( ; CHECK-SAME: i8 [[X:%.*]]) { ; CHECK-NEXT: [[Z:%.*]] = zext i8 [[X]] to i16 ; CHECK-NEXT: [[M:%.*]] = mul nuw nsw i16 [[Z]], 3 ; CHECK-NEXT: [[U:%.*]] = call i16 @llvm.umin.i16(i16 [[M]], i16 255) ; CHECK-NEXT: [[T:%.*]] = trunc nuw i16 [[U]] to i8 ; CHECK-NEXT: call void @use_i8(i8 [[T]]) ; CHECK-NEXT: ret i8 [[T]] ; %z = zext i8 %x to i32 %m = mul nuw nsw i32 %z, 3 %u = call i32 @llvm.umin.i32(i32 %m, i32 255) %t = trunc i32 %u to i8 call void @use_i8(i8 %t) ret i8 %t } define i8 @umin_asymmetric(i8 %x, i32 %y) { ; CHECK-LABEL: define i8 @umin_asymmetric( ; CHECK-SAME: i8 [[X:%.*]], i32 [[Y:%.*]]) { ; CHECK-NEXT: [[Z:%.*]] = zext i8 [[X]] to i32 ; CHECK-NEXT: [[U:%.*]] = call i32 @llvm.umin.i32(i32 [[Z]], i32 [[Y]]) ; CHECK-NEXT: [[T:%.*]] = trunc nuw i32 [[U]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %z = zext i8 %x to i32 %u = call i32 @llvm.umin.i32(i32 %z, i32 %y) %t = trunc i32 %u to i8 ret i8 %t } define i8 @umin_shared_subexpr(i8 %x) { ; CHECK-LABEL: define i8 @umin_shared_subexpr( ; CHECK-SAME: i8 [[X:%.*]]) { ; CHECK-NEXT: [[Z:%.*]] = zext i8 [[X]] to i16 ; CHECK-NEXT: [[A:%.*]] = mul nuw nsw i16 [[Z]], 3 ; CHECK-NEXT: [[B:%.*]] = add nuw nsw i16 [[Z]], 50 ; CHECK-NEXT: [[U:%.*]] = call i16 @llvm.umin.i16(i16 [[A]], i16 [[B]]) ; CHECK-NEXT: [[T:%.*]] = trunc i16 [[U]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %z = zext i8 %x to i32 %a = mul nuw nsw i32 %z, 3 %b = add nuw nsw i32 %z, 50 %u = call i32 @llvm.umin.i32(i32 %a, i32 %b) %t = trunc i32 %u to i8 ret i8 %t } define i8 @umin_or_known_high_bit(i8 %x, i32 %y) { ; CHECK-LABEL: define i8 @umin_or_known_high_bit( ; CHECK-SAME: i8 [[X:%.*]], i32 [[Y:%.*]]) { ; CHECK-NEXT: [[Z:%.*]] = zext i8 [[X]] to i32 ; CHECK-NEXT: [[OR:%.*]] = or disjoint i32 [[Z]], 256 ; CHECK-NEXT: [[A:%.*]] = and i32 [[Y]], 511 ; CHECK-NEXT: [[U:%.*]] = call i32 @llvm.umin.i32(i32 [[OR]], i32 [[A]]) ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[U]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %z = zext i8 %x to i32 %or = or i32 %z, 256 %a = and i32 %y, 511 %u = call i32 @llvm.umin.i32(i32 %or, i32 %a) %t = trunc i32 %u to i8 ret i8 %t } define i8 @smin_add_two_sexts(i8 %x, i8 %y) { ; CHECK-LABEL: define i8 @smin_add_two_sexts( ; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) { ; CHECK-NEXT: [[SX:%.*]] = sext i8 [[X]] to i16 ; CHECK-NEXT: [[SY:%.*]] = sext i8 [[Y]] to i16 ; CHECK-NEXT: [[ADD:%.*]] = add nsw i16 [[SX]], [[SY]] ; CHECK-NEXT: [[U:%.*]] = call i16 @llvm.smin.i16(i16 [[ADD]], i16 100) ; CHECK-NEXT: [[T:%.*]] = trunc i16 [[U]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %sx = sext i8 %x to i32 %sy = sext i8 %y to i32 %add = add nsw i32 %sx, %sy %u = call i32 @llvm.smin.i32(i32 %add, i32 100) %t = trunc i32 %u to i8 ret i8 %t } define i8 @smax_add_two_sexts(i8 %x, i8 %y) { ; CHECK-LABEL: define i8 @smax_add_two_sexts( ; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) { ; CHECK-NEXT: [[SX:%.*]] = sext i8 [[X]] to i16 ; CHECK-NEXT: [[SY:%.*]] = sext i8 [[Y]] to i16 ; CHECK-NEXT: [[ADD:%.*]] = add nsw i16 [[SX]], [[SY]] ; CHECK-NEXT: [[U:%.*]] = call i16 @llvm.smax.i16(i16 [[ADD]], i16 -100) ; CHECK-NEXT: [[T:%.*]] = trunc i16 [[U]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %sx = sext i8 %x to i32 %sy = sext i8 %y to i32 %add = add nsw i32 %sx, %sy %u = call i32 @llvm.smax.i32(i32 %add, i32 -100) %t = trunc i32 %u to i8 ret i8 %t } define i8 @smax_of_smin_chain(i8 %x) { ; CHECK-LABEL: define i8 @smax_of_smin_chain( ; CHECK-SAME: i8 [[X:%.*]]) { ; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 -100) ; CHECK-NEXT: [[TMP3:%.*]] = call i8 @llvm.smin.i8(i8 [[TMP2]], i8 100) ; CHECK-NEXT: ret i8 [[TMP3]] ; %s = sext i8 %x to i32 %u1 = call i32 @llvm.smin.i32(i32 %s, i32 100) %u2 = call i32 @llvm.smax.i32(i32 %u1, i32 -100) %t = trunc i32 %u2 to i8 ret i8 %t } define i8 @smin_unknown_operand(i32 %x) { ; CHECK-LABEL: define i8 @smin_unknown_operand( ; CHECK-SAME: i32 [[X:%.*]]) { ; CHECK-NEXT: [[U:%.*]] = call i32 @llvm.smin.i32(i32 [[X]], i32 50) ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[U]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %u = call i32 @llvm.smin.i32(i32 %x, i32 50) %t = trunc i32 %u to i8 ret i8 %t } define i8 @smin_asymmetric(i8 %x, i32 %y) { ; CHECK-LABEL: define i8 @smin_asymmetric( ; CHECK-SAME: i8 [[X:%.*]], i32 [[Y:%.*]]) { ; CHECK-NEXT: [[S:%.*]] = sext i8 [[X]] to i32 ; CHECK-NEXT: [[U:%.*]] = call i32 @llvm.smin.i32(i32 [[S]], i32 [[Y]]) ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[U]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %s = sext i8 %x to i32 %u = call i32 @llvm.smin.i32(i32 %s, i32 %y) %t = trunc i32 %u to i8 ret i8 %t } define i8 @smin_chain_multi_use(i8 %x, i8 %y) { ; CHECK-LABEL: define i8 @smin_chain_multi_use( ; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) { ; CHECK-NEXT: [[SX:%.*]] = sext i8 [[X]] to i32 ; CHECK-NEXT: [[SY:%.*]] = sext i8 [[Y]] to i32 ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[SX]], [[SY]] ; CHECK-NEXT: [[U:%.*]] = call i32 @llvm.smin.i32(i32 [[ADD]], i32 100) ; CHECK-NEXT: call void @use_i32(i32 [[U]]) ; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[U]] to i8 ; CHECK-NEXT: ret i8 [[TMP1]] ; %sx = sext i8 %x to i32 %sy = sext i8 %y to i32 %add = add nsw i32 %sx, %sy %u = call i32 @llvm.smin.i32(i32 %add, i32 100) call void @use_i32(i32 %u) %t = trunc i32 %u to i8 ret i8 %t } define i8 @smin_boundary_intmin(i8 %x) { ; CHECK-LABEL: define i8 @smin_boundary_intmin( ; CHECK-SAME: i8 [[X:%.*]]) { ; CHECK-NEXT: ret i8 -128 ; %s = sext i8 %x to i32 %u = call i32 @llvm.smin.i32(i32 %s, i32 -128) %t = trunc i32 %u to i8 ret i8 %t } define i8 @smax_boundary_intmax(i8 %x) { ; CHECK-LABEL: define i8 @smax_boundary_intmax( ; CHECK-SAME: i8 [[X:%.*]]) { ; CHECK-NEXT: ret i8 127 ; %s = sext i8 %x to i32 %u = call i32 @llvm.smax.i32(i32 %s, i32 127) %t = trunc i32 %u to i8 ret i8 %t } define i8 @smin_one_short_sign_bits(i9 %x) { ; CHECK-LABEL: define i8 @smin_one_short_sign_bits( ; CHECK-SAME: i9 [[X:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i9 @llvm.smin.i9(i9 [[X]], i9 50) ; CHECK-NEXT: [[T:%.*]] = trunc i9 [[TMP1]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %s = sext i9 %x to i32 %u = call i32 @llvm.smin.i32(i32 %s, i32 50) %t = trunc i32 %u to i8 ret i8 %t } define i8 @smax_one_short_sign_bits(i9 %x) { ; CHECK-LABEL: define i8 @smax_one_short_sign_bits( ; CHECK-SAME: i9 [[X:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i9 @llvm.smax.i9(i9 [[X]], i9 50) ; CHECK-NEXT: [[T:%.*]] = trunc nuw i9 [[TMP1]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; %s = sext i9 %x to i32 %u = call i32 @llvm.smax.i32(i32 %s, i32 50) %t = trunc i32 %u to i8 ret i8 %t } define <4 x i8> @umin_or_two_zexts_vec(<4 x i8> %x, <4 x i8> %y) { ; CHECK-LABEL: define <4 x i8> @umin_or_two_zexts_vec( ; CHECK-SAME: <4 x i8> [[X:%.*]], <4 x i8> [[Y:%.*]]) { ; CHECK-NEXT: [[OR1:%.*]] = or <4 x i8> [[X]], [[Y]] ; CHECK-NEXT: [[TMP1:%.*]] = call <4 x i8> @llvm.umin.v4i8(<4 x i8> [[OR1]], <4 x i8> splat (i8 100)) ; CHECK-NEXT: ret <4 x i8> [[TMP1]] ; %zx = zext <4 x i8> %x to <4 x i32> %zy = zext <4 x i8> %y to <4 x i32> %or = or <4 x i32> %zx, %zy %u = call <4 x i32> @llvm.umin.v4i32(<4 x i32> %or, <4 x i32> ) %t = trunc <4 x i32> %u to <4 x i8> ret <4 x i8> %t } define <4 x i8> @smax_xor_two_sexts_vec(<4 x i8> %x, <4 x i8> %y) { ; CHECK-LABEL: define <4 x i8> @smax_xor_two_sexts_vec( ; CHECK-SAME: <4 x i8> [[X:%.*]], <4 x i8> [[Y:%.*]]) { ; CHECK-NEXT: [[XOR1:%.*]] = xor <4 x i8> [[X]], [[Y]] ; CHECK-NEXT: [[TMP1:%.*]] = call <4 x i8> @llvm.smax.v4i8(<4 x i8> [[XOR1]], <4 x i8> splat (i8 -50)) ; CHECK-NEXT: ret <4 x i8> [[TMP1]] ; %sx = sext <4 x i8> %x to <4 x i32> %sy = sext <4 x i8> %y to <4 x i32> %xor = xor <4 x i32> %sx, %sy %u = call <4 x i32> @llvm.smax.v4i32(<4 x i32> %xor, <4 x i32> ) %t = trunc <4 x i32> %u to <4 x i8> ret <4 x i8> %t } define <4 x i8> @smin_phi_self_loop_vec(i1 %c, <4 x i8> %x) { ; CHECK-LABEL: define <4 x i8> @smin_phi_self_loop_vec( ; CHECK-SAME: i1 [[C:%.*]], <4 x i8> [[X:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*]]: ; CHECK-NEXT: br label %[[LOOP:.*]] ; CHECK: [[LOOP]]: ; CHECK-NEXT: [[ACC:%.*]] = phi <4 x i32> [ splat (i32 127), %[[ENTRY]] ], [ [[M:%.*]], %[[LOOP]] ] ; CHECK-NEXT: [[A:%.*]] = and <4 x i32> [[ACC]], splat (i32 127) ; CHECK-NEXT: [[EXT:%.*]] = sext <4 x i8> [[X]] to <4 x i32> ; CHECK-NEXT: [[M]] = call <4 x i32> @llvm.smin.v4i32(<4 x i32> [[A]], <4 x i32> [[EXT]]) ; CHECK-NEXT: br i1 [[C]], label %[[EXIT:.*]], label %[[LOOP]] ; CHECK: [[EXIT]]: ; CHECK-NEXT: [[T:%.*]] = trunc <4 x i32> [[M]] to <4 x i8> ; CHECK-NEXT: ret <4 x i8> [[T]] ; entry: br label %loop loop: %acc = phi <4 x i32> [ splat (i32 127), %entry ], [ %m, %loop ] %a = and <4 x i32> %acc, splat (i32 127) %ext = sext <4 x i8> %x to <4 x i32> %m = call <4 x i32> @llvm.smin.v4i32(<4 x i32> %a, <4 x i32> %ext) br i1 %c, label %exit, label %loop exit: %t = trunc <4 x i32> %m to <4 x i8> ret <4 x i8> %t } define i8 @smin_phi_self_loop(i1 %c, i8 %x) { ; CHECK-LABEL: define i8 @smin_phi_self_loop( ; CHECK-SAME: i1 [[C:%.*]], i8 [[X:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*]]: ; CHECK-NEXT: br label %[[LOOP:.*]] ; CHECK: [[LOOP]]: ; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 127, %[[ENTRY]] ], [ [[M:%.*]], %[[LOOP]] ] ; CHECK-NEXT: [[A:%.*]] = and i32 [[ACC]], 127 ; CHECK-NEXT: [[EXT:%.*]] = sext i8 [[X]] to i32 ; CHECK-NEXT: [[M]] = call i32 @llvm.smin.i32(i32 [[A]], i32 [[EXT]]) ; CHECK-NEXT: br i1 [[C]], label %[[EXIT:.*]], label %[[LOOP]] ; CHECK: [[EXIT]]: ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[M]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; entry: br label %loop loop: %acc = phi i32 [ 127, %entry ], [ %m, %loop ] %a = and i32 %acc, 127 %ext = sext i8 %x to i32 %m = call i32 @llvm.smin.i32(i32 %a, i32 %ext) br i1 %c, label %exit, label %loop exit: %t = trunc i32 %m to i8 ret i8 %t } define i8 @smax_phi_self_loop(i1 %c, i8 %x) { ; CHECK-LABEL: define i8 @smax_phi_self_loop( ; CHECK-SAME: i1 [[C:%.*]], i8 [[X:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*]]: ; CHECK-NEXT: br label %[[LOOP:.*]] ; CHECK: [[LOOP]]: ; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ -128, %[[ENTRY]] ], [ [[M:%.*]], %[[LOOP]] ] ; CHECK-NEXT: [[A:%.*]] = and i32 [[ACC]], 127 ; CHECK-NEXT: [[EXT:%.*]] = sext i8 [[X]] to i32 ; CHECK-NEXT: [[M]] = call i32 @llvm.smax.i32(i32 [[A]], i32 [[EXT]]) ; CHECK-NEXT: br i1 [[C]], label %[[EXIT:.*]], label %[[LOOP]] ; CHECK: [[EXIT]]: ; CHECK-NEXT: [[T:%.*]] = trunc i32 [[M]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; entry: br label %loop loop: %acc = phi i32 [ -128, %entry ], [ %m, %loop ] %a = and i32 %acc, 127 %ext = sext i8 %x to i32 %m = call i32 @llvm.smax.i32(i32 %a, i32 %ext) br i1 %c, label %exit, label %loop exit: %t = trunc i32 %m to i8 ret i8 %t } define i8 @umin_phi_self_loop(i1 %c, i8 %x) { ; CHECK-LABEL: define i8 @umin_phi_self_loop( ; CHECK-SAME: i1 [[C:%.*]], i8 [[X:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*]]: ; CHECK-NEXT: br label %[[LOOP:.*]] ; CHECK: [[LOOP]]: ; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 1, %[[ENTRY]] ], [ [[M:%.*]], %[[LOOP]] ] ; CHECK-NEXT: [[A:%.*]] = and i32 [[ACC]], 255 ; CHECK-NEXT: [[EXT:%.*]] = zext i8 [[X]] to i32 ; CHECK-NEXT: [[M]] = call i32 @llvm.umin.i32(i32 [[A]], i32 [[EXT]]) ; CHECK-NEXT: br i1 [[C]], label %[[EXIT:.*]], label %[[LOOP]] ; CHECK: [[EXIT]]: ; CHECK-NEXT: [[T:%.*]] = trunc nuw i32 [[M]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; entry: br label %loop loop: %acc = phi i32 [ 1, %entry ], [ %m, %loop ] %a = and i32 %acc, 255 %ext = zext i8 %x to i32 %m = call i32 @llvm.umin.i32(i32 %a, i32 %ext) br i1 %c, label %exit, label %loop exit: %t = trunc i32 %m to i8 ret i8 %t } define i8 @umax_phi_self_loop(i1 %c, i8 %x) { ; CHECK-LABEL: define i8 @umax_phi_self_loop( ; CHECK-SAME: i1 [[C:%.*]], i8 [[X:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*]]: ; CHECK-NEXT: br label %[[LOOP:.*]] ; CHECK: [[LOOP]]: ; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 1, %[[ENTRY]] ], [ [[M:%.*]], %[[LOOP]] ] ; CHECK-NEXT: [[A:%.*]] = and i32 [[ACC]], 255 ; CHECK-NEXT: [[EXT:%.*]] = zext i8 [[X]] to i32 ; CHECK-NEXT: [[M]] = call i32 @llvm.umax.i32(i32 [[A]], i32 [[EXT]]) ; CHECK-NEXT: br i1 [[C]], label %[[EXIT:.*]], label %[[LOOP]] ; CHECK: [[EXIT]]: ; CHECK-NEXT: [[T:%.*]] = trunc nuw i32 [[M]] to i8 ; CHECK-NEXT: ret i8 [[T]] ; entry: br label %loop loop: %acc = phi i32 [ 1, %entry ], [ %m, %loop ] %a = and i32 %acc, 255 %ext = zext i8 %x to i32 %m = call i32 @llvm.umax.i32(i32 %a, i32 %ext) br i1 %c, label %exit, label %loop exit: %t = trunc i32 %m to i8 ret i8 %t } define @umin_zext_scalable_vec( %x, %y) { ; CHECK-LABEL: define @umin_zext_scalable_vec( ; CHECK-SAME: [[X:%.*]], [[Y:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call @llvm.umin.nxv4i8( [[X]], [[Y]]) ; CHECK-NEXT: ret [[TMP1]] ; %zx = zext %x to %zy = zext %y to %u = call @llvm.umin.nxv4i32( %zx, %zy) %t = trunc %u to ret %t } define @smax_sext_scalable_vec( %x, %y) { ; CHECK-LABEL: define @smax_sext_scalable_vec( ; CHECK-SAME: [[X:%.*]], [[Y:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call @llvm.smax.nxv4i8( [[X]], [[Y]]) ; CHECK-NEXT: ret [[TMP1]] ; %sx = sext %x to %sy = sext %y to %u = call @llvm.smax.nxv4i32( %sx, %sy) %t = trunc %u to ret %t }