[llvm] [AMDGPU][GlobalISel] Add frexp_mant/fract intrinsic RegBankLegalize r… (PR #177512)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 23 08:40:01 PST 2026


https://github.com/vangthao95 updated https://github.com/llvm/llvm-project/pull/177512

>From d8bf6787fbe3926e3c335e582c9ae726cad360a6 Mon Sep 17 00:00:00 2001
From: Vang Thao <vang.thao at amd.com>
Date: Thu, 22 Jan 2026 17:29:24 -0800
Subject: [PATCH 1/2] [AMDGPU][GlobalISel] Add frexp_mant/fract intrinsic
 RegBankLegalize rules

---
 .../AMDGPU/AMDGPURegBankLegalizeRules.cpp     |  8 ++
 .../AMDGPU/GlobalISel/llvm.amdgcn.fract.ll    | 76 +++++++++++++++++++
 .../GlobalISel/llvm.amdgcn.frexp.mant.ll      | 76 +++++++++++++++++++
 3 files changed, 160 insertions(+)
 create mode 100644 llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.fract.ll
 create mode 100644 llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.frexp.mant.ll

diff --git a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp
index 7441846dc3e34..96c94d73ced7e 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPURegBankLegalizeRules.cpp
@@ -1204,6 +1204,14 @@ RegBankLegalizeRules::RegBankLegalizeRules(const GCNSubtarget &_ST,
       .Uni(S32, {{UniInVgprS32}, {IntrId, Vgpr32, Vgpr32}})
       .Div(S32, {{Vgpr32}, {IntrId, Vgpr32, Vgpr32}});
 
+  addRulesForIOpcs({amdgcn_frexp_mant, amdgcn_fract}, Standard)
+      .Uni(S16, {{UniInVgprS16}, {IntrId, Vgpr16}})
+      .Div(S16, {{Vgpr16}, {IntrId, Vgpr16}})
+      .Uni(S32, {{UniInVgprS32}, {IntrId, Vgpr32}})
+      .Div(S32, {{Vgpr32}, {IntrId, Vgpr32}})
+      .Uni(S64, {{UniInVgprS64}, {IntrId, Vgpr64}})
+      .Div(S64, {{Vgpr64}, {IntrId, Vgpr64}});
+
   addRulesForIOpcs({amdgcn_ubfe, amdgcn_sbfe}, Standard)
       .Div(S32, {{Vgpr32}, {IntrId, Vgpr32, Vgpr32, Vgpr32}})
       .Uni(S32, {{Sgpr32}, {IntrId, Sgpr32, Sgpr32, Sgpr32}, S_BFE})
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.fract.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.fract.ll
new file mode 100644
index 0000000000000..ec34086035659
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.fract.ll
@@ -0,0 +1,76 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -global-isel -new-reg-bank-select -mtriple=amdgcn -mcpu=gfx900 < %s | FileCheck -check-prefix=GFX9 %s
+
+declare half @llvm.amdgcn.fract.f16(half)
+declare float @llvm.amdgcn.fract.f32(float)
+declare double @llvm.amdgcn.fract.f64(double)
+
+define amdgpu_ps half @s_fract_f16(half inreg %src) {
+; GFX9-LABEL: s_fract_f16:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    v_fract_f16_e32 v0, s0
+; GFX9-NEXT:    v_add_f16_e32 v0, v0, v0
+; GFX9-NEXT:    ; return to shader part epilog
+  %fract = call half @llvm.amdgcn.fract.f16(half %src)
+  %res = fadd half %fract, %fract
+  ret half %res
+}
+
+define amdgpu_ps half @v_fract_f16(half %src) {
+; GFX9-LABEL: v_fract_f16:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    v_fract_f16_e32 v0, v0
+; GFX9-NEXT:    v_add_f16_e32 v0, v0, v0
+; GFX9-NEXT:    ; return to shader part epilog
+  %fract = call half @llvm.amdgcn.fract.f16(half %src)
+  %res = fadd half %fract, %fract
+  ret half %res
+}
+
+define amdgpu_ps float @s_fract_f32(float inreg %src) {
+; GFX9-LABEL: s_fract_f32:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    v_fract_f32_e32 v0, s0
+; GFX9-NEXT:    v_add_f32_e32 v0, v0, v0
+; GFX9-NEXT:    ; return to shader part epilog
+  %fract = call float @llvm.amdgcn.fract.f32(float %src)
+  %res = fadd float %fract, %fract
+  ret float %res
+}
+
+define amdgpu_ps float @v_fract_f32(float %src) {
+; GFX9-LABEL: v_fract_f32:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    v_fract_f32_e32 v0, v0
+; GFX9-NEXT:    v_add_f32_e32 v0, v0, v0
+; GFX9-NEXT:    ; return to shader part epilog
+  %fract = call float @llvm.amdgcn.fract.f32(float %src)
+  %res = fadd float %fract, %fract
+  ret float %res
+}
+
+define amdgpu_ps double @s_fract_f64(double inreg %src) {
+; GFX9-LABEL: s_fract_f64:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    v_fract_f64_e32 v[0:1], s[0:1]
+; GFX9-NEXT:    v_add_f64 v[0:1], v[0:1], v[0:1]
+; GFX9-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX9-NEXT:    v_readfirstlane_b32 s1, v1
+; GFX9-NEXT:    ; return to shader part epilog
+  %fract = call double @llvm.amdgcn.fract.f64(double %src)
+  %res = fadd double %fract, %fract
+  ret double %res
+}
+
+define amdgpu_ps double @v_fract_f64(double %src) {
+; GFX9-LABEL: v_fract_f64:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    v_fract_f64_e32 v[0:1], v[0:1]
+; GFX9-NEXT:    v_add_f64 v[0:1], v[0:1], v[0:1]
+; GFX9-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX9-NEXT:    v_readfirstlane_b32 s1, v1
+; GFX9-NEXT:    ; return to shader part epilog
+  %fract = call double @llvm.amdgcn.fract.f64(double %src)
+  %res = fadd double %fract, %fract
+  ret double %res
+}
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.frexp.mant.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.frexp.mant.ll
new file mode 100644
index 0000000000000..8dfcb85c714a8
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.frexp.mant.ll
@@ -0,0 +1,76 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -global-isel -new-reg-bank-select -mtriple=amdgcn -mcpu=gfx900 < %s | FileCheck -check-prefix=GFX9 %s
+
+declare half @llvm.amdgcn.frexp.mant.f16(half)
+declare float @llvm.amdgcn.frexp.mant.f32(float)
+declare double @llvm.amdgcn.frexp.mant.f64(double)
+
+define amdgpu_ps half @s_frexp_mant_f16(half inreg %src) {
+; GFX9-LABEL: s_frexp_mant_f16:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    v_frexp_mant_f16_e32 v0, s0
+; GFX9-NEXT:    v_add_f16_e32 v0, v0, v0
+; GFX9-NEXT:    ; return to shader part epilog
+  %mant = call half @llvm.amdgcn.frexp.mant.f16(half %src)
+  %res = fadd half %mant, %mant
+  ret half %res
+}
+
+define amdgpu_ps half @v_frexp_mant_f16(half %src) {
+; GFX9-LABEL: v_frexp_mant_f16:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    v_frexp_mant_f16_e32 v0, v0
+; GFX9-NEXT:    v_add_f16_e32 v0, v0, v0
+; GFX9-NEXT:    ; return to shader part epilog
+  %mant = call half @llvm.amdgcn.frexp.mant.f16(half %src)
+  %res = fadd half %mant, %mant
+  ret half %res
+}
+
+define amdgpu_ps float @s_frexp_mant_f32(float inreg %src) {
+; GFX9-LABEL: s_frexp_mant_f32:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    v_frexp_mant_f32_e32 v0, s0
+; GFX9-NEXT:    v_add_f32_e32 v0, v0, v0
+; GFX9-NEXT:    ; return to shader part epilog
+  %mant = call float @llvm.amdgcn.frexp.mant.f32(float %src)
+  %res = fadd float %mant, %mant
+  ret float %res
+}
+
+define amdgpu_ps float @v_frexp_mant_f32(float %src) {
+; GFX9-LABEL: v_frexp_mant_f32:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    v_frexp_mant_f32_e32 v0, v0
+; GFX9-NEXT:    v_add_f32_e32 v0, v0, v0
+; GFX9-NEXT:    ; return to shader part epilog
+  %mant = call float @llvm.amdgcn.frexp.mant.f32(float %src)
+  %res = fadd float %mant, %mant
+  ret float %res
+}
+
+define amdgpu_ps double @s_frexp_mant_f64(double inreg %src) {
+; GFX9-LABEL: s_frexp_mant_f64:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    v_frexp_mant_f64_e32 v[0:1], s[0:1]
+; GFX9-NEXT:    v_add_f64 v[0:1], v[0:1], v[0:1]
+; GFX9-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX9-NEXT:    v_readfirstlane_b32 s1, v1
+; GFX9-NEXT:    ; return to shader part epilog
+  %mant = call double @llvm.amdgcn.frexp.mant.f64(double %src)
+  %res = fadd double %mant, %mant
+  ret double %res
+}
+
+define amdgpu_ps double @v_frexp_mant_f64(double %src) {
+; GFX9-LABEL: v_frexp_mant_f64:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    v_frexp_mant_f64_e32 v[0:1], v[0:1]
+; GFX9-NEXT:    v_add_f64 v[0:1], v[0:1], v[0:1]
+; GFX9-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX9-NEXT:    v_readfirstlane_b32 s1, v1
+; GFX9-NEXT:    ; return to shader part epilog
+  %mant = call double @llvm.amdgcn.frexp.mant.f64(double %src)
+  %res = fadd double %mant, %mant
+  ret double %res
+}

>From 26b7c893557e9fa1a42b614ecdf5c03a5165fcd1 Mon Sep 17 00:00:00 2001
From: Vang Thao <vang.thao at amd.com>
Date: Fri, 23 Jan 2026 08:38:51 -0800
Subject: [PATCH 2/2] Change fract test to gfx12 and changed f64 salu fract
 test.

---
 .../AMDGPU/GlobalISel/llvm.amdgcn.fract.ll    | 98 +++++++++++--------
 1 file changed, 59 insertions(+), 39 deletions(-)

diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.fract.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.fract.ll
index ec34086035659..bf23b635c4d22 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.fract.ll
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/llvm.amdgcn.fract.ll
@@ -1,75 +1,95 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -global-isel -new-reg-bank-select -mtriple=amdgcn -mcpu=gfx900 < %s | FileCheck -check-prefix=GFX9 %s
+; RUN: llc -global-isel -new-reg-bank-select -mtriple=amdgcn -mcpu=gfx1200 < %s | FileCheck -check-prefix=GFX12 %s
 
 declare half @llvm.amdgcn.fract.f16(half)
 declare float @llvm.amdgcn.fract.f32(float)
 declare double @llvm.amdgcn.fract.f64(double)
 
 define amdgpu_ps half @s_fract_f16(half inreg %src) {
-; GFX9-LABEL: s_fract_f16:
-; GFX9:       ; %bb.0:
-; GFX9-NEXT:    v_fract_f16_e32 v0, s0
-; GFX9-NEXT:    v_add_f16_e32 v0, v0, v0
-; GFX9-NEXT:    ; return to shader part epilog
+; GFX12-LABEL: s_fract_f16:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    v_fract_f16_e32 v0, s0
+; GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_2) | instid1(SALU_CYCLE_2)
+; GFX12-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX12-NEXT:    s_add_f16 s0, s0, s0
+; GFX12-NEXT:    s_wait_alu depctr_sa_sdst(0)
+; GFX12-NEXT:    v_mov_b32_e32 v0, s0
+; GFX12-NEXT:    ; return to shader part epilog
   %fract = call half @llvm.amdgcn.fract.f16(half %src)
   %res = fadd half %fract, %fract
   ret half %res
 }
 
 define amdgpu_ps half @v_fract_f16(half %src) {
-; GFX9-LABEL: v_fract_f16:
-; GFX9:       ; %bb.0:
-; GFX9-NEXT:    v_fract_f16_e32 v0, v0
-; GFX9-NEXT:    v_add_f16_e32 v0, v0, v0
-; GFX9-NEXT:    ; return to shader part epilog
+; GFX12-LABEL: v_fract_f16:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    v_fract_f16_e32 v0, v0
+; GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT:    v_add_f16_e32 v0, v0, v0
+; GFX12-NEXT:    ; return to shader part epilog
   %fract = call half @llvm.amdgcn.fract.f16(half %src)
   %res = fadd half %fract, %fract
   ret half %res
 }
 
 define amdgpu_ps float @s_fract_f32(float inreg %src) {
-; GFX9-LABEL: s_fract_f32:
-; GFX9:       ; %bb.0:
-; GFX9-NEXT:    v_fract_f32_e32 v0, s0
-; GFX9-NEXT:    v_add_f32_e32 v0, v0, v0
-; GFX9-NEXT:    ; return to shader part epilog
+; GFX12-LABEL: s_fract_f32:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    v_fract_f32_e32 v0, s0
+; GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_2) | instid1(SALU_CYCLE_2)
+; GFX12-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX12-NEXT:    s_add_f32 s0, s0, s0
+; GFX12-NEXT:    s_wait_alu depctr_sa_sdst(0)
+; GFX12-NEXT:    v_mov_b32_e32 v0, s0
+; GFX12-NEXT:    ; return to shader part epilog
   %fract = call float @llvm.amdgcn.fract.f32(float %src)
   %res = fadd float %fract, %fract
   ret float %res
 }
 
 define amdgpu_ps float @v_fract_f32(float %src) {
-; GFX9-LABEL: v_fract_f32:
-; GFX9:       ; %bb.0:
-; GFX9-NEXT:    v_fract_f32_e32 v0, v0
-; GFX9-NEXT:    v_add_f32_e32 v0, v0, v0
-; GFX9-NEXT:    ; return to shader part epilog
+; GFX12-LABEL: v_fract_f32:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    v_fract_f32_e32 v0, v0
+; GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT:    v_add_f32_e32 v0, v0, v0
+; GFX12-NEXT:    ; return to shader part epilog
   %fract = call float @llvm.amdgcn.fract.f32(float %src)
   %res = fadd float %fract, %fract
   ret float %res
 }
 
-define amdgpu_ps double @s_fract_f64(double inreg %src) {
-; GFX9-LABEL: s_fract_f64:
-; GFX9:       ; %bb.0:
-; GFX9-NEXT:    v_fract_f64_e32 v[0:1], s[0:1]
-; GFX9-NEXT:    v_add_f64 v[0:1], v[0:1], v[0:1]
-; GFX9-NEXT:    v_readfirstlane_b32 s0, v0
-; GFX9-NEXT:    v_readfirstlane_b32 s1, v1
-; GFX9-NEXT:    ; return to shader part epilog
-  %fract = call double @llvm.amdgcn.fract.f64(double %src)
-  %res = fadd double %fract, %fract
-  ret double %res
+define amdgpu_ps void @s_fract_f64(double inreg %src, ptr addrspace(1) %out) {
+; GFX12-LABEL: s_fract_f64:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    v_fract_f64_e32 v[2:3], s[0:1]
+; GFX12-NEXT:    s_mov_b32 s2, 0
+; GFX12-NEXT:    s_brev_b32 s3, 1
+; GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX12-NEXT:    v_readfirstlane_b32 s0, v2
+; GFX12-NEXT:    v_readfirstlane_b32 s1, v3
+; GFX12-NEXT:    s_xor_b64 s[0:1], s[0:1], s[2:3]
+; GFX12-NEXT:    s_wait_alu depctr_sa_sdst(0)
+; GFX12-NEXT:    v_dual_mov_b32 v3, s1 :: v_dual_mov_b32 v2, s0
+; GFX12-NEXT:    global_store_b64 v[0:1], v[2:3], off
+; GFX12-NEXT:    s_endpgm
+ %fract = call double @llvm.amdgcn.fract.f64(double %src)
+ %fract.i64 = bitcast double %fract to i64
+ %neg = xor i64 %fract.i64, u0x8000000000000000
+ store i64 %neg, ptr addrspace(1) %out
+ ret void
 }
 
 define amdgpu_ps double @v_fract_f64(double %src) {
-; GFX9-LABEL: v_fract_f64:
-; GFX9:       ; %bb.0:
-; GFX9-NEXT:    v_fract_f64_e32 v[0:1], v[0:1]
-; GFX9-NEXT:    v_add_f64 v[0:1], v[0:1], v[0:1]
-; GFX9-NEXT:    v_readfirstlane_b32 s0, v0
-; GFX9-NEXT:    v_readfirstlane_b32 s1, v1
-; GFX9-NEXT:    ; return to shader part epilog
+; GFX12-LABEL: v_fract_f64:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    v_fract_f64_e32 v[0:1], v[0:1]
+; GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT:    v_add_f64_e32 v[0:1], v[0:1], v[0:1]
+; GFX12-NEXT:    v_readfirstlane_b32 s0, v0
+; GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_2)
+; GFX12-NEXT:    v_readfirstlane_b32 s1, v1
+; GFX12-NEXT:    ; return to shader part epilog
   %fract = call double @llvm.amdgcn.fract.f64(double %src)
   %res = fadd double %fract, %fract
   ret double %res



More information about the llvm-commits mailing list