Beispiel #1
0
ManagedValue ArgumentSource::getAsSingleValue(SILGenFunction &SGF,
                                              SGFContext C) && {
  switch (StoredKind) {
  case Kind::Invalid:
    llvm_unreachable("argument source is invalid");
  case Kind::LValue: {
    auto loc = getKnownLValueLocation();
    LValue &&lv = std::move(*this).asKnownLValue();
    return SGF.emitAddressOfLValue(loc, std::move(lv));
  }
  case Kind::RValue: {
    auto loc = getKnownRValueLocation();
    if (auto init = C.getEmitInto()) {
      std::move(*this).asKnownRValue(SGF)
                      .ensurePlusOne(SGF, loc)
                      .forwardInto(SGF, loc, init);
      return ManagedValue::forInContext();
    } else {
      return std::move(*this).asKnownRValue(SGF).getAsSingleValue(SGF, loc);
    }
  }
  case Kind::Expr: {
    auto e = std::move(*this).asKnownExpr();
    if (e->isSemanticallyInOutExpr()) {
      auto lv = SGF.emitLValue(e, SGFAccessKind::ReadWrite);
      return SGF.emitAddressOfLValue(e, std::move(lv));
    } else {
      return SGF.emitRValueAsSingleValue(e, C);
    }
  }
  }
  llvm_unreachable("bad kind");
}
Beispiel #2
0
ManagedValue SILGenFunction::manageOpaqueValue(OpaqueValueState &entry,
                                               SILLocation loc,
                                               SGFContext C) {
  // If the opaque value is consumable, we can just return the
  // value with a cleanup. There is no need to retain it separately.
  if (entry.IsConsumable) {
    assert(!entry.HasBeenConsumed
           && "Uniquely-referenced opaque value already consumed");
    entry.HasBeenConsumed = true;
    return entry.Value;
  }

  assert(!entry.Value.hasCleanup());

  // If the context wants a +0 value, guaranteed or immediate, we can
  // give it to them, because OpenExistential emission guarantees the
  // value.
  if (C.isGuaranteedPlusZeroOk()) {
    return entry.Value;
  }

  // If the context wants us to initialize a buffer, copy there instead
  // of making a temporary allocation.
  if (auto I = C.getEmitInto()) {
    if (SILValue address = I->getAddressForInPlaceInitialization()) {
      entry.Value.copyInto(*this, address, loc);
      I->finishInitialization(*this);
      return ManagedValue::forInContext();
    }
  }

  // Otherwise, copy the value into a temporary.
  return entry.Value.copyUnmanaged(*this, loc);
}
Beispiel #3
0
RValue
ArgumentSource::getKnownTupleAsRValue(SILGenFunction &SGF, SGFContext C) && {

  return std::move(*this).withKnownTupleElementSources<RValue>(
                            [&](SILLocation loc, CanTupleType type,
                                MutableArrayRef<ArgumentSource> elements) {
    // If there's a target initialization, and we can split it, do so.
    if (auto init = C.getEmitInto()) {
      if (init->canSplitIntoTupleElements()) {
        // Split the tuple.
        SmallVector<InitializationPtr, 4> scratch;
        auto eltInits = init->splitIntoTupleElements(SGF, loc, type, scratch);

        // Emit each element into the corresponding element initialization.
        for (auto i : indices(eltInits)) {
          std::move(elements[i]).forwardInto(SGF, eltInits[i].get());
        }

        // Finish initialization.
        init->finishInitialization(SGF);

        return RValue::forInContext();
      }
    }

    // Otherwise, emit all of the elements into a single big r-value.
    RValue result(type);
    for (auto &element : elements) {
      result.addElement(std::move(element).getAsRValue(SGF));
    }
    return result;
  });
}
Beispiel #4
0
ManagedValue SILGenBuilder::formalAccessBufferForExpr(
    SILLocation loc, SILType ty, const TypeLowering &lowering,
    SGFContext context, std::function<void(SILValue)> rvalueEmitter) {
  // If we have a single-buffer "emit into" initialization, use that for the
  // result.
  SILValue address = context.getAddressForInPlaceInitialization();

  // If we couldn't emit into the Initialization, emit into a temporary
  // allocation.
  if (!address) {
    address = gen.emitTemporaryAllocation(loc, ty.getObjectType());
  }

  rvalueEmitter(address);

  // If we have a single-buffer "emit into" initialization, use that for the
  // result.
  if (context.getAddressForInPlaceInitialization()) {
    context.getEmitInto()->finishInitialization(gen);
    return ManagedValue::forInContext();
  }

  // Add a cleanup for the temporary we allocated.
  if (lowering.isTrivial())
    return ManagedValue::forUnmanaged(address);

  return gen.emitFormalAccessManagedBufferWithCleanup(loc, address);
}
Beispiel #5
0
ManagedValue ArgumentSource::getAsSingleValue(SILGenFunction &SGF,
                                              SGFContext C) && {
  switch (StoredKind) {
  case Kind::Invalid:
    llvm_unreachable("argument source is invalid");
  case Kind::LValue: {
    auto loc = getKnownLValueLocation();
    return SGF.emitAddressOfLValue(loc, std::move(*this).asKnownLValue(),
                                   AccessKind::ReadWrite);
  }
  case Kind::RValue: {
    auto loc = getKnownRValueLocation();
    if (auto init = C.getEmitInto()) {
      std::move(*this).asKnownRValue().forwardInto(SGF, loc, init);
      return ManagedValue::forInContext();
    } else {
      return std::move(*this).asKnownRValue().getAsSingleValue(SGF, loc);
    }
  }
  case Kind::Expr: {
    auto e = std::move(*this).asKnownExpr();
    if (e->getType()->is<InOutType>()) {
      return SGF.emitAddressOfLValue(e, SGF.emitLValue(e, AccessKind::ReadWrite),
                                     AccessKind::ReadWrite);
    } else {
      return SGF.emitRValueAsSingleValue(e, C);
    }
  }
  case Kind::Tuple: {
    auto loc = getKnownTupleLocation();
    auto rvalue = std::move(*this).getKnownTupleAsRValue(SGF, C);
    if (rvalue.isInContext())
      return ManagedValue::forInContext();
    return std::move(rvalue).getAsSingleValue(SGF, loc);
  }
  }
  llvm_unreachable("bad kind");
}
Beispiel #6
0
RValue Lowering::emitConditionalCheckedCast(SILGenFunction &SGF,
                                            SILLocation loc,
                                            ManagedValue operand,
                                            Type operandType,
                                            Type optTargetType,
                                            CheckedCastKind castKind,
                                            SGFContext C) {
  // Drill into the result type.
  CanType resultObjectType =
    optTargetType->getCanonicalType().getAnyOptionalObjectType();
  assert(resultObjectType);

  // Handle collection downcasts directly; they have specific library
  // entry points.
  if (castKind == CheckedCastKind::ArrayDowncast ||
      castKind == CheckedCastKind::DictionaryDowncast ||
      castKind == CheckedCastKind::SetDowncast) {
    return emitCollectionDowncastExpr(SGF, operand, operandType, loc,
                                      resultObjectType, C,
                                      /*conditional=*/true);
  }

  operand = adjustForConditionalCheckedCastOperand(loc, operand,
                                               operandType->getCanonicalType(),
                                                   resultObjectType, SGF);

  auto someDecl = SGF.getASTContext().getOptionalSomeDecl();
  auto &resultTL = SGF.getTypeLowering(optTargetType);

  // Set up a result buffer if desirable/required.
  SILValue resultBuffer;
  SILValue resultObjectBuffer;
  Optional<TemporaryInitialization> resultObjectTemp;
  SGFContext resultObjectCtx;
  if (resultTL.isAddressOnly() ||
      (C.getEmitInto() && C.getEmitInto()->getAddressOrNull())) {
    SILType resultTy = resultTL.getLoweredType();
    resultBuffer = SGF.getBufferForExprResult(loc, resultTy, C);
    resultObjectBuffer =
      SGF.B.createInitEnumDataAddr(loc, resultBuffer, someDecl,
                    resultTy.getAnyOptionalObjectType().getAddressType());
    resultObjectTemp.emplace(resultObjectBuffer, CleanupHandle::invalid());
    resultObjectCtx = SGFContext(&resultObjectTemp.getValue());
  }

  // Prepare a jump destination here.
  ExitableFullExpr scope(SGF, CleanupLocation::get(loc));

  auto operandCMV = ConsumableManagedValue::forOwned(operand);
  SGF.emitCheckedCastBranch(loc, operandCMV, operandType,
                            resultObjectType, resultObjectCtx,
    // The success path.
    [&](ManagedValue objectValue) {
      // If we're not emitting into a temporary, just wrap up the result
      // in Some and go to the continuation block.
      if (!resultObjectTemp) {
        auto some = SGF.B.createEnum(loc, objectValue.forward(SGF),
                                     someDecl, resultTL.getLoweredType());
        SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, { some });
        return;
      }

      // Otherwise, make sure the value is in the context.
      if (!objectValue.isInContext()) {
        objectValue.forwardInto(SGF, loc, resultObjectBuffer);
      }
      SGF.B.createInjectEnumAddr(loc, resultBuffer, someDecl);
      SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc);
    },
    // The failure path.
    [&] {
      auto noneDecl = SGF.getASTContext().getOptionalNoneDecl();

      // If we're not emitting into a temporary, just wrap up the result
      // in None and go to the continuation block.
      if (!resultObjectTemp) {
        auto none =
          SGF.B.createEnum(loc, nullptr, noneDecl, resultTL.getLoweredType());
        SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, { none });

      // Just construct the enum directly in the context.
      } else {
        SGF.B.createInjectEnumAddr(loc, resultBuffer, noneDecl);
        SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc);
      }
    });

  // Enter the continuation block.
  auto contBB = scope.exit();

  ManagedValue result;
  if (resultObjectTemp) {
    result = SGF.manageBufferForExprResult(resultBuffer, resultTL, C);
  } else {
    auto argument =
      new (SGF.F.getModule()) SILArgument(contBB, resultTL.getLoweredType());
    result = SGF.emitManagedRValueWithCleanup(argument, resultTL);
  }

  return RValue(SGF, loc, optTargetType->getCanonicalType(), result);
}