CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
624 lines
21 KiB
LLVM
624 lines
21 KiB
LLVM
; 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> <i32 100, i32 100, i32 100, i32 100>)
|
|
%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> <i32 -50, i32 -50, i32 -50, i32 -50>)
|
|
%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 <vscale x 4 x i8> @umin_zext_scalable_vec(<vscale x 4 x i8> %x, <vscale x 4 x i8> %y) {
|
|
; CHECK-LABEL: define <vscale x 4 x i8> @umin_zext_scalable_vec(
|
|
; CHECK-SAME: <vscale x 4 x i8> [[X:%.*]], <vscale x 4 x i8> [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 4 x i8> @llvm.umin.nxv4i8(<vscale x 4 x i8> [[X]], <vscale x 4 x i8> [[Y]])
|
|
; CHECK-NEXT: ret <vscale x 4 x i8> [[TMP1]]
|
|
;
|
|
%zx = zext <vscale x 4 x i8> %x to <vscale x 4 x i32>
|
|
%zy = zext <vscale x 4 x i8> %y to <vscale x 4 x i32>
|
|
%u = call <vscale x 4 x i32> @llvm.umin.nxv4i32(<vscale x 4 x i32> %zx, <vscale x 4 x i32> %zy)
|
|
%t = trunc <vscale x 4 x i32> %u to <vscale x 4 x i8>
|
|
ret <vscale x 4 x i8> %t
|
|
}
|
|
|
|
define <vscale x 4 x i8> @smax_sext_scalable_vec(<vscale x 4 x i8> %x, <vscale x 4 x i8> %y) {
|
|
; CHECK-LABEL: define <vscale x 4 x i8> @smax_sext_scalable_vec(
|
|
; CHECK-SAME: <vscale x 4 x i8> [[X:%.*]], <vscale x 4 x i8> [[Y:%.*]]) {
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 4 x i8> @llvm.smax.nxv4i8(<vscale x 4 x i8> [[X]], <vscale x 4 x i8> [[Y]])
|
|
; CHECK-NEXT: ret <vscale x 4 x i8> [[TMP1]]
|
|
;
|
|
%sx = sext <vscale x 4 x i8> %x to <vscale x 4 x i32>
|
|
%sy = sext <vscale x 4 x i8> %y to <vscale x 4 x i32>
|
|
%u = call <vscale x 4 x i32> @llvm.smax.nxv4i32(<vscale x 4 x i32> %sx, <vscale x 4 x i32> %sy)
|
|
%t = trunc <vscale x 4 x i32> %u to <vscale x 4 x i8>
|
|
ret <vscale x 4 x i8> %t
|
|
}
|