[llvm] [NVPTX] Fix fptosi/fptoui to i1. (PR #200718)
via llvm-commits
llvm-commits at lists.llvm.org
Sun May 31 22:33:34 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-nvptx
Author: Justin Lebar (jlebar)
<details>
<summary>Changes</summary>
The langref says:
> The ‘fptosi’ instruction converts its floating-point operand into the
> nearest (rounding towards zero) signed integer value. If the value
> cannot fit in ty2, the result is a poison value.
Previously `fptosi to i1` and `fptoui to i1` were lowered as `x == 0.0`,
which is clearly incorrect.
A valid lowering for `fptosi to i1` is `and (cvt.rzi.s32.fNN x), 1`, i.e.
- convert float to s32 with "round-to-nearest-integer in the direction
of zero" mode, then
- take the low-order bit.
Same for `fptoui to i1` except we convert to u32.
This works because the only results we care about are
- rounding to 0 and -1 (for the signed case) and,
- rounding to 0 and 1 (for the unsigned case)
and these give us the i1 values of 0 and 1 as expected. (Other rounded
values are poison so we can return any value.)
---
Full diff: https://github.com/llvm/llvm-project/pull/200718.diff
3 Files Affected:
- (modified) llvm/lib/Target/NVPTX/NVPTXInstrInfo.td (+8-8)
- (added) llvm/test/CodeGen/NVPTX/convert-fp-i1-narrow.ll (+14)
- (modified) llvm/test/CodeGen/NVPTX/convert-fp.ll (+26)
``````````diff
diff --git a/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td b/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
index 982d664e694f8..8ffd1e00fbf0d 100644
--- a/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
+++ b/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
@@ -2106,25 +2106,25 @@ def : Pat<(f64 (uint_to_fp i64:$a)), (CVT_f64_u64 $a, CvtRN)>;
// f16 -> sint
-def : Pat<(i1 (fp_to_sint f16:$a)), (SETP_i16ri $a, 0, CmpEQ)>;
+def : Pat<(i1 (fp_to_sint f16:$a)), (SETP_i32ri (AND_b32ri (CVT_s32_f16 $a, CvtRZI), 1), 0, CmpNE)>;
def : Pat<(i16 (fp_to_sint f16:$a)), (CVT_s16_f16 $a, CvtRZI)>;
def : Pat<(i32 (fp_to_sint f16:$a)), (CVT_s32_f16 $a, CvtRZI)>;
def : Pat<(i64 (fp_to_sint f16:$a)), (CVT_s64_f16 $a, CvtRZI)>;
// f16 -> uint
-def : Pat<(i1 (fp_to_uint f16:$a)), (SETP_i16ri $a, 0, CmpEQ)>;
+def : Pat<(i1 (fp_to_uint f16:$a)), (SETP_i32ri (AND_b32ri (CVT_u32_f16 $a, CvtRZI), 1), 0, CmpNE)>;
def : Pat<(i16 (fp_to_uint f16:$a)), (CVT_u16_f16 $a, CvtRZI)>;
def : Pat<(i32 (fp_to_uint f16:$a)), (CVT_u32_f16 $a, CvtRZI)>;
def : Pat<(i64 (fp_to_uint f16:$a)), (CVT_u64_f16 $a, CvtRZI)>;
// bf16 -> sint
-def : Pat<(i1 (fp_to_sint bf16:$a)), (SETP_i16ri $a, 0, CmpEQ)>;
+def : Pat<(i1 (fp_to_sint bf16:$a)), (SETP_i32ri (AND_b32ri (CVT_s32_bf16 $a, CvtRZI), 1), 0, CmpNE)>;
def : Pat<(i16 (fp_to_sint bf16:$a)), (CVT_s16_bf16 $a, CvtRZI)>;
def : Pat<(i32 (fp_to_sint bf16:$a)), (CVT_s32_bf16 $a, CvtRZI)>;
def : Pat<(i64 (fp_to_sint bf16:$a)), (CVT_s64_bf16 $a, CvtRZI)>;
// bf16 -> uint
-def : Pat<(i1 (fp_to_uint bf16:$a)), (SETP_i16ri $a, 0, CmpEQ)>;
+def : Pat<(i1 (fp_to_uint bf16:$a)), (SETP_i32ri (AND_b32ri (CVT_u32_bf16 $a, CvtRZI), 1), 0, CmpNE)>;
def : Pat<(i16 (fp_to_uint bf16:$a)), (CVT_u16_bf16 $a, CvtRZI)>;
def : Pat<(i32 (fp_to_uint bf16:$a)), (CVT_u32_bf16 $a, CvtRZI)>;
def : Pat<(i64 (fp_to_uint bf16:$a)), (CVT_u64_bf16 $a, CvtRZI)>;
@@ -2134,7 +2134,7 @@ let Predicates = [doF32FTZ] in {
def : Pat<(i32 (fp_to_sint f32:$a)), (CVT_s32_f32 $a, CvtRZI_FTZ)>;
def : Pat<(i64 (fp_to_sint f32:$a)), (CVT_s64_f32 $a, CvtRZI_FTZ)>;
}
-def : Pat<(i1 (fp_to_sint f32:$a)), (SETP_i32ri $a, 0, CmpEQ)>;
+def : Pat<(i1 (fp_to_sint f32:$a)), (SETP_i32ri (AND_b32ri (CVT_s32_f32 $a, CvtRZI), 1), 0, CmpNE)>;
def : Pat<(i16 (fp_to_sint f32:$a)), (CVT_s16_f32 $a, CvtRZI)>;
def : Pat<(i32 (fp_to_sint f32:$a)), (CVT_s32_f32 $a, CvtRZI)>;
def : Pat<(i64 (fp_to_sint f32:$a)), (CVT_s64_f32 $a, CvtRZI)>;
@@ -2145,19 +2145,19 @@ let Predicates = [doF32FTZ] in {
def : Pat<(i32 (fp_to_uint f32:$a)), (CVT_u32_f32 $a, CvtRZI_FTZ)>;
def : Pat<(i64 (fp_to_uint f32:$a)), (CVT_u64_f32 $a, CvtRZI_FTZ)>;
}
-def : Pat<(i1 (fp_to_uint f32:$a)), (SETP_i32ri $a, 0, CmpEQ)>;
+def : Pat<(i1 (fp_to_uint f32:$a)), (SETP_i32ri (AND_b32ri (CVT_u32_f32 $a, CvtRZI), 1), 0, CmpNE)>;
def : Pat<(i16 (fp_to_uint f32:$a)), (CVT_u16_f32 $a, CvtRZI)>;
def : Pat<(i32 (fp_to_uint f32:$a)), (CVT_u32_f32 $a, CvtRZI)>;
def : Pat<(i64 (fp_to_uint f32:$a)), (CVT_u64_f32 $a, CvtRZI)>;
// f64 -> sint
-def : Pat<(i1 (fp_to_sint f64:$a)), (SETP_i64ri $a, 0, CmpEQ)>;
+def : Pat<(i1 (fp_to_sint f64:$a)), (SETP_i32ri (AND_b32ri (CVT_s32_f64 $a, CvtRZI), 1), 0, CmpNE)>;
def : Pat<(i16 (fp_to_sint f64:$a)), (CVT_s16_f64 $a, CvtRZI)>;
def : Pat<(i32 (fp_to_sint f64:$a)), (CVT_s32_f64 $a, CvtRZI)>;
def : Pat<(i64 (fp_to_sint f64:$a)), (CVT_s64_f64 $a, CvtRZI)>;
// f64 -> uint
-def : Pat<(i1 (fp_to_uint f64:$a)), (SETP_i64ri $a, 0, CmpEQ)>;
+def : Pat<(i1 (fp_to_uint f64:$a)), (SETP_i32ri (AND_b32ri (CVT_u32_f64 $a, CvtRZI), 1), 0, CmpNE)>;
def : Pat<(i16 (fp_to_uint f64:$a)), (CVT_u16_f64 $a, CvtRZI)>;
def : Pat<(i32 (fp_to_uint f64:$a)), (CVT_u32_f64 $a, CvtRZI)>;
def : Pat<(i64 (fp_to_uint f64:$a)), (CVT_u64_f64 $a, CvtRZI)>;
diff --git a/llvm/test/CodeGen/NVPTX/convert-fp-i1-narrow.ll b/llvm/test/CodeGen/NVPTX/convert-fp-i1-narrow.ll
new file mode 100644
index 0000000000000..7670757469e04
--- /dev/null
+++ b/llvm/test/CodeGen/NVPTX/convert-fp-i1-narrow.ll
@@ -0,0 +1,14 @@
+; fptoui/fptosi from half to i1 (sm_53+) must convert-to-int then test the low
+; bit, like the f32/f64 cases. (bf16 widens to f32 below sm_80, so it exercises
+; the f32 path, not a distinct bf16 pattern.)
+; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_53 | FileCheck %s
+
+; CHECK-LABEL: cvt_u1_f16(
+; CHECK: cvt.rzi.u32.f16 %r{{[0-9]+}}, %rs{{[0-9]+}};
+; CHECK: and.b32 %r{{[0-9]+}}, %r{{[0-9]+}}, 1;
+define i1 @cvt_u1_f16(half %x) { %a = fptoui half %x to i1 ret i1 %a }
+
+; CHECK-LABEL: cvt_s1_f16(
+; CHECK: cvt.rzi.s32.f16 %r{{[0-9]+}}, %rs{{[0-9]+}};
+; CHECK: and.b32 %r{{[0-9]+}}, %r{{[0-9]+}}, 1;
+define i1 @cvt_s1_f16(half %x) { %a = fptosi half %x to i1 ret i1 %a }
diff --git a/llvm/test/CodeGen/NVPTX/convert-fp.ll b/llvm/test/CodeGen/NVPTX/convert-fp.ll
index 59b33b1bce7a7..7bcd7993643d3 100644
--- a/llvm/test/CodeGen/NVPTX/convert-fp.ll
+++ b/llvm/test/CodeGen/NVPTX/convert-fp.ll
@@ -163,3 +163,29 @@ define i64 @cvt_s64_f64(double %x) {
%a = fptosi double %x to i64
ret i64 %a
}
+
+
+define i1 @cvt_u1_f32(float %x) {
+; CHECK-LABEL: cvt_u1_f32
+; CHECK: cvt.rzi.u32.f32 %r{{[0-9]+}}, %r{{[0-9]+}};
+; CHECK: and.b32 %r{{[0-9]+}}, %r{{[0-9]+}}, 1;
+; CHECK: ret;
+ %a = fptoui float %x to i1
+ ret i1 %a
+}
+define i1 @cvt_s1_f32(float %x) {
+; CHECK-LABEL: cvt_s1_f32
+; CHECK: cvt.rzi.s32.f32 %r{{[0-9]+}}, %r{{[0-9]+}};
+; CHECK: and.b32 %r{{[0-9]+}}, %r{{[0-9]+}}, 1;
+; CHECK: ret;
+ %a = fptosi float %x to i1
+ ret i1 %a
+}
+; CHECK-LABEL: cvt_u1_f64(
+; CHECK: cvt.rzi.u32.f64 %r{{[0-9]+}}, %rd{{[0-9]+}};
+; CHECK: and.b32 %r{{[0-9]+}}, %r{{[0-9]+}}, 1;
+define i1 @cvt_u1_f64(double %x) { %a = fptoui double %x to i1 ret i1 %a }
+; CHECK-LABEL: cvt_s1_f64(
+; CHECK: cvt.rzi.s32.f64 %r{{[0-9]+}}, %rd{{[0-9]+}};
+; CHECK: and.b32 %r{{[0-9]+}}, %r{{[0-9]+}}, 1;
+define i1 @cvt_s1_f64(double %x) { %a = fptosi double %x to i1 ret i1 %a }
``````````
</details>
https://github.com/llvm/llvm-project/pull/200718
More information about the llvm-commits
mailing list