Exemple #1
0
// Since we have an RValue, we know that RValue invariants imply that all
// subvalues that are addresses must be address only types. Such address only
// types if they are +1 rvalues should be independent of any values from outside
// the +1 rvalue emission (that is if someone else has a reference to the
// address only type, we should have produced a copy). This means that it is
// safe to move the value into new memory that is guaranteed to live through the
// scope being pushed. As an additional complication due to SIL enforcing stack
// ordering, we can not use a temporary stack location since any stack locations
// that are inside the scope will be cleaned up while such a scope jumping stack
// is still alive (violating stack ordering). Instead we use an alloc_box to
// store the new value. allocbox-to-stack will then reorder/expand the stack
// lifetimes to resolve the issues.
static void lifetimeExtendAddressOnlyRValueSubValues(
    SILGenFunction &SGF, SILLocation loc,
    llvm::SmallVectorImpl<SILValue> &values,
    llvm::SmallVectorImpl<SILValue> &lifetimeExtendingBoxes) {
  for (SILValue &v : values) {
    // If v is not an address, it isn't interesting, continue.
    if (!v->getType().isAddress()) {
      continue;
    }

    // Otherwise, create the box and move the address only value into the box.
    assert(v->getType().isAddressOnly(SGF.getModule()) &&
           "RValue invariants imply that all RValue subtypes that are "
           "addresses must be address only.");
    auto boxTy = SILBoxType::get(v->getType().getSwiftRValueType());
    SILValue box = SGF.B.createAllocBox(loc, boxTy);
    SILValue addr = SGF.B.createProjectBox(loc, box, 0);
    SGF.B.createCopyAddr(loc, v, addr, IsTake, IsInitialization);

    // Then save the box so we create the box destroy in the caller and
    // overwrite v with the project box since that is where the value is now.
    lifetimeExtendingBoxes.emplace_back(box);
    v = addr;
  }
}
Exemple #2
0
// TODO: This should really be an operation on type lowering.
void SILBuilder::emitShallowDestructureValueOperation(
    SILLocation Loc, SILValue V, llvm::SmallVectorImpl<SILValue> &Results) {
  // Once destructure is allowed everywhere, remove the projection code.

  // If we do not have a tuple or a struct, add to our results list and return.
  SILType Ty = V->getType();
  if (!(Ty.is<TupleType>() || Ty.getStructOrBoundGenericStruct())) {
    Results.emplace_back(V);
    return;
  }

  // Otherwise, we want to destructure add the destructure and return.
  if (getFunction().hasQualifiedOwnership()) {
    auto *DI = emitDestructureValueOperation(Loc, V);
    copy(DI->getResults(), std::back_inserter(Results));
    return;
  }

  // In non qualified ownership SIL, drop back to using projection code.
  llvm::SmallVector<Projection, 16> Projections;
  Projection::getFirstLevelProjections(V->getType(), getModule(), Projections);
  transform(Projections, std::back_inserter(Results),
            [&](const Projection &P) -> SILValue {
              return P.createObjectProjection(*this, Loc, V).get();
            });
}
/// If AI is the version of an initializer where we pass in either an apply or
/// an alloc_ref to initialize in place, validate that we are able to continue
/// optimizing and return To
static bool getDeadInstsAfterInitializerRemoved(
    ApplyInst *AI, llvm::SmallVectorImpl<SILInstruction *> &ToDestroy) {
  assert(ToDestroy.empty() && "We assume that ToDestroy is empty, so on "
                              "failure we can clear without worrying about the "
                              "caller accumulating and thus our eliminating "
                              "passed in state.");
  SILValue Arg0 = AI->getArgument(0);

  if (Arg0->getType().isExistentialType()) {
    // This is a version of the initializer which receives a pre-allocated
    // buffer as first argument. To completely eliminate the allocation, we must
    // destroy the extra allocations as well as the initializer,
    if (auto *Result = dyn_cast<ApplyInst>(Arg0)) {
      ToDestroy.emplace_back(Result);
      return true;
    }

    return false;
  }

  if (auto *ARI = dyn_cast<AllocRefInst>(Arg0)) {
    if (all_of(ARI->getUses(), [&](Operand *Op) -> bool {
          if (Op->getUser() == AI)
            return true;
          if (auto *SRI = dyn_cast<StrongReleaseInst>(Op->getUser())) {
            ToDestroy.emplace_back(SRI);
            return true;
          }
          return false;
        })) {
      return true;
    }
  }

  // We may have added elements to the array before we failed. To avoid such a
  // problem, we clear the out array here. We assert at the beginning that the
  // out array is empty, so this is safe.
  ToDestroy.clear();
  return true;
}
Exemple #4
0
// TODO: Can we put this on type lowering? It would take a little bit of work
// since we would need to be able to handle aggregate trivial types which is not
// represented today in TypeLowering.
void SILBuilder::emitShallowDestructureAddressOperation(
    SILLocation Loc, SILValue V, llvm::SmallVectorImpl<SILValue> &Results) {

  // If we do not have a tuple or a struct, add to our results list.
  SILType Ty = V->getType();
  if (!(Ty.is<TupleType>() || Ty.getStructOrBoundGenericStruct())) {
    Results.emplace_back(V);
    return;
  }

  llvm::SmallVector<Projection, 16> Projections;
  Projection::getFirstLevelProjections(V->getType(), getModule(), Projections);
  transform(Projections, std::back_inserter(Results),
            [&](const Projection &P) -> SILValue {
              return P.createAddressProjection(*this, Loc, V).get();
            });
}