|
27 | 27 | #include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
|
28 | 28 | #include "llvm/CodeGen/MachineInstrBuilder.h"
|
29 | 29 | #include "llvm/CodeGen/MachineRegisterInfo.h"
|
| 30 | +#include "llvm/IR/IntrinsicsDirectX.h" |
30 | 31 | #include "llvm/IR/IntrinsicsSPIRV.h"
|
31 | 32 | #include "llvm/Support/Debug.h"
|
32 | 33 |
|
@@ -194,6 +195,9 @@ class SPIRVInstructionSelector : public InstructionSelector {
|
194 | 195 | bool selectLog10(Register ResVReg, const SPIRVType *ResType,
|
195 | 196 | MachineInstr &I) const;
|
196 | 197 |
|
| 198 | + bool selectDXThreadId(Register ResVReg, const SPIRVType *ResType, |
| 199 | + MachineInstr &I) const; |
| 200 | + |
197 | 201 | bool selectUnmergeValues(MachineInstr &I) const;
|
198 | 202 |
|
199 | 203 | Register buildI32Constant(uint32_t Val, MachineInstr &I,
|
@@ -301,6 +305,7 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
|
301 | 305 | case TargetOpcode::G_FREEZE:
|
302 | 306 | return selectFreeze(ResVReg, ResType, I);
|
303 | 307 |
|
| 308 | + case TargetOpcode::G_INTRINSIC: |
304 | 309 | case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
|
305 | 310 | case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
|
306 | 311 | return selectIntrinsic(ResVReg, ResType, I);
|
@@ -1614,6 +1619,8 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
|
1614 | 1619 | .addUse(I.getOperand(2).getReg())
|
1615 | 1620 | .addUse(I.getOperand(3).getReg());
|
1616 | 1621 | break;
|
| 1622 | + case Intrinsic::dx_thread_id: |
| 1623 | + return selectDXThreadId(ResVReg, ResType, I); |
1617 | 1624 | default:
|
1618 | 1625 | llvm_unreachable("Intrinsic selection not implemented");
|
1619 | 1626 | }
|
@@ -1864,6 +1871,68 @@ bool SPIRVInstructionSelector::selectLog10(Register ResVReg,
|
1864 | 1871 | return Result;
|
1865 | 1872 | }
|
1866 | 1873 |
|
| 1874 | +bool SPIRVInstructionSelector::selectDXThreadId(Register ResVReg, |
| 1875 | + const SPIRVType *ResType, |
| 1876 | + MachineInstr &I) const { |
| 1877 | + // DX intrinsic: @llvm.dx.thread.id(i32) |
| 1878 | + // ID Name Description |
| 1879 | + // 93 ThreadId reads the thread ID |
| 1880 | + |
| 1881 | + MachineIRBuilder MIRBuilder(I); |
| 1882 | + const SPIRVType *U32Type = GR.getOrCreateSPIRVIntegerType(32, MIRBuilder); |
| 1883 | + const SPIRVType *Vec3Ty = |
| 1884 | + GR.getOrCreateSPIRVVectorType(U32Type, 3, MIRBuilder); |
| 1885 | + const SPIRVType *PtrType = GR.getOrCreateSPIRVPointerType( |
| 1886 | + Vec3Ty, MIRBuilder, SPIRV::StorageClass::Input); |
| 1887 | + |
| 1888 | + // Create new register for GlobalInvocationID builtin variable. |
| 1889 | + Register NewRegister = |
| 1890 | + MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::IDRegClass); |
| 1891 | + MIRBuilder.getMRI()->setType(NewRegister, LLT::pointer(0, 32)); |
| 1892 | + GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF()); |
| 1893 | + |
| 1894 | + // Build GlobalInvocationID global variable with the necessary decorations. |
| 1895 | + Register Variable = GR.buildGlobalVariable( |
| 1896 | + NewRegister, PtrType, |
| 1897 | + getLinkStringForBuiltIn(SPIRV::BuiltIn::GlobalInvocationId), nullptr, |
| 1898 | + SPIRV::StorageClass::Input, nullptr, true, true, |
| 1899 | + SPIRV::LinkageType::Import, MIRBuilder, false); |
| 1900 | + |
| 1901 | + // Create new register for loading value. |
| 1902 | + MachineRegisterInfo *MRI = MIRBuilder.getMRI(); |
| 1903 | + Register LoadedRegister = MRI->createVirtualRegister(&SPIRV::IDRegClass); |
| 1904 | + MIRBuilder.getMRI()->setType(LoadedRegister, LLT::pointer(0, 32)); |
| 1905 | + GR.assignSPIRVTypeToVReg(Vec3Ty, LoadedRegister, MIRBuilder.getMF()); |
| 1906 | + |
| 1907 | + // Load v3uint value from the global variable. |
| 1908 | + BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad)) |
| 1909 | + .addDef(LoadedRegister) |
| 1910 | + .addUse(GR.getSPIRVTypeID(Vec3Ty)) |
| 1911 | + .addUse(Variable); |
| 1912 | + |
| 1913 | + // Get Thread ID index. Expecting operand is a constant immediate value, |
| 1914 | + // wrapped in a type assignment. |
| 1915 | + assert(I.getOperand(2).isReg()); |
| 1916 | + Register ThreadIdReg = I.getOperand(2).getReg(); |
| 1917 | + SPIRVType *ConstTy = this->MRI->getVRegDef(ThreadIdReg); |
| 1918 | + assert(ConstTy && ConstTy->getOpcode() == SPIRV::ASSIGN_TYPE && |
| 1919 | + ConstTy->getOperand(1).isReg()); |
| 1920 | + Register ConstReg = ConstTy->getOperand(1).getReg(); |
| 1921 | + const MachineInstr *Const = this->MRI->getVRegDef(ConstReg); |
| 1922 | + assert(Const && Const->getOpcode() == TargetOpcode::G_CONSTANT); |
| 1923 | + const llvm::APInt &Val = Const->getOperand(1).getCImm()->getValue(); |
| 1924 | + const uint32_t ThreadId = Val.getZExtValue(); |
| 1925 | + |
| 1926 | + // Extract the thread ID from the loaded vector value. |
| 1927 | + MachineBasicBlock &BB = *I.getParent(); |
| 1928 | + auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpCompositeExtract)) |
| 1929 | + .addDef(ResVReg) |
| 1930 | + .addUse(GR.getSPIRVTypeID(ResType)) |
| 1931 | + .addUse(LoadedRegister) |
| 1932 | + .addImm(ThreadId); |
| 1933 | + return MIB.constrainAllUses(TII, TRI, RBI); |
| 1934 | +} |
| 1935 | + |
1867 | 1936 | namespace llvm {
|
1868 | 1937 | InstructionSelector *
|
1869 | 1938 | createSPIRVInstructionSelector(const SPIRVTargetMachine &TM,
|
|
0 commit comments