@@ -3976,6 +3976,7 @@ bool LLVMToSPIRVBase::isKnownIntrinsic(Intrinsic::ID Id) {
3976
3976
case Intrinsic::arithmetic_fence:
3977
3977
case Intrinsic::masked_gather:
3978
3978
case Intrinsic::masked_scatter:
3979
+ case Intrinsic::modf:
3979
3980
return true ;
3980
3981
default :
3981
3982
// Unknown intrinsics' declarations should always be translated
@@ -4076,6 +4077,8 @@ static SPIRVWord getBuiltinIdForIntrinsic(Intrinsic::ID IID) {
4076
4077
return OpenCLLIB::Tanh;
4077
4078
case Intrinsic::trunc:
4078
4079
return OpenCLLIB::Trunc;
4080
+ case Intrinsic::modf:
4081
+ return OpenCLLIB::Modf;
4079
4082
default :
4080
4083
assert (false && " Builtin ID requested for Unhandled intrinsic!" );
4081
4084
return 0 ;
@@ -4273,6 +4276,50 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
4273
4276
return BM->addExtInst (FTy, BM->getExtInstSetId (SPIRVEIS_OpenCL), ExtOp, Ops,
4274
4277
BB);
4275
4278
}
4279
+ case Intrinsic::modf: {
4280
+ // llvm.modf has a single arg --the number to be decomposed-- and returns a
4281
+ // struct { double, double }, while OpenCLLIB::modf has two args --the
4282
+ // number to be decomposed and a pointer--, returns the fractional part and
4283
+ // the integral part is stored in the pointer argument. Therefore, we can't
4284
+ // use directly the OpenCLLIB::modf intrinsic. However, we can do some
4285
+ // scaffolding to make it work. The idea is to create an alloca instruction
4286
+ // to get a ptr, pass this ptr to OpenCLLIB::modf, and then load the value
4287
+ // from this ptr to place it in the struct.
4288
+
4289
+ // llvm.modf returns the fractional part as the first element of the result,
4290
+ // and the integral part as the second element of the result. Therefore, the
4291
+ // first element is the return value of OpenCLLIB::modf, and the second
4292
+ // element is the value loaded from the ptr of the alloca we created.
4293
+
4294
+ // Create the alloca instruction.
4295
+ SPIRVType *IntegralTy = transType (II->getType ()->getStructElementType (1 ));
4296
+ // IntegralTy is the type of the result. We want to create a pointer to this
4297
+ // that we can pass to OpenCLLIB::modf to store the integral part.
4298
+ SPIRVTypePointer *IntegralPtrTy =
4299
+ BM->addPointerType (StorageClassFunction, IntegralTy);
4300
+ // We need to use the entry BB of the function calling llvm.modf.*, instead
4301
+ // of the current BB. For that, we'll find current BB's parent and get its
4302
+ // first BB, which is the entry BB of the function.
4303
+ SPIRVBasicBlock *EntryBB = BB->getParent ()->getBasicBlock (0 );
4304
+ SPIRVValue *Ptr = BM->addVariable (
4305
+ IntegralPtrTy, nullptr , false , spv::internal::LinkageTypeInternal,
4306
+ nullptr , " " , StorageClassFunction, EntryBB);
4307
+
4308
+ // Create the OpenCLLIB::modf instruction.
4309
+ SPIRVType *FTy = transType (II->getType ()->getStructElementType (0 ));
4310
+ SPIRVValue *Arg = transValue (II->getArgOperand (0 ), BB);
4311
+ std::vector<SPIRVValue *> Ops{Arg, Ptr};
4312
+ SPIRVValue *Modf = BM->addExtInst (FTy, BM->getExtInstSetId (SPIRVEIS_OpenCL),
4313
+ OpenCLLIB::Modf, Ops, BB);
4314
+
4315
+ // Load the value from the ptr.
4316
+ SPIRVValue *IntegralVal = BM->addLoadInst (Ptr, {}, BB, IntegralTy);
4317
+
4318
+ // Create the struct.
4319
+ SPIRVType *STy = transType (II->getType ());
4320
+ std::vector<SPIRVId> StructVals{Modf->getId (), IntegralVal->getId ()};
4321
+ return BM->addCompositeConstructInst (STy, StructVals, BB);
4322
+ }
4276
4323
// Binary FP intrinsics
4277
4324
case Intrinsic::atan2:
4278
4325
case Intrinsic::copysign:
0 commit comments