[llvm] 9058b9c - [RISCV][GlobalISel] Fix fptosi/fptoui from half to i64 on RV32 (#222316)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 17:56:07 PDT 2026


Author: Kane Wang
Date: 2026-09-24T08:56:01+08:00
New Revision: 9058b9c58e0788fcf3e00a3543587a82b12fa62a

URL: https://github.com/llvm/llvm-project/commit/9058b9c58e0788fcf3e00a3543587a82b12fa62a
DIFF: https://github.com/llvm/llvm-project/commit/9058b9c58e0788fcf3e00a3543587a82b12fa62a.diff

LOG: [RISCV][GlobalISel] Fix fptosi/fptoui from half to i64 on RV32 (#222316)

The fcvt.l[u].h patterns are RV64-only, so RV32 had no rule for
`G_FPTOSI/G_FPTOUI` with `{s64, s16}.` The magnitude of a half is at
most `65504`, so with Zfh the i32 result of `fcvt.w[u].h` never
overflows and can simply be extended to i64.

Added: 
    llvm/test/CodeGen/RISCV/GlobalISel/half-convert.ll

Modified: 
    llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index 451d21df4d95c..ff62ee25236f2 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -82,6 +82,7 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
   const LLT s1 = LLT::scalar(1);
   const LLT s8 = LLT::scalar(8);
   const LLT s16 = LLT::scalar(16);
+  const LLT f16 = LLT::float16();
   const LLT s32 = LLT::scalar(32);
   const LLT s64 = LLT::scalar(64);
   const LLT s128 = LLT::scalar(128);
@@ -641,6 +642,10 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
       .customFor(ST.is64Bit() && ST.hasStdExtZfh(), {{s32, s16}})
       .widenScalarToNextPow2(0)
       .minScalar(0, s32)
+      // The magnitude of a half is at most 65504, so with Zfh use fcvt.w[u].h
+      // and extend the i32 result. Without Zfh, use the libcalls.
+      .libcallFor(!ST.hasStdExtZfh(), {{s64, f16}})
+      .narrowScalarFor({{s64, f16}}, changeTo(0, s32))
       .libcallFor({{s32, s32}, {s64, s32}, {s32, s64}, {s64, s64}})
       .libcallFor(ST.is64Bit(), {{s32, s128}, {s64, s128}}) // FIXME RV32.
       .libcallFor(ST.is64Bit(), {{s128, s32}, {s128, s64}, {s128, s128}});

diff  --git a/llvm/test/CodeGen/RISCV/GlobalISel/half-convert.ll b/llvm/test/CodeGen/RISCV/GlobalISel/half-convert.ll
new file mode 100644
index 0000000000000..3338be0aad09d
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/half-convert.ll
@@ -0,0 +1,75 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -global-isel -mattr=+f,+d,+zfh \
+; RUN:   -target-abi=ilp32d < %s | FileCheck %s --check-prefixes=RV32
+; RUN: llc -mtriple=riscv64 -global-isel -mattr=+f,+d,+zfh \
+; RUN:   -target-abi=lp64d < %s | FileCheck %s --check-prefixes=RV64
+; RUN: llc -mtriple=riscv32 -global-isel -mattr=+f,+d \
+; RUN:   -target-abi=ilp32d < %s | FileCheck %s --check-prefixes=RV32NOZFH
+; RUN: llc -mtriple=riscv64 -global-isel -mattr=+f,+d \
+; RUN:   -target-abi=lp64d < %s | FileCheck %s --check-prefixes=RV64NOZFH
+
+define i64 @fptoui_i64_f16(half %x) nounwind {
+; RV32-LABEL: fptoui_i64_f16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    fcvt.wu.h a0, fa0, rtz
+; RV32-NEXT:    li a1, 0
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: fptoui_i64_f16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    fcvt.lu.h a0, fa0, rtz
+; RV64-NEXT:    ret
+;
+; RV32NOZFH-LABEL: fptoui_i64_f16:
+; RV32NOZFH:       # %bb.0:
+; RV32NOZFH-NEXT:    addi sp, sp, -16
+; RV32NOZFH-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; RV32NOZFH-NEXT:    call __fixunshfdi
+; RV32NOZFH-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
+; RV32NOZFH-NEXT:    addi sp, sp, 16
+; RV32NOZFH-NEXT:    ret
+;
+; RV64NOZFH-LABEL: fptoui_i64_f16:
+; RV64NOZFH:       # %bb.0:
+; RV64NOZFH-NEXT:    addi sp, sp, -16
+; RV64NOZFH-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64NOZFH-NEXT:    call __fixunshfdi
+; RV64NOZFH-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64NOZFH-NEXT:    addi sp, sp, 16
+; RV64NOZFH-NEXT:    ret
+  %a = fptoui half %x to i64
+  ret i64 %a
+}
+
+define i64 @fptosi_i64_f16(half %x) nounwind {
+; RV32-LABEL: fptosi_i64_f16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    fcvt.w.h a0, fa0, rtz
+; RV32-NEXT:    srai a1, a0, 31
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: fptosi_i64_f16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    fcvt.l.h a0, fa0, rtz
+; RV64-NEXT:    ret
+;
+; RV32NOZFH-LABEL: fptosi_i64_f16:
+; RV32NOZFH:       # %bb.0:
+; RV32NOZFH-NEXT:    addi sp, sp, -16
+; RV32NOZFH-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; RV32NOZFH-NEXT:    call __fixhfdi
+; RV32NOZFH-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
+; RV32NOZFH-NEXT:    addi sp, sp, 16
+; RV32NOZFH-NEXT:    ret
+;
+; RV64NOZFH-LABEL: fptosi_i64_f16:
+; RV64NOZFH:       # %bb.0:
+; RV64NOZFH-NEXT:    addi sp, sp, -16
+; RV64NOZFH-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64NOZFH-NEXT:    call __fixhfdi
+; RV64NOZFH-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64NOZFH-NEXT:    addi sp, sp, 16
+; RV64NOZFH-NEXT:    ret
+  %a = fptosi half %x to i64
+  ret i64 %a
+}


        


More information about the llvm-commits mailing list