@@ -296,6 +296,8 @@ class SPIRVInstructionSelector : public InstructionSelector {
296
296
bool selectImageWriteIntrinsic (MachineInstr &I) const ;
297
297
bool selectResourceGetPointer (Register &ResVReg, const SPIRVType *ResType,
298
298
MachineInstr &I) const ;
299
+ bool selectModf (Register ResVReg, const SPIRVType *ResType,
300
+ MachineInstr &I) const ;
299
301
300
302
// Utilities
301
303
std::pair<Register, bool >
@@ -3235,6 +3237,9 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
3235
3237
case Intrinsic::spv_discard: {
3236
3238
return selectDiscard (ResVReg, ResType, I);
3237
3239
}
3240
+ case Intrinsic::modf: {
3241
+ return selectModf (ResVReg, ResType, I);
3242
+ }
3238
3243
default : {
3239
3244
std::string DiagMsg;
3240
3245
raw_string_ostream OS (DiagMsg);
@@ -4018,6 +4023,83 @@ bool SPIRVInstructionSelector::selectLog10(Register ResVReg,
4018
4023
.constrainAllUses (TII, TRI, RBI);
4019
4024
}
4020
4025
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
+
4021
4103
// Generate the instructions to load 3-element vector builtin input
4022
4104
// IDs/Indices.
4023
4105
// Like: GlobalInvocationId, LocalInvocationId, etc....
0 commit comments