@@ -194,6 +194,42 @@ 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+ // - OnLiteralIndexing when the index is a known constant value.
200+ // Parameters:
201+ // PointedType: the pointed type resulting of this indexing.
202+ // If the parent type is an array, this is the index in the array.
203+ // If the parent type is a struct, this is the field index.
204+ // Index: index of the element in the parent type.
205+ // - OnDynamnicIndexing when the index is a non-constant value.
206+ // This callback is only called when indexing into an array.
207+ // Parameters:
208+ // ElementType: the type of the elements stored in the parent array.
209+ // Offset: the Value* containing the byte offset into the array.
210+ // Return true if an error occured during the walk, false otherwise.
211+ bool walkLogicalAccessChain (
212+ GetElementPtrInst &GEP,
213+ const std::function<void (Type *PointedType, uint64_t Index)>
214+ &OnLiteralIndexing,
215+ const std::function<void(Type *ElementType, Value *Offset)>
216+ &OnDynamicIndexing);
217+
218+ // Returns the type accessed using the given GEP instruction by relying
219+ // on the GEP type.
220+ // FIXME: GEP types are not supposed to be used to retrieve the pointed
221+ // type. This must be fixed.
222+ Type *getGEPType (GetElementPtrInst *GEP);
223+
224+ // Returns the type accessed using the given GEP instruction by walking
225+ // the source type using the GEP indices.
226+ // FIXME: without help from the frontend, this method cannot reliably retrieve
227+ // the stored type, nor can robustly determine the depth of the type
228+ // we are accessing.
229+ Type *getGEPTypeLogical (GetElementPtrInst *GEP);
230+
231+ Instruction *buildLogicalAccessChainFromGEP (GetElementPtrInst &GEP);
232+
197233public:
198234 static char ID;
199235 SPIRVEmitIntrinsics (SPIRVTargetMachine *TM = nullptr )
@@ -246,6 +282,17 @@ bool expectIgnoredInIRTranslation(const Instruction *I) {
246282 }
247283}
248284
285+ // Returns the source pointer from `I` ignoring intermediate ptrcast.
286+ Value *getPointerRoot (Value *I) {
287+ if (auto *II = dyn_cast<IntrinsicInst>(I)) {
288+ if (II->getIntrinsicID () == Intrinsic::spv_ptrcast) {
289+ Value *V = II->getArgOperand (0 );
290+ return getPointerRoot (V);
291+ }
292+ }
293+ return I;
294+ }
295+
249296} // namespace
250297
251298char SPIRVEmitIntrinsics::ID = 0 ;
@@ -555,7 +602,111 @@ void SPIRVEmitIntrinsics::maybeAssignPtrType(Type *&Ty, Value *Op, Type *RefTy,
555602 Ty = RefTy;
556603}
557604
558- Type *getGEPType (GetElementPtrInst *Ref) {
605+ bool SPIRVEmitIntrinsics::walkLogicalAccessChain (
606+ GetElementPtrInst &GEP,
607+ const std::function<void (Type *, uint64_t )> &OnLiteralIndexing,
608+ const std::function<void(Type *, Value *)> &OnDynamicIndexing) {
609+ // We only rewrite i8* GEP. Other should be left as-is.
610+ // Valid i8* GEP must always have a single index.
611+ assert (GEP.getSourceElementType () ==
612+ IntegerType::getInt8Ty (CurrF->getContext ()));
613+ assert (GEP.getNumIndices () == 1 );
614+
615+ auto &DL = CurrF->getDataLayout ();
616+ Value *Src = getPointerRoot (GEP.getPointerOperand ());
617+ Type *CurType = deduceElementType (Src, true );
618+
619+ Value *Operand = *GEP.idx_begin ();
620+ ConstantInt *CI = dyn_cast<ConstantInt>(Operand);
621+ if (!CI) {
622+ ArrayType *AT = dyn_cast<ArrayType>(CurType);
623+ // Operand is not constant. Either we have an array and accept it, or we
624+ // give up.
625+ if (AT)
626+ OnDynamicIndexing (AT->getElementType (), Operand);
627+ return AT == nullptr ;
628+ }
629+
630+ assert (CI);
631+ uint64_t Offset = CI->getZExtValue ();
632+
633+ do {
634+ if (ArrayType *AT = dyn_cast<ArrayType>(CurType)) {
635+ uint32_t EltTypeSize = DL.getTypeSizeInBits (AT->getElementType ()) / 8 ;
636+ assert (Offset < AT->getNumElements () * EltTypeSize);
637+ uint64_t Index = Offset / EltTypeSize;
638+ Offset = Offset - (Index * EltTypeSize);
639+ CurType = AT->getElementType ();
640+ OnLiteralIndexing (CurType, Index);
641+ } else if (StructType *ST = dyn_cast<StructType>(CurType)) {
642+ uint32_t StructSize = DL.getTypeSizeInBits (ST) / 8 ;
643+ assert (Offset < StructSize);
644+ const auto &STL = DL.getStructLayout (ST);
645+ unsigned Element = STL->getElementContainingOffset (Offset);
646+ Offset -= STL->getElementOffset (Element);
647+ CurType = ST->getElementType (Element);
648+ OnLiteralIndexing (CurType, Element);
649+ } else {
650+ // Vector type indexing should not use GEP.
651+ // So if we have an index left, something is wrong. Giving up.
652+ return true ;
653+ }
654+ } while (Offset > 0 );
655+
656+ return false ;
657+ }
658+
659+ Instruction *
660+ SPIRVEmitIntrinsics::buildLogicalAccessChainFromGEP (GetElementPtrInst &GEP) {
661+ auto &DL = CurrF->getDataLayout ();
662+ IRBuilder<> B (GEP.getParent ());
663+ B.SetInsertPoint (&GEP);
664+
665+ std::vector<Value *> Indices;
666+ Indices.push_back (ConstantInt::get (
667+ IntegerType::getInt32Ty (CurrF->getContext ()), 0 , /* Signed= */ false ));
668+ walkLogicalAccessChain (
669+ GEP,
670+ [&Indices, &B](Type *EltType, uint64_t Index) {
671+ Indices.push_back (
672+ ConstantInt::get (B.getInt64Ty (), Index, /* Signed= */ false ));
673+ },
674+ [&Indices, &B, &DL](Type *EltType, Value *Offset) {
675+ uint32_t EltTypeSize = DL.getTypeSizeInBits (EltType) / 8 ;
676+ Value *Index = B.CreateUDiv (
677+ Offset, ConstantInt::get (Offset->getType (), EltTypeSize,
678+ /* Signed= */ false ));
679+ Indices.push_back (Index);
680+ });
681+
682+ SmallVector<Type *, 2 > Types = {GEP.getType (), GEP.getOperand (0 )->getType ()};
683+ SmallVector<Value *, 4 > Args;
684+ Args.push_back (B.getInt1 (GEP.isInBounds ()));
685+ Args.push_back (GEP.getOperand (0 ));
686+ llvm::append_range (Args, Indices);
687+ auto *NewI = B.CreateIntrinsic (Intrinsic::spv_gep, {Types}, {Args});
688+ replaceAllUsesWithAndErase (B, &GEP, NewI);
689+ return NewI;
690+ }
691+
692+ Type *SPIRVEmitIntrinsics::getGEPTypeLogical (GetElementPtrInst *GEP) {
693+
694+ Type *CurType = GEP->getResultElementType ();
695+
696+ bool Interrupted = walkLogicalAccessChain (
697+ *GEP, [&CurType](Type *EltType, uint64_t Index) { CurType = EltType; },
698+ [&CurType](Type *EltType, Value *Index) { CurType = EltType; });
699+
700+ return Interrupted ? GEP->getResultElementType () : CurType;
701+ }
702+
703+ Type *SPIRVEmitIntrinsics::getGEPType (GetElementPtrInst *Ref) {
704+ if (Ref->getSourceElementType () ==
705+ IntegerType::getInt8Ty (CurrF->getContext ()) &&
706+ TM->getSubtargetImpl ()->isLogicalSPIRV ()) {
707+ return getGEPTypeLogical (Ref);
708+ }
709+
559710 Type *Ty = nullptr ;
560711 // TODO: not sure if GetElementPtrInst::getTypeAtIndex() does anything
561712 // useful here
@@ -1395,6 +1546,13 @@ Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) {
13951546}
13961547
13971548Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst (GetElementPtrInst &I) {
1549+ if (I.getSourceElementType () == IntegerType::getInt8Ty (CurrF->getContext ()) &&
1550+ TM->getSubtargetImpl ()->isLogicalSPIRV ()) {
1551+ Instruction *Result = buildLogicalAccessChainFromGEP (I);
1552+ if (Result)
1553+ return Result;
1554+ }
1555+
13981556 IRBuilder<> B (I.getParent ());
13991557 B.SetInsertPoint (&I);
14001558 SmallVector<Type *, 2 > Types = {I.getType (), I.getOperand (0 )->getType ()};
@@ -1588,7 +1746,24 @@ void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
15881746 }
15891747 if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {
15901748 Value *Pointer = GEPI->getPointerOperand ();
1591- Type *OpTy = GEPI->getSourceElementType ();
1749+ Type *OpTy = nullptr ;
1750+
1751+ // Knowing the accessed type is mandatory for logical SPIR-V. Sadly,
1752+ // the GEP source element type should not be used for this purpose, and
1753+ // the alternative type-scavenging method is not working.
1754+ // Physical SPIR-V can work around this, but not logical, hence still
1755+ // try to rely on the broken type scavenging for logical.
1756+ bool IsRewrittenGEP =
1757+ GEPI->getSourceElementType () == IntegerType::getInt8Ty (I->getContext ());
1758+ if (IsRewrittenGEP && TM->getSubtargetImpl ()->isLogicalSPIRV ()) {
1759+ Value *Src = getPointerRoot (Pointer);
1760+ OpTy = GR->findDeducedElementType (Src);
1761+ }
1762+
1763+ // In all cases, fall back to the GEP type if type scavenging failed.
1764+ if (!OpTy)
1765+ OpTy = GEPI->getSourceElementType ();
1766+
15921767 replacePointerOperandWithPtrCast (I, Pointer, OpTy, 0 , B);
15931768 if (isNestedPointer (OpTy))
15941769 insertTodoType (Pointer);
0 commit comments