@@ -57,8 +57,14 @@ class SPIRVEmitIntrinsics
57
57
bool TrackConstants = true ;
58
58
DenseMap<Instruction *, Constant *> AggrConsts;
59
59
DenseSet<Instruction *> AggrStores;
60
+
61
+ // deduce values type
62
+ DenseMap<Value *, Type *> DeducedElTys;
63
+ Type *deduceElementType (Value *I);
64
+
60
65
void preprocessCompositeConstants (IRBuilder<> &B);
61
66
void preprocessUndefs (IRBuilder<> &B);
67
+
62
68
CallInst *buildIntrWithMD (Intrinsic::ID IntrID, ArrayRef<Type *> Types,
63
69
Value *Arg, Value *Arg2, ArrayRef<Constant *> Imms,
64
70
IRBuilder<> &B) {
@@ -72,6 +78,7 @@ class SPIRVEmitIntrinsics
72
78
Args.push_back (Imm);
73
79
return B.CreateIntrinsic (IntrID, {Types}, Args);
74
80
}
81
+
75
82
void replaceMemInstrUses (Instruction *Old, Instruction *New, IRBuilder<> &B);
76
83
void processInstrAfterVisit (Instruction *I, IRBuilder<> &B);
77
84
void insertAssignPtrTypeIntrs (Instruction *I, IRBuilder<> &B);
@@ -156,6 +163,48 @@ static inline void reportFatalOnTokenType(const Instruction *I) {
156
163
false );
157
164
}
158
165
166
+ // Deduce and return a successfully deduced Type of the Instruction,
167
+ // or nullptr otherwise.
168
+ static Type *deduceElementTypeHelper (Value *I,
169
+ std::unordered_set<Value *> &Visited,
170
+ DenseMap<Value *, Type *> &DeducedElTys) {
171
+ // maybe already known
172
+ auto It = DeducedElTys.find (I);
173
+ if (It != DeducedElTys.end ())
174
+ return It->second ;
175
+
176
+ // maybe a cycle
177
+ if (Visited.find (I) != Visited.end ())
178
+ return nullptr ;
179
+ Visited.insert (I);
180
+
181
+ // fallback value in case when we fail to deduce a type
182
+ Type *Ty = nullptr ;
183
+ // look for known basic patterns of type inference
184
+ if (auto *Ref = dyn_cast<AllocaInst>(I))
185
+ Ty = Ref->getAllocatedType ();
186
+ else if (auto *Ref = dyn_cast<GetElementPtrInst>(I))
187
+ Ty = Ref->getResultElementType ();
188
+ else if (auto *Ref = dyn_cast<GlobalValue>(I))
189
+ Ty = Ref->getValueType ();
190
+ else if (auto *Ref = dyn_cast<AddrSpaceCastInst>(I))
191
+ Ty = deduceElementTypeHelper (Ref->getPointerOperand (), Visited,
192
+ DeducedElTys);
193
+
194
+ // remember the found relationship
195
+ if (Ty)
196
+ DeducedElTys[I] = Ty;
197
+
198
+ return Ty;
199
+ }
200
+
201
+ Type *SPIRVEmitIntrinsics::deduceElementType (Value *I) {
202
+ std::unordered_set<Value *> Visited;
203
+ if (Type *Ty = deduceElementTypeHelper (I, Visited, DeducedElTys))
204
+ return Ty;
205
+ return IntegerType::getInt8Ty (I->getContext ());
206
+ }
207
+
159
208
void SPIRVEmitIntrinsics::replaceMemInstrUses (Instruction *Old,
160
209
Instruction *New,
161
210
IRBuilder<> &B) {
@@ -280,7 +329,7 @@ Instruction *SPIRVEmitIntrinsics::visitBitCastInst(BitCastInst &I) {
280
329
// varying element types. In case of IR coming from older versions of LLVM
281
330
// such bitcasts do not provide sufficient information, should be just skipped
282
331
// here, and handled in insertPtrCastOrAssignTypeInstr.
283
- if (I.getType ()-> isPointerTy ( )) {
332
+ if (isPointerTy ( I.getType ())) {
284
333
I.replaceAllUsesWith (Source);
285
334
I.eraseFromParent ();
286
335
return nullptr ;
@@ -333,20 +382,10 @@ void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
333
382
while (BitCastInst *BC = dyn_cast<BitCastInst>(Pointer))
334
383
Pointer = BC->getOperand (0 );
335
384
336
- // Do not emit spv_ptrcast if Pointer is a GlobalValue of expected type.
337
- GlobalValue *GV = dyn_cast<GlobalValue>(Pointer);
338
- if (GV && GV->getValueType () == ExpectedElementType)
339
- return ;
340
-
341
- // Do not emit spv_ptrcast if Pointer is a result of alloca with expected
342
- // type.
343
- AllocaInst *A = dyn_cast<AllocaInst>(Pointer);
344
- if (A && A->getAllocatedType () == ExpectedElementType)
345
- return ;
346
-
347
- // Do not emit spv_ptrcast if Pointer is a result of GEP of expected type.
348
- GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(Pointer);
349
- if (GEPI && GEPI->getResultElementType () == ExpectedElementType)
385
+ // Do not emit spv_ptrcast if Pointer's element type is ExpectedElementType
386
+ std::unordered_set<Value *> Visited;
387
+ Type *PointerElemTy = deduceElementTypeHelper (Pointer, Visited, DeducedElTys);
388
+ if (PointerElemTy == ExpectedElementType)
350
389
return ;
351
390
352
391
setInsertPointSkippingPhis (B, I);
@@ -356,7 +395,7 @@ void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
356
395
ValueAsMetadata::getConstant (ExpectedElementTypeConst);
357
396
MDTuple *TyMD = MDNode::get (F->getContext (), CM);
358
397
MetadataAsValue *VMD = MetadataAsValue::get (F->getContext (), TyMD);
359
- unsigned AddressSpace = Pointer->getType ()-> getPointerAddressSpace ( );
398
+ unsigned AddressSpace = getPointerAddressSpace ( Pointer->getType ());
360
399
bool FirstPtrCastOrAssignPtrType = true ;
361
400
362
401
// Do not emit new spv_ptrcast if equivalent one already exists or when
@@ -401,9 +440,11 @@ void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
401
440
// spv_assign_ptr_type instead.
402
441
if (FirstPtrCastOrAssignPtrType &&
403
442
(isa<Instruction>(Pointer) || isa<Argument>(Pointer))) {
404
- buildIntrWithMD (Intrinsic::spv_assign_ptr_type, {Pointer->getType ()},
405
- ExpectedElementTypeConst, Pointer,
406
- {B.getInt32 (AddressSpace)}, B);
443
+ CallInst *CI = buildIntrWithMD (
444
+ Intrinsic::spv_assign_ptr_type, {Pointer->getType ()},
445
+ ExpectedElementTypeConst, Pointer, {B.getInt32 (AddressSpace)}, B);
446
+ DeducedElTys[CI] = ExpectedElementType;
447
+ DeducedElTys[Pointer] = ExpectedElementType;
407
448
return ;
408
449
}
409
450
@@ -419,7 +460,7 @@ void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
419
460
// Handle basic instructions:
420
461
StoreInst *SI = dyn_cast<StoreInst>(I);
421
462
if (SI && F->getCallingConv () == CallingConv::SPIR_KERNEL &&
422
- SI->getValueOperand ()->getType ()-> isPointerTy ( ) &&
463
+ isPointerTy ( SI->getValueOperand ()->getType ()) &&
423
464
isa<Argument>(SI->getValueOperand ())) {
424
465
return replacePointerOperandWithPtrCast (
425
466
I, SI->getValueOperand (), IntegerType::getInt8Ty (F->getContext ()), 0 ,
@@ -440,9 +481,34 @@ void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
440
481
if (!CI || CI->isIndirectCall () || CI->getCalledFunction ()->isIntrinsic ())
441
482
return ;
442
483
484
+ // collect information about formal parameter types
485
+ Function *CalledF = CI->getCalledFunction ();
486
+ SmallVector<Type *, 4 > CalledArgTys;
487
+ bool HaveTypes = false ;
488
+ for (auto &CalledArg : CalledF->args ()) {
489
+ if (!isPointerTy (CalledArg.getType ())) {
490
+ CalledArgTys.push_back (nullptr );
491
+ continue ;
492
+ }
493
+ auto It = DeducedElTys.find (&CalledArg);
494
+ Type *ParamTy = It != DeducedElTys.end () ? It->second : nullptr ;
495
+ if (!ParamTy) {
496
+ for (User *U : CalledArg.users ()) {
497
+ if (Instruction *Inst = dyn_cast<Instruction>(U)) {
498
+ std::unordered_set<Value *> Visited;
499
+ ParamTy = deduceElementTypeHelper (Inst, Visited, DeducedElTys);
500
+ if (ParamTy)
501
+ break ;
502
+ }
503
+ }
504
+ }
505
+ HaveTypes |= ParamTy != nullptr ;
506
+ CalledArgTys.push_back (ParamTy);
507
+ }
508
+
443
509
std::string DemangledName =
444
510
getOclOrSpirvBuiltinDemangledName (CI->getCalledFunction ()->getName ());
445
- if (DemangledName.empty ())
511
+ if (DemangledName.empty () && !HaveTypes )
446
512
return ;
447
513
448
514
for (unsigned OpIdx = 0 ; OpIdx < CI->arg_size (); OpIdx++) {
@@ -455,8 +521,11 @@ void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
455
521
if (!isa<Instruction>(ArgOperand) && !isa<Argument>(ArgOperand))
456
522
continue ;
457
523
458
- Type *ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType (
459
- DemangledName, OpIdx, I->getContext ());
524
+ Type *ExpectedType =
525
+ OpIdx < CalledArgTys.size () ? CalledArgTys[OpIdx] : nullptr ;
526
+ if (!ExpectedType && !DemangledName.empty ())
527
+ ExpectedType = SPIRV::parseBuiltinCallArgumentBaseType (
528
+ DemangledName, OpIdx, I->getContext ());
460
529
if (!ExpectedType)
461
530
continue ;
462
531
@@ -639,30 +708,25 @@ void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,
639
708
void SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs (Instruction *I,
640
709
IRBuilder<> &B) {
641
710
reportFatalOnTokenType (I);
642
- if (!I->getType ()-> isPointerTy ( ) || !requireAssignType (I) ||
711
+ if (!isPointerTy ( I->getType ()) || !requireAssignType (I) ||
643
712
isa<BitCastInst>(I))
644
713
return ;
645
714
646
715
setInsertPointSkippingPhis (B, I->getNextNode ());
647
716
648
- Constant *EltTyConst;
649
- unsigned AddressSpace = I->getType ()->getPointerAddressSpace ();
650
- if (auto *AI = dyn_cast<AllocaInst>(I))
651
- EltTyConst = UndefValue::get (AI->getAllocatedType ());
652
- else if (auto *GEP = dyn_cast<GetElementPtrInst>(I))
653
- EltTyConst = UndefValue::get (GEP->getResultElementType ());
654
- else
655
- EltTyConst = UndefValue::get (IntegerType::getInt8Ty (I->getContext ()));
656
-
657
- buildIntrWithMD (Intrinsic::spv_assign_ptr_type, {I->getType ()}, EltTyConst, I,
658
- {B.getInt32 (AddressSpace)}, B);
717
+ Type *ElemTy = deduceElementType (I);
718
+ Constant *EltTyConst = UndefValue::get (ElemTy);
719
+ unsigned AddressSpace = getPointerAddressSpace (I->getType ());
720
+ CallInst *CI = buildIntrWithMD (Intrinsic::spv_assign_ptr_type, {I->getType ()},
721
+ EltTyConst, I, {B.getInt32 (AddressSpace)}, B);
722
+ DeducedElTys[CI] = ElemTy;
659
723
}
660
724
661
725
void SPIRVEmitIntrinsics::insertAssignTypeIntrs (Instruction *I,
662
726
IRBuilder<> &B) {
663
727
reportFatalOnTokenType (I);
664
728
Type *Ty = I->getType ();
665
- if (!Ty->isVoidTy () && !Ty-> isPointerTy () && requireAssignType (I)) {
729
+ if (!Ty->isVoidTy () && !isPointerTy (Ty ) && requireAssignType (I)) {
666
730
setInsertPointSkippingPhis (B, I->getNextNode ());
667
731
Type *TypeToAssign = Ty;
668
732
if (auto *II = dyn_cast<IntrinsicInst>(I)) {
0 commit comments