[llvm] 6b0c183 - [RISCV][GlobalISel] Support G_INTRINSIC_LRINT/G_INTRINSIC_LLRINT (#221992)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 9 18:09:48 PDT 2026
Author: Kane Wang
Date: 2026-09-10T09:09:43+08:00
New Revision: 6b0c1836d05ab22f55ec5b8e76bc797415de10f3
URL: https://github.com/llvm/llvm-project/commit/6b0c1836d05ab22f55ec5b8e76bc797415de10f3
DIFF: https://github.com/llvm/llvm-project/commit/6b0c1836d05ab22f55ec5b8e76bc797415de10f3.diff
LOG: [RISCV][GlobalISel] Support G_INTRINSIC_LRINT/G_INTRINSIC_LLRINT (#221992)
Add legalizer rules so llvm.lrint/llrint lower to fcvt.{w,l}.{h,s,d}
with FRM_DYN, mirroring the existing G_LROUND/G_LLROUND handling.
Added:
llvm/test/CodeGen/RISCV/GlobalISel/lrint-llrint-f16.ll
llvm/test/CodeGen/RISCV/GlobalISel/lrint-llrint.ll
Modified:
llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index d0ee9bb39cc8b..d587b7090c6b4 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -649,6 +649,19 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
{s32, s128},
{s64, s128}});
+ getActionDefinitionsBuilder({G_INTRINSIC_LRINT, G_INTRINSIC_LLRINT})
+ .legalFor(ST.hasStdExtF(), {{sXLen, s32}})
+ .legalFor(ST.hasStdExtD(), {{sXLen, s64}})
+ .legalFor(ST.hasStdExtZfh(), {{sXLen, s16}})
+ .minScalar(0, sXLen)
+ .widenScalarIf(typeIs(1, s16), LegalizeMutations::changeTo(1, s32))
+ .libcallFor({{s32, s32},
+ {s64, s32},
+ {s32, s64},
+ {s64, s64},
+ {s32, s128},
+ {s64, s128}});
+
getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
.legalFor(ST.hasStdExtF(), {{s32, sXLen}})
.legalFor(ST.hasStdExtD(), {{s64, sXLen}})
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
index 53399a13611d2..d6a9df281ceb1 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
@@ -170,6 +170,8 @@ bool RISCVRegisterBankInfo::onlyUsesFP(const MachineInstr &MI,
case TargetOpcode::G_FPTOUI:
case TargetOpcode::G_LROUND:
case TargetOpcode::G_LLROUND:
+ case TargetOpcode::G_INTRINSIC_LRINT:
+ case TargetOpcode::G_INTRINSIC_LLRINT:
case TargetOpcode::G_FCMP:
return true;
default:
@@ -466,6 +468,8 @@ RISCVRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case TargetOpcode::G_FPTOUI:
case TargetOpcode::G_LROUND:
case TargetOpcode::G_LLROUND:
+ case TargetOpcode::G_INTRINSIC_LRINT:
+ case TargetOpcode::G_INTRINSIC_LLRINT:
case RISCV::G_FCLASS: {
LLT Ty = MRI.getType(MI.getOperand(1).getReg());
OpdsMapping[0] = GPRValueMapping;
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
index a9a045daaaa9f..8e350e59123ca 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
@@ -187,11 +187,12 @@
# DEBUG-NEXT: .. the first uncovered type index: 1, OK
# DEBUG-NEXT: .. the first uncovered imm index: 0, OK
# DEBUG-NEXT: G_INTRINSIC_LRINT (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
-# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
-# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
+# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
+# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: G_INTRINSIC_LLRINT (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
-# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
-# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
+# DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}}
+# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
+# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: G_INTRINSIC_ROUNDEVEN (opcode {{[0-9]+}}): 1 type index, 0 imm indices
# DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}}
# DEBUG-NEXT: .. the first uncovered type index: 1, OK
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/lrint-llrint-f16.ll b/llvm/test/CodeGen/RISCV/GlobalISel/lrint-llrint-f16.ll
new file mode 100644
index 0000000000000..a60d1d0cccfa1
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/lrint-llrint-f16.ll
@@ -0,0 +1,41 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -global-isel -mattr=+f,+d,+zfh -target-abi=ilp32d < %s | FileCheck %s --check-prefixes=CHECK,RV32IFD
+; RUN: llc -mtriple=riscv64 -global-isel -mattr=+f,+d,+zfh -target-abi=lp64d < %s | FileCheck %s --check-prefixes=CHECK,RV64IFD
+
+define i32 @lrint_f16(half %a) nounwind {
+; RV32IFD-LABEL: lrint_f16:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: fcvt.w.h a0, fa0
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: lrint_f16:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.l.h a0, fa0
+; RV64IFD-NEXT: ret
+ %r = call i32 @llvm.lrint.f16(half %a)
+ ret i32 %r
+}
+
+define i64 @llrint_f16(half %a) nounwind {
+; RV32IFD-LABEL: llrint_f16:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -16
+; RV32IFD-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: fcvt.s.h fa0, fa0
+; RV32IFD-NEXT: call llrintf
+; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: llrint_f16:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.l.h a0, fa0
+; RV64IFD-NEXT: ret
+ %r = call i64 @llvm.llrint.f16(half %a)
+ ret i64 %r
+}
+
+declare i32 @llvm.lrint.f16(half)
+declare i64 @llvm.llrint.f16(half)
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK: {{.*}}
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/lrint-llrint.ll b/llvm/test/CodeGen/RISCV/GlobalISel/lrint-llrint.ll
new file mode 100644
index 0000000000000..33a3e08d27960
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/lrint-llrint.ll
@@ -0,0 +1,268 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -global-isel -mattr=+f,+d -target-abi=ilp32d < %s | FileCheck %s --check-prefixes=CHECK,RV32IFD
+; RUN: llc -mtriple=riscv64 -global-isel -mattr=+f,+d -target-abi=lp64d < %s | FileCheck %s --check-prefixes=CHECK,RV64IFD
+; RUN: llc -mtriple=riscv32 -global-isel < %s | FileCheck %s --check-prefixes=CHECK,RV32I
+; RUN: llc -mtriple=riscv64 -global-isel < %s | FileCheck %s --check-prefixes=CHECK,RV64I
+
+define i32 @lrint_f32(float %a) nounwind {
+; RV32IFD-LABEL: lrint_f32:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: fcvt.w.s a0, fa0
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: lrint_f32:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.l.s a0, fa0
+; RV64IFD-NEXT: ret
+;
+; RV32I-LABEL: lrint_f32:
+; RV32I: # %bb.0:
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT: call lrintf
+; RV32I-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: lrint_f32:
+; RV64I: # %bb.0:
+; RV64I-NEXT: addi sp, sp, -16
+; RV64I-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT: call lrintf
+; RV64I-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT: addi sp, sp, 16
+; RV64I-NEXT: ret
+ %r = call i32 @llvm.lrint.f32(float %a)
+ ret i32 %r
+}
+
+define i32 @lrint_f64(double %a) nounwind {
+; RV32IFD-LABEL: lrint_f64:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: fcvt.w.d a0, fa0
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: lrint_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.l.d a0, fa0
+; RV64IFD-NEXT: ret
+;
+; RV32I-LABEL: lrint_f64:
+; RV32I: # %bb.0:
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT: call lrint
+; RV32I-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: lrint_f64:
+; RV64I: # %bb.0:
+; RV64I-NEXT: addi sp, sp, -16
+; RV64I-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT: call lrint
+; RV64I-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT: addi sp, sp, 16
+; RV64I-NEXT: ret
+ %r = call i32 @llvm.lrint.f64(double %a)
+ ret i32 %r
+}
+
+define i64 @llrint_f32(float %a) nounwind {
+; RV32IFD-LABEL: llrint_f32:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -16
+; RV32IFD-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: call llrintf
+; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: llrint_f32:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.l.s a0, fa0
+; RV64IFD-NEXT: ret
+;
+; RV32I-LABEL: llrint_f32:
+; RV32I: # %bb.0:
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT: call llrintf
+; RV32I-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: llrint_f32:
+; RV64I: # %bb.0:
+; RV64I-NEXT: addi sp, sp, -16
+; RV64I-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT: call llrintf
+; RV64I-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT: addi sp, sp, 16
+; RV64I-NEXT: ret
+ %r = call i64 @llvm.llrint.f32(float %a)
+ ret i64 %r
+}
+
+define i64 @llrint_f64(double %a) nounwind {
+; RV32IFD-LABEL: llrint_f64:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -16
+; RV32IFD-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: call llrint
+; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: llrint_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.l.d a0, fa0
+; RV64IFD-NEXT: ret
+;
+; RV32I-LABEL: llrint_f64:
+; RV32I: # %bb.0:
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT: call llrint
+; RV32I-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: llrint_f64:
+; RV64I: # %bb.0:
+; RV64I-NEXT: addi sp, sp, -16
+; RV64I-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT: call llrint
+; RV64I-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT: addi sp, sp, 16
+; RV64I-NEXT: ret
+ %r = call i64 @llvm.llrint.f64(double %a)
+ ret i64 %r
+}
+
+; fp128 has no native path; it lowers to the lrintl/llrintl libcalls
+; (RISC-V long double == fp128).
+define i32 @lrint_f128(fp128 %a) nounwind {
+; RV32IFD-LABEL: lrint_f128:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -144
+; RV32IFD-NEXT: sw ra, 140(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: lw a1, 0(a0)
+; RV32IFD-NEXT: lw a2, 4(a0)
+; RV32IFD-NEXT: lw a3, 8(a0)
+; RV32IFD-NEXT: lw a4, 12(a0)
+; RV32IFD-NEXT: mv a0, sp
+; RV32IFD-NEXT: sw a1, 0(sp)
+; RV32IFD-NEXT: sw a2, 4(sp)
+; RV32IFD-NEXT: sw a3, 8(sp)
+; RV32IFD-NEXT: sw a4, 12(sp)
+; RV32IFD-NEXT: call lrintl
+; RV32IFD-NEXT: lw ra, 140(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 144
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: lrint_f128:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: call lrintl
+; RV64IFD-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+;
+; RV32I-LABEL: lrint_f128:
+; RV32I: # %bb.0:
+; RV32I-NEXT: addi sp, sp, -144
+; RV32I-NEXT: sw ra, 140(sp) # 4-byte Folded Spill
+; RV32I-NEXT: lw a1, 0(a0)
+; RV32I-NEXT: lw a2, 4(a0)
+; RV32I-NEXT: lw a3, 8(a0)
+; RV32I-NEXT: lw a4, 12(a0)
+; RV32I-NEXT: mv a0, sp
+; RV32I-NEXT: sw a1, 0(sp)
+; RV32I-NEXT: sw a2, 4(sp)
+; RV32I-NEXT: sw a3, 8(sp)
+; RV32I-NEXT: sw a4, 12(sp)
+; RV32I-NEXT: call lrintl
+; RV32I-NEXT: lw ra, 140(sp) # 4-byte Folded Reload
+; RV32I-NEXT: addi sp, sp, 144
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: lrint_f128:
+; RV64I: # %bb.0:
+; RV64I-NEXT: addi sp, sp, -16
+; RV64I-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT: call lrintl
+; RV64I-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT: addi sp, sp, 16
+; RV64I-NEXT: ret
+ %r = call i32 @llvm.lrint.f128(fp128 %a)
+ ret i32 %r
+}
+
+define i64 @llrint_f128(fp128 %a) nounwind {
+; RV32IFD-LABEL: llrint_f128:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -144
+; RV32IFD-NEXT: sw ra, 140(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: lw a1, 0(a0)
+; RV32IFD-NEXT: lw a2, 4(a0)
+; RV32IFD-NEXT: lw a3, 8(a0)
+; RV32IFD-NEXT: lw a4, 12(a0)
+; RV32IFD-NEXT: mv a0, sp
+; RV32IFD-NEXT: sw a1, 0(sp)
+; RV32IFD-NEXT: sw a2, 4(sp)
+; RV32IFD-NEXT: sw a3, 8(sp)
+; RV32IFD-NEXT: sw a4, 12(sp)
+; RV32IFD-NEXT: call llrintl
+; RV32IFD-NEXT: lw ra, 140(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 144
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: llrint_f128:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: call llrintl
+; RV64IFD-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+;
+; RV32I-LABEL: llrint_f128:
+; RV32I: # %bb.0:
+; RV32I-NEXT: addi sp, sp, -144
+; RV32I-NEXT: sw ra, 140(sp) # 4-byte Folded Spill
+; RV32I-NEXT: lw a1, 0(a0)
+; RV32I-NEXT: lw a2, 4(a0)
+; RV32I-NEXT: lw a3, 8(a0)
+; RV32I-NEXT: lw a4, 12(a0)
+; RV32I-NEXT: mv a0, sp
+; RV32I-NEXT: sw a1, 0(sp)
+; RV32I-NEXT: sw a2, 4(sp)
+; RV32I-NEXT: sw a3, 8(sp)
+; RV32I-NEXT: sw a4, 12(sp)
+; RV32I-NEXT: call llrintl
+; RV32I-NEXT: lw ra, 140(sp) # 4-byte Folded Reload
+; RV32I-NEXT: addi sp, sp, 144
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: llrint_f128:
+; RV64I: # %bb.0:
+; RV64I-NEXT: addi sp, sp, -16
+; RV64I-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT: call llrintl
+; RV64I-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT: addi sp, sp, 16
+; RV64I-NEXT: ret
+ %r = call i64 @llvm.llrint.f128(fp128 %a)
+ ret i64 %r
+}
+
+declare i32 @llvm.lrint.f32(float)
+declare i32 @llvm.lrint.f64(double)
+declare i64 @llvm.llrint.f32(float)
+declare i64 @llvm.llrint.f64(double)
+declare i32 @llvm.lrint.f128(fp128)
+declare i64 @llvm.llrint.f128(fp128)
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK: {{.*}}
More information about the llvm-commits
mailing list