[llvm] [SPIRV] Implement translation for llvm.modf.* intrinsics (PR #147556)

Marcos Maronas via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 17 02:17:33 PDT 2025


https://github.com/maarquitos14 updated https://github.com/llvm/llvm-project/pull/147556

>From 5bfcf335626b0a20cfc64ecbe17a619368bbadf5 Mon Sep 17 00:00:00 2001
From: Marcos Maronas <marcos.maronas at intel.com>
Date: Tue, 8 Jul 2025 17:08:54 +0200
Subject: [PATCH 1/5] Implement translation for llvm.modf.* intrinsics.

---
 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 76 +++++++++++++++++++
 1 file changed, 76 insertions(+)

diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 40a0bd97adaf9..ad6025804608d 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -296,6 +296,8 @@ class SPIRVInstructionSelector : public InstructionSelector {
   bool selectImageWriteIntrinsic(MachineInstr &I) const;
   bool selectResourceGetPointer(Register &ResVReg, const SPIRVType *ResType,
                                 MachineInstr &I) const;
+  bool selectModf(Register ResVReg, const SPIRVType *ResType,
+                  MachineInstr &I) const;
 
   // Utilities
   std::pair<Register, bool>
@@ -3207,6 +3209,9 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
   case Intrinsic::spv_discard: {
     return selectDiscard(ResVReg, ResType, I);
   }
+  case Intrinsic::modf: {
+    return selectModf(ResVReg, ResType, I);
+  }
   default: {
     std::string DiagMsg;
     raw_string_ostream OS(DiagMsg);
@@ -3990,6 +3995,77 @@ bool SPIRVInstructionSelector::selectLog10(Register ResVReg,
                        .constrainAllUses(TII, TRI, RBI);
 }
 
+bool SPIRVInstructionSelector::selectModf(Register ResVReg,
+                                          const SPIRVType *ResType,
+                                          MachineInstr &I) const {
+  // llvm.modf has a single arg --the number to be decomposed-- and returns a
+  // struct { restype, restype }, while OpenCLLIB::modf has two args --the
+  // number to be decomposed and a pointer--, returns the fractional part and
+  // the integral part is stored in the pointer argument. Therefore, we can't
+  // use directly the OpenCLLIB::modf intrinsic. However, we can do some
+  // scaffolding to make it work. The idea is to create an alloca instruction
+  // to get a ptr, pass this ptr to OpenCL::modf, and then load the value
+  // from this ptr to place it in the struct. llvm.modf returns the fractional
+  // part as the first element of the result, and the integral part as the
+  // second element of the result.
+
+  // At this point, the return type is not a struct anymore, but rather two
+  // independent elements of SPIRVResType. We can get each independent element
+  // from I.getDefs() or I.getOperands().
+  ExtInstList ExtInsts = {{SPIRV::InstructionSet::OpenCL_std, CL::modf},
+                          {SPIRV::InstructionSet::GLSL_std_450, GL::Modf}};
+  for (const auto &Ex : ExtInsts) {
+    SPIRV::InstructionSet::InstructionSet Set = Ex.first;
+    uint32_t Opcode = Ex.second;
+    if (STI.canUseExtInstSet(Set)) {
+      MachineIRBuilder MIRBuilder(I);
+      // Get pointer type for alloca variable.
+      const SPIRVType *PtrType = GR.getOrCreateSPIRVPointerType(
+          ResType, MIRBuilder, SPIRV::StorageClass::Input);
+      // Create new register for the pointer type of alloca variable.
+      Register NewRegister =
+          MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass);
+      MIRBuilder.getMRI()->setType(NewRegister, LLT::pointer(0, 64));
+      // Assign SPIR-V type of the pointer type of the alloca variable to the
+      // new register.
+      GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF());
+      // Build the alloca variable.
+      Register Variable = GR.buildGlobalVariable(
+          NewRegister, PtrType, "placeholder", nullptr,
+          SPIRV::StorageClass::Function, nullptr, true, false,
+          SPIRV::LinkageType::Import, MIRBuilder, false);
+      // Modf must have 4 operands, the first two are the 2 parts of the result,
+      // the third is the operand, and the last one is the floating point value.
+      assert(I.getNumOperands() == 4 &&
+             "Expected 4 operands for modf instruction");
+      MachineBasicBlock &BB = *I.getParent();
+      // Create the OpenCLLIB::modf instruction.
+      auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
+                     .addDef(ResVReg)
+                     .addUse(GR.getSPIRVTypeID(ResType))
+                     .addImm(static_cast<uint32_t>(Set))
+                     .addImm(Opcode)
+                     .setMIFlags(I.getFlags())
+                     .add(I.getOperand(3)) // Floating point value.
+                     .addUse(Variable);    // Pointer to integral part.
+      // Assign the integral part stored in the ptr to the second element of the
+      // result.
+      Register IntegralPartReg = I.getOperand(1).getReg();
+      if (IntegralPartReg.isValid()) {
+        // Load the value from the pointer to integral part.
+        auto LoadMIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
+                           .addDef(IntegralPartReg)
+                           .addUse(GR.getSPIRVTypeID(ResType))
+                           .addUse(Variable);
+        return LoadMIB.constrainAllUses(TII, TRI, RBI);
+      }
+
+      return MIB.constrainAllUses(TII, TRI, RBI);
+    }
+  }
+  return false;
+}
+
 // Generate the instructions to load 3-element vector builtin input
 // IDs/Indices.
 // Like: GlobalInvocationId, LocalInvocationId, etc....

>From 7d87ed35b8b1dcc3f98eff98ee9814684c4880e0 Mon Sep 17 00:00:00 2001
From: Marcos Maronas <marcos.maronas at intel.com>
Date: Tue, 8 Jul 2025 17:41:35 +0200
Subject: [PATCH 2/5] Add testing for llvm.modf.* intrinsics.

---
 .../SPIRV/llvm-intrinsics/fp-intrinsics.ll    | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll
index 3d46b527bf14f..91c6174e63d77 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll
@@ -337,3 +337,25 @@ entry:
 }
 
 declare float @llvm.fma.f32(float, float, float)
+
+; CHECK: OpFunction
+; CHECK: %[[#d:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#fracPtr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#integralPtr:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#varPtr:]] = OpVariable %[[#]] Function
+; CHECK: %[[#frac:]] = OpExtInst %[[#var2]] %[[#extinst_id]] modf %[[#d]] %[[#varPtr]]
+; CHECK: %[[#integral:]] = OpLoad %[[#var2]] %[[#varPtr]]
+; CHECK: OpStore %[[#fracPtr]] %[[#frac]]
+; CHECK: OpStore %[[#integralPtr]] %[[#integral]]
+; CHECK: OpFunctionEnd
+define void @foo(double %d, ptr addrspace(1) %frac, ptr addrspace(1) %integral) {
+entry:
+  %4 = tail call { double, double } @llvm.modf.f64(double %d)
+  %5 = extractvalue { double, double } %4, 0
+  %6 = extractvalue { double, double } %4, 1
+  store double %5, ptr addrspace(1) %frac, align 8
+  store double %6, ptr addrspace(1) %integral, align 8
+  ret void
+}
+
+declare { double, double } @llvm.modf.f64(double)

>From e07f9153da6fce144b9feb4b7105d8df3427796e Mon Sep 17 00:00:00 2001
From: Marcos Maronas <marcos.maronas at intel.com>
Date: Tue, 15 Jul 2025 22:37:08 +0200
Subject: [PATCH 3/5] Address code review feedback.

---
 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 125 +++++++++++-------
 .../SPIRV/llvm-intrinsics/fp-intrinsics.ll    |  39 +++++-
 2 files changed, 114 insertions(+), 50 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index ad6025804608d..3f1fa03916fe2 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -4012,56 +4012,83 @@ bool SPIRVInstructionSelector::selectModf(Register ResVReg,
   // At this point, the return type is not a struct anymore, but rather two
   // independent elements of SPIRVResType. We can get each independent element
   // from I.getDefs() or I.getOperands().
-  ExtInstList ExtInsts = {{SPIRV::InstructionSet::OpenCL_std, CL::modf},
-                          {SPIRV::InstructionSet::GLSL_std_450, GL::Modf}};
-  for (const auto &Ex : ExtInsts) {
-    SPIRV::InstructionSet::InstructionSet Set = Ex.first;
-    uint32_t Opcode = Ex.second;
-    if (STI.canUseExtInstSet(Set)) {
-      MachineIRBuilder MIRBuilder(I);
-      // Get pointer type for alloca variable.
-      const SPIRVType *PtrType = GR.getOrCreateSPIRVPointerType(
-          ResType, MIRBuilder, SPIRV::StorageClass::Input);
-      // Create new register for the pointer type of alloca variable.
-      Register NewRegister =
-          MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass);
-      MIRBuilder.getMRI()->setType(NewRegister, LLT::pointer(0, 64));
-      // Assign SPIR-V type of the pointer type of the alloca variable to the
-      // new register.
-      GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF());
-      // Build the alloca variable.
-      Register Variable = GR.buildGlobalVariable(
-          NewRegister, PtrType, "placeholder", nullptr,
-          SPIRV::StorageClass::Function, nullptr, true, false,
-          SPIRV::LinkageType::Import, MIRBuilder, false);
-      // Modf must have 4 operands, the first two are the 2 parts of the result,
-      // the third is the operand, and the last one is the floating point value.
-      assert(I.getNumOperands() == 4 &&
-             "Expected 4 operands for modf instruction");
-      MachineBasicBlock &BB = *I.getParent();
-      // Create the OpenCLLIB::modf instruction.
-      auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
-                     .addDef(ResVReg)
-                     .addUse(GR.getSPIRVTypeID(ResType))
-                     .addImm(static_cast<uint32_t>(Set))
-                     .addImm(Opcode)
-                     .setMIFlags(I.getFlags())
-                     .add(I.getOperand(3)) // Floating point value.
-                     .addUse(Variable);    // Pointer to integral part.
-      // Assign the integral part stored in the ptr to the second element of the
-      // result.
-      Register IntegralPartReg = I.getOperand(1).getReg();
-      if (IntegralPartReg.isValid()) {
-        // Load the value from the pointer to integral part.
-        auto LoadMIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
-                           .addDef(IntegralPartReg)
-                           .addUse(GR.getSPIRVTypeID(ResType))
-                           .addUse(Variable);
-        return LoadMIB.constrainAllUses(TII, TRI, RBI);
-      }
-
-      return MIB.constrainAllUses(TII, TRI, RBI);
+  if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
+    uint32_t Opcode = CL::modf;
+    MachineIRBuilder MIRBuilder(I);
+    // Get pointer type for alloca variable.
+    const SPIRVType *PtrType = GR.getOrCreateSPIRVPointerType(
+        ResType, MIRBuilder, SPIRV::StorageClass::Function);
+    // Create new register for the pointer type of alloca variable.
+    Register PtrTyReg =
+        MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass);
+    MIRBuilder.getMRI()->setType(
+        PtrTyReg,
+        LLT::pointer(storageClassToAddressSpace(SPIRV::StorageClass::Function),
+                     GR.getPointerSize()));
+    // Assign SPIR-V type of the pointer type of the alloca variable to the
+    // new register.
+    GR.assignSPIRVTypeToVReg(PtrType, PtrTyReg, MIRBuilder.getMF());
+    MachineBasicBlock &EntryBB = I.getMF()->front();
+    // At this point it's difficult to find the right position to insert the
+    // variable, because most instructions are still MachineInstruction and
+    // don't have SPIRV opcodes yet. OpFunction and OpFunctionParameter are
+    // already translated, so we will aim to insert the variable just after the
+    // last OpFunctionParameter, if any, or just after OpFunction otherwise.
+    auto VarPos = EntryBB.begin();
+    while (VarPos != EntryBB.end() &&
+           VarPos->getOpcode() != SPIRV::OpFunction) {
+      ++VarPos;
+    }
+    // Advance VarPos to the next instruction after OpFunction, it will either
+    // be an OpFunctionParameter, so that we can start the next loop, or the 
+    // position to insert the OpVariable instruction.
+    ++VarPos;
+    while (VarPos != EntryBB.end() &&
+           VarPos->getOpcode() == SPIRV::OpFunctionParameter) {
+      ++VarPos;
     }
+    // VarPos is now pointing at after the last OpFunctionParameter, if any,
+    // or after OpFunction, if no parameters.
+    // Create a new MachineInstruction for alloca variable in the
+    // entry block.
+    auto AllocaMIB =
+        BuildMI(EntryBB, VarPos, I.getDebugLoc(), TII.get(SPIRV::OpVariable))
+            .addDef(PtrTyReg)
+            .addUse(GR.getSPIRVTypeID(PtrType))
+            .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function));
+    Register Variable = AllocaMIB->getOperand(0).getReg();
+    // Modf must have 4 operands, the first two are the 2 parts of the result,
+    // the third is the operand, and the last one is the floating point value.
+    assert(I.getNumOperands() == 4 &&
+           "Expected 4 operands for modf instruction");
+    MachineBasicBlock &BB = *I.getParent();
+    // Create the OpenCLLIB::modf instruction.
+    auto MIB =
+        BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
+            .addDef(ResVReg)
+            .addUse(GR.getSPIRVTypeID(ResType))
+            .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std))
+            .addImm(Opcode)
+            .setMIFlags(I.getFlags())
+            .add(I.getOperand(3)) // Floating point value.
+            .addUse(Variable);    // Pointer to integral part.
+    // Assign the integral part stored in the ptr to the second element of the
+    // result.
+    Register IntegralPartReg = I.getOperand(1).getReg();
+    if (IntegralPartReg.isValid()) {
+      // Load the value from the pointer to integral part.
+      auto LoadMIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
+                         .addDef(IntegralPartReg)
+                         .addUse(GR.getSPIRVTypeID(ResType))
+                         .addUse(Variable);
+      return LoadMIB.constrainAllUses(TII, TRI, RBI);
+    }
+
+    return MIB.constrainAllUses(TII, TRI, RBI);
+  } else if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
+    assert(false && "GLSL::Modf is deprecated.");
+    // FIXME: GL::Modf is deprecated, use Modfstruct instead.
+    return false;
   }
   return false;
 }
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll
index 91c6174e63d77..54bd69679d50c 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll
@@ -1,4 +1,5 @@
 ; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
 ; CHECK: %[[#extinst_id:]] = OpExtInstImport "OpenCL.std"
 
@@ -348,7 +349,7 @@ declare float @llvm.fma.f32(float, float, float)
 ; CHECK: OpStore %[[#fracPtr]] %[[#frac]]
 ; CHECK: OpStore %[[#integralPtr]] %[[#integral]]
 ; CHECK: OpFunctionEnd
-define void @foo(double %d, ptr addrspace(1) %frac, ptr addrspace(1) %integral) {
+define void @TestModf(double %d, ptr addrspace(1) %frac, ptr addrspace(1) %integral) {
 entry:
   %4 = tail call { double, double } @llvm.modf.f64(double %d)
   %5 = extractvalue { double, double } %4, 0
@@ -358,4 +359,40 @@ entry:
   ret void
 }
 
+define dso_local void @TestModf2(double noundef %d, ptr noundef %frac, ptr noundef %integral) {
+entry:
+  %d.addr = alloca double, align 4
+  %frac.addr = alloca ptr, align 8
+  %integral.addr = alloca ptr, align 8
+  store double %d, ptr %d.addr, align 4
+  store ptr %frac, ptr %frac.addr, align 8
+  store ptr %integral, ptr %integral.addr, align 8
+  %0 = load ptr, ptr %frac.addr, align 8
+  %tobool = icmp ne ptr %0, null
+  br i1 %tobool, label %lor.lhs.false, label %if.then
+
+lor.lhs.false:
+  %1 = load ptr, ptr %integral.addr, align 8
+  %tobool1 = icmp ne ptr %1, null
+  br i1 %tobool1, label %if.end, label %if.then
+
+if.then:
+  br label %return
+
+if.end:
+  %2 = load ptr, ptr %frac.addr, align 8
+  %3 = load double, ptr %2, align 4
+  %4 = load ptr, ptr %integral.addr, align 8
+  %5 = load double, ptr %4, align 4
+  %6 = tail call { double, double } @llvm.modf.f64(double %d)
+  %7 = extractvalue { double, double } %6, 0
+  %8 = extractvalue { double, double } %6, 1
+  store double %7, ptr %frac, align 4
+  store double %7, ptr %integral, align 4
+  br label %return
+
+return:
+  ret void
+}
+
 declare { double, double } @llvm.modf.f64(double)

>From cdc25716a91737c35ab3fad7dbfbbb1e0bb89f4d Mon Sep 17 00:00:00 2001
From: Marcos Maronas <marcos.maronas at intel.com>
Date: Tue, 15 Jul 2025 22:40:14 +0200
Subject: [PATCH 4/5] Fix clang-format issue.

---
 llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 3f1fa03916fe2..5ec356e18c989 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -4040,7 +4040,7 @@ bool SPIRVInstructionSelector::selectModf(Register ResVReg,
       ++VarPos;
     }
     // Advance VarPos to the next instruction after OpFunction, it will either
-    // be an OpFunctionParameter, so that we can start the next loop, or the 
+    // be an OpFunctionParameter, so that we can start the next loop, or the
     // position to insert the OpVariable instruction.
     ++VarPos;
     while (VarPos != EntryBB.end() &&

>From 4a17c2188469938a0ae1a3a1e1616b34e37bd5ac Mon Sep 17 00:00:00 2001
From: Marcos Maronas <marcos.maronas at intel.com>
Date: Thu, 17 Jul 2025 11:17:14 +0200
Subject: [PATCH 5/5] Address code review feedback.

---
 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 26 ++-----------------
 llvm/lib/Target/SPIRV/SPIRVUtils.cpp          | 22 ++++++++++++++++
 llvm/lib/Target/SPIRV/SPIRVUtils.h            |  2 ++
 .../SPIRV/llvm-intrinsics/fp-intrinsics.ll    | 16 +++---------
 4 files changed, 29 insertions(+), 37 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 5ec356e18c989..5fb3c00356861 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -4013,7 +4013,6 @@ bool SPIRVInstructionSelector::selectModf(Register ResVReg,
   // independent elements of SPIRVResType. We can get each independent element
   // from I.getDefs() or I.getOperands().
   if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
-    uint32_t Opcode = CL::modf;
     MachineIRBuilder MIRBuilder(I);
     // Get pointer type for alloca variable.
     const SPIRVType *PtrType = GR.getOrCreateSPIRVPointerType(
@@ -4029,28 +4028,7 @@ bool SPIRVInstructionSelector::selectModf(Register ResVReg,
     // new register.
     GR.assignSPIRVTypeToVReg(PtrType, PtrTyReg, MIRBuilder.getMF());
     MachineBasicBlock &EntryBB = I.getMF()->front();
-    // At this point it's difficult to find the right position to insert the
-    // variable, because most instructions are still MachineInstruction and
-    // don't have SPIRV opcodes yet. OpFunction and OpFunctionParameter are
-    // already translated, so we will aim to insert the variable just after the
-    // last OpFunctionParameter, if any, or just after OpFunction otherwise.
-    auto VarPos = EntryBB.begin();
-    while (VarPos != EntryBB.end() &&
-           VarPos->getOpcode() != SPIRV::OpFunction) {
-      ++VarPos;
-    }
-    // Advance VarPos to the next instruction after OpFunction, it will either
-    // be an OpFunctionParameter, so that we can start the next loop, or the
-    // position to insert the OpVariable instruction.
-    ++VarPos;
-    while (VarPos != EntryBB.end() &&
-           VarPos->getOpcode() == SPIRV::OpFunctionParameter) {
-      ++VarPos;
-    }
-    // VarPos is now pointing at after the last OpFunctionParameter, if any,
-    // or after OpFunction, if no parameters.
-    // Create a new MachineInstruction for alloca variable in the
-    // entry block.
+    MachineBasicBlock::iterator VarPos = getPosForOpVariableWithinBlock(EntryBB);
     auto AllocaMIB =
         BuildMI(EntryBB, VarPos, I.getDebugLoc(), TII.get(SPIRV::OpVariable))
             .addDef(PtrTyReg)
@@ -4068,7 +4046,7 @@ bool SPIRVInstructionSelector::selectModf(Register ResVReg,
             .addDef(ResVReg)
             .addUse(GR.getSPIRVTypeID(ResType))
             .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std))
-            .addImm(Opcode)
+            .addImm(CL::modf)
             .setMIFlags(I.getFlags())
             .add(I.getOperand(3)) // Floating point value.
             .addUse(Variable);    // Pointer to integral part.
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 768efb96a53e9..543b1ea502967 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -995,4 +995,26 @@ unsigned getArrayComponentCount(const MachineRegisterInfo *MRI,
   return foldImm(ResType->getOperand(2), MRI);
 }
 
+MachineBasicBlock::iterator
+getPosForOpVariableWithinBlock(MachineBasicBlock &BB) {
+  // Find the position to insert the OpVariable instruction.
+  // We will insert it after the last OpFunctionParameter, if any, or
+  // after OpFunction otherwise.
+  MachineBasicBlock::iterator VarPos = BB.begin();
+  while (VarPos != BB.end() && VarPos->getOpcode() != SPIRV::OpFunction) {
+    ++VarPos;
+  }
+  // Advance VarPos to the next instruction after OpFunction, it will either
+  // be an OpFunctionParameter, so that we can start the next loop, or the
+  // position to insert the OpVariable instruction.
+  ++VarPos;
+  while (VarPos != BB.end() &&
+         VarPos->getOpcode() == SPIRV::OpFunctionParameter) {
+    ++VarPos;
+  }
+  // VarPos is now pointing at after the last OpFunctionParameter, if any,
+  // or after OpFunction, if no parameters.
+  return VarPos;
+}
+
 } // namespace llvm
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index d732188f9289f..a8924513e4c59 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -506,6 +506,8 @@ MachineInstr *getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI);
 int64_t foldImm(const MachineOperand &MO, const MachineRegisterInfo *MRI);
 unsigned getArrayComponentCount(const MachineRegisterInfo *MRI,
                                 const MachineInstr *ResType);
+MachineBasicBlock::iterator
+getPosForOpVariableWithinBlock(MachineBasicBlock &BB);
 
 } // namespace llvm
 #endif // LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll
index 54bd69679d50c..b7a4cb8a02a6a 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll
@@ -361,18 +361,12 @@ entry:
 
 define dso_local void @TestModf2(double noundef %d, ptr noundef %frac, ptr noundef %integral) {
 entry:
-  %d.addr = alloca double, align 4
-  %frac.addr = alloca ptr, align 8
-  %integral.addr = alloca ptr, align 8
-  store double %d, ptr %d.addr, align 4
-  store ptr %frac, ptr %frac.addr, align 8
-  store ptr %integral, ptr %integral.addr, align 8
-  %0 = load ptr, ptr %frac.addr, align 8
+  %0 = load ptr, ptr %frac, align 8
   %tobool = icmp ne ptr %0, null
   br i1 %tobool, label %lor.lhs.false, label %if.then
 
 lor.lhs.false:
-  %1 = load ptr, ptr %integral.addr, align 8
+  %1 = load ptr, ptr %integral, align 8
   %tobool1 = icmp ne ptr %1, null
   br i1 %tobool1, label %if.end, label %if.then
 
@@ -380,15 +374,11 @@ if.then:
   br label %return
 
 if.end:
-  %2 = load ptr, ptr %frac.addr, align 8
-  %3 = load double, ptr %2, align 4
-  %4 = load ptr, ptr %integral.addr, align 8
-  %5 = load double, ptr %4, align 4
   %6 = tail call { double, double } @llvm.modf.f64(double %d)
   %7 = extractvalue { double, double } %6, 0
   %8 = extractvalue { double, double } %6, 1
   store double %7, ptr %frac, align 4
-  store double %7, ptr %integral, align 4
+  store double %8, ptr %integral, align 4
   br label %return
 
 return:



More information about the llvm-commits mailing list