// 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(); }
/// 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); }