From 7a1a678f167cf66b5696c890b7ff7ec5354c7566 Mon Sep 17 00:00:00 2001 From: "Maronas, Marcos" Date: Wed, 26 Mar 2025 17:39:10 +0100 Subject: [PATCH 1/2] Add translation for llvm.modf.* --- lib/SPIRV/SPIRVWriter.cpp | 43 +++++++++++++++++++++++++++ test/llvm-intrinsics/fp-intrinsics.ll | 13 ++++++++ 2 files changed, 56 insertions(+) diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp index 70773d2062..a767d91ef4 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -3976,6 +3976,7 @@ bool LLVMToSPIRVBase::isKnownIntrinsic(Intrinsic::ID Id) { case Intrinsic::arithmetic_fence: case Intrinsic::masked_gather: case Intrinsic::masked_scatter: + case Intrinsic::modf: return true; default: // Unknown intrinsics' declarations should always be translated @@ -4076,6 +4077,8 @@ static SPIRVWord getBuiltinIdForIntrinsic(Intrinsic::ID IID) { return OpenCLLIB::Tanh; case Intrinsic::trunc: return OpenCLLIB::Trunc; + case Intrinsic::modf: + return OpenCLLIB::Modf; default: assert(false && "Builtin ID requested for Unhandled intrinsic!"); return 0; @@ -4273,6 +4276,46 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II, return BM->addExtInst(FTy, BM->getExtInstSetId(SPIRVEIS_OpenCL), ExtOp, Ops, BB); } + case Intrinsic::modf: { + // llvm.modf has a single arg --the number to be decomposed-- and returns a + // struct { double, double }, while OpenCLLIB::modf has two args --the + // number to be decomposed and a pointer--, returns the fractional part and + // the integral part is stored in the pointer argument. Therefore, we can't + // use directly the OpenCLLIB::modf intrinsic. However, we can do some + // scaffolding to make it work. The idea is to create an alloca instruction + // to get a ptr, pass this ptr to OpenCLLIB::modf, and then load the value + // from this ptr to place it in the struct. + + // llvm.modf returns the fractional part as the first element of the result, + // and the integral part as the second element of the result. Therefore, the + // first element is the return value of OpenCLLIB::modf, and the second + // element is the value loaded from the ptr of the alloca we created. + + // Create the alloca instruction. + SPIRVType *IntegralTy = transType(II->getType()->getStructElementType(1)); + // IntegralTy is the type of the result. We want to create a pointer to this + // that we can pass to OpenCLLIB::modf to store the integral part. + SPIRVTypePointer *IntegralPtrTy = + BM->addPointerType(StorageClassFunction, IntegralTy); + SPIRVValue *Ptr = BM->addVariable(IntegralPtrTy, nullptr, false, + spv::internal::LinkageTypeInternal, + nullptr, "", StorageClassFunction, BB); + + // Create the OpenCLLIB::modf instruction. + SPIRVType *FTy = transType(II->getType()->getStructElementType(0)); + SPIRVValue *Arg = transValue(II->getArgOperand(0), BB); + std::vector Ops{Arg, Ptr}; + SPIRVValue *Modf = BM->addExtInst(FTy, BM->getExtInstSetId(SPIRVEIS_OpenCL), + OpenCLLIB::Modf, Ops, BB); + + // Load the value from the ptr. + SPIRVValue *IntegralVal = BM->addLoadInst(Ptr, {}, BB, IntegralTy); + + // Create the struct. + SPIRVType *STy = transType(II->getType()); + std::vector StructVals{Modf->getId(), IntegralVal->getId()}; + return BM->addCompositeConstructInst(STy, StructVals, BB); + } // Binary FP intrinsics case Intrinsic::atan2: case Intrinsic::copysign: diff --git a/test/llvm-intrinsics/fp-intrinsics.ll b/test/llvm-intrinsics/fp-intrinsics.ll index 9f0ff861fd..5b7f6b62e9 100644 --- a/test/llvm-intrinsics/fp-intrinsics.ll +++ b/test/llvm-intrinsics/fp-intrinsics.ll @@ -436,3 +436,16 @@ entry: } declare float @llvm.atan2.f32(float, float) + +; CHECK: Function +; CHECK: FunctionParameter {{[0-9]+}} [[x:[0-9]+]] +; CHECK: ExtInst [[var2]] {{[0-9]+}} [[extinst_id]] modf [[x]] [[ptr:[0-9]+]] +; CHECK: FunctionEnd + +define spir_func {double, double} @TestModf(double %x) { +entry: + %t = tail call {double, double} @llvm.modf.f64(double %x) + ret {double, double} %t +} + +declare {double, double} @llvm.modf.f64(double) From 8c4821f5968f5ec1b0c51feed80c06d3a4ab81d5 Mon Sep 17 00:00:00 2001 From: "Maronas, Marcos" Date: Thu, 27 Mar 2025 11:16:30 +0100 Subject: [PATCH 2/2] Address code review feedback. --- lib/SPIRV/SPIRVWriter.cpp | 10 +++++++--- test/llvm-intrinsics/fp-intrinsics.ll | 9 +++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp index a767d91ef4..56a559c95c 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -4297,9 +4297,13 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II, // that we can pass to OpenCLLIB::modf to store the integral part. SPIRVTypePointer *IntegralPtrTy = BM->addPointerType(StorageClassFunction, IntegralTy); - SPIRVValue *Ptr = BM->addVariable(IntegralPtrTy, nullptr, false, - spv::internal::LinkageTypeInternal, - nullptr, "", StorageClassFunction, BB); + // We need to use the entry BB of the function calling llvm.modf.*, instead + // of the current BB. For that, we'll find current BB's parent and get its + // first BB, which is the entry BB of the function. + SPIRVBasicBlock *EntryBB = BB->getParent()->getBasicBlock(0); + SPIRVValue *Ptr = BM->addVariable( + IntegralPtrTy, nullptr, false, spv::internal::LinkageTypeInternal, + nullptr, "", StorageClassFunction, EntryBB); // Create the OpenCLLIB::modf instruction. SPIRVType *FTy = transType(II->getType()->getStructElementType(0)); diff --git a/test/llvm-intrinsics/fp-intrinsics.ll b/test/llvm-intrinsics/fp-intrinsics.ll index 5b7f6b62e9..d840701632 100644 --- a/test/llvm-intrinsics/fp-intrinsics.ll +++ b/test/llvm-intrinsics/fp-intrinsics.ll @@ -437,11 +437,16 @@ entry: declare float @llvm.atan2.f32(float, float) -; CHECK: Function +; CHECK: Function [[ResTy:[0-9]+]] ; CHECK: FunctionParameter {{[0-9]+}} [[x:[0-9]+]] -; CHECK: ExtInst [[var2]] {{[0-9]+}} [[extinst_id]] modf [[x]] [[ptr:[0-9]+]] +; CHECK: Variable [[PtrTy:[0-9]+]] [[Ptr:[0-9]+]] 7 +; CHECK: ExtInst [[var2]] [[ResFirstElem:[0-9]+]] [[extinst_id]] modf [[x]] [[Ptr]] +; CHECK: Load [[var2]] [[ResSecondElem:[0-9]+]] [[Ptr]] +; CHECK: CompositeConstruct [[ResTy]] [[RetVal:[0-9]+]] [[ResFirstElem]] [[ResSecondElem]] +; CHECK: ReturnValue [[RetVal]] ; CHECK: FunctionEnd + define spir_func {double, double} @TestModf(double %x) { entry: %t = tail call {double, double} @llvm.modf.f64(double %x)