[llvm] [InstCombine] Pattern match minmax calls for unsigned saturation. (PR #99250)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 19 01:19:58 PDT 2024


================
@@ -0,0 +1,517 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
+
+define i32 @uadd_sat32(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @uadd_sat32(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[B]], i32 [[A]])
+; CHECK-NEXT:    ret i32 [[TMP0]]
+;
+entry:
+  %conv = zext i32 %a to i64
+  %conv1 = zext i32 %b to i64
+  %add = add i64 %conv1, %conv
+  %0 = icmp ult i64 %add, 4294967295
+  %select = select i1 %0, i64 %add, i64 4294967295
+  %conv2 = trunc i64 %select to i32
+  ret i32 %conv2
+}
+
+define i32 @uadd_sat32_min(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @uadd_sat32_min(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[B]], i32 [[A]])
+; CHECK-NEXT:    ret i32 [[TMP0]]
+;
+entry:
+  %conv = zext i32 %a to i64
+  %conv1 = zext i32 %b to i64
+  %add = add i64 %conv1, %conv
+  %min = call i64 @llvm.umin.i64(i64 %add, i64 4294967295)
+  %conv2 = trunc i64 %min to i32
+  ret i32 %conv2
+}
+
+define i32 @usub_sat32(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @usub_sat32(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[A]], i32 [[B]])
+; CHECK-NEXT:    ret i32 [[TMP0]]
+;
+entry:
+  %conv = zext i32 %a to i64
+  %conv1 = zext i32 %b to i64
+  %sub = sub i64 %conv, %conv1
+  %cmp4 = icmp sgt i64 %sub, 0
+  %cmp6 = icmp slt i64 %sub, 4294967295
+  %cond = select i1 %cmp6, i64 %sub, i64 4294967295
+  %cond11 = select i1 %cmp4, i64 %cond, i64 0
+  %conv12 = trunc i64 %cond11 to i32
+  ret i32 %conv12
+}
+
+define i32 @usub_sat32_minmax(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @usub_sat32_minmax(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[A]], i32 [[B]])
+; CHECK-NEXT:    ret i32 [[TMP0]]
+;
+entry:
+  %conv = zext i32 %a to i64
+  %conv1 = zext i32 %b to i64
+  %sub = sub i64 %conv, %conv1
+  %cond = call i64 @llvm.smin.i64(i64 %sub, i64 4294967295)
+  %cond11 = call i64 @llvm.smax.i64(i64 %cond, i64 0)
+  %conv12 = trunc i64 %cond11 to i32
+  ret i32 %conv12
+}
+
+define i16 @uadd_sat16(i16 %a, i16 %b) {
+; CHECK-LABEL: define i16 @uadd_sat16(
+; CHECK-SAME: i16 [[A:%.*]], i16 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call i16 @llvm.uadd.sat.i16(i16 [[B]], i16 [[A]])
+; CHECK-NEXT:    ret i16 [[TMP0]]
+;
+entry:
+  %conv = zext i16 %a to i32
+  %conv1 = zext i16 %b to i32
+  %add = add i32 %conv1, %conv
+  %0 = icmp ult i32 %add, 65535
+  %select = select i1 %0, i32 %add, i32 65535
+  %conv2 = trunc i32 %select to i16
+  ret i16 %conv2
+}
+
+define i16 @uadd_sat16_min(i16 %a, i16 %b) {
+; CHECK-LABEL: define i16 @uadd_sat16_min(
+; CHECK-SAME: i16 [[A:%.*]], i16 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call i16 @llvm.uadd.sat.i16(i16 [[B]], i16 [[A]])
+; CHECK-NEXT:    ret i16 [[TMP0]]
+;
+entry:
+  %conv = zext i16 %a to i32
+  %conv1 = zext i16 %b to i32
+  %add = add i32 %conv1, %conv
+  %min = call i32 @llvm.umin.i32(i32 %add, i32 65535)
+  %conv2 = trunc i32 %min to i16
+  ret i16 %conv2
+}
+
+define i16 @usub_sat16(i16 %a, i16 %b) {
+; CHECK-LABEL: define i16 @usub_sat16(
+; CHECK-SAME: i16 [[A:%.*]], i16 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call i16 @llvm.usub.sat.i16(i16 [[A]], i16 [[B]])
+; CHECK-NEXT:    ret i16 [[TMP0]]
+;
+entry:
+  %conv = zext i16 %a to i32
+  %conv1 = zext i16 %b to i32
+  %sub = sub i32 %conv, %conv1
+  %cmp4 = icmp sgt i32 %sub, 0
+  %cmp6 = icmp slt i32 %sub, 65535
+  %cond = select i1 %cmp6, i32 %sub, i32 65535
+  %cond11 = select i1 %cmp4, i32 %cond, i32 0
+  %conv12 = trunc i32 %cond11 to i16
+  ret i16 %conv12
+}
+
+define i16 @usub_sat16_minmax(i16 %a, i16 %b) {
+; CHECK-LABEL: define i16 @usub_sat16_minmax(
+; CHECK-SAME: i16 [[A:%.*]], i16 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call i16 @llvm.usub.sat.i16(i16 [[A]], i16 [[B]])
+; CHECK-NEXT:    ret i16 [[TMP0]]
+;
+entry:
+  %conv = zext i16 %a to i32
+  %conv1 = zext i16 %b to i32
+  %sub = sub i32 %conv, %conv1
+  %cond = call i32 @llvm.smin.i32(i32 %sub, i32 65535)
+  %cond11 = call i32 @llvm.smax.i32(i32 %cond, i32 0)
+  %conv12 = trunc i32 %cond11 to i16
+  ret i16 %conv12
+}
+
+define i8 @uadd_sat8(i8 %a, i8 %b) {
+; CHECK-LABEL: define i8 @uadd_sat8(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[B]], i8 [[A]])
+; CHECK-NEXT:    ret i8 [[TMP0]]
+;
+entry:
+  %conv = zext i8 %a to i32
+  %conv1 = zext i8 %b to i32
+  %add = add i32 %conv1, %conv
+  %0 = icmp ult i32 %add, 255
+  %select = select i1 %0, i32 %add, i32 255
+  %conv2 = trunc i32 %select to i8
+  ret i8 %conv2
+}
+
+define i8 @uadd_sat8_min(i8 %a, i8 %b) {
+; CHECK-LABEL: define i8 @uadd_sat8_min(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[B]], i8 [[A]])
+; CHECK-NEXT:    ret i8 [[TMP0]]
+;
+entry:
+  %conv = zext i8 %a to i32
+  %conv1 = zext i8 %b to i32
+  %add = add i32 %conv1, %conv
+  %min = call i32 @llvm.umin.i32(i32 %add, i32 255)
+  %conv2 = trunc i32 %min to i8
+  ret i8 %conv2
+}
+
+define i8 @usub_sat8(i8 %a, i8 %b) {
+; CHECK-LABEL: define i8 @usub_sat8(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[A]], i8 [[B]])
+; CHECK-NEXT:    ret i8 [[TMP0]]
+;
+entry:
+  %conv = zext i8 %a to i32
+  %conv1 = zext i8 %b to i32
+  %sub = sub i32 %conv, %conv1
+  %cmp4 = icmp sgt i32 %sub, 0
+  %cmp6 = icmp slt i32 %sub, 255
+  %cond = select i1 %cmp6, i32 %sub, i32 255
+  %cond11 = select i1 %cmp4, i32 %cond, i32 0
+  %conv12 = trunc i32 %cond11 to i8
+  ret i8 %conv12
+}
+
+define i8 @usub_sat8_minmax(i8 %a, i8 %b) {
+; CHECK-LABEL: define i8 @usub_sat8_minmax(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[A]], i8 [[B]])
+; CHECK-NEXT:    ret i8 [[TMP0]]
+;
+entry:
+  %conv = zext i8 %a to i32
+  %conv1 = zext i8 %b to i32
+  %sub = sub i32 %conv, %conv1
+  %cond = call i32 @llvm.smin.i32(i32 %sub, i32 255)
+  %cond11 = call i32 @llvm.smax.i32(i32 %cond, i32 0)
+  %conv12 = trunc i32 %cond11 to i8
+  ret i8 %conv12
+}
+
+define i64 @uadd_sat64(i64 %a, i64 %b) {
+; CHECK-LABEL: define i64 @uadd_sat64(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call i64 @llvm.uadd.sat.i64(i64 [[B]], i64 [[A]])
+; CHECK-NEXT:    ret i64 [[TMP0]]
+;
+entry:
+  %conv = zext i64 %a to i128
+  %conv1 = zext i64 %b to i128
+  %add = add i128 %conv1, %conv
+  %0 = icmp ult i128 %add, 18446744073709551615
+  %select = select i1 %0, i128 %add, i128 18446744073709551615
+  %conv2 = trunc i128 %select to i64
+  ret i64 %conv2
+}
+
+define i64 @usub_sat64(i64 %a, i64 %b) {
+; CHECK-LABEL: define i64 @usub_sat64(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A]], i64 [[B]])
+; CHECK-NEXT:    ret i64 [[TMP0]]
+;
+entry:
+  %conv = zext i64 %a to i128
+  %conv1 = zext i64 %b to i128
+  %sub = sub i128 %conv, %conv1
+  %cmp4 = icmp sgt i128 %sub, 0
+  %cmp6 = icmp slt i128 %sub, 18446744073709551615
+  %cond = select i1 %cmp6, i128 %sub, i128 18446744073709551615
+  %cond11 = select i1 %cmp4, i128 %cond, i128 0
+  %conv12 = trunc i128 %cond11 to i64
+  ret i64 %conv12
+}
+
+define <4 x i32> @uadd_satv4i32(<4 x i32> %a, <4 x i32> %b) {
+; CHECK-LABEL: define <4 x i32> @uadd_satv4i32(
+; CHECK-SAME: <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call <4 x i32> @llvm.uadd.sat.v4i32(<4 x i32> [[B]], <4 x i32> [[A]])
+; CHECK-NEXT:    ret <4 x i32> [[TMP0]]
+;
+entry:
+  %conv = zext <4 x i32> %a to <4 x i64>
+  %conv1 = zext <4 x i32> %b to <4 x i64>
+  %add = add <4 x i64> %conv1, %conv
+  %0 = icmp ult <4 x i64> %add, <i64 4294967295, i64 4294967295, i64 4294967295, i64 4294967295>
+  %select = select <4 x i1> %0, <4 x i64> %add, <4 x i64> <i64 4294967295, i64 4294967295, i64 4294967295, i64 4294967295>
+  %conv7 = trunc <4 x i64> %select to <4 x i32>
+  ret <4 x i32> %conv7
+}
+
+define <8 x i16> @uadd_satv8i16_minmax(<8 x i16> %a, <8 x i16> %b) {
+; CHECK-LABEL: define <8 x i16> @uadd_satv8i16_minmax(
+; CHECK-SAME: <8 x i16> [[A:%.*]], <8 x i16> [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call <8 x i16> @llvm.uadd.sat.v8i16(<8 x i16> [[B]], <8 x i16> [[A]])
+; CHECK-NEXT:    ret <8 x i16> [[TMP0]]
+;
+entry:
+  %conv = zext <8 x i16> %a to <8 x i32>
+  %conv1 = zext <8 x i16> %b to <8 x i32>
+  %add = add <8 x i32> %conv1, %conv
+  %select = call <8 x i32> @llvm.umin.v8i32(<8 x i32> %add, <8 x i32> <i32 65535, i32 65535, i32 65535, i32 65535, i32 65535, i32 65535, i32 65535, i32 65535>)
+  %conv7 = trunc <8 x i32> %select to <8 x i16>
+  ret <8 x i16> %conv7
+}
+
+define <16 x i8> @usub_satv16i8(<16 x i8> %a, <16 x i8> %b) {
+; CHECK-LABEL: define <16 x i8> @usub_satv16i8(
+; CHECK-SAME: <16 x i8> [[A:%.*]], <16 x i8> [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call <16 x i8> @llvm.usub.sat.v16i8(<16 x i8> [[B]], <16 x i8> [[A]])
+; CHECK-NEXT:    ret <16 x i8> [[TMP0]]
+;
+entry:
+  %conv = zext <16 x i8> %a to <16 x i32>
+  %conv1 = zext <16 x i8> %b to <16 x i32>
+  %sub = sub <16 x i32> %conv1, %conv
+  %0 = icmp slt <16 x i32> %sub, <i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255>
+  %select = select <16 x i1> %0, <16 x i32> %sub, <16 x i32> <i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255, i32 255>
+  %1 = icmp sgt <16 x i32> %select, <i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0>
+  %select8 = select <16 x i1> %1, <16 x i32> %select, <16 x i32> <i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0>
+  %conv7 = trunc <16 x i32> %select8 to <16 x i8>
+  ret <16 x i8> %conv7
+}
+
+define <2 x i64> @usub_satv2i64_minmax(<2 x i64> %a, <2 x i64> %b) {
+; CHECK-LABEL: define <2 x i64> @usub_satv2i64_minmax(
+; CHECK-SAME: <2 x i64> [[A:%.*]], <2 x i64> [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call <2 x i64> @llvm.usub.sat.v2i64(<2 x i64> [[B]], <2 x i64> [[A]])
+; CHECK-NEXT:    ret <2 x i64> [[TMP0]]
+;
+entry:
+  %conv = zext <2 x i64> %a to <2 x i128>
+  %conv1 = zext <2 x i64> %b to <2 x i128>
+  %sub = sub <2 x i128> %conv1, %conv
+  %select = call <2 x i128> @llvm.smin.v2i128(<2 x i128> %sub, <2 x i128> <i128 18446744073709551615, i128 18446744073709551615>)
+  %select8 = call <2 x i128> @llvm.smax.v2i128(<2 x i128> %select, <2 x i128> <i128 0, i128 0>)
+  %conv7 = trunc <2 x i128> %select8 to <2 x i64>
+  ret <2 x i64> %conv7
+}
+
+define i32 @uadd_sat32_extra_use_1(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @uadd_sat32_extra_use_1(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[B]], i32 [[A]])
+; CHECK-NEXT:    [[SELECT:%.*]] = zext i32 [[TMP0]] to i64
+; CHECK-NEXT:    call void @use64(i64 [[SELECT]])
+; CHECK-NEXT:    ret i32 [[TMP0]]
+;
+entry:
+  %conv = zext i32 %a to i64
+  %conv1 = zext i32 %b to i64
+  %add = add i64 %conv1, %conv
+  %0 = icmp ult i64 %add, 4294967295
+  %select = select i1 %0, i64 %add, i64 4294967295
+  %conv7 = trunc i64 %select to i32
+  call void @use64(i64 %select)
+  ret i32 %conv7
+}
+
+define i32 @uadd_sat32_extra_use_2(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @uadd_sat32_extra_use_2(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[CONV:%.*]] = zext i32 [[A]] to i64
+; CHECK-NEXT:    [[CONV1:%.*]] = zext i32 [[B]] to i64
+; CHECK-NEXT:    [[ADD:%.*]] = add nuw nsw i64 [[CONV1]], [[CONV]]
+; CHECK-NEXT:    [[SELECT:%.*]] = call i64 @llvm.umin.i64(i64 [[ADD]], i64 4294967295)
+; CHECK-NEXT:    [[CONV7:%.*]] = trunc nuw i64 [[SELECT]] to i32
+; CHECK-NEXT:    call void @use64(i64 [[ADD]])
+; CHECK-NEXT:    ret i32 [[CONV7]]
+;
+entry:
+  %conv = zext i32 %a to i64
+  %conv1 = zext i32 %b to i64
+  %add = add i64 %conv1, %conv
+  %0 = icmp ult i64 %add, 4294967295
+  %select = select i1 %0, i64 %add, i64 4294967295
+  %conv7 = trunc i64 %select to i32
+  call void @use64(i64 %add)
+  ret i32 %conv7
+}
+
+define i32 @usub_sat32_extra_use_3(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @usub_sat32_extra_use_3(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[CONV:%.*]] = zext i32 [[A]] to i64
+; CHECK-NEXT:    [[CONV1:%.*]] = zext i32 [[B]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i64 [[CONV]], [[CONV1]]
+; CHECK-NEXT:    [[COND:%.*]] = call i64 @llvm.smin.i64(i64 [[SUB]], i64 4294967295)
+; CHECK-NEXT:    [[COND11:%.*]] = call i64 @llvm.smax.i64(i64 [[COND]], i64 0)
+; CHECK-NEXT:    [[TMP0:%.*]] = trunc i64 [[COND11]] to i32
+; CHECK-NEXT:    call void @use64(i64 [[COND]])
+; CHECK-NEXT:    ret i32 [[TMP0]]
+;
+entry:
+  %conv = zext i32 %a to i64
+  %conv1 = zext i32 %b to i64
+  %sub = sub i64 %conv, %conv1
+  %cmp4 = icmp sgt i64 %sub, 0
+  %cmp6 = icmp slt i64 %sub, 4294967295
+  %cond = select i1 %cmp6, i64 %sub, i64 4294967295
+  %cond11 = select i1 %cmp4, i64 %cond, i64 0
+  %conv12 = trunc i64 %cond11 to i32
+  call void @use64(i64 %cond)
+  ret i32 %conv12
+}
+
+define i32 @usub_sat32_minmax_extra_use_4(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @usub_sat32_minmax_extra_use_4(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[CONV:%.*]] = zext i32 [[A]] to i64
+; CHECK-NEXT:    [[CONV1:%.*]] = zext i32 [[B]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i64 [[CONV]], [[CONV1]]
+; CHECK-NEXT:    [[COND:%.*]] = call i64 @llvm.smin.i64(i64 [[SUB]], i64 4294967295)
+; CHECK-NEXT:    [[COND11:%.*]] = call i64 @llvm.smax.i64(i64 [[COND]], i64 0)
+; CHECK-NEXT:    [[CONV12:%.*]] = trunc i64 [[COND11]] to i32
+; CHECK-NEXT:    call void @use64(i64 [[COND]])
+; CHECK-NEXT:    ret i32 [[CONV12]]
+;
+entry:
+  %conv = zext i32 %a to i64
+  %conv1 = zext i32 %b to i64
+  %sub = sub i64 %conv, %conv1
+  %cond = call i64 @llvm.smin.i64(i64 %sub, i64 4294967295)
+  %cond11 = call i64 @llvm.smax.i64(i64 %cond, i64 0)
+  %conv12 = trunc i64 %cond11 to i32
+  call void @use64(i64 %cond)
+  ret i32 %conv12
+}
+
+define i32 @usub_sat32_sext(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @usub_sat32_sext(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[CONV:%.*]] = sext i32 [[A]] to i64
+; CHECK-NEXT:    [[CONV1:%.*]] = sext i32 [[B]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i64 [[CONV]], [[CONV1]]
+; CHECK-NEXT:    [[COND:%.*]] = call i64 @llvm.smin.i64(i64 [[SUB]], i64 4294967295)
+; CHECK-NEXT:    [[COND11:%.*]] = call i64 @llvm.smax.i64(i64 [[COND]], i64 0)
+; CHECK-NEXT:    [[CONV12:%.*]] = trunc i64 [[COND11]] to i32
+; CHECK-NEXT:    ret i32 [[CONV12]]
+;
+entry:
+  %conv = sext i32 %a to i64
+  %conv1 = sext i32 %b to i64
+  %sub = sub i64 %conv, %conv1
+  %cmp4 = icmp sgt i64 %sub, 0
+  %cmp6 = icmp slt i64 %sub, 4294967295
+  %cond = select i1 %cmp6, i64 %sub, i64 4294967295
+  %cond11 = select i1 %cmp4, i64 %cond, i64 0
+  %conv12 = trunc i64 %cond11 to i32
+  ret i32 %conv12
+}
+
+define i32 @usub_sat32_maxmin(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @usub_sat32_maxmin(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[CONV12:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[A]], i32 [[B]])
+; CHECK-NEXT:    ret i32 [[CONV12]]
+;
+entry:
+  %conv = zext i32 %a to i64
+  %conv1 = zext i32 %b to i64
+  %sub = sub i64 %conv, %conv1
+  %cmp4 = icmp sgt i64 %sub, 0
+  %cmp6 = icmp slt i64 %sub, 4294967295
+  %cond = select i1 %cmp4, i64 %sub, i64 0
+  %cond11 = select i1 %cmp6, i64 %cond, i64 4294967295
+  %conv12 = trunc i64 %cond11 to i32
+  ret i32 %conv12
+}
+
+define i64 @uadd_sat32_no_trunc(i32 %a, i32 %b) {
+; CHECK-LABEL: define i64 @uadd_sat32_no_trunc(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[B]], i32 [[A]])
+; CHECK-NEXT:    [[SELECT:%.*]] = zext i32 [[TMP0]] to i64
+; CHECK-NEXT:    ret i64 [[SELECT]]
+;
+entry:
+  %conv = zext i32 %a to i64
+  %conv1 = zext i32 %b to i64
+  %add = add i64 %conv1, %conv
+  %0 = icmp ult i64 %add, 4294967295
+  %select = select i1 %0, i64 %add, i64 4294967295
+  ret i64 %select
+}
+
+define i8 @const(i8 %X) {
+; CHECK-LABEL: define i8 @const(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:    [[CONV10:%.*]] = zext i8 [[X]] to i16
+; CHECK-NEXT:    [[TMP1:%.*]] = call i16 @llvm.smax.i16(i16 [[CONV10]], i16 10)
+; CHECK-NEXT:    [[TMP2:%.*]] = trunc nuw i16 [[TMP1]] to i8
+; CHECK-NEXT:    [[CONV:%.*]] = add i8 [[TMP2]], -10
+; CHECK-NEXT:    ret i8 [[CONV]]
+;
+  %conv10 = zext i8 %X to i16
+  %sub = sub i16 %conv10, 10
+  %l9 = icmp slt i16 %sub, 255
+  %l10 = select i1 %l9, i16 %sub, i16 255
+  %l11 = icmp sgt i16 %sub, 0
+  %l12 = select i1 %l11, i16 %l10, i16 0
+  %conv = trunc i16 %l12 to i8
+  ret i8 %conv
+}
+
+define i32 @invalid_sub_could_be_negative(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @invalid_sub_could_be_negative(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT:    [[CONV:%.*]] = zext i32 [[A]] to i64
+; CHECK-NEXT:    [[CONV3:%.*]] = zext i32 [[B]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i64 [[CONV]], [[CONV3]]
+; CHECK-NEXT:    [[SPEC_STORE_SELECT13:%.*]] = call i64 @llvm.umin.i64(i64 [[SUB]], i64 4294967295)
+; CHECK-NEXT:    [[CONV10:%.*]] = trunc nuw i64 [[SPEC_STORE_SELECT13]] to i32
+; CHECK-NEXT:    ret i32 [[CONV10]]
+;
+  %conv = zext i32 %a to i64
+  %conv3 = zext i32 %b to i64
+  %sub = sub nsw i64 %conv, %conv3
+  %spec.store.select13 = call i64 @llvm.umin.i64(i64 %sub, i64 4294967295)
+  %conv10 = trunc i64 %spec.store.select13 to i32
+  ret i32 %conv10
+}
+
+declare void @use64(i64)
+declare i64 @llvm.umin.i64(i64, i64)
+declare i64 @llvm.smin.i64(i64, i64)
+declare i64 @llvm.smax.i64(i64, i64)
+declare i32 @llvm.umin.i32(i32, i32)
+declare i32 @llvm.smin.i32(i32, i32)
+declare i32 @llvm.smax.i32(i32, i32)
+declare <8 x i32> @llvm.umin.v8i32(<8 x i32>, <8 x i32>)
+declare <2 x i128> @llvm.smin.v2i128(<2 x i128>, <2 x i128>)
+declare <2 x i128> @llvm.smax.v2i128(<2 x i128>, <2 x i128>)
----------------
dtcxzyw wrote:

```suggestion
```

Intrinsic declarations will be implied by LLParser.


https://github.com/llvm/llvm-project/pull/99250


More information about the llvm-commits mailing list