Skip to content

Commit 11df329

Browse files
authored
"[SPIRV] Implement translation for llvm.modf.* intrinsics (#147556)" cherry-pick (#19725)
Cherry-pick the patch llvm/llvm-project@1d02de28dd6: ``` Based on KhronosGroup/SPIRV-LLVM-Translator#3100, I'm adding translation for `llvm.modf.*` intrinsics. ``` And reenable tests that were unsupported because of this issue. Fixes #17813.
1 parent 6114c43 commit 11df329

File tree

8 files changed

+173
-8
lines changed

8 files changed

+173
-8
lines changed

llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@ class SPIRVInstructionSelector : public InstructionSelector {
296296
bool selectImageWriteIntrinsic(MachineInstr &I) const;
297297
bool selectResourceGetPointer(Register &ResVReg, const SPIRVType *ResType,
298298
MachineInstr &I) const;
299+
bool selectModf(Register ResVReg, const SPIRVType *ResType,
300+
MachineInstr &I) const;
299301

300302
// Utilities
301303
std::pair<Register, bool>
@@ -3218,6 +3220,9 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
32183220
case Intrinsic::spv_discard: {
32193221
return selectDiscard(ResVReg, ResType, I);
32203222
}
3223+
case Intrinsic::modf: {
3224+
return selectModf(ResVReg, ResType, I);
3225+
}
32213226
default: {
32223227
std::string DiagMsg;
32233228
raw_string_ostream OS(DiagMsg);
@@ -4001,6 +4006,83 @@ bool SPIRVInstructionSelector::selectLog10(Register ResVReg,
40014006
.constrainAllUses(TII, TRI, RBI);
40024007
}
40034008

4009+
bool SPIRVInstructionSelector::selectModf(Register ResVReg,
4010+
const SPIRVType *ResType,
4011+
MachineInstr &I) const {
4012+
// llvm.modf has a single arg --the number to be decomposed-- and returns a
4013+
// struct { restype, restype }, while OpenCLLIB::modf has two args --the
4014+
// number to be decomposed and a pointer--, returns the fractional part and
4015+
// the integral part is stored in the pointer argument. Therefore, we can't
4016+
// use directly the OpenCLLIB::modf intrinsic. However, we can do some
4017+
// scaffolding to make it work. The idea is to create an alloca instruction
4018+
// to get a ptr, pass this ptr to OpenCL::modf, and then load the value
4019+
// from this ptr to place it in the struct. llvm.modf returns the fractional
4020+
// part as the first element of the result, and the integral part as the
4021+
// second element of the result.
4022+
4023+
// At this point, the return type is not a struct anymore, but rather two
4024+
// independent elements of SPIRVResType. We can get each independent element
4025+
// from I.getDefs() or I.getOperands().
4026+
if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
4027+
MachineIRBuilder MIRBuilder(I);
4028+
// Get pointer type for alloca variable.
4029+
const SPIRVType *PtrType = GR.getOrCreateSPIRVPointerType(
4030+
ResType, MIRBuilder, SPIRV::StorageClass::Function);
4031+
// Create new register for the pointer type of alloca variable.
4032+
Register PtrTyReg =
4033+
MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass);
4034+
MIRBuilder.getMRI()->setType(
4035+
PtrTyReg,
4036+
LLT::pointer(storageClassToAddressSpace(SPIRV::StorageClass::Function),
4037+
GR.getPointerSize()));
4038+
// Assign SPIR-V type of the pointer type of the alloca variable to the
4039+
// new register.
4040+
GR.assignSPIRVTypeToVReg(PtrType, PtrTyReg, MIRBuilder.getMF());
4041+
MachineBasicBlock &EntryBB = I.getMF()->front();
4042+
MachineBasicBlock::iterator VarPos =
4043+
getFirstValidInstructionInsertPoint(EntryBB);
4044+
auto AllocaMIB =
4045+
BuildMI(EntryBB, VarPos, I.getDebugLoc(), TII.get(SPIRV::OpVariable))
4046+
.addDef(PtrTyReg)
4047+
.addUse(GR.getSPIRVTypeID(PtrType))
4048+
.addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function));
4049+
Register Variable = AllocaMIB->getOperand(0).getReg();
4050+
// Modf must have 4 operands, the first two are the 2 parts of the result,
4051+
// the third is the operand, and the last one is the floating point value.
4052+
assert(I.getNumOperands() == 4 &&
4053+
"Expected 4 operands for modf instruction");
4054+
MachineBasicBlock &BB = *I.getParent();
4055+
// Create the OpenCLLIB::modf instruction.
4056+
auto MIB =
4057+
BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst))
4058+
.addDef(ResVReg)
4059+
.addUse(GR.getSPIRVTypeID(ResType))
4060+
.addImm(static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std))
4061+
.addImm(CL::modf)
4062+
.setMIFlags(I.getFlags())
4063+
.add(I.getOperand(3)) // Floating point value.
4064+
.addUse(Variable); // Pointer to integral part.
4065+
// Assign the integral part stored in the ptr to the second element of the
4066+
// result.
4067+
Register IntegralPartReg = I.getOperand(1).getReg();
4068+
if (IntegralPartReg.isValid()) {
4069+
// Load the value from the pointer to integral part.
4070+
auto LoadMIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
4071+
.addDef(IntegralPartReg)
4072+
.addUse(GR.getSPIRVTypeID(ResType))
4073+
.addUse(Variable);
4074+
return LoadMIB.constrainAllUses(TII, TRI, RBI);
4075+
}
4076+
4077+
return MIB.constrainAllUses(TII, TRI, RBI);
4078+
} else if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) {
4079+
assert(false && "GLSL::Modf is deprecated.");
4080+
// FIXME: GL::Modf is deprecated, use Modfstruct instead.
4081+
return false;
4082+
}
4083+
return false;
4084+
}
4085+
40044086
// Generate the instructions to load 3-element vector builtin input
40054087
// IDs/Indices.
40064088
// Like: GlobalInvocationId, LocalInvocationId, etc....

llvm/lib/Target/SPIRV/SPIRVUtils.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,4 +995,27 @@ unsigned getArrayComponentCount(const MachineRegisterInfo *MRI,
995995
return foldImm(ResType->getOperand(2), MRI);
996996
}
997997

998+
MachineBasicBlock::iterator
999+
getFirstValidInstructionInsertPoint(MachineBasicBlock &BB) {
1000+
// Find the position to insert the OpVariable instruction.
1001+
// We will insert it after the last OpFunctionParameter, if any, or
1002+
// after OpFunction otherwise.
1003+
MachineBasicBlock::iterator VarPos = BB.begin();
1004+
while (VarPos != BB.end() && VarPos->getOpcode() != SPIRV::OpFunction) {
1005+
++VarPos;
1006+
}
1007+
// Advance VarPos to the next instruction after OpFunction, it will either
1008+
// be an OpFunctionParameter, so that we can start the next loop, or the
1009+
// position to insert the OpVariable instruction.
1010+
++VarPos;
1011+
while (VarPos != BB.end() &&
1012+
VarPos->getOpcode() == SPIRV::OpFunctionParameter) {
1013+
++VarPos;
1014+
}
1015+
// VarPos is now pointing at after the last OpFunctionParameter, if any,
1016+
// or after OpFunction, if no parameters.
1017+
return VarPos != BB.end() && VarPos->getOpcode() == SPIRV::OpLabel ? ++VarPos
1018+
: VarPos;
1019+
}
1020+
9981021
} // namespace llvm

llvm/lib/Target/SPIRV/SPIRVUtils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@ MachineInstr *getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI);
493493
int64_t foldImm(const MachineOperand &MO, const MachineRegisterInfo *MRI);
494494
unsigned getArrayComponentCount(const MachineRegisterInfo *MRI,
495495
const MachineInstr *ResType);
496+
MachineBasicBlock::iterator
497+
getFirstValidInstructionInsertPoint(MachineBasicBlock &BB);
496498

497499
} // namespace llvm
498500
#endif // LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H

llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
2+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
23

34
; CHECK: %[[#extinst_id:]] = OpExtInstImport "OpenCL.std"
45

@@ -337,3 +338,68 @@ entry:
337338
}
338339

339340
declare float @llvm.fma.f32(float, float, float)
341+
342+
; CHECK: OpFunction
343+
; CHECK: %[[#d:]] = OpFunctionParameter %[[#]]
344+
; CHECK: %[[#fracPtr:]] = OpFunctionParameter %[[#]]
345+
; CHECK: %[[#integralPtr:]] = OpFunctionParameter %[[#]]
346+
; CHECK: %[[#varPtr:]] = OpVariable %[[#]] Function
347+
; CHECK: %[[#frac:]] = OpExtInst %[[#var2]] %[[#extinst_id]] modf %[[#d]] %[[#varPtr]]
348+
; CHECK: %[[#integral:]] = OpLoad %[[#var2]] %[[#varPtr]]
349+
; CHECK: OpStore %[[#fracPtr]] %[[#frac]]
350+
; CHECK: OpStore %[[#integralPtr]] %[[#integral]]
351+
; CHECK: OpFunctionEnd
352+
define void @TestModf(double %d, ptr addrspace(1) %frac, ptr addrspace(1) %integral) {
353+
entry:
354+
%4 = tail call { double, double } @llvm.modf.f64(double %d)
355+
%5 = extractvalue { double, double } %4, 0
356+
%6 = extractvalue { double, double } %4, 1
357+
store double %5, ptr addrspace(1) %frac, align 8
358+
store double %6, ptr addrspace(1) %integral, align 8
359+
ret void
360+
}
361+
362+
; CHECK: OpFunction
363+
; CHECK: %[[#d:]] = OpFunctionParameter %[[#]]
364+
; CHECK: %[[#fracPtr:]] = OpFunctionParameter %[[#]]
365+
; CHECK: %[[#integralPtr:]] = OpFunctionParameter %[[#]]
366+
; CHECK: %[[#entryBlock:]] = OpLabel
367+
; CHECK: %[[#varPtr:]] = OpVariable %[[#]] Function
368+
; CHECK: OpBranchConditional %[[#]] %[[#lor_lhs_falseBlock:]] %[[#if_thenBlock:]]
369+
; CHECK: %[[#lor_lhs_falseBlock]] = OpLabel
370+
; CHECK: OpBranchConditional %[[#]] %[[#if_endBlock:]] %[[#if_thenBlock]]
371+
; CHECK: %[[#if_thenBlock]] = OpLabel
372+
; CHECK: OpBranch %[[#returnBlock:]]
373+
; CHECK: %[[#if_endBlock]] = OpLabel
374+
; CHECK: %[[#frac:]] = OpExtInst %[[#var2]] %[[#extinst_id]] modf %[[#d]] %[[#varPtr]]
375+
; CHECK: %[[#integral:]] = OpLoad %[[#var2]] %[[#varPtr]]
376+
; CHECK: OpStore %[[#fracPtr]] %[[#frac]]
377+
; CHECK: OpStore %[[#integralPtr]] %[[#integral]]
378+
; CHECK: OpFunctionEnd
379+
define dso_local void @TestModf2(double noundef %d, ptr noundef %frac, ptr noundef %integral) {
380+
entry:
381+
%0 = load ptr, ptr %frac, align 8
382+
%tobool = icmp ne ptr %0, null
383+
br i1 %tobool, label %lor.lhs.false, label %if.then
384+
385+
lor.lhs.false:
386+
%1 = load ptr, ptr %integral, align 8
387+
%tobool1 = icmp ne ptr %1, null
388+
br i1 %tobool1, label %if.end, label %if.then
389+
390+
if.then:
391+
br label %return
392+
393+
if.end:
394+
%6 = tail call { double, double } @llvm.modf.f64(double %d)
395+
%7 = extractvalue { double, double } %6, 0
396+
%8 = extractvalue { double, double } %6, 1
397+
store double %7, ptr %frac, align 4
398+
store double %8, ptr %integral, align 4
399+
br label %return
400+
401+
return:
402+
ret void
403+
}
404+
405+
declare { double, double } @llvm.modf.f64(double)

sycl/test-e2e/DeviceLib/cmath_fp64_test.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// UNSUPPORTED: spirv-backend
2-
// UNSUPPORTED-TRACKER: https://github.com/intel/llvm/issues/17813
31
// REQUIRES: aspect-fp64
42

53
// DEFINE: %{mathflags} = %if cl_options %{/clang:-fno-fast-math%} %else %{-fno-fast-math%}

sycl/test-e2e/DeviceLib/cmath_test.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// UNSUPPORTED: spirv-backend
2-
// UNSUPPORTED-TRACKER: https://github.com/intel/llvm/issues/17813
31
// DEFINE: %{mathflags} = %if cl_options %{/clang:-fno-fast-math%} %else %{-fno-fast-math%}
42

53
// RUN: %{build} -fno-builtin %{mathflags} -o %t1.out

sycl/test-e2e/DeviceLib/math_fp64_test.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// UNSUPPORTED: spirv-backend
2-
// UNSUPPORTED-TRACKER: https://github.com/intel/llvm/issues/17813
31
// REQUIRES: aspect-fp64
42

53
// DEFINE: %{mathflags} = %if cl_options %{/clang:-fno-fast-math%} %else %{-fno-fast-math%}

sycl/test-e2e/DeviceLib/math_test.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// UNSUPPORTED: spirv-backend
2-
// UNSUPPORTED-TRACKER: https://github.com/intel/llvm/issues/17813
31
// DEFINE: %{mathflags} = %if cl_options %{/clang:-fno-fast-math%} %else %{-fno-fast-math%}
42

53
// RUN: %{build} %{mathflags} -o %t1.out

0 commit comments

Comments
 (0)