@@ -74,6 +74,7 @@ class SPIRVEmitIntrinsics
74
74
void processInstrAfterVisit (Instruction *I);
75
75
void insertAssignPtrTypeIntrs (Instruction *I);
76
76
void insertAssignTypeIntrs (Instruction *I);
77
+ void insertPtrCastInstr (Instruction *I);
77
78
void processGlobalValue (GlobalVariable &GV);
78
79
79
80
public:
@@ -255,7 +256,19 @@ Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) {
255
256
}
256
257
257
258
Instruction *SPIRVEmitIntrinsics::visitBitCastInst (BitCastInst &I) {
258
- SmallVector<Type *, 2 > Types = {I.getType (), I.getOperand (0 )->getType ()};
259
+ Value *Source = I.getOperand (0 );
260
+
261
+ // SPIR-V, contrary to LLVM 17+ IR, supports bitcasts between pointers of
262
+ // varying element types. In case of IR coming from older versions of LLVM
263
+ // such bitcasts do not provide sufficient information, should be just skipped
264
+ // here, and handled in insertPtrCastInstr.
265
+ if (I.getType ()->isPointerTy ()) {
266
+ I.replaceAllUsesWith (Source);
267
+ I.eraseFromParent ();
268
+ return nullptr ;
269
+ }
270
+
271
+ SmallVector<Type *, 2 > Types = {I.getType (), Source->getType ()};
259
272
SmallVector<Value *> Args (I.op_begin (), I.op_end ());
260
273
auto *NewI = IRB->CreateIntrinsic (Intrinsic::spv_bitcast, {Types}, {Args});
261
274
std::string InstName = I.hasName () ? I.getName ().str () : " " ;
@@ -265,6 +278,111 @@ Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) {
265
278
return NewI;
266
279
}
267
280
281
+ void SPIRVEmitIntrinsics::insertPtrCastInstr (Instruction *I) {
282
+ Value *Pointer;
283
+ Type *ExpectedElementType;
284
+ unsigned OperandToReplace;
285
+ if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
286
+ Pointer = SI->getPointerOperand ();
287
+ ExpectedElementType = SI->getValueOperand ()->getType ();
288
+ OperandToReplace = 1 ;
289
+ } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
290
+ Pointer = LI->getPointerOperand ();
291
+ ExpectedElementType = LI->getType ();
292
+ OperandToReplace = 0 ;
293
+ } else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {
294
+ Pointer = GEPI->getPointerOperand ();
295
+ ExpectedElementType = GEPI->getSourceElementType ();
296
+ OperandToReplace = 0 ;
297
+ } else {
298
+ return ;
299
+ }
300
+
301
+ // If Pointer is the result of nop BitCastInst (ptr -> ptr), use the source
302
+ // pointer instead. The BitCastInst should be later removed when visited.
303
+ while (BitCastInst *BC = dyn_cast<BitCastInst>(Pointer))
304
+ Pointer = BC->getOperand (0 );
305
+
306
+ // Do not emit spv_ptrcast if Pointer is a GlobalValue of expected type.
307
+ GlobalValue *GV = dyn_cast<GlobalValue>(Pointer);
308
+ if (GV && GV->getValueType () == ExpectedElementType)
309
+ return ;
310
+
311
+ // Do not emit spv_ptrcast if Pointer is a result of alloca with expected
312
+ // type.
313
+ AllocaInst *A = dyn_cast<AllocaInst>(Pointer);
314
+ if (A && A->getAllocatedType () == ExpectedElementType)
315
+ return ;
316
+
317
+ if (dyn_cast<GetElementPtrInst>(Pointer))
318
+ return ;
319
+
320
+ setInsertPointSkippingPhis (*IRB, I);
321
+ Constant *ExpectedElementTypeConst =
322
+ Constant::getNullValue (ExpectedElementType);
323
+ ConstantAsMetadata *CM =
324
+ ValueAsMetadata::getConstant (ExpectedElementTypeConst);
325
+ MDTuple *TyMD = MDNode::get (F->getContext (), CM);
326
+ MetadataAsValue *VMD = MetadataAsValue::get (F->getContext (), TyMD);
327
+ unsigned AddressSpace = Pointer->getType ()->getPointerAddressSpace ();
328
+ bool FirstPtrCastOrAssignPtrType = true ;
329
+
330
+ // Do not emit new spv_ptrcast if equivalent one already exists or when
331
+ // spv_assign_ptr_type already targets this pointer with the same element
332
+ // type.
333
+ for (auto User : Pointer->users ()) {
334
+ auto *II = dyn_cast<IntrinsicInst>(User);
335
+ if (!II ||
336
+ (II->getIntrinsicID () != Intrinsic::spv_assign_ptr_type &&
337
+ II->getIntrinsicID () != Intrinsic::spv_ptrcast) ||
338
+ II->getOperand (0 ) != Pointer)
339
+ continue ;
340
+
341
+ // There is some spv_ptrcast/spv_assign_ptr_type already targeting this
342
+ // pointer.
343
+ FirstPtrCastOrAssignPtrType = false ;
344
+ if (II->getOperand (1 ) != VMD ||
345
+ dyn_cast<ConstantInt>(II->getOperand (2 ))->getSExtValue () !=
346
+ AddressSpace)
347
+ continue ;
348
+
349
+ // The spv_ptrcast/spv_assign_ptr_type targeting this pointer is of the same
350
+ // element type and address space.
351
+ if (II->getIntrinsicID () != Intrinsic::spv_ptrcast)
352
+ return ;
353
+
354
+ // This must be a spv_ptrcast, do not emit new if this one has the same BB
355
+ // as I. Otherwise, search for other spv_ptrcast/spv_assign_ptr_type.
356
+ if (II->getParent () != I->getParent ())
357
+ continue ;
358
+
359
+ I->setOperand (OperandToReplace, II);
360
+ return ;
361
+ }
362
+
363
+ // Do not emit spv_ptrcast if it would cast to the default pointer element
364
+ // type (i8) of the same address space.
365
+ if (ExpectedElementType->isIntegerTy (8 ))
366
+ return ;
367
+
368
+ // If this would be the first spv_ptrcast and there is no spv_assign_ptr_type
369
+ // for this pointer before, do not emit spv_ptrcast but emit
370
+ // spv_assign_ptr_type instead.
371
+ if (FirstPtrCastOrAssignPtrType && isa<Instruction>(Pointer)) {
372
+ buildIntrWithMD (Intrinsic::spv_assign_ptr_type, {Pointer->getType ()},
373
+ ExpectedElementTypeConst, Pointer,
374
+ {IRB->getInt32 (AddressSpace)});
375
+ return ;
376
+ } else {
377
+ SmallVector<Type *, 2 > Types = {Pointer->getType (), Pointer->getType ()};
378
+ SmallVector<Value *, 2 > Args = {Pointer, VMD, IRB->getInt32 (AddressSpace)};
379
+ auto *PtrCastI =
380
+ IRB->CreateIntrinsic (Intrinsic::spv_ptrcast, {Types}, Args);
381
+ I->setOperand (OperandToReplace, PtrCastI);
382
+ return ;
383
+ }
384
+ }
385
+
268
386
Instruction *SPIRVEmitIntrinsics::visitInsertElementInst (InsertElementInst &I) {
269
387
SmallVector<Type *, 4 > Types = {I.getType (), I.getOperand (0 )->getType (),
270
388
I.getOperand (1 )->getType (),
@@ -522,13 +640,18 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
522
640
for (auto &I : Worklist) {
523
641
insertAssignPtrTypeIntrs (I);
524
642
insertAssignTypeIntrs (I);
643
+ insertPtrCastInstr (I);
525
644
}
526
645
527
646
for (auto *I : Worklist) {
528
647
TrackConstants = true ;
529
648
if (!I->getType ()->isVoidTy () || isa<StoreInst>(I))
530
649
IRB->SetInsertPoint (I->getNextNode ());
650
+ // Visitors return either the original/newly created instruction for further
651
+ // processing, nullptr otherwise.
531
652
I = visit (*I);
653
+ if (!I)
654
+ continue ;
532
655
processInstrAfterVisit (I);
533
656
}
534
657
return true ;
0 commit comments