@@ -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 >
@@ -3218,6 +3220,9 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
32183220 case Intrinsic::spv_discard: {
32193221 return selectDiscard (ResVReg, ResType, I);
32203222 }
3223+ case Intrinsic::modf: {
3224+ return selectModf (ResVReg, ResType, I);
3225+ }
32213226 default : {
32223227 std::string DiagMsg;
32233228 raw_string_ostream OS (DiagMsg);
@@ -4001,6 +4006,83 @@ bool SPIRVInstructionSelector::selectLog10(Register ResVReg,
40014006 .constrainAllUses (TII, TRI, RBI);
40024007}
40034008
4009+ bool SPIRVInstructionSelector::selectModf (Register ResVReg,
4010+ const SPIRVType *ResType,
4011+ MachineInstr &I) const {
4012+ // llvm.modf has a single arg --the number to be decomposed-- and returns a
4013+ // struct { restype, restype }, while OpenCLLIB::modf has two args --the
4014+ // number to be decomposed and a pointer--, returns the fractional part and
4015+ // the integral part is stored in the pointer argument. Therefore, we can't
4016+ // use directly the OpenCLLIB::modf intrinsic. However, we can do some
4017+ // scaffolding to make it work. The idea is to create an alloca instruction
4018+ // to get a ptr, pass this ptr to OpenCL::modf, and then load the value
4019+ // from this ptr to place it in the struct. llvm.modf returns the fractional
4020+ // part as the first element of the result, and the integral part as the
4021+ // second element of the result.
4022+
4023+ // At this point, the return type is not a struct anymore, but rather two
4024+ // independent elements of SPIRVResType. We can get each independent element
4025+ // from I.getDefs() or I.getOperands().
4026+ if (STI.canUseExtInstSet (SPIRV::InstructionSet::OpenCL_std)) {
4027+ MachineIRBuilder MIRBuilder (I);
4028+ // Get pointer type for alloca variable.
4029+ const SPIRVType *PtrType = GR.getOrCreateSPIRVPointerType (
4030+ ResType, MIRBuilder, SPIRV::StorageClass::Function);
4031+ // Create new register for the pointer type of alloca variable.
4032+ Register PtrTyReg =
4033+ MIRBuilder.getMRI ()->createVirtualRegister (&SPIRV::iIDRegClass);
4034+ MIRBuilder.getMRI ()->setType (
4035+ PtrTyReg,
4036+ LLT::pointer (storageClassToAddressSpace (SPIRV::StorageClass::Function),
4037+ GR.getPointerSize ()));
4038+ // Assign SPIR-V type of the pointer type of the alloca variable to the
4039+ // new register.
4040+ GR.assignSPIRVTypeToVReg (PtrType, PtrTyReg, MIRBuilder.getMF ());
4041+ MachineBasicBlock &EntryBB = I.getMF ()->front ();
4042+ MachineBasicBlock::iterator VarPos =
4043+ getFirstValidInstructionInsertPoint (EntryBB);
4044+ auto AllocaMIB =
4045+ BuildMI (EntryBB, VarPos, I.getDebugLoc (), TII.get (SPIRV::OpVariable))
4046+ .addDef (PtrTyReg)
4047+ .addUse (GR.getSPIRVTypeID (PtrType))
4048+ .addImm (static_cast <uint32_t >(SPIRV::StorageClass::Function));
4049+ Register Variable = AllocaMIB->getOperand (0 ).getReg ();
4050+ // Modf must have 4 operands, the first two are the 2 parts of the result,
4051+ // the third is the operand, and the last one is the floating point value.
4052+ assert (I.getNumOperands () == 4 &&
4053+ " Expected 4 operands for modf instruction" );
4054+ MachineBasicBlock &BB = *I.getParent ();
4055+ // Create the OpenCLLIB::modf instruction.
4056+ auto MIB =
4057+ BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpExtInst))
4058+ .addDef (ResVReg)
4059+ .addUse (GR.getSPIRVTypeID (ResType))
4060+ .addImm (static_cast <uint32_t >(SPIRV::InstructionSet::OpenCL_std))
4061+ .addImm (CL::modf)
4062+ .setMIFlags (I.getFlags ())
4063+ .add (I.getOperand (3 )) // Floating point value.
4064+ .addUse (Variable); // Pointer to integral part.
4065+ // Assign the integral part stored in the ptr to the second element of the
4066+ // result.
4067+ Register IntegralPartReg = I.getOperand (1 ).getReg ();
4068+ if (IntegralPartReg.isValid ()) {
4069+ // Load the value from the pointer to integral part.
4070+ auto LoadMIB = BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpLoad))
4071+ .addDef (IntegralPartReg)
4072+ .addUse (GR.getSPIRVTypeID (ResType))
4073+ .addUse (Variable);
4074+ return LoadMIB.constrainAllUses (TII, TRI, RBI);
4075+ }
4076+
4077+ return MIB.constrainAllUses (TII, TRI, RBI);
4078+ } else if (STI.canUseExtInstSet (SPIRV::InstructionSet::GLSL_std_450)) {
4079+ assert (false && " GLSL::Modf is deprecated." );
4080+ // FIXME: GL::Modf is deprecated, use Modfstruct instead.
4081+ return false ;
4082+ }
4083+ return false ;
4084+ }
4085+
40044086// Generate the instructions to load 3-element vector builtin input
40054087// IDs/Indices.
40064088// Like: GlobalInvocationId, LocalInvocationId, etc....
0 commit comments