@@ -301,8 +301,9 @@ class SPIRVInstructionSelector : public InstructionSelector {
301
301
302
302
bool selectReadImageIntrinsic (Register &ResVReg, const SPIRVType *ResType,
303
303
MachineInstr &I) const ;
304
-
305
304
bool selectImageWriteIntrinsic (MachineInstr &I) const ;
305
+ bool selectResourceGetPointer (Register &ResVReg, const SPIRVType *ResType,
306
+ MachineInstr &I) const ;
306
307
307
308
// Utilities
308
309
std::pair<Register, bool >
@@ -332,10 +333,15 @@ class SPIRVInstructionSelector : public InstructionSelector {
332
333
SPIRVType *widenTypeToVec4 (const SPIRVType *Type, MachineInstr &I) const ;
333
334
bool extractSubvector (Register &ResVReg, const SPIRVType *ResType,
334
335
Register &ReadReg, MachineInstr &InsertionPoint) const ;
336
+ bool generateImageRead (Register &ResVReg, const SPIRVType *ResType,
337
+ Register ImageReg, Register IdxReg, DebugLoc Loc,
338
+ MachineInstr &Pos) const ;
335
339
bool BuildCOPY (Register DestReg, Register SrcReg, MachineInstr &I) const ;
336
340
bool loadVec3BuiltinInputID (SPIRV::BuiltIn::BuiltIn BuiltInValue,
337
341
Register ResVReg, const SPIRVType *ResType,
338
342
MachineInstr &I) const ;
343
+ bool loadHandleBeforePosition (Register &HandleReg, const SPIRVType *ResType,
344
+ GIntrinsic &HandleDef, MachineInstr &Pos) const ;
339
345
};
340
346
341
347
} // end anonymous namespace
@@ -1043,6 +1049,25 @@ bool SPIRVInstructionSelector::selectLoad(Register ResVReg,
1043
1049
MachineInstr &I) const {
1044
1050
unsigned OpOffset = isa<GIntrinsic>(I) ? 1 : 0 ;
1045
1051
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
+
1046
1071
auto MIB = BuildMI (*I.getParent (), I, I.getDebugLoc (), TII.get (SPIRV::OpLoad))
1047
1072
.addDef (ResVReg)
1048
1073
.addUse (GR.getSPIRVTypeID (ResType))
@@ -1062,6 +1087,29 @@ bool SPIRVInstructionSelector::selectStore(MachineInstr &I) const {
1062
1087
unsigned OpOffset = isa<GIntrinsic>(I) ? 1 : 0 ;
1063
1088
Register StoreVal = I.getOperand (0 + OpOffset).getReg ();
1064
1089
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
+
1065
1113
MachineBasicBlock &BB = *I.getParent ();
1066
1114
auto MIB = BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpStore))
1067
1115
.addUse (Ptr)
@@ -3066,6 +3114,9 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
3066
3114
case Intrinsic::spv_resource_load_typedbuffer: {
3067
3115
return selectReadImageIntrinsic (ResVReg, ResType, I);
3068
3116
}
3117
+ case Intrinsic::spv_resource_getpointer: {
3118
+ return selectResourceGetPointer (ResVReg, ResType, I);
3119
+ }
3069
3120
case Intrinsic::spv_discard: {
3070
3121
return selectDiscard (ResVReg, ResType, I);
3071
3122
}
@@ -3083,27 +3134,7 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
3083
3134
bool SPIRVInstructionSelector::selectHandleFromBinding (Register &ResVReg,
3084
3135
const SPIRVType *ResType,
3085
3136
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 ;
3107
3138
}
3108
3139
3109
3140
bool SPIRVInstructionSelector::selectReadImageIntrinsic (
@@ -3116,42 +3147,75 @@ bool SPIRVInstructionSelector::selectReadImageIntrinsic(
3116
3147
// We will do that when we can, but for now trying to move forward with other
3117
3148
// issues.
3118
3149
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;
3121
3160
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 {
3122
3169
uint64_t ResultSize = GR.getScalarOrVectorComponentCount (ResType);
3123
3170
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))
3126
3172
.addDef (ResVReg)
3127
3173
.addUse (GR.getSPIRVTypeID (ResType))
3128
3174
.addUse (ImageReg)
3129
- .addUse (I. getOperand ( 3 ). getReg () )
3175
+ .addUse (IdxReg )
3130
3176
.constrainAllUses (TII, TRI, RBI);
3131
3177
}
3132
3178
3133
- SPIRVType *ReadType = widenTypeToVec4 (ResType, I );
3179
+ SPIRVType *ReadType = widenTypeToVec4 (ResType, Pos );
3134
3180
Register ReadReg = MRI->createVirtualRegister (GR.getRegClass (ReadType));
3135
3181
bool Succeed =
3136
- BuildMI (*I .getParent (), I, I. getDebugLoc () , TII.get (SPIRV::OpImageRead))
3182
+ BuildMI (*Pos .getParent (), Pos, Loc , TII.get (SPIRV::OpImageRead))
3137
3183
.addDef (ReadReg)
3138
3184
.addUse (GR.getSPIRVTypeID (ReadType))
3139
3185
.addUse (ImageReg)
3140
- .addUse (I. getOperand ( 3 ). getReg () )
3186
+ .addUse (IdxReg )
3141
3187
.constrainAllUses (TII, TRI, RBI);
3142
3188
if (!Succeed)
3143
3189
return false ;
3144
3190
3145
3191
if (ResultSize == 1 ) {
3146
- return BuildMI (*I .getParent (), I, I. getDebugLoc () ,
3192
+ return BuildMI (*Pos .getParent (), Pos, Loc ,
3147
3193
TII.get (SPIRV::OpCompositeExtract))
3148
3194
.addDef (ResVReg)
3149
3195
.addUse (GR.getSPIRVTypeID (ResType))
3150
3196
.addUse (ReadReg)
3151
3197
.addImm (0 )
3152
3198
.constrainAllUses (TII, TRI, RBI);
3153
3199
}
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 ;
3155
3219
}
3156
3220
3157
3221
bool SPIRVInstructionSelector::extractSubvector (
@@ -3203,15 +3267,20 @@ bool SPIRVInstructionSelector::selectImageWriteIntrinsic(
3203
3267
// We will do that when we can, but for now trying to move forward with other
3204
3268
// issues.
3205
3269
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
+
3208
3277
Register CoordinateReg = I.getOperand (2 ).getReg ();
3209
3278
Register DataReg = I.getOperand (3 ).getReg ();
3210
3279
assert (GR.getResultType (DataReg)->getOpcode () == SPIRV::OpTypeVector);
3211
3280
assert (GR.getScalarOrVectorComponentCount (GR.getResultType (DataReg)) == 4 );
3212
3281
return BuildMI (*I.getParent (), I, I.getDebugLoc (),
3213
3282
TII.get (SPIRV::OpImageWrite))
3214
- .addUse (ImageReg )
3283
+ .addUse (NewImageReg )
3215
3284
.addUse (CoordinateReg)
3216
3285
.addUse (DataReg)
3217
3286
.constrainAllUses (TII, TRI, RBI);
@@ -3878,6 +3947,36 @@ SPIRVType *SPIRVInstructionSelector::widenTypeToVec4(const SPIRVType *Type,
3878
3947
return GR.getOrCreateSPIRVVectorType (ScalarType, 4 , MIRBuilder);
3879
3948
}
3880
3949
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
+
3881
3980
namespace llvm {
3882
3981
InstructionSelector *
3883
3982
createSPIRVInstructionSelector (const SPIRVTargetMachine &TM,
0 commit comments