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