IRAccess TempScopInfo::buildIRAccess(Instruction *Inst, Loop *L, Region *R, const ScopDetection::BoxedLoopsSetTy *BoxedLoops) { unsigned Size; Type *SizeType; enum IRAccess::TypeKind Type; if (LoadInst *Load = dyn_cast<LoadInst>(Inst)) { SizeType = Load->getType(); Size = TD->getTypeStoreSize(SizeType); Type = IRAccess::READ; } else { StoreInst *Store = cast<StoreInst>(Inst); SizeType = Store->getValueOperand()->getType(); Size = TD->getTypeStoreSize(SizeType); Type = IRAccess::MUST_WRITE; } const SCEV *AccessFunction = SE->getSCEVAtScope(getPointerOperand(*Inst), L); const SCEVUnknown *BasePointer = dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFunction)); assert(BasePointer && "Could not find base pointer"); AccessFunction = SE->getMinusSCEV(AccessFunction, BasePointer); auto AccItr = InsnToMemAcc.find(Inst); if (PollyDelinearize && AccItr != InsnToMemAcc.end()) return IRAccess(Type, BasePointer->getValue(), AccessFunction, Size, true, AccItr->second.DelinearizedSubscripts, AccItr->second.Shape->DelinearizedSizes); // Check if the access depends on a loop contained in a non-affine subregion. bool isVariantInNonAffineLoop = false; if (BoxedLoops) { SetVector<const Loop *> Loops; findLoops(AccessFunction, Loops); for (const Loop *L : Loops) if (BoxedLoops->count(L)) isVariantInNonAffineLoop = true; } bool IsAffine = !isVariantInNonAffineLoop && isAffineExpr(R, AccessFunction, *SE, BasePointer->getValue()); SmallVector<const SCEV *, 4> Subscripts, Sizes; Subscripts.push_back(AccessFunction); Sizes.push_back(SE->getConstant(ZeroOffset->getType(), Size)); if (!IsAffine && Type == IRAccess::MUST_WRITE) Type = IRAccess::MAY_WRITE; return IRAccess(Type, BasePointer->getValue(), AccessFunction, Size, IsAffine, Subscripts, Sizes); }
bool ScopDetection::hasAffineMemoryAccesses(DetectionContext &Context) const { Region &CurRegion = Context.CurRegion; for (const SCEVUnknown *BasePointer : Context.NonAffineAccesses) { Value *BaseValue = BasePointer->getValue(); ArrayShape *Shape = new ArrayShape(BasePointer); bool BasePtrHasNonAffine = false; // First step: collect parametric terms in all array references. SmallVector<const SCEV *, 4> Terms; for (const auto &Pair : Context.Accesses[BasePointer]) { const SCEVAddRecExpr *AccessFunction = dyn_cast<SCEVAddRecExpr>(Pair.second); if (AccessFunction) AccessFunction->collectParametricTerms(*SE, Terms); } // Second step: find array shape. SE->findArrayDimensions(Terms, Shape->DelinearizedSizes, Context.ElementSize[BasePointer]); // No array shape derived. if (Shape->DelinearizedSizes.empty()) { if (AllowNonAffine) continue; for (const auto &Pair : Context.Accesses[BasePointer]) { const Instruction *Insn = Pair.first; const SCEV *AF = Pair.second; if (!isAffineExpr(&CurRegion, AF, *SE, BaseValue)) { invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF, Insn, BaseValue); if (!KeepGoing) return false; } } continue; } // Third step: compute the access functions for each subscript. // // We first store the resulting memory accesses in TempMemoryAccesses. Only // if the access functions for all memory accesses have been successfully // delinearized we continue. Otherwise, we either report a failure or, if // non-affine accesses are allowed, we drop the information. In case the // information is dropped the memory accesses need to be overapproximated // when translated to a polyhedral representation. MapInsnToMemAcc TempMemoryAccesses; for (const auto &Pair : Context.Accesses[BasePointer]) { const Instruction *Insn = Pair.first; const SCEVAddRecExpr *AF = dyn_cast<SCEVAddRecExpr>(Pair.second); bool IsNonAffine = false; MemAcc *Acc = new MemAcc(Insn, Shape); TempMemoryAccesses.insert({Insn, Acc}); if (!AF) { if (isAffineExpr(&CurRegion, Pair.second, *SE, BaseValue)) Acc->DelinearizedSubscripts.push_back(Pair.second); else IsNonAffine = true; } else { AF->computeAccessFunctions(*SE, Acc->DelinearizedSubscripts, Shape->DelinearizedSizes); if (Acc->DelinearizedSubscripts.size() == 0) IsNonAffine = true; for (const SCEV *S : Acc->DelinearizedSubscripts) if (!isAffineExpr(&CurRegion, S, *SE, BaseValue)) IsNonAffine = true; } // (Possibly) report non affine access if (IsNonAffine) { BasePtrHasNonAffine = true; if (!AllowNonAffine) invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, Pair.second, Insn, BaseValue); if (!KeepGoing && !AllowNonAffine) return false; } } if (!BasePtrHasNonAffine) InsnToMemAcc.insert(TempMemoryAccesses.begin(), TempMemoryAccesses.end()); } return true; }