[llvm] [AArch64][GlobalISel] Add basic scalar handling for i32 lround and lrint (PR #170175)

David Green via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 1 09:49:05 PST 2025


https://github.com/davemgreen updated https://github.com/llvm/llvm-project/pull/170175

>From 9199eb3595c84fb31df0dc46113468f6aec6a4b5 Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Mon, 1 Dec 2025 17:48:55 +0000
Subject: [PATCH] [AArch64][GlobalISel] Add basic scalar handling for i32
 lround and lrint.

This covers the windows variants, where long == i32. We can treat them as legal
and generate the expected fcvtas instruction. The lround/llround and
lrint/llrint were rejigged to allow the common parts to legalize in the same
manner.
---
 .../AArch64/GISel/AArch64LegalizerInfo.cpp    | 14 ++---
 .../GlobalISel/legalizer-info-validation.mir  |  2 +-
 .../CodeGen/AArch64/lrint-conv-fp16-win.ll    |  6 +-
 llvm/test/CodeGen/AArch64/lrint-conv-win.ll   |  7 +--
 .../CodeGen/AArch64/lround-conv-fp16-win.ll   | 56 ++++++-----------
 llvm/test/CodeGen/AArch64/lround-conv-win.ll  | 63 ++++++-------------
 llvm/test/CodeGen/AArch64/vector-lrint.ll     | 29 +++++----
 7 files changed, 65 insertions(+), 112 deletions(-)

diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
index 1025b2502211a..51c0b1bf3589c 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -432,11 +432,6 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
       .minScalar(0, s32)
       .scalarize(0);
 
-  getActionDefinitionsBuilder({G_INTRINSIC_LRINT, G_INTRINSIC_LLRINT})
-      .legalFor({{s64, MinFPScalar}, {s64, s32}, {s64, s64}})
-      .libcallFor({{s64, s128}})
-      .minScalarOrElt(1, MinFPScalar);
-
   getActionDefinitionsBuilder({G_FCOS, G_FSIN, G_FPOW, G_FLOG, G_FLOG2,
                                G_FLOG10, G_FTAN, G_FEXP, G_FEXP2, G_FEXP10,
                                G_FACOS, G_FASIN, G_FATAN, G_FATAN2, G_FCOSH,
@@ -451,9 +446,14 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
       .minScalar(0, s32)
       .libcallFor({{s32, s32}, {s64, s32}, {s128, s32}});
 
-  getActionDefinitionsBuilder({G_LROUND, G_LLROUND})
+  getActionDefinitionsBuilder({G_LROUND, G_INTRINSIC_LRINT})
+      .legalFor({{s32, s32}, {s32, s64}, {s64, s32}, {s64, s64}})
+      .legalFor(HasFP16, {{s32, s16}, {s64, s16}})
+      .minScalar(1, s32)
+      .libcallFor({{s64, s128}});
+  getActionDefinitionsBuilder({G_LLROUND, G_INTRINSIC_LLRINT})
       .legalFor({{s64, s32}, {s64, s64}})
-      .legalFor(HasFP16, {{s64, s16}})
+      .legalFor(HasFP16, {{s32, s16}, {s64, s16}})
       .minScalar(0, s64)
       .minScalar(1, s32)
       .libcallFor({{s64, s128}});
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
index e68278dadc4b8..af72ffbcfadce 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
@@ -187,6 +187,7 @@
 # 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: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}}
 # DEBUG-NEXT: .. the first uncovered type index: 2, OK
 # DEBUG-NEXT: .. the first uncovered imm index: 0, OK
 # DEBUG-NEXT: G_INTRINSIC_LLRINT (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
@@ -698,7 +699,6 @@
 # DEBUG-NEXT: .. the first uncovered type index: 2, OK
 # DEBUG-NEXT: .. the first uncovered imm index: 0, OK
 # DEBUG-NEXT: G_LLROUND (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
-# DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}}
 # DEBUG-NEXT: .. the first uncovered type index: 2, OK
 # DEBUG-NEXT: .. the first uncovered imm index: 0, OK
 # DEBUG-NEXT: G_BR (opcode {{[0-9]+}}): 0 type indices, 0 imm indices
diff --git a/llvm/test/CodeGen/AArch64/lrint-conv-fp16-win.ll b/llvm/test/CodeGen/AArch64/lrint-conv-fp16-win.ll
index 0fc8b9a9f57ad..610ab92c01221 100644
--- a/llvm/test/CodeGen/AArch64/lrint-conv-fp16-win.ll
+++ b/llvm/test/CodeGen/AArch64/lrint-conv-fp16-win.ll
@@ -1,10 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: llc < %s -mtriple=aarch64 -mattr=+neon | FileCheck %s --check-prefixes=CHECK,CHECK-SD
-; RUN: llc < %s -mtriple=aarch64 -mattr=+neon -global-isel -global-isel-abort=2 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-GI
-
-; CHECK-GI:       warning: Instruction selection used fallback path for testmhhs
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for testmhws
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for testmhxs
+; RUN: llc < %s -mtriple=aarch64 -mattr=+neon -global-isel | FileCheck %s --check-prefixes=CHECK,CHECK-GI
 
 define i16 @testmhhs(half %x) {
 ; CHECK-LABEL: testmhhs:
diff --git a/llvm/test/CodeGen/AArch64/lrint-conv-win.ll b/llvm/test/CodeGen/AArch64/lrint-conv-win.ll
index 164dbd854173c..00fc862eaa4f4 100644
--- a/llvm/test/CodeGen/AArch64/lrint-conv-win.ll
+++ b/llvm/test/CodeGen/AArch64/lrint-conv-win.ll
@@ -1,11 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: llc < %s -mtriple=aarch64 -mattr=+neon | FileCheck %s --check-prefixes=CHECK,CHECK-SD
-; RUN: llc < %s -mtriple=aarch64 -mattr=+neon -global-isel -global-isel-abort=2 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-GI
-
-; CHECK-GI:       warning: Instruction selection used fallback path for testmsxs
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for testmsws
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for testmsxd
-; CHECK-GI-NEXT:  warning: Instruction selection used fallback path for testmswd
+; RUN: llc < %s -mtriple=aarch64 -mattr=+neon -global-isel | FileCheck %s --check-prefixes=CHECK,CHECK-GI
 
 define i64 @testmsxs(float %x) {
 ; CHECK-LABEL: testmsxs:
diff --git a/llvm/test/CodeGen/AArch64/lround-conv-fp16-win.ll b/llvm/test/CodeGen/AArch64/lround-conv-fp16-win.ll
index e5390169c51d6..63539a154add4 100644
--- a/llvm/test/CodeGen/AArch64/lround-conv-fp16-win.ll
+++ b/llvm/test/CodeGen/AArch64/lround-conv-fp16-win.ll
@@ -3,18 +3,11 @@
 ; RUN: llc < %s -mtriple=aarch64 -mattr=+neon -global-isel | FileCheck %s --check-prefixes=CHECK,CHECK-GI
 
 define i16 @testmhhs(half %x) {
-; CHECK-SD-LABEL: testmhhs:
-; CHECK-SD:       // %bb.0: // %entry
-; CHECK-SD-NEXT:    fcvt s0, h0
-; CHECK-SD-NEXT:    fcvtas w0, s0
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: testmhhs:
-; CHECK-GI:       // %bb.0: // %entry
-; CHECK-GI-NEXT:    fcvt s0, h0
-; CHECK-GI-NEXT:    fcvtas x0, s0
-; CHECK-GI-NEXT:    // kill: def $w0 killed $w0 killed $x0
-; CHECK-GI-NEXT:    ret
+; CHECK-LABEL: testmhhs:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fcvt s0, h0
+; CHECK-NEXT:    fcvtas w0, s0
+; CHECK-NEXT:    ret
 entry:
   %0 = tail call i32 @llvm.lround.i32.f16(half %x)
   %conv = trunc i32 %0 to i16
@@ -22,41 +15,28 @@ entry:
 }
 
 define i32 @testmhws(half %x) {
-; CHECK-SD-LABEL: testmhws:
-; CHECK-SD:       // %bb.0: // %entry
-; CHECK-SD-NEXT:    fcvt s0, h0
-; CHECK-SD-NEXT:    fcvtas w0, s0
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: testmhws:
-; CHECK-GI:       // %bb.0: // %entry
-; CHECK-GI-NEXT:    fcvt s0, h0
-; CHECK-GI-NEXT:    fcvtas x0, s0
-; CHECK-GI-NEXT:    // kill: def $w0 killed $w0 killed $x0
-; CHECK-GI-NEXT:    ret
+; CHECK-LABEL: testmhws:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fcvt s0, h0
+; CHECK-NEXT:    fcvtas w0, s0
+; CHECK-NEXT:    ret
 entry:
   %0 = tail call i32 @llvm.lround.i32.f16(half %x)
   ret i32 %0
 }
 
 define i64 @testmhxs(half %x) {
-; CHECK-SD-LABEL: testmhxs:
-; CHECK-SD:       // %bb.0: // %entry
-; CHECK-SD-NEXT:    fcvt s0, h0
-; CHECK-SD-NEXT:    fcvtas w8, s0
-; CHECK-SD-NEXT:    sxtw x0, w8
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: testmhxs:
-; CHECK-GI:       // %bb.0: // %entry
-; CHECK-GI-NEXT:    fcvt s0, h0
-; CHECK-GI-NEXT:    fcvtas x8, s0
-; CHECK-GI-NEXT:    sxtw x0, w8
-; CHECK-GI-NEXT:    ret
+; CHECK-LABEL: testmhxs:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fcvt s0, h0
+; CHECK-NEXT:    fcvtas w8, s0
+; CHECK-NEXT:    sxtw x0, w8
+; CHECK-NEXT:    ret
 entry:
   %0 = tail call i32 @llvm.lround.i32.f16(half %x)
   %conv = sext i32 %0 to i64
   ret i64 %conv
 }
 ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK: {{.*}}
+; CHECK-GI: {{.*}}
+; CHECK-SD: {{.*}}
diff --git a/llvm/test/CodeGen/AArch64/lround-conv-win.ll b/llvm/test/CodeGen/AArch64/lround-conv-win.ll
index 02c1e9381eb06..5bb4525586662 100644
--- a/llvm/test/CodeGen/AArch64/lround-conv-win.ll
+++ b/llvm/test/CodeGen/AArch64/lround-conv-win.ll
@@ -3,17 +3,11 @@
 ; RUN: llc < %s -mtriple=aarch64 -mattr=+neon -global-isel | FileCheck %s --check-prefixes=CHECK,CHECK-GI
 
 define i64 @testmsxs(float %x) {
-; CHECK-SD-LABEL: testmsxs:
-; CHECK-SD:       // %bb.0: // %entry
-; CHECK-SD-NEXT:    fcvtas w8, s0
-; CHECK-SD-NEXT:    sxtw x0, w8
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: testmsxs:
-; CHECK-GI:       // %bb.0: // %entry
-; CHECK-GI-NEXT:    fcvtas x8, s0
-; CHECK-GI-NEXT:    sxtw x0, w8
-; CHECK-GI-NEXT:    ret
+; CHECK-LABEL: testmsxs:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fcvtas w8, s0
+; CHECK-NEXT:    sxtw x0, w8
+; CHECK-NEXT:    ret
 entry:
   %0 = tail call i32 @llvm.lround.i32.f32(float %x)
   %conv = sext i32 %0 to i64
@@ -21,33 +15,21 @@ entry:
 }
 
 define i32 @testmsws(float %x) {
-; CHECK-SD-LABEL: testmsws:
-; CHECK-SD:       // %bb.0: // %entry
-; CHECK-SD-NEXT:    fcvtas w0, s0
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: testmsws:
-; CHECK-GI:       // %bb.0: // %entry
-; CHECK-GI-NEXT:    fcvtas x0, s0
-; CHECK-GI-NEXT:    // kill: def $w0 killed $w0 killed $x0
-; CHECK-GI-NEXT:    ret
+; CHECK-LABEL: testmsws:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fcvtas w0, s0
+; CHECK-NEXT:    ret
 entry:
   %0 = tail call i32 @llvm.lround.i32.f32(float %x)
   ret i32 %0
 }
 
 define i64 @testmsxd(double %x) {
-; CHECK-SD-LABEL: testmsxd:
-; CHECK-SD:       // %bb.0: // %entry
-; CHECK-SD-NEXT:    fcvtas w8, d0
-; CHECK-SD-NEXT:    sxtw x0, w8
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: testmsxd:
-; CHECK-GI:       // %bb.0: // %entry
-; CHECK-GI-NEXT:    fcvtas x8, d0
-; CHECK-GI-NEXT:    sxtw x0, w8
-; CHECK-GI-NEXT:    ret
+; CHECK-LABEL: testmsxd:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fcvtas w8, d0
+; CHECK-NEXT:    sxtw x0, w8
+; CHECK-NEXT:    ret
 entry:
   %0 = tail call i32 @llvm.lround.i32.f64(double %x)
   %conv = sext i32 %0 to i64
@@ -55,20 +37,15 @@ entry:
 }
 
 define i32 @testmswd(double %x) {
-; CHECK-SD-LABEL: testmswd:
-; CHECK-SD:       // %bb.0: // %entry
-; CHECK-SD-NEXT:    fcvtas w0, d0
-; CHECK-SD-NEXT:    ret
-;
-; CHECK-GI-LABEL: testmswd:
-; CHECK-GI:       // %bb.0: // %entry
-; CHECK-GI-NEXT:    fcvtas x0, d0
-; CHECK-GI-NEXT:    // kill: def $w0 killed $w0 killed $x0
-; CHECK-GI-NEXT:    ret
+; CHECK-LABEL: testmswd:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fcvtas w0, d0
+; CHECK-NEXT:    ret
 entry:
   %0 = tail call i32 @llvm.lround.i32.f64(double %x)
   ret i32 %0
 }
 
 ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK: {{.*}}
+; CHECK-GI: {{.*}}
+; CHECK-SD: {{.*}}
diff --git a/llvm/test/CodeGen/AArch64/vector-lrint.ll b/llvm/test/CodeGen/AArch64/vector-lrint.ll
index c226ec3c3e25c..305f8cd67a044 100644
--- a/llvm/test/CodeGen/AArch64/vector-lrint.ll
+++ b/llvm/test/CodeGen/AArch64/vector-lrint.ll
@@ -1,6 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 ; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=aarch64 -mattr=+neon |\
-; RUN:   FileCheck %s --check-prefixes=CHECK-i32
+; RUN:   FileCheck %s --check-prefixes=CHECK-i32,CHECK-i32-SD
 ; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=aarch64 -mattr=+neon |\
 ; RUN:   FileCheck %s --check-prefixes=CHECK-i64,CHECK-i64-SD
 ; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=aarch64 -mattr=+neon \
@@ -10,19 +10,16 @@
 ; RUN:   -global-isel -global-isel-abort=2 2>&1 |\
 ; RUN:   FileCheck %s --check-prefixes=CHECK-i64,CHECK-i64-GI
 
-; CHECK-i32-GI:       warning: Instruction selection used fallback path for lrint_v1f16
-; CHECK-i32-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v2f16
+; CHECK-i32-GI:       warning: Instruction selection used fallback path for lrint_v2f16
 ; CHECK-i32-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v4f16
 ; CHECK-i32-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v8f16
 ; CHECK-i32-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v16f16
 ; CHECK-i32-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v32f16
-; CHECK-i32-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v1f32
 ; CHECK-i32-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v2f32
 ; CHECK-i32-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v4f32
 ; CHECK-i32-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v8f32
 ; CHECK-i32-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v16f32
 ; CHECK-i32-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v32f32
-; CHECK-i32-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v1f64
 ; CHECK-i32-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v2f64
 ; CHECK-i32-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v4f64
 ; CHECK-i32-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v8f64
@@ -53,6 +50,9 @@
 ; CHECK-i64-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v4fp128
 ; CHECK-i64-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v8fp128
 ; CHECK-i64-GI-NEXT:  warning: Instruction selection used fallback path for lrint_v16fp128
+;
+;
+;
 
 
 define <1 x iXLen> @lrint_v1f16(<1 x half> %x) nounwind {
@@ -759,11 +759,11 @@ define <32 x iXLen> @lrint_v32f16(<32 x half> %x) nounwind {
 declare <32 x iXLen> @llvm.lrint.v32iXLen.v32f16(<32 x half>)
 
 define <1 x iXLen> @lrint_v1f32(<1 x float> %x) nounwind {
-; CHECK-i32-LABEL: lrint_v1f32:
-; CHECK-i32:       // %bb.0:
-; CHECK-i32-NEXT:    frintx v0.2s, v0.2s
-; CHECK-i32-NEXT:    fcvtzs v0.2s, v0.2s
-; CHECK-i32-NEXT:    ret
+; CHECK-i32-SD-LABEL: lrint_v1f32:
+; CHECK-i32-SD:       // %bb.0:
+; CHECK-i32-SD-NEXT:    frintx v0.2s, v0.2s
+; CHECK-i32-SD-NEXT:    fcvtzs v0.2s, v0.2s
+; CHECK-i32-SD-NEXT:    ret
 ;
 ; CHECK-i64-SD-LABEL: lrint_v1f32:
 ; CHECK-i64-SD:       // %bb.0:
@@ -773,6 +773,13 @@ define <1 x iXLen> @lrint_v1f32(<1 x float> %x) nounwind {
 ; CHECK-i64-SD-NEXT:    fmov d0, x8
 ; CHECK-i64-SD-NEXT:    ret
 ;
+; CHECK-i32-GI-LABEL: lrint_v1f32:
+; CHECK-i32-GI:       // %bb.0:
+; CHECK-i32-GI-NEXT:    frintx s0, s0
+; CHECK-i32-GI-NEXT:    fcvtzs w8, s0
+; CHECK-i32-GI-NEXT:    fmov s0, w8
+; CHECK-i32-GI-NEXT:    ret
+;
 ; CHECK-i64-GI-LABEL: lrint_v1f32:
 ; CHECK-i64-GI:       // %bb.0:
 ; CHECK-i64-GI-NEXT:    frintx s0, s0
@@ -1791,5 +1798,3 @@ define <16 x iXLen> @lrint_v16fp128(<16 x fp128> %x) nounwind {
 }
 declare <16 x iXLen> @llvm.lrint.v16iXLen.v16fp128(<16 x fp128>)
 
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK-i32-GI: {{.*}}



More information about the llvm-commits mailing list