@@ -194,6 +194,31 @@ class SPIRVEmitIntrinsics
194
194
195
195
void useRoundingMode (ConstrainedFPIntrinsic *FPI, IRBuilder<> &B);
196
196
197
+ // Tries to walk the type accessed by the given GEP instruction.
198
+ // For each nested type access, one of the 2 callbacks is called:
199
+ // - OnStaticIndex when the index is a known constant value.
200
+ // - OnDynamnicIndexing when the index is a non-constant value.
201
+ // Return true if an error occured during the walk, false otherwise.
202
+ bool walkLogicalAccessChain (
203
+ GetElementPtrInst &GEP,
204
+ const std::function<void (Type *, uint64_t )> &OnStaticIndexing,
205
+ const std::function<void(Type *, Value *)> &OnDynamicIndexing);
206
+
207
+ // Returns the type accessed using the given GEP instruction by relying
208
+ // on the GEP type.
209
+ // FIXME: GEP types are not supposed to be used to retrieve the pointed
210
+ // type. This must be fixed.
211
+ Type *getGEPType (GetElementPtrInst *GEP);
212
+
213
+ // Returns the type accessed using the given GEP instruction by walking
214
+ // the source type using the GEP indices.
215
+ // FIXME: without help from the frontend, this method cannot reliably retrieve
216
+ // the stored type, nor can robustly determine the depth of the type
217
+ // we are accessing.
218
+ Type *getGEPTypeLogical (GetElementPtrInst *GEP);
219
+
220
+ Instruction *buildLogicalAccessChainFromGEP (GetElementPtrInst &GEP);
221
+
197
222
public:
198
223
static char ID;
199
224
SPIRVEmitIntrinsics (SPIRVTargetMachine *TM = nullptr )
@@ -246,6 +271,17 @@ bool expectIgnoredInIRTranslation(const Instruction *I) {
246
271
}
247
272
}
248
273
274
+ // Returns the source pointer from `I` ignoring intermediate ptrcast.
275
+ Value *getPointerRoot (Value *I) {
276
+ if (auto *II = dyn_cast<IntrinsicInst>(I)) {
277
+ if (II->getIntrinsicID () == Intrinsic::spv_ptrcast) {
278
+ Value *V = II->getArgOperand (0 );
279
+ return getPointerRoot (V);
280
+ }
281
+ }
282
+ return I;
283
+ }
284
+
249
285
} // namespace
250
286
251
287
char SPIRVEmitIntrinsics::ID = 0 ;
@@ -555,7 +591,97 @@ void SPIRVEmitIntrinsics::maybeAssignPtrType(Type *&Ty, Value *Op, Type *RefTy,
555
591
Ty = RefTy;
556
592
}
557
593
558
- Type *getGEPType (GetElementPtrInst *Ref) {
594
+ bool SPIRVEmitIntrinsics::walkLogicalAccessChain (
595
+ GetElementPtrInst &GEP,
596
+ const std::function<void (Type *, uint64_t )> &OnStaticIndexing,
597
+ const std::function<void(Type *, Value *)> &OnDynamicIndexing) {
598
+ auto &DL = CurrF->getDataLayout ();
599
+ Value *Src = getPointerRoot (GEP.getPointerOperand ());
600
+ Type *CurType = deduceElementType (Src, true );
601
+
602
+ for (Value *V : GEP.indices ()) {
603
+ if (ConstantInt *CI = dyn_cast<ConstantInt>(V)) {
604
+ uint64_t Offset = CI->getZExtValue ();
605
+
606
+ do {
607
+ if (ArrayType *AT = dyn_cast<ArrayType>(CurType)) {
608
+ uint32_t EltTypeSize = DL.getTypeSizeInBits (AT->getElementType ()) / 8 ;
609
+ assert (Offset < AT->getNumElements () * EltTypeSize);
610
+ uint64_t Index = Offset / EltTypeSize;
611
+ Offset = Offset - (Index * EltTypeSize);
612
+ CurType = AT->getElementType ();
613
+ OnStaticIndexing (CurType, Index);
614
+ } else if (StructType *ST = dyn_cast<StructType>(CurType)) {
615
+ uint32_t StructSize = DL.getTypeSizeInBits (ST) / 8 ;
616
+ assert (Offset < StructSize);
617
+ const auto &STL = DL.getStructLayout (ST);
618
+ unsigned Element = STL->getElementContainingOffset (Offset);
619
+ Offset -= STL->getElementOffset (Element);
620
+ CurType = ST->getElementType (Element);
621
+ OnStaticIndexing (CurType, Element);
622
+ } else {
623
+ // Vector type indexing should not use GEP.
624
+ // So if we have an index left, something is wrong. Giving up.
625
+ return true ;
626
+ }
627
+ } while (Offset > 0 );
628
+
629
+ } else if (ArrayType *AT = dyn_cast<ArrayType>(CurType)) {
630
+ // Index is not constant. Either we have an array and accept it, or we
631
+ // give up.
632
+ CurType = AT->getElementType ();
633
+ OnDynamicIndexing (CurType, V);
634
+ } else
635
+ return true ;
636
+ }
637
+
638
+ return false ;
639
+ }
640
+
641
+ Instruction *
642
+ SPIRVEmitIntrinsics::buildLogicalAccessChainFromGEP (GetElementPtrInst &GEP) {
643
+ IRBuilder<> B (GEP.getParent ());
644
+
645
+ std::vector<Value *> Indices;
646
+ Indices.push_back (ConstantInt::get (
647
+ IntegerType::getInt32Ty (CurrF->getContext ()), 0 , /* Signed= */ false ));
648
+ walkLogicalAccessChain (
649
+ GEP,
650
+ [&Indices, &B](Type *EltType, uint64_t Index) {
651
+ Indices.push_back (
652
+ ConstantInt::get (B.getInt64Ty (), Index, /* Signed= */ false ));
653
+ },
654
+ [&Indices](Type *EltType, Value *Index) { Indices.push_back (Index); });
655
+
656
+ B.SetInsertPoint (&GEP);
657
+ SmallVector<Type *, 2 > Types = {GEP.getType (), GEP.getOperand (0 )->getType ()};
658
+ SmallVector<Value *, 4 > Args;
659
+ Args.push_back (B.getInt1 (GEP.isInBounds ()));
660
+ Args.push_back (GEP.getOperand (0 ));
661
+ llvm::append_range (Args, Indices);
662
+ auto *NewI = B.CreateIntrinsic (Intrinsic::spv_gep, {Types}, {Args});
663
+ replaceAllUsesWithAndErase (B, &GEP, NewI);
664
+ return NewI;
665
+ }
666
+
667
+ Type *SPIRVEmitIntrinsics::getGEPTypeLogical (GetElementPtrInst *GEP) {
668
+
669
+ Type *CurType = GEP->getResultElementType ();
670
+
671
+ bool Interrupted = walkLogicalAccessChain (
672
+ *GEP, [&CurType](Type *EltType, uint64_t Index) { CurType = EltType; },
673
+ [&CurType](Type *EltType, Value *Index) { CurType = EltType; });
674
+
675
+ return Interrupted ? GEP->getResultElementType () : CurType;
676
+ }
677
+
678
+ Type *SPIRVEmitIntrinsics::getGEPType (GetElementPtrInst *Ref) {
679
+ if (Ref->getSourceElementType () ==
680
+ IntegerType::getInt8Ty (CurrF->getContext ()) &&
681
+ TM->getSubtargetImpl ()->isLogicalSPIRV ()) {
682
+ return getGEPTypeLogical (Ref);
683
+ }
684
+
559
685
Type *Ty = nullptr ;
560
686
// TODO: not sure if GetElementPtrInst::getTypeAtIndex() does anything
561
687
// useful here
@@ -1395,6 +1521,13 @@ Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) {
1395
1521
}
1396
1522
1397
1523
Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst (GetElementPtrInst &I) {
1524
+ if (I.getSourceElementType () == IntegerType::getInt8Ty (CurrF->getContext ()) &&
1525
+ TM->getSubtargetImpl ()->isLogicalSPIRV ()) {
1526
+ Instruction *Result = buildLogicalAccessChainFromGEP (I);
1527
+ if (Result)
1528
+ return Result;
1529
+ }
1530
+
1398
1531
IRBuilder<> B (I.getParent ());
1399
1532
B.SetInsertPoint (&I);
1400
1533
SmallVector<Type *, 2 > Types = {I.getType (), I.getOperand (0 )->getType ()};
@@ -1588,7 +1721,22 @@ void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
1588
1721
}
1589
1722
if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {
1590
1723
Value *Pointer = GEPI->getPointerOperand ();
1591
- Type *OpTy = GEPI->getSourceElementType ();
1724
+ Type *OpTy = nullptr ;
1725
+
1726
+ // Knowing the accessed type is mandatory for logical SPIR-V. Sadly,
1727
+ // the GEP source element type should not be used for this purpose, and
1728
+ // the alternative type-scavenging method is not working.
1729
+ // Physical SPIR-V can work around this, but not logical, hence still
1730
+ // try to rely on the broken type scavenging for logical.
1731
+ if (TM->getSubtargetImpl ()->isLogicalSPIRV ()) {
1732
+ Value *Src = getPointerRoot (Pointer);
1733
+ OpTy = GR->findDeducedElementType (Src);
1734
+ }
1735
+
1736
+ // In all cases, fall back to the GEP type if type scavenging failed.
1737
+ if (!OpTy)
1738
+ OpTy = GEPI->getSourceElementType ();
1739
+
1592
1740
replacePointerOperandWithPtrCast (I, Pointer, OpTy, 0 , B);
1593
1741
if (isNestedPointer (OpTy))
1594
1742
insertTodoType (Pointer);
0 commit comments