[llvm] [NVPTX] Fix fptosi/fptoui to i1. (PR #200718)

Justin Lebar via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 1 10:57:27 PDT 2026


https://github.com/jlebar updated https://github.com/llvm/llvm-project/pull/200718

>From 7d12bd57813f42d5d2144344c0988e07b9d5c5ad Mon Sep 17 00:00:00 2001
From: Justin Lebar <justin.lebar at gmail.com>
Date: Sun, 31 May 2026 18:07:01 -0700
Subject: [PATCH] [NVPTX] Fix fptosi/fptoui to i1.

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.

Because the conversion truncates toward zero, the only results that are
not poison are:

 - 0 and -1 for the signed case, and
 - 0 and 1 for the unsigned case.

So the i1 result is fully determined by a single fp compare:

 - `fptosi x to i1`  ==  `x <= -1.0`
 - `fptoui x to i1`  ==  `x >= 1.0`

with any value being acceptable for the poison (out-of-range) inputs.
---
 llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp | 13 +++++++
 llvm/lib/Target/NVPTX/NVPTXInstrInfo.td     | 11 ++----
 llvm/test/CodeGen/NVPTX/convert-fp.ll       | 39 ++++++++++++++++++---
 3 files changed, 51 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp b/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp
index d1d01089aa49e..21b61cecfd6c4 100644
--- a/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp
@@ -994,6 +994,7 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM,
         MVT::bf16, Custom);
   }
 
+  setOperationAction({ISD::FP_TO_SINT, ISD::FP_TO_UINT}, MVT::i1, Custom);
   setOperationAction(ISD::FROUND, MVT::f16, Promote);
   setOperationAction(ISD::FROUND, MVT::v2f16, Expand);
   setOperationAction(ISD::FROUND, MVT::v2bf16, Expand);
@@ -3481,6 +3482,18 @@ NVPTXTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
     return LowerINT_TO_FP(Op, DAG);
   case ISD::FP_TO_SINT:
   case ISD::FP_TO_UINT:
+    // fptosi/fptoui to i1 truncate toward zero, so the only defined results
+    // are {0,-1} (signed) and {0,1} (unsigned); every other input results in
+    // poison. Thus we can simply lower to `x <= -1.0` or `x >= 1.0`.
+    if (Op.getValueType() == MVT::i1) {
+      SDLoc DL(Op);
+      SDValue X = Op.getOperand(0);
+      bool IsSigned = Op.getOpcode() == ISD::FP_TO_SINT;
+      return DAG.getSetCC(
+          DL, MVT::i1, X,
+          DAG.getConstantFP(IsSigned ? -1.0 : 1.0, DL, X.getValueType()),
+          IsSigned ? ISD::SETOLE : ISD::SETOGE);
+    }
     return LowerFP_TO_INT(Op, DAG);
   case ISD::FP_ROUND:
     return LowerFP_ROUND(Op, DAG);
diff --git a/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td b/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
index 982d664e694f8..ff3e5144c6fbe 100644
--- a/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
+++ b/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
@@ -2105,26 +2105,25 @@ def : Pat<(f64 (uint_to_fp i32:$a)), (CVT_f64_u32 $a, CvtRN)>;
 def : Pat<(f64 (uint_to_fp i64:$a)), (CVT_f64_u64 $a, CvtRN)>;
 
 
+// fp_to_sint/uint to i1 is custom-lowered to an fp compare
+// (NVPTXTargetLowering::LowerOperation), so no i1 patterns appear below.
+
 // f16 -> sint
-def : Pat<(i1  (fp_to_sint f16:$a)), (SETP_i16ri $a, 0, CmpEQ)>;
 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<(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<(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<(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 +2133,6 @@ 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<(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 +2143,16 @@ 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<(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<(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<(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.ll b/llvm/test/CodeGen/NVPTX/convert-fp.ll
index 59b33b1bce7a7..f03287a811339 100644
--- a/llvm/test/CodeGen/NVPTX/convert-fp.ll
+++ b/llvm/test/CodeGen/NVPTX/convert-fp.ll
@@ -1,7 +1,7 @@
-; RUN: llc < %s -mtriple=nvptx -mcpu=sm_20 | FileCheck %s
-; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_20 | FileCheck %s
-; RUN: %if ptxas-ptr32 %{ llc < %s -mtriple=nvptx -mcpu=sm_20 | %ptxas-verify %}
-; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_20 | %ptxas-verify %}
+; RUN: llc < %s -mtriple=nvptx -mcpu=sm_53 | FileCheck %s
+; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_53 | FileCheck %s
+; RUN: %if ptxas-ptr32 %{ llc < %s -mtriple=nvptx -mcpu=sm_53 | %ptxas-verify %}
+; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_53 | %ptxas-verify %}
 
 define i16 @cvt_u16_f32(float %x) {
 ; CHECK: cvt.rzi.u16.f32 %rs{{[0-9]+}}, %r{{[0-9]+}};
@@ -163,3 +163,34 @@ define i64 @cvt_s64_f64(double %x) {
   %a = fptosi double %x to i64
   ret i64 %a
 }
+
+
+; fptoui/fptosi to i1 truncate toward zero, so the result is just
+; (x >= 1.0) / (x <= -1.0) — a single fp compare.
+; CHECK-LABEL: cvt_u1_f32
+; CHECK: setp.ge.f32 %p{{[0-9]+}}, %r{{[0-9]+}}, 0f3F800000;
+; CHECK: ret;
+define i1 @cvt_u1_f32(float %x) { %a = fptoui float %x to i1   ret i1 %a }
+
+; CHECK-LABEL: cvt_s1_f32
+; CHECK: setp.le.f32 %p{{[0-9]+}}, %r{{[0-9]+}}, 0fBF800000;
+; CHECK: ret;
+define i1 @cvt_s1_f32(float %x) { %a = fptosi float %x to i1 ret i1 %a }
+
+; CHECK-LABEL: cvt_u1_f64(
+; CHECK: setp.ge.f64 %p{{[0-9]+}}, %rd{{[0-9]+}}, 0d3FF0000000000000;
+define i1 @cvt_u1_f64(double %x) { %a = fptoui double %x to i1  ret i1 %a }
+
+; CHECK-LABEL: cvt_s1_f64(
+; CHECK: setp.le.f64 %p{{[0-9]+}}, %rd{{[0-9]+}}, 0dBFF0000000000000;
+define i1 @cvt_s1_f64(double %x) { %a = fptosi double %x to i1  ret i1 %a }
+
+; CHECK-LABEL: cvt_u1_f16(
+; CHECK: mov.b16 %rs{{[0-9]+}}, 0x3C00;
+; CHECK: setp.ge.f16 %p{{[0-9]+}}, %rs{{[0-9]+}}, %rs{{[0-9]+}};
+define i1 @cvt_u1_f16(half %x) { %a = fptoui half %x to i1  ret i1 %a }
+
+; CHECK-LABEL: cvt_s1_f16(
+; CHECK: mov.b16 %rs{{[0-9]+}}, 0xBC00;
+; CHECK: setp.le.f16 %p{{[0-9]+}}, %rs{{[0-9]+}}, %rs{{[0-9]+}};
+define i1 @cvt_s1_f16(half %x) { %a = fptosi half %x to i1  ret i1 %a }



More information about the llvm-commits mailing list