Files
TheRock/compiler/amd-llvm/llvm/test/Transforms/InstCombine/sext-nonneg-sub.ll
T
derek.holloway 7502bf64a4
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
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

195 lines
7.6 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
; Test that b - smin(b, a) is recognized as non-negative
define i64 @func1(i32 %a, i32 %b) {
; CHECK-LABEL: define i64 @func1(
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = tail call i32 @llvm.smin.i32(i32 [[B]], i32 [[A]])
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[B]], [[SPEC_SELECT]]
; CHECK-NEXT: [[CONV:%.*]] = zext nneg i32 [[SUB]] to i64
; CHECK-NEXT: ret i64 [[CONV]]
;
entry:
%spec.select = tail call i32 @llvm.smin.i32(i32 %b, i32 %a)
%sub = sub nsw i32 %b, %spec.select
%conv = sext i32 %sub to i64
ret i64 %conv
}
; Test commutative smin pattern: b - smin(a, b) should also optimize
define i64 @smin_commutative(i32 %a, i32 %b) {
; CHECK-LABEL: define i64 @smin_commutative(
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.smin.i32(i32 [[A]], i32 [[B]])
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[B]], [[MIN]]
; CHECK-NEXT: [[EXT:%.*]] = zext nneg i32 [[SUB]] to i64
; CHECK-NEXT: ret i64 [[EXT]]
;
%min = call i32 @llvm.smin.i32(i32 %a, i32 %b)
%sub = sub nsw i32 %b, %min
%ext = sext i32 %sub to i64
ret i64 %ext
}
; NEGATIVE TEST: mismatched operands should not optimize
define i64 @smin_mismatch(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: define i64 @smin_mismatch(
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
; CHECK-NEXT: [[MIN:%.*]] = call i32 @llvm.smin.i32(i32 [[B]], i32 [[C]])
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[A]], [[MIN]]
; CHECK-NEXT: [[EXT:%.*]] = sext i32 [[SUB]] to i64
; CHECK-NEXT: ret i64 [[EXT]]
;
%min = call i32 @llvm.smin.i32(i32 %b, i32 %c)
%sub = sub nsw i32 %a, %min
%ext = sext i32 %sub to i64
ret i64 %ext
}
; NEGATIVE TEST: unguarded subtraction should NOT optimize
define i64 @neg_unguarded_sub(i32 %a, i32 %b) {
; CHECK-LABEL: define i64 @neg_unguarded_sub(
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[B]], [[A]]
; CHECK-NEXT: [[EXT:%.*]] = sext i32 [[SUB]] to i64
; CHECK-NEXT: ret i64 [[EXT]]
;
%sub = sub nsw i32 %b, %a
%ext = sext i32 %sub to i64
ret i64 %ext
}
; Test that select i1 (X < Y) ? 0 : X - Y is recognized as non-negative, converting sext to zext
define i64 @select_nonnegative_slt(i32 noundef %x, i32 %y) {
; CHECK-LABEL: define i64 @select_nonnegative_slt(
; CHECK-SAME: i32 noundef [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[Y]], i32 [[X]])
; CHECK-NEXT: [[COND:%.*]] = sub nsw i32 [[X]], [[TMP1]]
; CHECK-NEXT: [[CONV:%.*]] = zext nneg i32 [[COND]] to i64
; CHECK-NEXT: ret i64 [[CONV]]
;
%cmp = icmp slt i32 %x, %y ; b < a
%sub = sub nsw i32 %x, %y ; b - a
%cond = select i1 %cmp, i32 0, i32 %sub ; (X < Y) ? 0 : X - Y
%conv = sext i32 %cond to i64
ret i64 %conv
}
; Test that select <4 x i1> (X < Y) ? 0 : X - Y is recognized as non-negative, converting sext to zext
define <4 x i64> @select_nonnegative_slt_vec(<4 x i32> noundef %x, <4 x i32> %y) {
; CHECK-LABEL: define <4 x i64> @select_nonnegative_slt_vec(
; CHECK-SAME: <4 x i32> noundef [[X:%.*]], <4 x i32> [[Y:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call <4 x i32> @llvm.smin.v4i32(<4 x i32> [[Y]], <4 x i32> [[X]])
; CHECK-NEXT: [[COND:%.*]] = sub nsw <4 x i32> [[X]], [[TMP1]]
; CHECK-NEXT: [[CONV:%.*]] = zext nneg <4 x i32> [[COND]] to <4 x i64>
; CHECK-NEXT: ret <4 x i64> [[CONV]]
;
%cmp = icmp slt <4 x i32> %x, %y
%sub = sub nsw <4 x i32> %x, %y
%cond = select <4 x i1> %cmp, <4 x i32> zeroinitializer, <4 x i32> %sub
%conv = sext <4 x i32> %cond to <4 x i64>
ret <4 x i64> %conv
}
; Scalable vector should transform
define <vscale x 4 x i64> @select_nonnegative_slt_scalable(<vscale x 4 x i32> noundef %x, <vscale x 4 x i32> %y) {
; CHECK-LABEL: define <vscale x 4 x i64> @select_nonnegative_slt_scalable(
; CHECK-SAME: <vscale x 4 x i32> noundef [[X:%.*]], <vscale x 4 x i32> [[Y:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 4 x i32> @llvm.smin.nxv4i32(<vscale x 4 x i32> [[Y]], <vscale x 4 x i32> [[X]])
; CHECK-NEXT: [[COND:%.*]] = sub nsw <vscale x 4 x i32> [[X]], [[TMP1]]
; CHECK-NEXT: [[CONV:%.*]] = zext nneg <vscale x 4 x i32> [[COND]] to <vscale x 4 x i64>
; CHECK-NEXT: ret <vscale x 4 x i64> [[CONV]]
;
%cmp = icmp slt <vscale x 4 x i32> %x, %y
%sub = sub nsw <vscale x 4 x i32> %x, %y
%cond = select <vscale x 4 x i1> %cmp, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> %sub
%conv = sext <vscale x 4 x i32> %cond to <vscale x 4 x i64>
ret <vscale x 4 x i64> %conv
}
define i64 @slt_commuted(i32 %x, i32 noundef %y) {
; CHECK-LABEL: define i64 @slt_commuted(
; CHECK-SAME: i32 [[X:%.*]], i32 noundef [[Y:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT: [[SEL:%.*]] = sub nsw i32 [[Y]], [[TMP1]]
; CHECK-NEXT: [[EXT:%.*]] = zext nneg i32 [[SEL]] to i64
; CHECK-NEXT: ret i64 [[EXT]]
;
%cmp = icmp sgt i32 %y, %x
%sub = sub nsw i32 %y, %x
%sel = select i1 %cmp, i32 %sub, i32 0 ; (X < Y) ? Y - X : 0
%ext = sext i32 %sel to i64
ret i64 %ext
}
define i64 @sgt_commuted(i32 noundef %x, i32 %y) {
; CHECK-LABEL: define i64 @sgt_commuted(
; CHECK-SAME: i32 noundef [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[Y]], i32 [[X]])
; CHECK-NEXT: [[SEL:%.*]] = sub nsw i32 [[X]], [[TMP1]]
; CHECK-NEXT: [[EXT:%.*]] = zext nneg i32 [[SEL]] to i64
; CHECK-NEXT: ret i64 [[EXT]]
;
%cmp = icmp slt i32 %y, %x ;
%sub = sub nsw i32 %x, %y ;
%sel = select i1 %cmp, i32 %sub, i32 0 ; (X > Y) ? X - Y : 0
%ext = sext i32 %sel to i64
ret i64 %ext
}
; NEGATIVE TEST: FVal is negative
define i64 @sgt_negative_fval(i32 noundef %x, i32 %y) {
; CHECK-LABEL: define i64 @sgt_negative_fval(
; CHECK-SAME: i32 noundef [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[Y]], [[X]]
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 -1
; CHECK-NEXT: [[EXT:%.*]] = sext i32 [[SEL]] to i64
; CHECK-NEXT: ret i64 [[EXT]]
;
%cmp = icmp slt i32 %y, %x ;
%sub = sub nsw i32 %x, %y ;
%sel = select i1 %cmp, i32 %sub, i32 -1 ; (X > Y) ? X - Y : -1
%ext = sext i32 %sel to i64
ret i64 %ext
}
; NEGATIVE TEST: Wrong operand in select arm
define i64 @slt_wrong_sub_order(i32 noundef %x, i32 %y) {
; CHECK-LABEL: define i64 @slt_wrong_sub_order(
; CHECK-SAME: i32 noundef [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X]], [[Y]]
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
; CHECK-NEXT: [[EXT:%.*]] = sext i32 [[SEL]] to i64
; CHECK-NEXT: ret i64 [[EXT]]
;
%cmp = icmp slt i32 %x, %y
%sub = sub nsw i32 %x, %y
%sel = select i1 %cmp, i32 %sub, i32 0 ; (X < Y) ? X - Y : 0
%ext = sext i32 %sel to i64
ret i64 %ext
}
; NEGATIVE TEST: TVal is negative
define i64 @slt_negative_tval(i32 %x, i32 noundef %y) {
;
; CHECK-LABEL: define i64 @slt_negative_tval(
; CHECK-SAME: i32 [[X:%.*]], i32 noundef [[Y:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X]], [[Y]]
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[Y]], [[X]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 -1, i32 [[SUB]]
; CHECK-NEXT: [[EXT:%.*]] = sext i32 [[SEL]] to i64
; CHECK-NEXT: ret i64 [[EXT]]
;
%cmp = icmp slt i32 %x, %y
%sub = sub nsw i32 %y, %x
%sel = select i1 %cmp, i32 -1, i32 %sub ; (X < Y) ? -1 : Y - X
%ext = sext i32 %sel to i64
ret i64 %ext
}