Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions lib/SPIRV/SPIRVWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Copy link
Contributor

@MrSidims MrSidims Mar 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally it should be not current BB, but entry BB of the functions to satisfy "All OpVariable instructions in a function must be in the first block in the function".

SPIRVFunction class in the translator has BB vector, so it might be possible to query first basic block and then call getVariableInsertionPoint to get a place where to insert OpVariable (or alternatively just create alloca in the beginning of the function using LLVM API and call transValue here).


// Create the OpenCLLIB::modf instruction.
SPIRVType *FTy = transType(II->getType()->getStructElementType(0));
SPIRVValue *Arg = transValue(II->getArgOperand(0), BB);
std::vector<SPIRVValue *> 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<SPIRVId> StructVals{Modf->getId(), IntegralVal->getId()};
return BM->addCompositeConstructInst(STy, StructVals, BB);
}
// Binary FP intrinsics
case Intrinsic::atan2:
case Intrinsic::copysign:
Expand Down
13 changes: 13 additions & 0 deletions test/llvm-intrinsics/fp-intrinsics.ll
Original file line number Diff line number Diff line change
Expand Up @@ -436,3 +436,16 @@ entry:
}

declare float @llvm.atan2.f32(float, float)

; CHECK: Function
; CHECK: FunctionParameter {{[0-9]+}} [[x:[0-9]+]]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a check for OpVariable

; 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)
Loading