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

Victor Lomuller via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 16 08:23:12 PDT 2025


================
@@ -3990,6 +3995,104 @@ 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().
+  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)
----------------
Naghasan wrote:

```suggestion
            .addImm(CL::modf)
```

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


More information about the llvm-commits mailing list