@@ -301,8 +301,9 @@ class SPIRVInstructionSelector : public InstructionSelector {
301301
302302 bool selectReadImageIntrinsic (Register &ResVReg, const SPIRVType *ResType,
303303 MachineInstr &I) const ;
304-
305304 bool selectImageWriteIntrinsic (MachineInstr &I) const ;
305+ bool selectResourceGetPointer (Register &ResVReg, const SPIRVType *ResType,
306+ MachineInstr &I) const ;
306307
307308 // Utilities
308309 std::pair<Register, bool >
@@ -332,10 +333,15 @@ class SPIRVInstructionSelector : public InstructionSelector {
332333 SPIRVType *widenTypeToVec4 (const SPIRVType *Type, MachineInstr &I) const ;
333334 bool extractSubvector (Register &ResVReg, const SPIRVType *ResType,
334335 Register &ReadReg, MachineInstr &InsertionPoint) const ;
336+ bool generateImageRead (Register &ResVReg, const SPIRVType *ResType,
337+ Register ImageReg, Register IdxReg, DebugLoc Loc,
338+ MachineInstr &Pos) const ;
335339 bool BuildCOPY (Register DestReg, Register SrcReg, MachineInstr &I) const ;
336340 bool loadVec3BuiltinInputID (SPIRV::BuiltIn::BuiltIn BuiltInValue,
337341 Register ResVReg, const SPIRVType *ResType,
338342 MachineInstr &I) const ;
343+ bool loadHandleBeforePosition (Register &HandleReg, const SPIRVType *ResType,
344+ GIntrinsic &HandleDef, MachineInstr &Pos) const ;
339345};
340346
341347} // end anonymous namespace
@@ -1043,6 +1049,25 @@ bool SPIRVInstructionSelector::selectLoad(Register ResVReg,
10431049 MachineInstr &I) const {
10441050 unsigned OpOffset = isa<GIntrinsic>(I) ? 1 : 0 ;
10451051 Register Ptr = I.getOperand (1 + OpOffset).getReg ();
1052+
1053+ auto *PtrDef = getVRegDef (*MRI, Ptr);
1054+ auto *IntPtrDef = dyn_cast<GIntrinsic>(PtrDef);
1055+ if (IntPtrDef &&
1056+ IntPtrDef->getIntrinsicID () == Intrinsic::spv_resource_getpointer) {
1057+ Register ImageReg = IntPtrDef->getOperand (2 ).getReg ();
1058+ Register NewImageReg =
1059+ MRI->createVirtualRegister (MRI->getRegClass (ImageReg));
1060+ auto *ImageDef = cast<GIntrinsic>(getVRegDef (*MRI, ImageReg));
1061+ if (!loadHandleBeforePosition (NewImageReg, GR.getSPIRVTypeForVReg (ImageReg),
1062+ *ImageDef, I)) {
1063+ return false ;
1064+ }
1065+
1066+ Register IdxReg = IntPtrDef->getOperand (3 ).getReg ();
1067+ return generateImageRead (ResVReg, ResType, NewImageReg, IdxReg,
1068+ I.getDebugLoc (), I);
1069+ }
1070+
10461071 auto MIB = BuildMI (*I.getParent (), I, I.getDebugLoc (), TII.get (SPIRV::OpLoad))
10471072 .addDef (ResVReg)
10481073 .addUse (GR.getSPIRVTypeID (ResType))
@@ -1062,6 +1087,29 @@ bool SPIRVInstructionSelector::selectStore(MachineInstr &I) const {
10621087 unsigned OpOffset = isa<GIntrinsic>(I) ? 1 : 0 ;
10631088 Register StoreVal = I.getOperand (0 + OpOffset).getReg ();
10641089 Register Ptr = I.getOperand (1 + OpOffset).getReg ();
1090+
1091+ auto *PtrDef = getVRegDef (*MRI, Ptr);
1092+ auto *IntPtrDef = dyn_cast<GIntrinsic>(PtrDef);
1093+ if (IntPtrDef &&
1094+ IntPtrDef->getIntrinsicID () == Intrinsic::spv_resource_getpointer) {
1095+ Register ImageReg = IntPtrDef->getOperand (2 ).getReg ();
1096+ Register NewImageReg =
1097+ MRI->createVirtualRegister (MRI->getRegClass (ImageReg));
1098+ auto *ImageDef = cast<GIntrinsic>(getVRegDef (*MRI, ImageReg));
1099+ if (!loadHandleBeforePosition (NewImageReg, GR.getSPIRVTypeForVReg (ImageReg),
1100+ *ImageDef, I)) {
1101+ return false ;
1102+ }
1103+
1104+ Register IdxReg = IntPtrDef->getOperand (3 ).getReg ();
1105+ return BuildMI (*I.getParent (), I, I.getDebugLoc (),
1106+ TII.get (SPIRV::OpImageWrite))
1107+ .addUse (NewImageReg)
1108+ .addUse (IdxReg)
1109+ .addUse (StoreVal)
1110+ .constrainAllUses (TII, TRI, RBI);
1111+ }
1112+
10651113 MachineBasicBlock &BB = *I.getParent ();
10661114 auto MIB = BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpStore))
10671115 .addUse (Ptr)
@@ -3066,6 +3114,9 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
30663114 case Intrinsic::spv_resource_load_typedbuffer: {
30673115 return selectReadImageIntrinsic (ResVReg, ResType, I);
30683116 }
3117+ case Intrinsic::spv_resource_getpointer: {
3118+ return selectResourceGetPointer (ResVReg, ResType, I);
3119+ }
30693120 case Intrinsic::spv_discard: {
30703121 return selectDiscard (ResVReg, ResType, I);
30713122 }
@@ -3083,27 +3134,7 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
30833134bool SPIRVInstructionSelector::selectHandleFromBinding (Register &ResVReg,
30843135 const SPIRVType *ResType,
30853136 MachineInstr &I) const {
3086-
3087- uint32_t Set = foldImm (I.getOperand (2 ), MRI);
3088- uint32_t Binding = foldImm (I.getOperand (3 ), MRI);
3089- uint32_t ArraySize = foldImm (I.getOperand (4 ), MRI);
3090- Register IndexReg = I.getOperand (5 ).getReg ();
3091- bool IsNonUniform = ArraySize > 1 && foldImm (I.getOperand (6 ), MRI);
3092-
3093- MachineIRBuilder MIRBuilder (I);
3094- Register VarReg = buildPointerToResource (ResType, Set, Binding, ArraySize,
3095- IndexReg, IsNonUniform, MIRBuilder);
3096-
3097- if (IsNonUniform)
3098- buildOpDecorate (ResVReg, I, TII, SPIRV::Decoration::NonUniformEXT, {});
3099-
3100- // TODO: For now we assume the resource is an image, which needs to be
3101- // loaded to get the handle. That will not be true for storage buffers.
3102- return BuildMI (*I.getParent (), I, I.getDebugLoc (), TII.get (SPIRV::OpLoad))
3103- .addDef (ResVReg)
3104- .addUse (GR.getSPIRVTypeID (ResType))
3105- .addUse (VarReg)
3106- .constrainAllUses (TII, TRI, RBI);
3137+ return true ;
31073138}
31083139
31093140bool SPIRVInstructionSelector::selectReadImageIntrinsic (
@@ -3116,42 +3147,75 @@ bool SPIRVInstructionSelector::selectReadImageIntrinsic(
31163147 // We will do that when we can, but for now trying to move forward with other
31173148 // issues.
31183149 Register ImageReg = I.getOperand (2 ).getReg ();
3119- assert (MRI->getVRegDef (ImageReg)->getParent () == I.getParent () &&
3120- " The image must be loaded in the same basic block as its use." );
3150+ auto *ImageDef = cast<GIntrinsic>(getVRegDef (*MRI, ImageReg));
3151+ Register NewImageReg = MRI->createVirtualRegister (MRI->getRegClass (ImageReg));
3152+ if (!loadHandleBeforePosition (NewImageReg, GR.getSPIRVTypeForVReg (ImageReg),
3153+ *ImageDef, I)) {
3154+ return false ;
3155+ }
3156+
3157+ Register IdxReg = I.getOperand (3 ).getReg ();
3158+ DebugLoc Loc = I.getDebugLoc ();
3159+ MachineInstr &Pos = I;
31213160
3161+ return generateImageRead (ResVReg, ResType, NewImageReg, IdxReg, Loc, Pos);
3162+ }
3163+
3164+ bool SPIRVInstructionSelector::generateImageRead (Register &ResVReg,
3165+ const SPIRVType *ResType,
3166+ Register ImageReg,
3167+ Register IdxReg, DebugLoc Loc,
3168+ MachineInstr &Pos) const {
31223169 uint64_t ResultSize = GR.getScalarOrVectorComponentCount (ResType);
31233170 if (ResultSize == 4 ) {
3124- return BuildMI (*I.getParent (), I, I.getDebugLoc (),
3125- TII.get (SPIRV::OpImageRead))
3171+ return BuildMI (*Pos.getParent (), Pos, Loc, TII.get (SPIRV::OpImageRead))
31263172 .addDef (ResVReg)
31273173 .addUse (GR.getSPIRVTypeID (ResType))
31283174 .addUse (ImageReg)
3129- .addUse (I. getOperand ( 3 ). getReg () )
3175+ .addUse (IdxReg )
31303176 .constrainAllUses (TII, TRI, RBI);
31313177 }
31323178
3133- SPIRVType *ReadType = widenTypeToVec4 (ResType, I );
3179+ SPIRVType *ReadType = widenTypeToVec4 (ResType, Pos );
31343180 Register ReadReg = MRI->createVirtualRegister (GR.getRegClass (ReadType));
31353181 bool Succeed =
3136- BuildMI (*I .getParent (), I, I. getDebugLoc () , TII.get (SPIRV::OpImageRead))
3182+ BuildMI (*Pos .getParent (), Pos, Loc , TII.get (SPIRV::OpImageRead))
31373183 .addDef (ReadReg)
31383184 .addUse (GR.getSPIRVTypeID (ReadType))
31393185 .addUse (ImageReg)
3140- .addUse (I. getOperand ( 3 ). getReg () )
3186+ .addUse (IdxReg )
31413187 .constrainAllUses (TII, TRI, RBI);
31423188 if (!Succeed)
31433189 return false ;
31443190
31453191 if (ResultSize == 1 ) {
3146- return BuildMI (*I .getParent (), I, I. getDebugLoc () ,
3192+ return BuildMI (*Pos .getParent (), Pos, Loc ,
31473193 TII.get (SPIRV::OpCompositeExtract))
31483194 .addDef (ResVReg)
31493195 .addUse (GR.getSPIRVTypeID (ResType))
31503196 .addUse (ReadReg)
31513197 .addImm (0 )
31523198 .constrainAllUses (TII, TRI, RBI);
31533199 }
3154- return extractSubvector (ResVReg, ResType, ReadReg, I);
3200+ return extractSubvector (ResVReg, ResType, ReadReg, Pos);
3201+ }
3202+
3203+ bool SPIRVInstructionSelector::selectResourceGetPointer (
3204+ Register &ResVReg, const SPIRVType *ResType, MachineInstr &I) const {
3205+ #ifdef ASSERT
3206+ // For now, the operand is an image. This will change once we start handling
3207+ // more resource types.
3208+ Register ResourcePtr = I.getOperand (2 ).getReg ();
3209+ SPIRVType *RegType = GR.getResultType (ResourcePtr);
3210+ assert (RegType->getOpcode () == SPIRV::OpTypeImage &&
3211+ " Can only handle texel buffers for now." );
3212+ #endif
3213+
3214+ // For texel buffers, the index into the image is part of the OpImageRead or
3215+ // OpImageWrite instructions. So we will do nothing in this case. This
3216+ // intrinsic will be combined with the load or store when selecting the load
3217+ // or store.
3218+ return true ;
31553219}
31563220
31573221bool SPIRVInstructionSelector::extractSubvector (
@@ -3203,15 +3267,20 @@ bool SPIRVInstructionSelector::selectImageWriteIntrinsic(
32033267 // We will do that when we can, but for now trying to move forward with other
32043268 // issues.
32053269 Register ImageReg = I.getOperand (1 ).getReg ();
3206- assert (MRI->getVRegDef (ImageReg)->getParent () == I.getParent () &&
3207- " The image must be loaded in the same basic block as its use." );
3270+ auto *ImageDef = cast<GIntrinsic>(getVRegDef (*MRI, ImageReg));
3271+ Register NewImageReg = MRI->createVirtualRegister (MRI->getRegClass (ImageReg));
3272+ if (!loadHandleBeforePosition (NewImageReg, GR.getSPIRVTypeForVReg (ImageReg),
3273+ *ImageDef, I)) {
3274+ return false ;
3275+ }
3276+
32083277 Register CoordinateReg = I.getOperand (2 ).getReg ();
32093278 Register DataReg = I.getOperand (3 ).getReg ();
32103279 assert (GR.getResultType (DataReg)->getOpcode () == SPIRV::OpTypeVector);
32113280 assert (GR.getScalarOrVectorComponentCount (GR.getResultType (DataReg)) == 4 );
32123281 return BuildMI (*I.getParent (), I, I.getDebugLoc (),
32133282 TII.get (SPIRV::OpImageWrite))
3214- .addUse (ImageReg )
3283+ .addUse (NewImageReg )
32153284 .addUse (CoordinateReg)
32163285 .addUse (DataReg)
32173286 .constrainAllUses (TII, TRI, RBI);
@@ -3878,6 +3947,36 @@ SPIRVType *SPIRVInstructionSelector::widenTypeToVec4(const SPIRVType *Type,
38783947 return GR.getOrCreateSPIRVVectorType (ScalarType, 4 , MIRBuilder);
38793948}
38803949
3950+ bool SPIRVInstructionSelector::loadHandleBeforePosition (
3951+ Register &HandleReg, const SPIRVType *ResType, GIntrinsic &HandleDef,
3952+ MachineInstr &Pos) const {
3953+
3954+ assert (HandleDef.getIntrinsicID () ==
3955+ Intrinsic::spv_resource_handlefrombinding);
3956+ uint32_t Set = foldImm (HandleDef.getOperand (2 ), MRI);
3957+ uint32_t Binding = foldImm (HandleDef.getOperand (3 ), MRI);
3958+ uint32_t ArraySize = foldImm (HandleDef.getOperand (4 ), MRI);
3959+ Register IndexReg = HandleDef.getOperand (5 ).getReg ();
3960+ bool IsNonUniform = ArraySize > 1 && foldImm (HandleDef.getOperand (6 ), MRI);
3961+
3962+ MachineIRBuilder MIRBuilder (HandleDef);
3963+ Register VarReg = buildPointerToResource (ResType, Set, Binding, ArraySize,
3964+ IndexReg, IsNonUniform, MIRBuilder);
3965+
3966+ if (IsNonUniform)
3967+ buildOpDecorate (HandleReg, HandleDef, TII, SPIRV::Decoration::NonUniformEXT,
3968+ {});
3969+
3970+ // TODO: For now we assume the resource is an image, which needs to be
3971+ // loaded to get the handle. That will not be true for storage buffers.
3972+ return BuildMI (*Pos.getParent (), Pos, HandleDef.getDebugLoc (),
3973+ TII.get (SPIRV::OpLoad))
3974+ .addDef (HandleReg)
3975+ .addUse (GR.getSPIRVTypeID (ResType))
3976+ .addUse (VarReg)
3977+ .constrainAllUses (TII, TRI, RBI);
3978+ }
3979+
38813980namespace llvm {
38823981InstructionSelector *
38833982createSPIRVInstructionSelector (const SPIRVTargetMachine &TM,
0 commit comments