| ; 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 |
| } |