@@ -316,6 +316,9 @@ class SPIRVInstructionSelector : public InstructionSelector {
316316 bool selectImageWriteIntrinsic (MachineInstr &I) const ;
317317 bool selectResourceGetPointer (Register &ResVReg, const SPIRVType *ResType,
318318 MachineInstr &I) const ;
319+ bool selectResourceNonUniformIndex (Register &ResVReg,
320+ const SPIRVType *ResType,
321+ MachineInstr &I) const ;
319322 bool selectModf (Register ResVReg, const SPIRVType *ResType,
320323 MachineInstr &I) const ;
321324 bool selectUpdateCounter (Register &ResVReg, const SPIRVType *ResType,
@@ -347,7 +350,7 @@ class SPIRVInstructionSelector : public InstructionSelector {
347350 SPIRV::StorageClass::StorageClass SC,
348351 uint32_t Set, uint32_t Binding,
349352 uint32_t ArraySize, Register IndexReg,
350- bool IsNonUniform, StringRef Name,
353+ StringRef Name,
351354 MachineIRBuilder MIRBuilder) const ;
352355 SPIRVType *widenTypeToVec4 (const SPIRVType *Type, MachineInstr &I) const ;
353356 bool extractSubvector (Register &ResVReg, const SPIRVType *ResType,
@@ -364,6 +367,7 @@ class SPIRVInstructionSelector : public InstructionSelector {
364367 MachineInstr &I) const ;
365368 bool loadHandleBeforePosition (Register &HandleReg, const SPIRVType *ResType,
366369 GIntrinsic &HandleDef, MachineInstr &Pos) const ;
370+ void decorateUsesAsNonUniform (Register &NonUniformReg) const ;
367371};
368372
369373bool sampledTypeIsSignedInteger (const llvm::Type *HandleType) {
@@ -3465,6 +3469,9 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
34653469 case Intrinsic::spv_discard: {
34663470 return selectDiscard (ResVReg, ResType, I);
34673471 }
3472+ case Intrinsic::spv_resource_nonuniformindex: {
3473+ return selectResourceNonUniformIndex (ResVReg, ResType, I);
3474+ }
34683475 default : {
34693476 std::string DiagMsg;
34703477 raw_string_ostream OS (DiagMsg);
@@ -3504,7 +3511,6 @@ bool SPIRVInstructionSelector::selectCounterHandleFromBinding(
35043511 uint32_t Binding = getIConstVal (Intr.getOperand (3 ).getReg (), MRI);
35053512 uint32_t ArraySize = getIConstVal (MainHandleDef->getOperand (4 ).getReg (), MRI);
35063513 Register IndexReg = MainHandleDef->getOperand (5 ).getReg ();
3507- const bool IsNonUniform = false ;
35083514 std::string CounterName =
35093515 getStringValueFromReg (MainHandleDef->getOperand (6 ).getReg (), *MRI) +
35103516 " .counter" ;
@@ -3513,7 +3519,7 @@ bool SPIRVInstructionSelector::selectCounterHandleFromBinding(
35133519 MachineIRBuilder MIRBuilder (I);
35143520 Register CounterVarReg = buildPointerToResource (
35153521 GR.getPointeeType (ResType), GR.getPointerStorageClass (ResType), Set,
3516- Binding, ArraySize, IndexReg, IsNonUniform, CounterName, MIRBuilder);
3522+ Binding, ArraySize, IndexReg, CounterName, MIRBuilder);
35173523
35183524 return BuildCOPY (ResVReg, CounterVarReg, I);
35193525}
@@ -3713,6 +3719,55 @@ bool SPIRVInstructionSelector::selectResourceGetPointer(
37133719 .constrainAllUses (TII, TRI, RBI);
37143720}
37153721
3722+ bool SPIRVInstructionSelector::selectResourceNonUniformIndex (
3723+ Register &ResVReg, const SPIRVType *ResType, MachineInstr &I) const {
3724+ Register ObjReg = I.getOperand (2 ).getReg ();
3725+ if (!BuildCOPY (ResVReg, ObjReg, I))
3726+ return false ;
3727+
3728+ buildOpDecorate (ResVReg, I, TII, SPIRV::Decoration::NonUniformEXT, {});
3729+ // Check for the registers that use the index marked as non-uniform
3730+ // and recursively mark them as non-uniform.
3731+ // Per the spec, it's necessary that the final argument used for
3732+ // load/store/sample/atomic must be decorated, so we need to propagate the
3733+ // decoration through access chains and copies.
3734+ // https://docs.vulkan.org/samples/latest/samples/extensions/descriptor_indexing/README.html#_when_to_use_non_uniform_indexing_qualifier
3735+ decorateUsesAsNonUniform (ResVReg);
3736+ return true ;
3737+ }
3738+
3739+ void SPIRVInstructionSelector::decorateUsesAsNonUniform (
3740+ Register &NonUniformReg) const {
3741+ llvm::SmallVector<Register> WorkList = {NonUniformReg};
3742+ while (WorkList.size () > 0 ) {
3743+ Register CurrentReg = WorkList.back ();
3744+ WorkList.pop_back ();
3745+
3746+ bool IsDecorated = false ;
3747+ for (MachineInstr &Use : MRI->use_instructions (CurrentReg)) {
3748+ if (Use.getOpcode () == SPIRV::OpDecorate &&
3749+ Use.getOperand (1 ).getImm () == SPIRV::Decoration::NonUniformEXT) {
3750+ IsDecorated = true ;
3751+ continue ;
3752+ }
3753+ // Check if the instruction has the result register and add it to the
3754+ // worklist.
3755+ if (Use.getOperand (0 ).isReg () && Use.getOperand (0 ).isDef ()) {
3756+ Register ResultReg = Use.getOperand (0 ).getReg ();
3757+ if (ResultReg == CurrentReg)
3758+ continue ;
3759+ WorkList.push_back (ResultReg);
3760+ }
3761+ }
3762+
3763+ if (!IsDecorated) {
3764+ buildOpDecorate (CurrentReg, *MRI->getVRegDef (CurrentReg), TII,
3765+ SPIRV::Decoration::NonUniformEXT, {});
3766+ }
3767+ }
3768+ return ;
3769+ }
3770+
37163771bool SPIRVInstructionSelector::extractSubvector (
37173772 Register &ResVReg, const SPIRVType *ResType, Register &ReadReg,
37183773 MachineInstr &InsertionPoint) const {
@@ -3784,7 +3839,7 @@ bool SPIRVInstructionSelector::selectImageWriteIntrinsic(
37843839Register SPIRVInstructionSelector::buildPointerToResource (
37853840 const SPIRVType *SpirvResType, SPIRV::StorageClass::StorageClass SC,
37863841 uint32_t Set, uint32_t Binding, uint32_t ArraySize, Register IndexReg,
3787- bool IsNonUniform, StringRef Name, MachineIRBuilder MIRBuilder) const {
3842+ StringRef Name, MachineIRBuilder MIRBuilder) const {
37883843 const Type *ResType = GR.getTypeForSPIRVType (SpirvResType);
37893844 if (ArraySize == 1 ) {
37903845 SPIRVType *PtrType =
@@ -3803,14 +3858,7 @@ Register SPIRVInstructionSelector::buildPointerToResource(
38033858
38043859 SPIRVType *ResPointerType =
38053860 GR.getOrCreateSPIRVPointerType (ResType, MIRBuilder, SC);
3806-
38073861 Register AcReg = MRI->createVirtualRegister (GR.getRegClass (ResPointerType));
3808- if (IsNonUniform) {
3809- // It is unclear which value needs to be marked an non-uniform, so both
3810- // the index and the access changed are decorated as non-uniform.
3811- buildOpDecorate (IndexReg, MIRBuilder, SPIRV::Decoration::NonUniformEXT, {});
3812- buildOpDecorate (AcReg, MIRBuilder, SPIRV::Decoration::NonUniformEXT, {});
3813- }
38143862
38153863 MIRBuilder.buildInstr (SPIRV::OpAccessChain)
38163864 .addDef (AcReg)
@@ -4560,9 +4608,6 @@ bool SPIRVInstructionSelector::loadHandleBeforePosition(
45604608 uint32_t Binding = foldImm (HandleDef.getOperand (3 ), MRI);
45614609 uint32_t ArraySize = foldImm (HandleDef.getOperand (4 ), MRI);
45624610 Register IndexReg = HandleDef.getOperand (5 ).getReg ();
4563- // FIXME: The IsNonUniform flag needs to be set based on resource analysis.
4564- // https://github.com/llvm/llvm-project/issues/155701
4565- bool IsNonUniform = false ;
45664611 std::string Name =
45674612 getStringValueFromReg (HandleDef.getOperand (6 ).getReg (), *MRI);
45684613
@@ -4576,13 +4621,8 @@ bool SPIRVInstructionSelector::loadHandleBeforePosition(
45764621 SC = GR.getPointerStorageClass (ResType);
45774622 }
45784623
4579- Register VarReg =
4580- buildPointerToResource (VarType, SC, Set, Binding, ArraySize, IndexReg,
4581- IsNonUniform, Name, MIRBuilder);
4582-
4583- if (IsNonUniform)
4584- buildOpDecorate (HandleReg, HandleDef, TII, SPIRV::Decoration::NonUniformEXT,
4585- {});
4624+ Register VarReg = buildPointerToResource (VarType, SC, Set, Binding, ArraySize,
4625+ IndexReg, Name, MIRBuilder);
45864626
45874627 // The handle for the buffer is the pointer to the resource. For an image, the
45884628 // handle is the image object. So images get an extra load.
0 commit comments