@@ -3976,6 +3976,7 @@ bool LLVMToSPIRVBase::isKnownIntrinsic(Intrinsic::ID Id) {
39763976 case Intrinsic::arithmetic_fence:
39773977 case Intrinsic::masked_gather:
39783978 case Intrinsic::masked_scatter:
3979+ case Intrinsic::modf:
39793980 return true ;
39803981 default :
39813982 // Unknown intrinsics' declarations should always be translated
@@ -4076,6 +4077,8 @@ static SPIRVWord getBuiltinIdForIntrinsic(Intrinsic::ID IID) {
40764077 return OpenCLLIB::Tanh;
40774078 case Intrinsic::trunc:
40784079 return OpenCLLIB::Trunc;
4080+ case Intrinsic::modf:
4081+ return OpenCLLIB::Modf;
40794082 default :
40804083 assert (false && " Builtin ID requested for Unhandled intrinsic!" );
40814084 return 0 ;
@@ -4273,6 +4276,50 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
42734276 return BM->addExtInst (FTy, BM->getExtInstSetId (SPIRVEIS_OpenCL), ExtOp, Ops,
42744277 BB);
42754278 }
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+ }
42764323 // Binary FP intrinsics
42774324 case Intrinsic::atan2:
42784325 case Intrinsic::copysign:
0 commit comments