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

Dmitry Sidorov via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 9 06:04:12 PDT 2025


================
@@ -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.
----------------
MrSidims wrote:

nit: Not necessary `OpenCLLIB::` as the code also handles `GLSL_std_450`

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


More information about the llvm-commits mailing list