blob: df3098f867619b82ae07c096f76ed915d1ab0127 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=amdgpu9.0a-amd-amdhsa < %s | FileCheck %s
; The generic DAG combiner folds select(setcc X, 0, SETUO), 0, (fp_to_sint X)
; into fp_to_sint_sat when the target supports it. On AMDGPU, the V_CVT
; instructions already return 0 for NaN, so fp_to_sint_sat lowers to a single
; conversion instruction with no extra compare/select overhead.
;; Positive tests
define i32 @nan_guard_fptosi_f32(float %x) {
; CHECK-LABEL: nan_guard_fptosi_f32:
; CHECK: ; %bb.0:
; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; CHECK-NEXT: v_cvt_i32_f32_e32 v0, v0
; CHECK-NEXT: s_setpc_b64 s[30:31]
%cmp = fcmp uno float %x, 0.000000e+00
%conv = fptosi float %x to i32
%sel = select i1 %cmp, i32 0, i32 %conv
ret i32 %sel
}
define i32 @nan_guard_fptosi_ord_f32(float %x) {
; CHECK-LABEL: nan_guard_fptosi_ord_f32:
; CHECK: ; %bb.0:
; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; CHECK-NEXT: v_cvt_i32_f32_e32 v0, v0
; CHECK-NEXT: s_setpc_b64 s[30:31]
%cmp = fcmp ord float %x, 0.000000e+00
%conv = fptosi float %x to i32
%sel = select i1 %cmp, i32 %conv, i32 0
ret i32 %sel
}
define i32 @nan_guard_fptoui_f32(float %x) {
; CHECK-LABEL: nan_guard_fptoui_f32:
; CHECK: ; %bb.0:
; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; CHECK-NEXT: v_cvt_u32_f32_e32 v0, v0
; CHECK-NEXT: s_setpc_b64 s[30:31]
%cmp = fcmp uno float %x, 0.000000e+00
%conv = fptoui float %x to i32
%sel = select i1 %cmp, i32 0, i32 %conv
ret i32 %sel
}
define i32 @nan_guard_fptoui_ord_f32(float %x) {
; CHECK-LABEL: nan_guard_fptoui_ord_f32:
; CHECK: ; %bb.0:
; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; CHECK-NEXT: v_cvt_u32_f32_e32 v0, v0
; CHECK-NEXT: s_setpc_b64 s[30:31]
%cmp = fcmp ord float %x, 0.000000e+00
%conv = fptoui float %x to i32
%sel = select i1 %cmp, i32 %conv, i32 0
ret i32 %sel
}
define i32 @nan_guard_fptosi_and_mask(float %x) {
; CHECK-LABEL: nan_guard_fptosi_and_mask:
; CHECK: ; %bb.0:
; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; CHECK-NEXT: v_cvt_i32_f32_e32 v0, v0
; CHECK-NEXT: v_and_b32_e32 v0, 3, v0
; CHECK-NEXT: s_setpc_b64 s[30:31]
%cmp = fcmp uno float %x, 0.000000e+00
%conv = fptosi float %x to i32
%and = and i32 %conv, 3
%sel = select i1 %cmp, i32 0, i32 %and
ret i32 %sel
}
; AND mask with a non-constant operand.
define i32 @nan_guard_fptosi_and_mask_var(float %x, i32 %m) {
; CHECK-LABEL: nan_guard_fptosi_and_mask_var:
; CHECK: ; %bb.0:
; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; CHECK-NEXT: v_cvt_i32_f32_e32 v0, v0
; CHECK-NEXT: v_and_b32_e32 v0, v0, v1
; CHECK-NEXT: s_setpc_b64 s[30:31]
%cmp = fcmp uno float %x, 0.000000e+00
%conv = fptosi float %x to i32
%and = and i32 %conv, %m
%sel = select i1 %cmp, i32 0, i32 %and
ret i32 %sel
}
; AND mask with a non-constant operand, commuted.
define i32 @nan_guard_fptosi_and_mask_commuted(float %x, i32 %m) {
; CHECK-LABEL: nan_guard_fptosi_and_mask_commuted:
; CHECK: ; %bb.0:
; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; CHECK-NEXT: v_cvt_i32_f32_e32 v0, v0
; CHECK-NEXT: v_and_b32_e32 v0, v0, v1
; CHECK-NEXT: s_setpc_b64 s[30:31]
%cmp = fcmp uno float %x, 0.000000e+00
%conv = fptosi float %x to i32
%and = and i32 %m, %conv
%sel = select i1 %cmp, i32 0, i32 %and
ret i32 %sel
}
define i32 @nan_guard_fptosi_f64(double %x) {
; CHECK-LABEL: nan_guard_fptosi_f64:
; CHECK: ; %bb.0:
; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; CHECK-NEXT: v_cvt_i32_f64_e32 v0, v[0:1]
; CHECK-NEXT: s_setpc_b64 s[30:31]
%cmp = fcmp uno double %x, 0.000000e+00
%conv = fptosi double %x to i32
%sel = select i1 %cmp, i32 0, i32 %conv
ret i32 %sel
}
;; Negative tests
define i32 @nan_guard_nonzero_constant(float %x) {
; CHECK-LABEL: nan_guard_nonzero_constant:
; CHECK: ; %bb.0:
; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; CHECK-NEXT: v_cvt_i32_f32_e32 v1, v0
; CHECK-NEXT: v_cmp_o_f32_e32 vcc, v0, v0
; CHECK-NEXT: v_cndmask_b32_e32 v0, 42, v1, vcc
; CHECK-NEXT: s_setpc_b64 s[30:31]
%cmp = fcmp uno float %x, 0.000000e+00
%conv = fptosi float %x to i32
%sel = select i1 %cmp, i32 42, i32 %conv
ret i32 %sel
}
define i32 @nan_guard_mismatched_operands(float %x, float %y) {
; CHECK-LABEL: nan_guard_mismatched_operands:
; CHECK: ; %bb.0:
; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; CHECK-NEXT: v_cvt_i32_f32_e32 v1, v1
; CHECK-NEXT: v_cmp_o_f32_e32 vcc, v0, v0
; CHECK-NEXT: v_cndmask_b32_e32 v0, 0, v1, vcc
; CHECK-NEXT: s_setpc_b64 s[30:31]
%cmp = fcmp uno float %x, 0.000000e+00
%conv = fptosi float %y to i32
%sel = select i1 %cmp, i32 0, i32 %conv
ret i32 %sel
}
; Compare is a different predicate (not uno/ord) -- should not fold.
define i32 @nan_guard_wrong_predicate(float %x) {
; CHECK-LABEL: nan_guard_wrong_predicate:
; CHECK: ; %bb.0:
; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; CHECK-NEXT: v_cvt_i32_f32_e32 v1, v0
; CHECK-NEXT: v_cmp_ngt_f32_e32 vcc, 0, v0
; CHECK-NEXT: v_cndmask_b32_e32 v0, 0, v1, vcc
; CHECK-NEXT: s_setpc_b64 s[30:31]
%cmp = fcmp olt float %x, 0.000000e+00
%conv = fptosi float %x to i32
%sel = select i1 %cmp, i32 0, i32 %conv
ret i32 %sel
}
; The vector cases below do not fold: AMDGPU lowers vector fp_to_sint_sat /
; fp_to_uint_sat via Expand, so shouldConvertFpToSat is false and the guard is
; preserved. (On targets with a native vector op, e.g. AArch64, they fold.)
define <4 x i32> @nan_guard_fptosi_v4f32(<4 x float> %x) {
; CHECK-LABEL: nan_guard_fptosi_v4f32:
; CHECK: ; %bb.0:
; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; CHECK-NEXT: v_cvt_i32_f32_e32 v5, v0
; CHECK-NEXT: v_cvt_i32_f32_e32 v7, v1
; CHECK-NEXT: v_cvt_i32_f32_e32 v6, v2
; CHECK-NEXT: v_cvt_i32_f32_e32 v4, v3
; CHECK-NEXT: v_cmp_o_f32_e32 vcc, v0, v0
; CHECK-NEXT: v_cndmask_b32_e32 v0, 0, v5, vcc
; CHECK-NEXT: v_cmp_o_f32_e32 vcc, v1, v1
; CHECK-NEXT: v_cndmask_b32_e32 v1, 0, v7, vcc
; CHECK-NEXT: v_cmp_o_f32_e32 vcc, v2, v2
; CHECK-NEXT: v_cndmask_b32_e32 v2, 0, v6, vcc
; CHECK-NEXT: v_cmp_o_f32_e32 vcc, v3, v3
; CHECK-NEXT: v_cndmask_b32_e32 v3, 0, v4, vcc
; CHECK-NEXT: s_setpc_b64 s[30:31]
%cmp = fcmp uno <4 x float> %x, zeroinitializer
%conv = fptosi <4 x float> %x to <4 x i32>
%sel = select <4 x i1> %cmp, <4 x i32> zeroinitializer, <4 x i32> %conv
ret <4 x i32> %sel
}
define <4 x i32> @nan_guard_fptosi_v4f32_and_mask(<4 x float> %x, <4 x i32> %m) {
; CHECK-LABEL: nan_guard_fptosi_v4f32_and_mask:
; CHECK: ; %bb.0:
; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; CHECK-NEXT: v_cvt_i32_f32_e32 v11, v0
; CHECK-NEXT: v_cvt_i32_f32_e32 v10, v1
; CHECK-NEXT: v_cvt_i32_f32_e32 v9, v2
; CHECK-NEXT: v_cvt_i32_f32_e32 v8, v3
; CHECK-NEXT: v_and_b32_e32 v4, v11, v4
; CHECK-NEXT: v_cmp_o_f32_e32 vcc, v0, v0
; CHECK-NEXT: v_and_b32_e32 v5, v10, v5
; CHECK-NEXT: v_cndmask_b32_e32 v0, 0, v4, vcc
; CHECK-NEXT: v_cmp_o_f32_e32 vcc, v1, v1
; CHECK-NEXT: v_and_b32_e32 v6, v9, v6
; CHECK-NEXT: v_cndmask_b32_e32 v1, 0, v5, vcc
; CHECK-NEXT: v_cmp_o_f32_e32 vcc, v2, v2
; CHECK-NEXT: v_and_b32_e32 v7, v8, v7
; CHECK-NEXT: v_cndmask_b32_e32 v2, 0, v6, vcc
; CHECK-NEXT: v_cmp_o_f32_e32 vcc, v3, v3
; CHECK-NEXT: v_cndmask_b32_e32 v3, 0, v7, vcc
; CHECK-NEXT: s_setpc_b64 s[30:31]
%cmp = fcmp uno <4 x float> %x, zeroinitializer
%conv = fptosi <4 x float> %x to <4 x i32>
%and = and <4 x i32> %conv, %m
%sel = select <4 x i1> %cmp, <4 x i32> zeroinitializer, <4 x i32> %and
ret <4 x i32> %sel
}