[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