@@ -296,6 +296,8 @@ class SPIRVInstructionSelector : public InstructionSelector {
296296 bool selectImageWriteIntrinsic (MachineInstr &I) const ;
297297 bool selectResourceGetPointer (Register &ResVReg, const SPIRVType *ResType,
298298 MachineInstr &I) const ;
299+ bool selectModf (Register ResVReg, const SPIRVType *ResType,
300+ MachineInstr &I) const ;
299301
300302 // Utilities
301303 std::pair<Register, bool >
@@ -3235,6 +3237,9 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
32353237 case Intrinsic::spv_discard: {
32363238 return selectDiscard (ResVReg, ResType, I);
32373239 }
3240+ case Intrinsic::modf: {
3241+ return selectModf (ResVReg, ResType, I);
3242+ }
32383243 default : {
32393244 std::string DiagMsg;
32403245 raw_string_ostream OS (DiagMsg);
@@ -4018,6 +4023,83 @@ bool SPIRVInstructionSelector::selectLog10(Register ResVReg,
40184023 .constrainAllUses (TII, TRI, RBI);
40194024}
40204025
4026+ bool SPIRVInstructionSelector::selectModf (Register ResVReg,
4027+ const SPIRVType *ResType,
4028+ MachineInstr &I) const {
4029+ // llvm.modf has a single arg --the number to be decomposed-- and returns a
4030+ // struct { restype, restype }, while OpenCLLIB::modf has two args --the
4031+ // number to be decomposed and a pointer--, returns the fractional part and
4032+ // the integral part is stored in the pointer argument. Therefore, we can't
4033+ // use directly the OpenCLLIB::modf intrinsic. However, we can do some
4034+ // scaffolding to make it work. The idea is to create an alloca instruction
4035+ // to get a ptr, pass this ptr to OpenCL::modf, and then load the value
4036+ // from this ptr to place it in the struct. llvm.modf returns the fractional
4037+ // part as the first element of the result, and the integral part as the
4038+ // second element of the result.
4039+
4040+ // At this point, the return type is not a struct anymore, but rather two
4041+ // independent elements of SPIRVResType. We can get each independent element
4042+ // from I.getDefs() or I.getOperands().
4043+ if (STI.canUseExtInstSet (SPIRV::InstructionSet::OpenCL_std)) {
4044+ MachineIRBuilder MIRBuilder (I);
4045+ // Get pointer type for alloca variable.
4046+ const SPIRVType *PtrType = GR.getOrCreateSPIRVPointerType (
4047+ ResType, MIRBuilder, SPIRV::StorageClass::Function);
4048+ // Create new register for the pointer type of alloca variable.
4049+ Register PtrTyReg =
4050+ MIRBuilder.getMRI ()->createVirtualRegister (&SPIRV::iIDRegClass);
4051+ MIRBuilder.getMRI ()->setType (
4052+ PtrTyReg,
4053+ LLT::pointer (storageClassToAddressSpace (SPIRV::StorageClass::Function),
4054+ GR.getPointerSize ()));
4055+ // Assign SPIR-V type of the pointer type of the alloca variable to the
4056+ // new register.
4057+ GR.assignSPIRVTypeToVReg (PtrType, PtrTyReg, MIRBuilder.getMF ());
4058+ MachineBasicBlock &EntryBB = I.getMF ()->front ();
4059+ MachineBasicBlock::iterator VarPos =
4060+ getFirstValidInstructionInsertPoint (EntryBB);
4061+ auto AllocaMIB =
4062+ BuildMI (EntryBB, VarPos, I.getDebugLoc (), TII.get (SPIRV::OpVariable))
4063+ .addDef (PtrTyReg)
4064+ .addUse (GR.getSPIRVTypeID (PtrType))
4065+ .addImm (static_cast <uint32_t >(SPIRV::StorageClass::Function));
4066+ Register Variable = AllocaMIB->getOperand (0 ).getReg ();
4067+ // Modf must have 4 operands, the first two are the 2 parts of the result,
4068+ // the third is the operand, and the last one is the floating point value.
4069+ assert (I.getNumOperands () == 4 &&
4070+ " Expected 4 operands for modf instruction" );
4071+ MachineBasicBlock &BB = *I.getParent ();
4072+ // Create the OpenCLLIB::modf instruction.
4073+ auto MIB =
4074+ BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpExtInst))
4075+ .addDef (ResVReg)
4076+ .addUse (GR.getSPIRVTypeID (ResType))
4077+ .addImm (static_cast <uint32_t >(SPIRV::InstructionSet::OpenCL_std))
4078+ .addImm (CL::modf)
4079+ .setMIFlags (I.getFlags ())
4080+ .add (I.getOperand (3 )) // Floating point value.
4081+ .addUse (Variable); // Pointer to integral part.
4082+ // Assign the integral part stored in the ptr to the second element of the
4083+ // result.
4084+ Register IntegralPartReg = I.getOperand (1 ).getReg ();
4085+ if (IntegralPartReg.isValid ()) {
4086+ // Load the value from the pointer to integral part.
4087+ auto LoadMIB = BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpLoad))
4088+ .addDef (IntegralPartReg)
4089+ .addUse (GR.getSPIRVTypeID (ResType))
4090+ .addUse (Variable);
4091+ return LoadMIB.constrainAllUses (TII, TRI, RBI);
4092+ }
4093+
4094+ return MIB.constrainAllUses (TII, TRI, RBI);
4095+ } else if (STI.canUseExtInstSet (SPIRV::InstructionSet::GLSL_std_450)) {
4096+ assert (false && " GLSL::Modf is deprecated." );
4097+ // FIXME: GL::Modf is deprecated, use Modfstruct instead.
4098+ return false ;
4099+ }
4100+ return false ;
4101+ }
4102+
40214103// Generate the instructions to load 3-element vector builtin input
40224104// IDs/Indices.
40234105// Like: GlobalInvocationId, LocalInvocationId, etc....
0 commit comments