@@ -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,9 @@ class SPIRVInstructionSelector : public InstructionSelector {
364367 MachineInstr &I) const ;
365368 bool loadHandleBeforePosition (Register &HandleReg, const SPIRVType *ResType,
366369 GIntrinsic &HandleDef, MachineInstr &Pos) const ;
370+ void recursivelyDecorateChildAsNonUniform (Register &NonUniformReg,
371+ const SPIRVType *RegType,
372+ MachineInstr &I) const ;
367373};
368374
369375bool sampledTypeIsSignedInteger (const llvm::Type *HandleType) {
@@ -3465,6 +3471,9 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
34653471 case Intrinsic::spv_discard: {
34663472 return selectDiscard (ResVReg, ResType, I);
34673473 }
3474+ case Intrinsic::spv_resource_nonuniformindex: {
3475+ return selectResourceNonUniformIndex (ResVReg, ResType, I);
3476+ }
34683477 default : {
34693478 std::string DiagMsg;
34703479 raw_string_ostream OS (DiagMsg);
@@ -3504,7 +3513,6 @@ bool SPIRVInstructionSelector::selectCounterHandleFromBinding(
35043513 uint32_t Binding = getIConstVal (Intr.getOperand (3 ).getReg (), MRI);
35053514 uint32_t ArraySize = getIConstVal (MainHandleDef->getOperand (4 ).getReg (), MRI);
35063515 Register IndexReg = MainHandleDef->getOperand (5 ).getReg ();
3507- const bool IsNonUniform = false ;
35083516 std::string CounterName =
35093517 getStringValueFromReg (MainHandleDef->getOperand (6 ).getReg (), *MRI) +
35103518 " .counter" ;
@@ -3513,7 +3521,7 @@ bool SPIRVInstructionSelector::selectCounterHandleFromBinding(
35133521 MachineIRBuilder MIRBuilder (I);
35143522 Register CounterVarReg = buildPointerToResource (
35153523 GR.getPointeeType (ResType), GR.getPointerStorageClass (ResType), Set,
3516- Binding, ArraySize, IndexReg, IsNonUniform, CounterName, MIRBuilder);
3524+ Binding, ArraySize, IndexReg, CounterName, MIRBuilder);
35173525
35183526 return BuildCOPY (ResVReg, CounterVarReg, I);
35193527}
@@ -3713,6 +3721,58 @@ bool SPIRVInstructionSelector::selectResourceGetPointer(
37133721 .constrainAllUses (TII, TRI, RBI);
37143722}
37153723
3724+ bool SPIRVInstructionSelector::selectResourceNonUniformIndex (
3725+ Register &ResVReg, const SPIRVType *ResType, MachineInstr &I) const {
3726+ Register ObjReg = I.getOperand (2 ).getReg ();
3727+ if (!BuildCOPY (ResVReg, ObjReg, I))
3728+ return false ;
3729+
3730+ buildOpDecorate (ResVReg, I, TII, SPIRV::Decoration::NonUniformEXT, {});
3731+ // Check for the registers that use the index marked as non-uniform
3732+ // and recursively mark them as non-uniform.
3733+ // Per the spec, it's necessary that the final argument used for
3734+ // load/store/sample/atomic must be decorated, so we need to propagate the
3735+ // decoration through access chains and copies.
3736+ // https://docs.vulkan.org/samples/latest/samples/extensions/descriptor_indexing/README.html#_when_to_use_non_uniform_indexing_qualifier
3737+ recursivelyDecorateChildAsNonUniform (ResVReg, ResType, I);
3738+ return true ;
3739+ }
3740+
3741+ void SPIRVInstructionSelector::recursivelyDecorateChildAsNonUniform (
3742+ Register &NonUniformReg, const SPIRVType *RegType, MachineInstr &I) const {
3743+ std::vector<std::tuple<Register, const SPIRVType *, MachineInstr *>> WorkList;
3744+ bool isDecorated = false ;
3745+ for (MachineInstr &Use :
3746+ RegType->getMF ()->getRegInfo ().use_instructions (NonUniformReg)) {
3747+ if (Use.getOpcode () != SPIRV::OpDecorate &&
3748+ Use.getOpcode () != SPIRV::OpAccessChain &&
3749+ Use.getOpcode () != SPIRV::OpCopyObject &&
3750+ Use.getOpcode () != SPIRV::OpLoad)
3751+ continue ;
3752+
3753+ if (Use.getOpcode () == SPIRV::OpDecorate &&
3754+ Use.getOperand (1 ).getImm () == SPIRV::Decoration::NonUniformEXT) {
3755+ isDecorated = true ;
3756+ continue ;
3757+ }
3758+
3759+ Register ResultReg = Use.getOperand (0 ).getReg ();
3760+ SPIRVType *ResultType = GR.getResultType (ResultReg);
3761+ WorkList.push_back (std::make_tuple (ResultReg, ResultType, &Use));
3762+ }
3763+
3764+ if (!isDecorated) {
3765+ buildOpDecorate (NonUniformReg, I, TII, SPIRV::Decoration::NonUniformEXT,
3766+ {});
3767+ }
3768+
3769+ for (auto &Item : WorkList) {
3770+ recursivelyDecorateChildAsNonUniform (std::get<0 >(Item), std::get<1 >(Item),
3771+ *std::get<2 >(Item));
3772+ }
3773+ return ;
3774+ }
3775+
37163776bool SPIRVInstructionSelector::extractSubvector (
37173777 Register &ResVReg, const SPIRVType *ResType, Register &ReadReg,
37183778 MachineInstr &InsertionPoint) const {
@@ -3784,7 +3844,7 @@ bool SPIRVInstructionSelector::selectImageWriteIntrinsic(
37843844Register SPIRVInstructionSelector::buildPointerToResource (
37853845 const SPIRVType *SpirvResType, SPIRV::StorageClass::StorageClass SC,
37863846 uint32_t Set, uint32_t Binding, uint32_t ArraySize, Register IndexReg,
3787- bool IsNonUniform, StringRef Name, MachineIRBuilder MIRBuilder) const {
3847+ StringRef Name, MachineIRBuilder MIRBuilder) const {
37883848 const Type *ResType = GR.getTypeForSPIRVType (SpirvResType);
37893849 if (ArraySize == 1 ) {
37903850 SPIRVType *PtrType =
@@ -3803,14 +3863,7 @@ Register SPIRVInstructionSelector::buildPointerToResource(
38033863
38043864 SPIRVType *ResPointerType =
38053865 GR.getOrCreateSPIRVPointerType (ResType, MIRBuilder, SC);
3806-
38073866 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- }
38143867
38153868 MIRBuilder.buildInstr (SPIRV::OpAccessChain)
38163869 .addDef (AcReg)
@@ -4560,9 +4613,6 @@ bool SPIRVInstructionSelector::loadHandleBeforePosition(
45604613 uint32_t Binding = foldImm (HandleDef.getOperand (3 ), MRI);
45614614 uint32_t ArraySize = foldImm (HandleDef.getOperand (4 ), MRI);
45624615 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 ;
45664616 std::string Name =
45674617 getStringValueFromReg (HandleDef.getOperand (6 ).getReg (), *MRI);
45684618
@@ -4576,13 +4626,8 @@ bool SPIRVInstructionSelector::loadHandleBeforePosition(
45764626 SC = GR.getPointerStorageClass (ResType);
45774627 }
45784628
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- {});
4629+ Register VarReg = buildPointerToResource (VarType, SC, Set, Binding, ArraySize,
4630+ IndexReg, Name, MIRBuilder);
45864631
45874632 // The handle for the buffer is the pointer to the resource. For an image, the
45884633 // handle is the image object. So images get an extra load.
0 commit comments