@@ -194,6 +194,31 @@ class SPIRVEmitIntrinsics
194194
195195 void useRoundingMode (ConstrainedFPIntrinsic *FPI, IRBuilder<> &B);
196196
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+
197222public:
198223 static char ID;
199224 SPIRVEmitIntrinsics (SPIRVTargetMachine *TM = nullptr )
@@ -246,6 +271,17 @@ bool expectIgnoredInIRTranslation(const Instruction *I) {
246271 }
247272}
248273
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+
249285} // namespace
250286
251287char SPIRVEmitIntrinsics::ID = 0 ;
@@ -555,7 +591,97 @@ void SPIRVEmitIntrinsics::maybeAssignPtrType(Type *&Ty, Value *Op, Type *RefTy,
555591 Ty = RefTy;
556592}
557593
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+
559685 Type *Ty = nullptr ;
560686 // TODO: not sure if GetElementPtrInst::getTypeAtIndex() does anything
561687 // useful here
@@ -1395,6 +1521,13 @@ Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) {
13951521}
13961522
13971523Instruction *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+
13981531 IRBuilder<> B (I.getParent ());
13991532 B.SetInsertPoint (&I);
14001533 SmallVector<Type *, 2 > Types = {I.getType (), I.getOperand (0 )->getType ()};
@@ -1588,7 +1721,22 @@ void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
15881721 }
15891722 if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {
15901723 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+
15921740 replacePointerOperandWithPtrCast (I, Pointer, OpTy, 0 , B);
15931741 if (isNestedPointer (OpTy))
15941742 insertTodoType (Pointer);
0 commit comments