diff options
Diffstat (limited to 'llvm/lib/Target/SPIRV')
-rw-r--r-- | llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp | 82 | ||||
-rw-r--r-- | llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp | 8 | ||||
-rw-r--r-- | llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 23 | ||||
-rw-r--r-- | llvm/lib/Target/SPIRV/SPIRVUtils.h | 2 |
4 files changed, 114 insertions, 1 deletions
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index 6608b3f..d4fa62a 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -296,6 +296,8 @@ private: bool selectImageWriteIntrinsic(MachineInstr &I) const; bool selectResourceGetPointer(Register &ResVReg, const SPIRVType *ResType, MachineInstr &I) const; + bool selectModf(Register ResVReg, const SPIRVType *ResType, + MachineInstr &I) const; // Utilities std::pair<Register, bool> @@ -3235,6 +3237,9 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, case Intrinsic::spv_discard: { return selectDiscard(ResVReg, ResType, I); } + case Intrinsic::modf: { + return selectModf(ResVReg, ResType, I); + } default: { std::string DiagMsg; raw_string_ostream OS(DiagMsg); @@ -4018,6 +4023,83 @@ bool SPIRVInstructionSelector::selectLog10(Register ResVReg, .constrainAllUses(TII, TRI, RBI); } +bool SPIRVInstructionSelector::selectModf(Register ResVReg, + const SPIRVType *ResType, + MachineInstr &I) const { + // llvm.modf has a single arg --the number to be decomposed-- and returns a + // struct { restype, restype }, 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 OpenCL::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. + + // At this point, the return type is not a struct anymore, but rather two + // independent elements of SPIRVResType. We can get each independent element + // from I.getDefs() or I.getOperands(). + if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) { + MachineIRBuilder MIRBuilder(I); + // Get pointer type for alloca variable. + const SPIRVType *PtrType = GR.getOrCreateSPIRVPointerType( + ResType, MIRBuilder, SPIRV::StorageClass::Function); + // Create new register for the pointer type of alloca variable. + Register PtrTyReg = + MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass); + MIRBuilder.getMRI()->setType( + PtrTyReg, + LLT::pointer(storageClassToAddressSpace(SPIRV::StorageClass::Function), + GR.getPointerSize())); + // Assign SPIR-V type of the pointer type of the alloca variable to the + // new register. + GR.assignSPIRVTypeToVReg(PtrType, PtrTyReg, MIRBuilder.getMF()); + MachineBasicBlock &EntryBB = I.getMF()->front(); + MachineBasicBlock::iterator VarPos = + getFirstValidInstructionInsertPoint(EntryBB); + auto AllocaMIB = + BuildMI(EntryBB, VarPos, I.getDebugLoc(), TII.get(SPIRV::OpVariable)) + .addDef(PtrTyReg) + .addUse(GR.getSPIRVTypeID(PtrType)) + .addImm(static_cast<uint32_t>(SPIRV::StorageClass::Function)); + Register Variable = AllocaMIB->getOperand(0).getReg(); + // Modf must have 4 operands, the first two are the 2 parts of the result, + // the third is the operand, and the last one is the floating point value. + assert(I.getNumOperands() == 4 && + "Expected 4 operands for modf instruction"); + MachineBasicBlock &BB = *I.getParent(); + // Create the OpenCLLIB::modf instruction. + auto MIB = + BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpExtInst)) + .addDef(ResVReg) + .addUse(GR.getSPIRVTypeID(ResType)) + .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std)) + .addImm(CL::modf) + .setMIFlags(I.getFlags()) + .add(I.getOperand(3)) // Floating point value. + .addUse(Variable); // Pointer to integral part. + // Assign the integral part stored in the ptr to the second element of the + // result. + Register IntegralPartReg = I.getOperand(1).getReg(); + if (IntegralPartReg.isValid()) { + // Load the value from the pointer to integral part. + auto LoadMIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLoad)) + .addDef(IntegralPartReg) + .addUse(GR.getSPIRVTypeID(ResType)) + .addUse(Variable); + return LoadMIB.constrainAllUses(TII, TRI, RBI); + } + + return MIB.constrainAllUses(TII, TRI, RBI); + } else if (STI.canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450)) { + assert(false && "GLSL::Modf is deprecated."); + // FIXME: GL::Modf is deprecated, use Modfstruct instead. + return false; + } + return false; +} + // Generate the instructions to load 3-element vector builtin input // IDs/Indices. // Like: GlobalInvocationId, LocalInvocationId, etc.... diff --git a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp index 2bffbf7..595424b 100644 --- a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp @@ -380,7 +380,7 @@ bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) { bool Changed = false; const SPIRVSubtarget &STI = TM.getSubtarget<SPIRVSubtarget>(*F); for (BasicBlock &BB : *F) { - for (Instruction &I : BB) { + for (Instruction &I : make_early_inc_range(BB)) { auto Call = dyn_cast<CallInst>(&I); if (!Call) continue; @@ -408,12 +408,18 @@ bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) { if (!STI.isShader()) { Changed |= toSpvOverloadedIntrinsic( II, Intrinsic::SPVIntrinsics::spv_lifetime_start, {1}); + } else { + II->eraseFromParent(); + Changed = true; } break; case Intrinsic::lifetime_end: if (!STI.isShader()) { Changed |= toSpvOverloadedIntrinsic( II, Intrinsic::SPVIntrinsics::spv_lifetime_end, {1}); + } else { + II->eraseFromParent(); + Changed = true; } break; case Intrinsic::ptr_annotation: diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp index 768efb9..416d811 100644 --- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp @@ -995,4 +995,27 @@ unsigned getArrayComponentCount(const MachineRegisterInfo *MRI, return foldImm(ResType->getOperand(2), MRI); } +MachineBasicBlock::iterator +getFirstValidInstructionInsertPoint(MachineBasicBlock &BB) { + // Find the position to insert the OpVariable instruction. + // We will insert it after the last OpFunctionParameter, if any, or + // after OpFunction otherwise. + MachineBasicBlock::iterator VarPos = BB.begin(); + while (VarPos != BB.end() && VarPos->getOpcode() != SPIRV::OpFunction) { + ++VarPos; + } + // Advance VarPos to the next instruction after OpFunction, it will either + // be an OpFunctionParameter, so that we can start the next loop, or the + // position to insert the OpVariable instruction. + ++VarPos; + while (VarPos != BB.end() && + VarPos->getOpcode() == SPIRV::OpFunctionParameter) { + ++VarPos; + } + // VarPos is now pointing at after the last OpFunctionParameter, if any, + // or after OpFunction, if no parameters. + return VarPos != BB.end() && VarPos->getOpcode() == SPIRV::OpLabel ? ++VarPos + : VarPos; +} + } // namespace llvm diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h index d732188..45c520a 100644 --- a/llvm/lib/Target/SPIRV/SPIRVUtils.h +++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h @@ -506,6 +506,8 @@ MachineInstr *getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI); int64_t foldImm(const MachineOperand &MO, const MachineRegisterInfo *MRI); unsigned getArrayComponentCount(const MachineRegisterInfo *MRI, const MachineInstr *ResType); +MachineBasicBlock::iterator +getFirstValidInstructionInsertPoint(MachineBasicBlock &BB); } // namespace llvm #endif // LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H |