SILValue MemLocation::reduceWithValues(MemLocation &Base, SILModule *Mod, MemLocationValueMap &Values, SILInstruction *InsertPt) { // Walk bottom up the projection tree, try to reason about how to construct // a single SILValue out of all the available values for all the memory // locations. // // First, get a list of all the leaf nodes and intermediate nodes for the // Base memory location. MemLocationList ALocs; ProjectionPathList Paths; ProjectionPath::expandTypeIntoLeafProjectionPaths(Base.getType(), Mod, Paths, false); for (auto &X : Paths) { ALocs.push_back(MemLocation::createMemLocation(Base.getBase(), X.getValue(), Base.getPath().getValue())); } // Second, go from leaf nodes to their parents. This guarantees that at the // point the parent is processed, its children have been processed already. for (auto I = ALocs.rbegin(), E = ALocs.rend(); I != E; ++I) { // This is a leaf node, we have a value for it. // // Reached the end of the projection tree, this is a leaf node. MemLocationList FirstLevel; I->getFirstLevelMemLocations(FirstLevel, Mod); if (FirstLevel.empty()) continue; // If this is a class reference type, we have reached end of the type tree. if (I->getType().getClassOrBoundGenericClass()) continue; // This is NOT a leaf node, we need to construct a value for it. // // If there are more than 1 children and all the children nodes have // LoadStoreValues with the same base. we can get away by not extracting // value // for every single field. // // Simply create a new node with all the aggregated base value, i.e. // stripping off the last level projection. // bool HasIdenticalValueBase = true; auto Iter = FirstLevel.begin(); LoadStoreValue &FirstVal = Values[*Iter]; SILValue FirstBase = FirstVal.getBase(); Iter = std::next(Iter); for (auto EndIter = FirstLevel.end(); Iter != EndIter; ++Iter) { LoadStoreValue &V = Values[*Iter]; HasIdenticalValueBase &= (FirstBase == V.getBase()); } if (HasIdenticalValueBase && (FirstLevel.size() > 1 || !FirstVal.hasEmptyProjectionPath())) { Values[*I] = FirstVal.stripLastLevelProjection(); // We have a value for the parent, remove all the values for children. removeMemLocations(Values, FirstLevel); continue; } // In 2 cases do we need aggregation. // // 1. If there is only 1 child and we can not strip off any projections, // that means we need to create an aggregation. // // 2. Children have values from different bases, We need to create // extractions and aggregation in this case. // llvm::SmallVector<SILValue, 8> Vals; for (auto &X : FirstLevel) { Vals.push_back(Values[X].materialize(InsertPt)); } SILBuilder Builder(InsertPt); NullablePtr<swift::SILInstruction> AI = Projection::createAggFromFirstLevelProjections( Builder, InsertPt->getLoc(), I->getType(), Vals); // This is the Value for the current node. ProjectionPath P; Values[*I] = LoadStoreValue(SILValue(AI.get()), P); removeMemLocations(Values, FirstLevel); // Keep iterating until we have reach the top-most level of the projection // tree. // i.e. the memory location represented by the Base. } assert(Values.size() == 1 && "Should have a single location this point"); // Finally materialize and return the forwarding SILValue. return Values.begin()->second.materialize(InsertPt); }
SILValue RLEContext::computePredecessorCoveringValue(SILBasicBlock *BB, MemLocation &L) { // This is a covering value, need to go to each of the predecessors to // materialize them and create a SILArgument to merge them. // // If any of the predecessors can not forward an edge value, bail out // for now. // // *NOTE* This is a strong argument in favor of representing PHI nodes // separately from SILArguments. // // TODO: we can create a trampoline basic block if the predecessor has // a non-edgevalue terminator inst. // if (!withTransistivelyForwardableEdges(BB)) return SILValue(); // At this point, we know this MemLocation has available value and we also // know we can forward a SILValue from every predecesor. It is safe to // insert the basic block argument. BBState &Forwarder = getBBLocState(BB); SILValue TheForwardingValue = BB->createBBArg(L.getType()); // For the given MemLocation, we just created a concrete value at the // beginning of this basic block. Update the ForwardValOut for the // current basic block. // // ForwardValOut keeps all the MemLocations and their forwarding values // at the end of the basic block. If a MemLocation has a covering value // at the end of the basic block, we can now replace the covering value with // this concrete SILArgument. // // However, if the MemLocation has a concrete value, we know there must // be an instruction that generated the concrete value between the current // instruction and the end of the basic block, we do not update the // ForwardValOut in this case. // // NOTE: This is necessary to prevent an infinite loop while materializing // the covering value. // // Imagine an empty selfloop block with 1 predecessor having a load [A], to // materialize [A]'s covering value, we go to its predecessors. However, // the backedge will carry a covering value as well in this case. // MemLocationList Locs; MemLocation::expand(L, &BB->getModule(), Locs, getTypeExpansionCache()); LoadStoreValueList Vals; MemLocation::expandWithValues(L, TheForwardingValue, &BB->getModule(), Locs, Vals); ValueTableMap &VTM = Forwarder.getForwardValOut(); for (unsigned i = 0; i < Locs.size(); ++i) { unsigned bit = getMemLocationBit(Locs[i]); if (!VTM[bit].isCoveringValue()) continue; VTM[bit] = Vals[i]; } // Compute the SILArgument for the covering value. llvm::SmallVector<SILBasicBlock *, 4> Preds; for (auto Pred : BB->getPreds()) { Preds.push_back(Pred); } llvm::DenseMap<SILBasicBlock *, SILValue> Args; for (auto Pred : Preds) { BBState &Forwarder = getBBLocState(Pred); // Call computeForwardingValues with using ForwardValOut as we are // computing the MemLocation value at the end of each predecessor. Args[Pred] = Forwarder.computeForwardingValues(*this, L, Pred->getTerminator(), true); assert(Args[Pred] && "Fail to create a forwarding value"); } // Create the new SILArgument and set ForwardingValue to it. for (auto Pred : Preds) { // Update all edges. We do not create new edges in between BBs so this // information should always be correct. addNewEdgeValueToBranch(Pred->getTerminator(), BB, Args[Pred]); } return TheForwardingValue; }