@@ -249,6 +249,7 @@ class SPIRVInstructionSelector : public InstructionSelector {
249
249
250
250
bool selectUnmergeValues (MachineInstr &I) const ;
251
251
252
+ // Utilities
252
253
Register buildI32Constant (uint32_t Val, MachineInstr &I,
253
254
const SPIRVType *ResType = nullptr ) const ;
254
255
@@ -260,6 +261,14 @@ class SPIRVInstructionSelector : public InstructionSelector {
260
261
261
262
bool wrapIntoSpecConstantOp (MachineInstr &I,
262
263
SmallVector<Register> &CompositeArgs) const ;
264
+
265
+ Register getUcharPtrTypeReg (MachineInstr &I,
266
+ SPIRV::StorageClass::StorageClass SC) const ;
267
+ MachineInstrBuilder buildSpecConstantOp (MachineInstr &I, Register Dest,
268
+ Register Src, Register DestType,
269
+ uint32_t Opcode) const ;
270
+ MachineInstrBuilder buildConstGenericPtr (MachineInstr &I, Register SrcPtr,
271
+ SPIRVType *SrcPtrTy) const ;
263
272
};
264
273
265
274
} // end anonymous namespace
@@ -1244,6 +1253,58 @@ static bool isUSMStorageClass(SPIRV::StorageClass::StorageClass SC) {
1244
1253
}
1245
1254
}
1246
1255
1256
+ // Returns true ResVReg is referred only from global vars and OpName's.
1257
+ static bool isASCastInGVar (MachineRegisterInfo *MRI, Register ResVReg) {
1258
+ bool IsGRef = false ;
1259
+ bool IsAllowedRefs =
1260
+ std::all_of (MRI->use_instr_begin (ResVReg), MRI->use_instr_end (),
1261
+ [&IsGRef](auto const &It) {
1262
+ unsigned Opcode = It.getOpcode ();
1263
+ if (Opcode == SPIRV::OpConstantComposite ||
1264
+ Opcode == SPIRV::OpVariable ||
1265
+ isSpvIntrinsic (It, Intrinsic::spv_init_global))
1266
+ return IsGRef = true ;
1267
+ return Opcode == SPIRV::OpName;
1268
+ });
1269
+ return IsAllowedRefs && IsGRef;
1270
+ }
1271
+
1272
+ Register SPIRVInstructionSelector::getUcharPtrTypeReg (
1273
+ MachineInstr &I, SPIRV::StorageClass::StorageClass SC) const {
1274
+ return GR.getSPIRVTypeID (GR.getOrCreateSPIRVPointerType (
1275
+ GR.getOrCreateSPIRVIntegerType (8 , I, TII), I, TII, SC));
1276
+ }
1277
+
1278
+ MachineInstrBuilder
1279
+ SPIRVInstructionSelector::buildSpecConstantOp (MachineInstr &I, Register Dest,
1280
+ Register Src, Register DestType,
1281
+ uint32_t Opcode) const {
1282
+ return BuildMI (*I.getParent (), I, I.getDebugLoc (),
1283
+ TII.get (SPIRV::OpSpecConstantOp))
1284
+ .addDef (Dest)
1285
+ .addUse (DestType)
1286
+ .addImm (Opcode)
1287
+ .addUse (Src);
1288
+ }
1289
+
1290
+ MachineInstrBuilder
1291
+ SPIRVInstructionSelector::buildConstGenericPtr (MachineInstr &I, Register SrcPtr,
1292
+ SPIRVType *SrcPtrTy) const {
1293
+ SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType (
1294
+ GR.getPointeeType (SrcPtrTy), I, TII, SPIRV::StorageClass::Generic);
1295
+ Register Tmp = MRI->createVirtualRegister (&SPIRV::pIDRegClass);
1296
+ MRI->setType (Tmp, LLT::pointer (storageClassToAddressSpace (
1297
+ SPIRV::StorageClass::Generic),
1298
+ GR.getPointerSize ()));
1299
+ MachineFunction *MF = I.getParent ()->getParent ();
1300
+ GR.assignSPIRVTypeToVReg (GenericPtrTy, Tmp, *MF);
1301
+ MachineInstrBuilder MIB = buildSpecConstantOp (
1302
+ I, Tmp, SrcPtr, GR.getSPIRVTypeID (GenericPtrTy),
1303
+ static_cast <uint32_t >(SPIRV::Opcode::PtrCastToGeneric));
1304
+ GR.add (MIB.getInstr (), MF, Tmp);
1305
+ return MIB;
1306
+ }
1307
+
1247
1308
// In SPIR-V address space casting can only happen to and from the Generic
1248
1309
// storage class. We can also only cast Workgroup, CrossWorkgroup, or Function
1249
1310
// pointers to and from Generic pointers. As such, we can convert e.g. from
@@ -1252,36 +1313,57 @@ static bool isUSMStorageClass(SPIRV::StorageClass::StorageClass SC) {
1252
1313
bool SPIRVInstructionSelector::selectAddrSpaceCast (Register ResVReg,
1253
1314
const SPIRVType *ResType,
1254
1315
MachineInstr &I) const {
1255
- // If the AddrSpaceCast user is single and in OpConstantComposite or
1256
- // OpVariable, we should select OpSpecConstantOp.
1257
- auto UIs = MRI->use_instructions (ResVReg);
1258
- if (!UIs.empty () && ++UIs.begin () == UIs.end () &&
1259
- (UIs.begin ()->getOpcode () == SPIRV::OpConstantComposite ||
1260
- UIs.begin ()->getOpcode () == SPIRV::OpVariable ||
1261
- isSpvIntrinsic (*UIs.begin (), Intrinsic::spv_init_global))) {
1262
- Register NewReg = I.getOperand (1 ).getReg ();
1263
- MachineBasicBlock &BB = *I.getParent ();
1264
- SPIRVType *SpvBaseTy = GR.getOrCreateSPIRVIntegerType (8 , I, TII);
1265
- ResType = GR.getOrCreateSPIRVPointerType (SpvBaseTy, I, TII,
1266
- SPIRV::StorageClass::Generic);
1267
- bool Result =
1268
- BuildMI (BB, I, I.getDebugLoc (), TII.get (SPIRV::OpSpecConstantOp))
1269
- .addDef (ResVReg)
1270
- .addUse (GR.getSPIRVTypeID (ResType))
1271
- .addImm (static_cast <uint32_t >(SPIRV::Opcode::PtrCastToGeneric))
1272
- .addUse (NewReg)
1273
- .constrainAllUses (TII, TRI, RBI);
1274
- return Result;
1275
- }
1316
+ MachineBasicBlock &BB = *I.getParent ();
1317
+ const DebugLoc &DL = I.getDebugLoc ();
1318
+
1276
1319
Register SrcPtr = I.getOperand (1 ).getReg ();
1277
1320
SPIRVType *SrcPtrTy = GR.getSPIRVTypeForVReg (SrcPtr);
1278
- SPIRV::StorageClass::StorageClass SrcSC = GR.getPointerStorageClass (SrcPtr);
1279
- SPIRV::StorageClass::StorageClass DstSC = GR.getPointerStorageClass (ResVReg);
1321
+
1322
+ // don't generate a cast for a null that may be represented by OpTypeInt
1323
+ if (SrcPtrTy->getOpcode () != SPIRV::OpTypePointer ||
1324
+ ResType->getOpcode () != SPIRV::OpTypePointer)
1325
+ return BuildMI (BB, I, DL, TII.get (TargetOpcode::COPY))
1326
+ .addDef (ResVReg)
1327
+ .addUse (SrcPtr)
1328
+ .constrainAllUses (TII, TRI, RBI);
1329
+
1330
+ SPIRV::StorageClass::StorageClass SrcSC = GR.getPointerStorageClass (SrcPtrTy);
1331
+ SPIRV::StorageClass::StorageClass DstSC = GR.getPointerStorageClass (ResType);
1332
+
1333
+ if (isASCastInGVar (MRI, ResVReg)) {
1334
+ // AddrSpaceCast uses within OpVariable and OpConstantComposite instructions
1335
+ // are expressed by OpSpecConstantOp with an Opcode.
1336
+ // TODO: maybe insert a check whether the Kernel capability was declared and
1337
+ // so PtrCastToGeneric/GenericCastToPtr are available.
1338
+ unsigned SpecOpcode =
1339
+ DstSC == SPIRV::StorageClass::Generic && isGenericCastablePtr (SrcSC)
1340
+ ? static_cast <uint32_t >(SPIRV::Opcode::PtrCastToGeneric)
1341
+ : (SrcSC == SPIRV::StorageClass::Generic &&
1342
+ isGenericCastablePtr (DstSC)
1343
+ ? static_cast <uint32_t >(SPIRV::Opcode::GenericCastToPtr)
1344
+ : 0 );
1345
+ // TODO: OpConstantComposite expects i8*, so we are forced to forget a
1346
+ // correct value of ResType and use general i8* instead. Maybe this should
1347
+ // be addressed in the emit-intrinsic step to infer a correct
1348
+ // OpConstantComposite type.
1349
+ if (SpecOpcode) {
1350
+ return buildSpecConstantOp (I, ResVReg, SrcPtr,
1351
+ getUcharPtrTypeReg (I, DstSC), SpecOpcode)
1352
+ .constrainAllUses (TII, TRI, RBI);
1353
+ } else if (isGenericCastablePtr (SrcSC) && isGenericCastablePtr (DstSC)) {
1354
+ MachineInstrBuilder MIB = buildConstGenericPtr (I, SrcPtr, SrcPtrTy);
1355
+ return MIB.constrainAllUses (TII, TRI, RBI) &&
1356
+ buildSpecConstantOp (
1357
+ I, ResVReg, MIB->getOperand (0 ).getReg (),
1358
+ getUcharPtrTypeReg (I, DstSC),
1359
+ static_cast <uint32_t >(SPIRV::Opcode::GenericCastToPtr))
1360
+ .constrainAllUses (TII, TRI, RBI);
1361
+ }
1362
+ }
1280
1363
1281
1364
// don't generate a cast between identical storage classes
1282
1365
if (SrcSC == DstSC)
1283
- return BuildMI (*I.getParent (), I, I.getDebugLoc (),
1284
- TII.get (TargetOpcode::COPY))
1366
+ return BuildMI (BB, I, DL, TII.get (TargetOpcode::COPY))
1285
1367
.addDef (ResVReg)
1286
1368
.addUse (SrcPtr)
1287
1369
.constrainAllUses (TII, TRI, RBI);
@@ -1297,8 +1379,6 @@ bool SPIRVInstructionSelector::selectAddrSpaceCast(Register ResVReg,
1297
1379
Register Tmp = MRI->createVirtualRegister (&SPIRV::iIDRegClass);
1298
1380
SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType (
1299
1381
GR.getPointeeType (SrcPtrTy), I, TII, SPIRV::StorageClass::Generic);
1300
- MachineBasicBlock &BB = *I.getParent ();
1301
- const DebugLoc &DL = I.getDebugLoc ();
1302
1382
bool Success = BuildMI (BB, I, DL, TII.get (SPIRV::OpPtrCastToGeneric))
1303
1383
.addDef (Tmp)
1304
1384
.addUse (GR.getSPIRVTypeID (GenericPtrTy))
0 commit comments