[llvm] [GlobalISel][ARM] Legalze set_fpmode and get_fpmode (PR #96467)

Serge Pavlov via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 25 02:02:58 PDT 2024


https://github.com/spavloff updated https://github.com/llvm/llvm-project/pull/96467

>From 524a3455ba119aad954d3a6ceb6502e104f13051 Mon Sep 17 00:00:00 2001
From: Serge Pavlov <sepavloff at gmail.com>
Date: Sat, 15 Jun 2024 00:02:32 +0700
Subject: [PATCH 1/2] [GlobalISel][ARM] Legalze set_fpmode and get_fpmode

Implement handling of get/set floating point control modes for ARM in
Global Instruction Selector.
---
 llvm/lib/Target/ARM/ARMLegalizerInfo.cpp    | 21 ++++++
 llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp |  1 +
 llvm/test/CodeGen/ARM/GlobalISel/fpenv.ll   | 84 +++++++++++++++++++++
 3 files changed, 106 insertions(+)

diff --git a/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp b/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp
index 00a29f8ecb232..e336fcc2030b5 100644
--- a/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp
@@ -159,6 +159,8 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
 
     getActionDefinitionsBuilder({G_GET_FPENV, G_SET_FPENV}).legalFor({s32});
     getActionDefinitionsBuilder(G_RESET_FPENV).alwaysLegal();
+    getActionDefinitionsBuilder(G_GET_FPMODE).legalFor({s32});
+    getActionDefinitionsBuilder(G_SET_FPMODE).customFor({s32});
   } else {
     getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
         .libcallFor({s32, s64});
@@ -187,6 +189,8 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
 
     getActionDefinitionsBuilder({G_GET_FPENV, G_SET_FPENV, G_RESET_FPENV})
         .libcall();
+    getActionDefinitionsBuilder({G_GET_FPMODE, G_SET_FPMODE, G_RESET_FPMODE})
+        .libcall();
   }
 
   // Just expand whatever loads and stores are left.
@@ -439,6 +443,23 @@ bool ARMLegalizerInfo::legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI,
                              *ConstantInt::get(Ctx, AsInteger));
     break;
   }
+  case G_SET_FPMODE: {
+    // New FPSCR = (FPSCR & FPStatusBits) | (Modes & ~FPStatusBits)
+    LLT FPEnvTy = LLT::scalar(32);
+    auto FPEnv = MRI.createGenericVirtualRegister(FPEnvTy);
+    auto Modes = MI.getOperand(0).getReg();
+    MIRBuilder.buildInstr(G_GET_FPENV).addDef({FPEnv});
+    auto StatusBitMask = MIRBuilder.buildConstant(FPEnvTy, ARM::FPStatusBits);
+    auto StatusBits =
+        MIRBuilder.buildAnd(FPEnvTy, FPEnv, StatusBitMask).getReg(0);
+    auto NotStatusBitMask =
+        MIRBuilder.buildConstant(FPEnvTy, ~ARM::FPStatusBits);
+    auto FPModeBits =
+        MIRBuilder.buildAnd(FPEnvTy, Modes, NotStatusBitMask).getReg(0);
+    auto NewFPSCR = MIRBuilder.buildOr(FPEnvTy, StatusBits, FPModeBits);
+    MIRBuilder.buildInstr(G_SET_FPENV).addUse(NewFPSCR.getReg(0));
+    break;
+  }
   }
 
   MI.eraseFromParent();
diff --git a/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp b/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp
index a6fdece10ba47..9234881c9407e 100644
--- a/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp
@@ -466,6 +466,7 @@ ARMRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
   }
   case G_GET_FPENV:
   case G_SET_FPENV:
+  case G_GET_FPMODE:
     OperandsMapping =
         getOperandsMapping({&ARM::ValueMappings[ARM::GPR3OpsIdx], nullptr});
     break;
diff --git a/llvm/test/CodeGen/ARM/GlobalISel/fpenv.ll b/llvm/test/CodeGen/ARM/GlobalISel/fpenv.ll
index f5aea62d4be79..72996066ba9b5 100644
--- a/llvm/test/CodeGen/ARM/GlobalISel/fpenv.ll
+++ b/llvm/test/CodeGen/ARM/GlobalISel/fpenv.ll
@@ -4,6 +4,9 @@
 declare i32 @llvm.get.fpenv.i32()
 declare void @llvm.set.fpenv.i32(i32)
 declare void @llvm.reset.fpenv()
+declare i32 @llvm.get.fpmode.i32()
+declare void @llvm.set.fpmode.i32(i32)
+declare void @llvm.reset.fpmode()
 
 define i32 @func_get_fpenv() {
 ; CHECK-LABEL: func_get_fpenv:
@@ -88,5 +91,86 @@ entry:
   ret void
 }
 
+
+define i32 @get_fpmode_soft() #0 {
+; CHECK-LABEL: get_fpmode_soft:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    .save {r4, lr}
+; CHECK-NEXT:    push {r4, lr}
+; CHECK-NEXT:    .pad #8
+; CHECK-NEXT:    sub sp, sp, #8
+; CHECK-NEXT:    add r4, sp, #4
+; CHECK-NEXT:    mov r0, r4
+; CHECK-NEXT:    bl fegetmode
+; CHECK-NEXT:    ldr r0, [r4]
+; CHECK-NEXT:    add sp, sp, #8
+; CHECK-NEXT:    pop {r4, lr}
+; CHECK-NEXT:    mov pc, lr
+entry:
+  %fpenv = call i32 @llvm.get.fpmode.i32()
+  ret i32 %fpenv
+}
+
+define i32 @get_fpmode() nounwind {
+; CHECK-LABEL: get_fpmode:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    vmrs r0, fpscr
+; CHECK-NEXT:    mov pc, lr
+entry:
+  %fpenv = call i32 @llvm.get.fpmode.i32()
+  ret i32 %fpenv
+}
+
+define void @set_fpmode_soft(i32 %fpmode) #0 {
+; CHECK-LABEL: set_fpmode_soft:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    .save {r11, lr}
+; CHECK-NEXT:    push {r11, lr}
+; CHECK-NEXT:    .pad #8
+; CHECK-NEXT:    sub sp, sp, #8
+; CHECK-NEXT:    add r1, sp, #4
+; CHECK-NEXT:    str r0, [r1]
+; CHECK-NEXT:    mov r0, r1
+; CHECK-NEXT:    bl fesetmode
+; CHECK-NEXT:    add sp, sp, #8
+; CHECK-NEXT:    pop {r11, lr}
+; CHECK-NEXT:    mov pc, lr
+entry:
+  call void @llvm.set.fpmode.i32(i32 %fpmode)
+  ret void
+}
+
+define void @set_fpmode(i32 %fpmode) nounwind {
+; CHECK-LABEL: set_fpmode:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    vmrs r1, fpscr
+; CHECK-NEXT:    mov r2, #159
+; CHECK-NEXT:    orr r2, r2, #-134217728
+; CHECK-NEXT:    and r1, r1, r2
+; CHECK-NEXT:    mvn r2, #159
+; CHECK-NEXT:    sub r2, r2, #-134217728
+; CHECK-NEXT:    and r0, r0, r2
+; CHECK-NEXT:    orr r0, r1, r0
+; CHECK-NEXT:    vmsr fpscr, r0
+; CHECK-NEXT:    mov pc, lr
+entry:
+  call void @llvm.set.fpmode.i32(i32 %fpmode)
+  ret void
+}
+
+define void @reset_fpmode_soft() #0 {
+; CHECK-LABEL: reset_fpmode_soft:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    .save {r11, lr}
+; CHECK-NEXT:    push {r11, lr}
+; CHECK-NEXT:    mvn r0, #0
+; CHECK-NEXT:    bl fesetmode
+; CHECK-NEXT:    pop {r11, lr}
+; CHECK-NEXT:    mov pc, lr
+entry:
+  call void @llvm.reset.fpmode()
+  ret void
+}
+
 attributes #0 = { nounwind "use-soft-float"="true" }
 

>From 5be531b2116e70ebc08a9cc7fef3ab85b7b9b00a Mon Sep 17 00:00:00 2001
From: Serge Pavlov <sepavloff at gmail.com>
Date: Mon, 24 Jun 2024 23:49:45 +0700
Subject: [PATCH 2/2] Address review comments

---
 .../llvm/CodeGen/GlobalISel/MachineIRBuilder.h   | 10 ++++++++++
 llvm/lib/Target/ARM/ARMLegalizerInfo.cpp         | 16 +++++++---------
 llvm/test/CodeGen/ARM/GlobalISel/fpenv.ll        |  7 -------
 3 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
index 92e05ee858a75..3034cf2739aef 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
@@ -2173,6 +2173,16 @@ class MachineIRBuilder {
     return buildInstr(TargetOpcode::G_BITREVERSE, {Dst}, {Src});
   }
 
+  /// Build and insert \p Dst = G_GET_FPENV
+  MachineInstrBuilder buildGetFPEnv(const DstOp &Dst) {
+    return buildInstr(TargetOpcode::G_GET_FPENV, {Dst}, {});
+  }
+
+  /// Build and insert G_SET_FPENV \p Src
+  MachineInstrBuilder buildSetFPEnv(const SrcOp &Src) {
+    return buildInstr(TargetOpcode::G_SET_FPENV, {}, {Src});
+  }
+
   virtual MachineInstrBuilder
   buildInstr(unsigned Opc, ArrayRef<DstOp> DstOps, ArrayRef<SrcOp> SrcOps,
              std::optional<unsigned> Flags = std::nullopt);
diff --git a/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp b/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp
index e336fcc2030b5..660f351bae64b 100644
--- a/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp
@@ -157,9 +157,9 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
     getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
         .legalForCartesianProduct({s32, s64}, {s32});
 
-    getActionDefinitionsBuilder({G_GET_FPENV, G_SET_FPENV}).legalFor({s32});
+    getActionDefinitionsBuilder({G_GET_FPENV, G_SET_FPENV, G_GET_FPMODE})
+        .legalFor({s32});
     getActionDefinitionsBuilder(G_RESET_FPENV).alwaysLegal();
-    getActionDefinitionsBuilder(G_GET_FPMODE).legalFor({s32});
     getActionDefinitionsBuilder(G_SET_FPMODE).customFor({s32});
   } else {
     getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
@@ -447,17 +447,15 @@ bool ARMLegalizerInfo::legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI,
     // New FPSCR = (FPSCR & FPStatusBits) | (Modes & ~FPStatusBits)
     LLT FPEnvTy = LLT::scalar(32);
     auto FPEnv = MRI.createGenericVirtualRegister(FPEnvTy);
-    auto Modes = MI.getOperand(0).getReg();
-    MIRBuilder.buildInstr(G_GET_FPENV).addDef({FPEnv});
+    Register Modes = MI.getOperand(0).getReg();
+    MIRBuilder.buildGetFPEnv(FPEnv);
     auto StatusBitMask = MIRBuilder.buildConstant(FPEnvTy, ARM::FPStatusBits);
-    auto StatusBits =
-        MIRBuilder.buildAnd(FPEnvTy, FPEnv, StatusBitMask).getReg(0);
+    auto StatusBits = MIRBuilder.buildAnd(FPEnvTy, FPEnv, StatusBitMask);
     auto NotStatusBitMask =
         MIRBuilder.buildConstant(FPEnvTy, ~ARM::FPStatusBits);
-    auto FPModeBits =
-        MIRBuilder.buildAnd(FPEnvTy, Modes, NotStatusBitMask).getReg(0);
+    auto FPModeBits = MIRBuilder.buildAnd(FPEnvTy, Modes, NotStatusBitMask);
     auto NewFPSCR = MIRBuilder.buildOr(FPEnvTy, StatusBits, FPModeBits);
-    MIRBuilder.buildInstr(G_SET_FPENV).addUse(NewFPSCR.getReg(0));
+    MIRBuilder.buildSetFPEnv(NewFPSCR);
     break;
   }
   }
diff --git a/llvm/test/CodeGen/ARM/GlobalISel/fpenv.ll b/llvm/test/CodeGen/ARM/GlobalISel/fpenv.ll
index 72996066ba9b5..f8dba64e7a01a 100644
--- a/llvm/test/CodeGen/ARM/GlobalISel/fpenv.ll
+++ b/llvm/test/CodeGen/ARM/GlobalISel/fpenv.ll
@@ -1,13 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4
 ; RUN: llc -mtriple=arm-eabi -mattr=+vfp2 -global-isel=1 --verify-machineinstrs %s -o - | FileCheck %s
 
-declare i32 @llvm.get.fpenv.i32()
-declare void @llvm.set.fpenv.i32(i32)
-declare void @llvm.reset.fpenv()
-declare i32 @llvm.get.fpmode.i32()
-declare void @llvm.set.fpmode.i32(i32)
-declare void @llvm.reset.fpmode()
-
 define i32 @func_get_fpenv() {
 ; CHECK-LABEL: func_get_fpenv:
 ; CHECK:       @ %bb.0: @ %entry



More information about the llvm-commits mailing list