// Get the aggregate member based on the top of the projection stack. static SILValue getMember(SILInstruction *inst, ProjectionPath &projStack) { if (!projStack.empty()) { const Projection &proj = projStack.back(); return proj.getOperandForAggregate(inst); } return SILValue(); }
MemLocation MemLocation::createMemLocation(SILValue Base, ProjectionPath &P1, ProjectionPath &P2) { ProjectionPath T; T.append(P1); T.append(P2); return MemLocation(Base, T); }
Optional<ProjectionPath> ProjectionPath::subtractPaths(const ProjectionPath &LHS, const ProjectionPath &RHS) { // If RHS is greater than or equal to LHS in size, RHS can not be a prefix of // LHS. Return None. unsigned RHSSize = RHS.size(); unsigned LHSSize = LHS.size(); if (RHSSize >= LHSSize) return llvm::NoneType::None; // First make sure that the prefix matches. Optional<ProjectionPath> P = ProjectionPath(); for (unsigned i = 0; i < RHSSize; i++) { if (LHS.Path[i] != RHS.Path[i]) { P.reset(); return P; } } // Add the rest of LHS to P and return P. for (unsigned i = RHSSize, e = LHSSize; i != e; ++i) { P->Path.push_back(LHS.Path[i]); } return P; }
void LSLocation::getFirstLevelLSLocations(LSLocationList &Locs, SILModule *Mod) { SILType Ty = getType(); llvm::SmallVector<Projection, 8> Out; Projection::getFirstLevelAddrProjections(Ty, *Mod, Out); for (auto &X : Out) { ProjectionPath P; P.append(X); P.append(Path.getValue()); Locs.push_back(LSLocation(Base, P)); } }
/// TODO: Integrate has empty non-symmetric difference into here. SubSeqRelation_t ProjectionPath:: computeSubSeqRelation(const ProjectionPath &RHS) const { // If either path is empty, we can not prove anything, return Unrelated. if (empty() || RHS.empty()) return SubSeqRelation_t::Unrelated; // We reverse the projection path to scan from the common object. auto LHSReverseIter = rbegin(); auto RHSReverseIter = RHS.rbegin(); unsigned MinPathSize = std::min(size(), RHS.size()); // For each index i until min path size... for (unsigned i = 0; i != MinPathSize; ++i) { // Grab the current projections. const Projection &LHSProj = *LHSReverseIter; const Projection &RHSProj = *RHSReverseIter; // If the two projections do not equal exactly, return Unrelated. // // TODO: If Index equals zero, then we know that the two lists have nothing // in common and should return unrelated. If Index is greater than zero, // then we know that the two projection paths have a common base but a // non-empty symmetric difference. For now we just return Unrelated since I // can not remember why I had the special check in the // hasNonEmptySymmetricDifference code. if (LHSProj != RHSProj) return SubSeqRelation_t::Unrelated; // Otherwise increment reverse iterators. LHSReverseIter++; RHSReverseIter++; } // Ok, we now know that one of the paths is a subsequence of the other. If // both size() and RHS.size() equal then we know that the entire sequences // equal. if (size() == RHS.size()) return SubSeqRelation_t::Equal; // If MinPathSize == size(), then we know that LHS is a strict subsequence of // RHS. if (MinPathSize == size()) return SubSeqRelation_t::LHSStrictSubSeqOfRHS; // Otherwise, we know that MinPathSize must be RHS.size() and RHS must be a // strict subsequence of LHS. Assert to check this and return. assert(MinPathSize == RHS.size() && "Since LHS and RHS don't equal and size() != MinPathSize, RHS.size() " "must equal MinPathSize"); return SubSeqRelation_t::RHSStrictSubSeqOfLHS; }
Optional<ProjectionPath> ProjectionPath::getAddrProjectionPath(SILValue Start, SILValue End, bool IgnoreCasts) { // Do not inspect the body of structs with unreferenced types such as // bitfields and unions. if (Start.getType().aggregateHasUnreferenceableStorage() || End.getType().aggregateHasUnreferenceableStorage()) { return llvm::NoneType::None; } ProjectionPath P; // If Start == End, there is a "trivial" address projection in between the // two. This is represented by returning an empty ProjectionPath. if (Start == End) return std::move(P); // Otherwise see if End can be projection extracted from Start. First see if // End is a projection at all. auto Iter = End; if (IgnoreCasts) Iter = Iter.stripCasts(); bool NextAddrIsIndex = false; while (Projection::isAddrProjection(Iter) && Start != Iter) { Projection AP = *Projection::addressProjectionForValue(Iter); P.Path.push_back(AP); NextAddrIsIndex = (AP.getKind() == ProjectionKind::Index); Iter = cast<SILInstruction>(*Iter).getOperand(0); if (IgnoreCasts) Iter = Iter.stripCasts(); } // Return None if we have an empty projection list or if Start == Iter. // If the next project is index_addr, then Start and End actually point to // disjoint locations (the value at Start has an implicit index_addr #0). if (P.empty() || Start != Iter || NextAddrIsIndex) return llvm::NoneType::None; // Otherwise, return P. return std::move(P); }
/// Returns true if the two paths have a non-empty symmetric difference. /// /// This means that the two objects have the same base but access different /// fields of the base object. bool ProjectionPath:: hasNonEmptySymmetricDifference(const ProjectionPath &RHS) const { // If either the LHS or RHS is empty, there is no common base class. Return // false. if (empty() || RHS.empty()) return false; // We reverse the projection path to scan from the common object. auto LHSReverseIter = Path.rbegin(); auto RHSReverseIter = RHS.Path.rbegin(); // For each index i until min path size... for (unsigned i = 0, e = std::min(size(), RHS.size()); i != e; ++i) { // Grab the current projections. const Projection &LHSProj = *LHSReverseIter; const Projection &RHSProj = *RHSReverseIter; // If we are accessing different fields of a common object, return // true. The two projection paths must have a non-empty symmetric // difference. if (areProjectionsToDifferentFields(LHSProj, RHSProj)) { DEBUG(llvm::dbgs() << " Path different at index: " << i << '\n'); return true; } // Otherwise, if the two projections equal exactly, they have no symmetric // difference. if (LHSProj == RHSProj) return false; // Continue if we are accessing the same field. LHSReverseIter++; RHSReverseIter++; } // We checked return false; }
SILValue ConstantTracker::getStoredValue(SILInstruction *loadInst, ProjectionPath &projStack) { SILInstruction *store = links[loadInst]; if (!store && callerTracker) store = callerTracker->links[loadInst]; if (!store) return SILValue(); assert(isa<LoadInst>(loadInst) || isa<CopyAddrInst>(loadInst)); // Push the address projections of the load onto the stack. SmallVector<Projection, 4> loadProjections; scanProjections(loadInst->getOperand(0), &loadProjections); for (const Projection &proj : loadProjections) { projStack.push_back(proj); } // Pop the address projections of the store from the stack. SmallVector<Projection, 4> storeProjections; scanProjections(store->getOperand(1), &storeProjections); for (auto iter = storeProjections.rbegin(); iter != storeProjections.rend(); ++iter) { const Projection &proj = *iter; // The corresponding load-projection must match the store-projection. if (projStack.empty() || projStack.back() != proj) return SILValue(); projStack.pop_back(); } if (isa<StoreInst>(store)) return store->getOperand(0); // The copy_addr instruction is both a load and a store. So we follow the link // again. assert(isa<CopyAddrInst>(store)); return getStoredValue(store, projStack); }
void ProjectionPath::expandTypeIntoLeafProjectionPaths(SILType B, SILModule *Mod, ProjectionPathList &Paths, bool OnlyLeafNode) { // Perform a BFS to expand the given type into projectionpath each of // which contains 1 field from the type. ProjectionPathList Worklist; llvm::SmallVector<Projection, 8> Projections; // Push an empty projection path to get started. SILType Ty; ProjectionPath P; Worklist.push_back(std::move(P)); do { // Get the next level projections based on current projection's type. Optional<ProjectionPath> PP = Worklist.pop_back_val(); // Get the current type to process, the very first projection path will be // empty. Ty = PP.getValue().empty() ? B : PP.getValue().front().getType(); // Get the first level projection of the current type. Projections.clear(); Projection::getFirstLevelAddrProjections(Ty, *Mod, Projections); // Reached the end of the projection tree, this field can not be expanded // anymore. if (Projections.empty()) { Paths.push_back(std::move(PP.getValue())); continue; } // If this is a class type, we also have reached the end of the type // tree for this type. // // We do not push its next level projection into the worklist, // if we do that, we could run into an infinite loop, e.g. // // class SelfLoop { // var p : SelfLoop // } // // struct XYZ { // var x : Int // var y : SelfLoop // } // // The worklist would never be empty in this case !. // if (Ty.getClassOrBoundGenericClass()) { Paths.push_back(std::move(PP.getValue())); continue; } // This is NOT a leaf node, keep the intermediate nodes as well. if (!OnlyLeafNode) Paths.push_back(std::move(PP.getValue())); // Keep expanding the location. for (auto &P : Projections) { ProjectionPath X; X.append(P); X.append(PP.getValue()); Worklist.push_back(std::move(X)); } // Keep iterating if the worklist is not empty. } while (!Worklist.empty()); }