@@ -276,8 +276,9 @@ class SPIRVInstructionSelector : public InstructionSelector {
276
276
277
277
bool selectReadImageIntrinsic (Register &ResVReg, const SPIRVType *ResType,
278
278
MachineInstr &I) const ;
279
-
280
279
bool selectImageWriteIntrinsic (MachineInstr &I) const ;
280
+ bool selectResourceGetPointer (Register &ResVReg, const SPIRVType *ResType,
281
+ MachineInstr &I) const ;
281
282
282
283
// Utilities
283
284
std::pair<Register, bool >
@@ -307,10 +308,15 @@ class SPIRVInstructionSelector : public InstructionSelector {
307
308
SPIRVType *widenTypeToVec4 (const SPIRVType *Type, MachineInstr &I) const ;
308
309
bool extractSubvector (Register &ResVReg, const SPIRVType *ResType,
309
310
Register &ReadReg, MachineInstr &InsertionPoint) const ;
311
+ bool generateImageRead (Register &ResVReg, const SPIRVType *ResType,
312
+ Register ImageReg, Register IdxReg, DebugLoc Loc,
313
+ MachineInstr &Pos) const ;
310
314
bool BuildCOPY (Register DestReg, Register SrcReg, MachineInstr &I) const ;
311
315
bool loadVec3BuiltinInputID (SPIRV::BuiltIn::BuiltIn BuiltInValue,
312
316
Register ResVReg, const SPIRVType *ResType,
313
317
MachineInstr &I) const ;
318
+ bool loadHandleBeforePosition (Register &HandleReg, const SPIRVType *ResType,
319
+ GIntrinsic &HandleDef, MachineInstr &Pos) const ;
314
320
};
315
321
316
322
} // end anonymous namespace
@@ -1018,6 +1024,25 @@ bool SPIRVInstructionSelector::selectLoad(Register ResVReg,
1018
1024
MachineInstr &I) const {
1019
1025
unsigned OpOffset = isa<GIntrinsic>(I) ? 1 : 0 ;
1020
1026
Register Ptr = I.getOperand (1 + OpOffset).getReg ();
1027
+
1028
+ auto *PtrDef = getVRegDef (*MRI, Ptr);
1029
+ auto *IntPtrDef = dyn_cast<GIntrinsic>(PtrDef);
1030
+ if (IntPtrDef &&
1031
+ IntPtrDef->getIntrinsicID () == Intrinsic::spv_resource_getpointer) {
1032
+ Register ImageReg = IntPtrDef->getOperand (2 ).getReg ();
1033
+ Register NewImageReg =
1034
+ MRI->createVirtualRegister (MRI->getRegClass (ImageReg));
1035
+ auto *ImageDef = cast<GIntrinsic>(getVRegDef (*MRI, ImageReg));
1036
+ if (!loadHandleBeforePosition (NewImageReg, GR.getSPIRVTypeForVReg (ImageReg),
1037
+ *ImageDef, I)) {
1038
+ return false ;
1039
+ }
1040
+
1041
+ Register IdxReg = IntPtrDef->getOperand (3 ).getReg ();
1042
+ return generateImageRead (ResVReg, ResType, NewImageReg, IdxReg,
1043
+ I.getDebugLoc (), I);
1044
+ }
1045
+
1021
1046
auto MIB = BuildMI (*I.getParent (), I, I.getDebugLoc (), TII.get (SPIRV::OpLoad))
1022
1047
.addDef (ResVReg)
1023
1048
.addUse (GR.getSPIRVTypeID (ResType))
@@ -1037,6 +1062,29 @@ bool SPIRVInstructionSelector::selectStore(MachineInstr &I) const {
1037
1062
unsigned OpOffset = isa<GIntrinsic>(I) ? 1 : 0 ;
1038
1063
Register StoreVal = I.getOperand (0 + OpOffset).getReg ();
1039
1064
Register Ptr = I.getOperand (1 + OpOffset).getReg ();
1065
+
1066
+ auto *PtrDef = getVRegDef (*MRI, Ptr);
1067
+ auto *IntPtrDef = dyn_cast<GIntrinsic>(PtrDef);
1068
+ if (IntPtrDef &&
1069
+ IntPtrDef->getIntrinsicID () == Intrinsic::spv_resource_getpointer) {
1070
+ Register ImageReg = IntPtrDef->getOperand (2 ).getReg ();
1071
+ Register NewImageReg =
1072
+ MRI->createVirtualRegister (MRI->getRegClass (ImageReg));
1073
+ auto *ImageDef = cast<GIntrinsic>(getVRegDef (*MRI, ImageReg));
1074
+ if (!loadHandleBeforePosition (NewImageReg, GR.getSPIRVTypeForVReg (ImageReg),
1075
+ *ImageDef, I)) {
1076
+ return false ;
1077
+ }
1078
+
1079
+ Register IdxReg = IntPtrDef->getOperand (3 ).getReg ();
1080
+ return BuildMI (*I.getParent (), I, I.getDebugLoc (),
1081
+ TII.get (SPIRV::OpImageWrite))
1082
+ .addUse (NewImageReg)
1083
+ .addUse (IdxReg)
1084
+ .addUse (StoreVal)
1085
+ .constrainAllUses (TII, TRI, RBI);
1086
+ }
1087
+
1040
1088
MachineBasicBlock &BB = *I.getParent ();
1041
1089
auto MIB = BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpStore))
1042
1090
.addUse (Ptr)
@@ -3007,6 +3055,9 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
3007
3055
case Intrinsic::spv_resource_load_typedbuffer: {
3008
3056
return selectReadImageIntrinsic (ResVReg, ResType, I);
3009
3057
}
3058
+ case Intrinsic::spv_resource_getpointer: {
3059
+ return selectResourceGetPointer (ResVReg, ResType, I);
3060
+ }
3010
3061
case Intrinsic::spv_discard: {
3011
3062
return selectDiscard (ResVReg, ResType, I);
3012
3063
}
@@ -3024,27 +3075,7 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
3024
3075
bool SPIRVInstructionSelector::selectHandleFromBinding (Register &ResVReg,
3025
3076
const SPIRVType *ResType,
3026
3077
MachineInstr &I) const {
3027
-
3028
- uint32_t Set = foldImm (I.getOperand (2 ), MRI);
3029
- uint32_t Binding = foldImm (I.getOperand (3 ), MRI);
3030
- uint32_t ArraySize = foldImm (I.getOperand (4 ), MRI);
3031
- Register IndexReg = I.getOperand (5 ).getReg ();
3032
- bool IsNonUniform = ArraySize > 1 && foldImm (I.getOperand (6 ), MRI);
3033
-
3034
- MachineIRBuilder MIRBuilder (I);
3035
- Register VarReg = buildPointerToResource (ResType, Set, Binding, ArraySize,
3036
- IndexReg, IsNonUniform, MIRBuilder);
3037
-
3038
- if (IsNonUniform)
3039
- buildOpDecorate (ResVReg, I, TII, SPIRV::Decoration::NonUniformEXT, {});
3040
-
3041
- // TODO: For now we assume the resource is an image, which needs to be
3042
- // loaded to get the handle. That will not be true for storage buffers.
3043
- return BuildMI (*I.getParent (), I, I.getDebugLoc (), TII.get (SPIRV::OpLoad))
3044
- .addDef (ResVReg)
3045
- .addUse (GR.getSPIRVTypeID (ResType))
3046
- .addUse (VarReg)
3047
- .constrainAllUses (TII, TRI, RBI);
3078
+ return true ;
3048
3079
}
3049
3080
3050
3081
bool SPIRVInstructionSelector::selectReadImageIntrinsic (
@@ -3057,42 +3088,75 @@ bool SPIRVInstructionSelector::selectReadImageIntrinsic(
3057
3088
// We will do that when we can, but for now trying to move forward with other
3058
3089
// issues.
3059
3090
Register ImageReg = I.getOperand (2 ).getReg ();
3060
- assert (MRI->getVRegDef (ImageReg)->getParent () == I.getParent () &&
3061
- " The image must be loaded in the same basic block as its use." );
3091
+ auto *ImageDef = cast<GIntrinsic>(getVRegDef (*MRI, ImageReg));
3092
+ Register NewImageReg = MRI->createVirtualRegister (MRI->getRegClass (ImageReg));
3093
+ if (!loadHandleBeforePosition (NewImageReg, GR.getSPIRVTypeForVReg (ImageReg),
3094
+ *ImageDef, I)) {
3095
+ return false ;
3096
+ }
3097
+
3098
+ Register IdxReg = I.getOperand (3 ).getReg ();
3099
+ DebugLoc Loc = I.getDebugLoc ();
3100
+ MachineInstr &Pos = I;
3062
3101
3102
+ return generateImageRead (ResVReg, ResType, NewImageReg, IdxReg, Loc, Pos);
3103
+ }
3104
+
3105
+ bool SPIRVInstructionSelector::generateImageRead (Register &ResVReg,
3106
+ const SPIRVType *ResType,
3107
+ Register ImageReg,
3108
+ Register IdxReg, DebugLoc Loc,
3109
+ MachineInstr &Pos) const {
3063
3110
uint64_t ResultSize = GR.getScalarOrVectorComponentCount (ResType);
3064
3111
if (ResultSize == 4 ) {
3065
- return BuildMI (*I.getParent (), I, I.getDebugLoc (),
3066
- TII.get (SPIRV::OpImageRead))
3112
+ return BuildMI (*Pos.getParent (), Pos, Loc, TII.get (SPIRV::OpImageRead))
3067
3113
.addDef (ResVReg)
3068
3114
.addUse (GR.getSPIRVTypeID (ResType))
3069
3115
.addUse (ImageReg)
3070
- .addUse (I. getOperand ( 3 ). getReg () )
3116
+ .addUse (IdxReg )
3071
3117
.constrainAllUses (TII, TRI, RBI);
3072
3118
}
3073
3119
3074
- SPIRVType *ReadType = widenTypeToVec4 (ResType, I );
3120
+ SPIRVType *ReadType = widenTypeToVec4 (ResType, Pos );
3075
3121
Register ReadReg = MRI->createVirtualRegister (GR.getRegClass (ReadType));
3076
3122
bool Succeed =
3077
- BuildMI (*I .getParent (), I, I. getDebugLoc () , TII.get (SPIRV::OpImageRead))
3123
+ BuildMI (*Pos .getParent (), Pos, Loc , TII.get (SPIRV::OpImageRead))
3078
3124
.addDef (ReadReg)
3079
3125
.addUse (GR.getSPIRVTypeID (ReadType))
3080
3126
.addUse (ImageReg)
3081
- .addUse (I. getOperand ( 3 ). getReg () )
3127
+ .addUse (IdxReg )
3082
3128
.constrainAllUses (TII, TRI, RBI);
3083
3129
if (!Succeed)
3084
3130
return false ;
3085
3131
3086
3132
if (ResultSize == 1 ) {
3087
- return BuildMI (*I .getParent (), I, I. getDebugLoc () ,
3133
+ return BuildMI (*Pos .getParent (), Pos, Loc ,
3088
3134
TII.get (SPIRV::OpCompositeExtract))
3089
3135
.addDef (ResVReg)
3090
3136
.addUse (GR.getSPIRVTypeID (ResType))
3091
3137
.addUse (ReadReg)
3092
3138
.addImm (0 )
3093
3139
.constrainAllUses (TII, TRI, RBI);
3094
3140
}
3095
- return extractSubvector (ResVReg, ResType, ReadReg, I);
3141
+ return extractSubvector (ResVReg, ResType, ReadReg, Pos);
3142
+ }
3143
+
3144
+ bool SPIRVInstructionSelector::selectResourceGetPointer (
3145
+ Register &ResVReg, const SPIRVType *ResType, MachineInstr &I) const {
3146
+ #ifdef ASSERT
3147
+ // For now, the operand is an image. This will change once we start handling
3148
+ // more resource types.
3149
+ Register ResourcePtr = I.getOperand (2 ).getReg ();
3150
+ SPIRVType *RegType = GR.getResultType (ResourcePtr);
3151
+ assert (RegType->getOpcode () == SPIRV::OpTypeImage &&
3152
+ " Can only handle texel buffers for now." );
3153
+ #endif
3154
+
3155
+ // For texel buffers, the index into the image is part of the OpImageRead or
3156
+ // OpImageWrite instructions. So we will do nothing in this case. This
3157
+ // intrinsic will be combined with the load or store when selecting the load
3158
+ // or store.
3159
+ return true ;
3096
3160
}
3097
3161
3098
3162
bool SPIRVInstructionSelector::extractSubvector (
@@ -3144,15 +3208,20 @@ bool SPIRVInstructionSelector::selectImageWriteIntrinsic(
3144
3208
// We will do that when we can, but for now trying to move forward with other
3145
3209
// issues.
3146
3210
Register ImageReg = I.getOperand (1 ).getReg ();
3147
- assert (MRI->getVRegDef (ImageReg)->getParent () == I.getParent () &&
3148
- " The image must be loaded in the same basic block as its use." );
3211
+ auto *ImageDef = cast<GIntrinsic>(getVRegDef (*MRI, ImageReg));
3212
+ Register NewImageReg = MRI->createVirtualRegister (MRI->getRegClass (ImageReg));
3213
+ if (!loadHandleBeforePosition (NewImageReg, GR.getSPIRVTypeForVReg (ImageReg),
3214
+ *ImageDef, I)) {
3215
+ return false ;
3216
+ }
3217
+
3149
3218
Register CoordinateReg = I.getOperand (2 ).getReg ();
3150
3219
Register DataReg = I.getOperand (3 ).getReg ();
3151
3220
assert (GR.getResultType (DataReg)->getOpcode () == SPIRV::OpTypeVector);
3152
3221
assert (GR.getScalarOrVectorComponentCount (GR.getResultType (DataReg)) == 4 );
3153
3222
return BuildMI (*I.getParent (), I, I.getDebugLoc (),
3154
3223
TII.get (SPIRV::OpImageWrite))
3155
- .addUse (ImageReg )
3224
+ .addUse (NewImageReg )
3156
3225
.addUse (CoordinateReg)
3157
3226
.addUse (DataReg)
3158
3227
.constrainAllUses (TII, TRI, RBI);
@@ -3677,6 +3746,36 @@ SPIRVType *SPIRVInstructionSelector::widenTypeToVec4(const SPIRVType *Type,
3677
3746
return GR.getOrCreateSPIRVVectorType (ScalarType, 4 , MIRBuilder);
3678
3747
}
3679
3748
3749
+ bool SPIRVInstructionSelector::loadHandleBeforePosition (
3750
+ Register &HandleReg, const SPIRVType *ResType, GIntrinsic &HandleDef,
3751
+ MachineInstr &Pos) const {
3752
+
3753
+ assert (HandleDef.getIntrinsicID () ==
3754
+ Intrinsic::spv_resource_handlefrombinding);
3755
+ uint32_t Set = foldImm (HandleDef.getOperand (2 ), MRI);
3756
+ uint32_t Binding = foldImm (HandleDef.getOperand (3 ), MRI);
3757
+ uint32_t ArraySize = foldImm (HandleDef.getOperand (4 ), MRI);
3758
+ Register IndexReg = HandleDef.getOperand (5 ).getReg ();
3759
+ bool IsNonUniform = ArraySize > 1 && foldImm (HandleDef.getOperand (6 ), MRI);
3760
+
3761
+ MachineIRBuilder MIRBuilder (HandleDef);
3762
+ Register VarReg = buildPointerToResource (ResType, Set, Binding, ArraySize,
3763
+ IndexReg, IsNonUniform, MIRBuilder);
3764
+
3765
+ if (IsNonUniform)
3766
+ buildOpDecorate (HandleReg, HandleDef, TII, SPIRV::Decoration::NonUniformEXT,
3767
+ {});
3768
+
3769
+ // TODO: For now we assume the resource is an image, which needs to be
3770
+ // loaded to get the handle. That will not be true for storage buffers.
3771
+ return BuildMI (*Pos.getParent (), Pos, HandleDef.getDebugLoc (),
3772
+ TII.get (SPIRV::OpLoad))
3773
+ .addDef (HandleReg)
3774
+ .addUse (GR.getSPIRVTypeID (ResType))
3775
+ .addUse (VarReg)
3776
+ .constrainAllUses (TII, TRI, RBI);
3777
+ }
3778
+
3680
3779
namespace llvm {
3681
3780
InstructionSelector *
3682
3781
createSPIRVInstructionSelector (const SPIRVTargetMachine &TM,
0 commit comments