Example #1
0
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;
}