| //===--- ArgumentSource.cpp - Latent value representation -----------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // A structure for holding a r-value or l-value |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "ArgumentSource.h" |
| #include "Conversion.h" |
| #include "Initialization.h" |
| |
| using namespace swift; |
| using namespace Lowering; |
| |
| RValue &ArgumentSource::peekRValue() & { |
| assert(isRValue() && "Undefined behavior to call this method without the " |
| "ArgumentSource actually being an RValue"); |
| return Storage.get<RValueStorage>(StoredKind).Value; |
| } |
| |
| RValue ArgumentSource::getAsRValue(SILGenFunction &SGF, SGFContext C) && { |
| switch (StoredKind) { |
| case Kind::Invalid: |
| llvm_unreachable("argument source is invalid"); |
| case Kind::LValue: |
| llvm_unreachable("cannot get l-value as r-value"); |
| case Kind::RValue: |
| return std::move(*this).asKnownRValue(SGF); |
| case Kind::Expr: |
| return SGF.emitRValue(std::move(*this).asKnownExpr(), C); |
| } |
| llvm_unreachable("bad kind"); |
| } |
| |
| 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"); |
| } |
| |
| |
| ManagedValue ArgumentSource::getAsSingleValue(SILGenFunction &SGF, |
| AbstractionPattern origFormalType, |
| SILType loweredTy, |
| SGFContext C) && { |
| auto substFormalType = getSubstRValueType(); |
| auto conversion = |
| Conversion::getSubstToOrig(origFormalType, substFormalType, loweredTy); |
| return std::move(*this).getConverted(SGF, conversion, C); |
| } |
| |
| ManagedValue ArgumentSource::getConverted(SILGenFunction &SGF, |
| const Conversion &conversion, |
| SGFContext C) && { |
| switch (StoredKind) { |
| case Kind::Invalid: |
| llvm_unreachable("argument source is invalid"); |
| case Kind::LValue: |
| llvm_unreachable("cannot get converted l-value"); |
| case Kind::RValue: |
| case Kind::Expr: |
| return SGF.emitConvertedRValue(getLocation(), conversion, C, |
| [&](SILGenFunction &SGF, SILLocation loc, SGFContext C) { |
| return std::move(*this).getAsSingleValue(SGF, C); |
| }); |
| } |
| llvm_unreachable("bad kind"); |
| } |
| |
| void ArgumentSource::forwardInto(SILGenFunction &SGF, Initialization *dest) && { |
| switch (StoredKind) { |
| case Kind::Invalid: |
| llvm_unreachable("argument source is invalid"); |
| case Kind::LValue: |
| llvm_unreachable("cannot forward an l-value"); |
| case Kind::RValue: { |
| auto loc = getKnownRValueLocation(); |
| std::move(*this).asKnownRValue(SGF).ensurePlusOne(SGF, loc).forwardInto(SGF, loc, dest); |
| return; |
| } |
| case Kind::Expr: { |
| auto e = std::move(*this).asKnownExpr(); |
| SGF.emitExprInto(e, dest); |
| return; |
| } |
| } |
| llvm_unreachable("bad kind"); |
| } |
| |
| // FIXME: Once uncurrying is removed, get rid of this constructor. |
| ArgumentSource::ArgumentSource(SILLocation loc, RValue &&rv, Kind kind) |
| : Storage(), StoredKind(kind) { |
| Storage.emplaceAggregate<RValueStorage>(StoredKind, std::move(rv), loc); |
| } |
| |
| ArgumentSource ArgumentSource::borrow(SILGenFunction &SGF) const & { |
| switch (StoredKind) { |
| case Kind::Invalid: |
| llvm_unreachable("argument source is invalid"); |
| case Kind::LValue: |
| llvm_unreachable("cannot borrow an l-value"); |
| case Kind::RValue: { |
| auto loc = getKnownRValueLocation(); |
| return ArgumentSource(loc, asKnownRValue().borrow(SGF, loc)); |
| } |
| case Kind::Expr: { |
| llvm_unreachable("cannot borrow an expression"); |
| } |
| } |
| llvm_unreachable("bad kind"); |
| } |
| |
| ManagedValue ArgumentSource::materialize(SILGenFunction &SGF) && { |
| if (isRValue()) { |
| auto loc = getKnownRValueLocation(); |
| return std::move(*this).asKnownRValue(SGF).materialize(SGF, loc); |
| } |
| |
| auto loc = getLocation(); |
| auto temp = SGF.emitTemporary(loc, SGF.getTypeLowering(getSubstRValueType())); |
| std::move(*this).forwardInto(SGF, temp.get()); |
| return temp->getManagedAddress(); |
| } |
| |
| ManagedValue ArgumentSource::materialize(SILGenFunction &SGF, |
| AbstractionPattern origFormalType, |
| SILType destType) && { |
| auto substFormalType = getSubstRValueType(); |
| assert(!destType || destType.getObjectType() == |
| SGF.getLoweredType(origFormalType, |
| substFormalType).getObjectType()); |
| |
| // Fast path: if the types match exactly, no abstraction difference |
| // is possible and we can just materialize as normal. |
| if (origFormalType.isExactType(substFormalType)) |
| return std::move(*this).materialize(SGF); |
| |
| auto &destTL = |
| (destType ? SGF.getTypeLowering(destType) |
| : SGF.getTypeLowering(origFormalType, substFormalType)); |
| if (!destType) destType = destTL.getLoweredType(); |
| |
| // If there's no abstraction difference, we can just materialize as normal. |
| if (destTL.getLoweredType() == SGF.getLoweredType(substFormalType)) { |
| return std::move(*this).materialize(SGF); |
| } |
| |
| // Emit a temporary at the given address. |
| auto temp = SGF.emitTemporary(getLocation(), destTL); |
| |
| // Forward into it. |
| std::move(*this).forwardInto(SGF, origFormalType, temp.get(), destTL); |
| |
| return temp->getManagedAddress(); |
| } |
| |
| void ArgumentSource::forwardInto(SILGenFunction &SGF, |
| AbstractionPattern origFormalType, |
| Initialization *dest, |
| const TypeLowering &destTL) && { |
| auto substFormalType = getSubstRValueType(); |
| assert(destTL.getLoweredType() == |
| SGF.getLoweredType(origFormalType, substFormalType)); |
| |
| // If there are no abstraction changes, we can just forward |
| // normally. |
| if (origFormalType.isExactType(substFormalType) || |
| destTL.getLoweredType() == SGF.getLoweredType(substFormalType)) { |
| std::move(*this).forwardInto(SGF, dest); |
| return; |
| } |
| |
| // Otherwise, emit as a single independent value. |
| SILLocation loc = getLocation(); |
| ManagedValue outputValue = |
| std::move(*this).getAsSingleValue(SGF, origFormalType, |
| destTL.getLoweredType(), |
| SGFContext(dest)); |
| |
| if (outputValue.isInContext()) return; |
| |
| // Use RValue's forward-into-initialization code. We have to lie to |
| // RValue about the formal type (by using the lowered type) because |
| // we're emitting into an abstracted value, which RValue doesn't |
| // really handle. |
| auto substLoweredType = destTL.getLoweredType().getASTType(); |
| RValue(SGF, loc, substLoweredType, outputValue).forwardInto(SGF, loc, dest); |
| } |
| |
| void ArgumentSource::dump() const { |
| dump(llvm::errs()); |
| } |
| |
| void ArgumentSource::dump(raw_ostream &out, unsigned indent) const { |
| out.indent(indent) << "ArgumentSource::"; |
| switch (StoredKind) { |
| case Kind::Invalid: |
| out << "Invalid\n"; |
| return; |
| case Kind::LValue: |
| out << "LValue\n"; |
| Storage.get<LValueStorage>(StoredKind).Value.dump(out, indent + 2); |
| return; |
| case Kind::RValue: |
| out << "RValue\n"; |
| Storage.get<RValueStorage>(StoredKind).Value.dump(out, indent + 2); |
| return; |
| case Kind::Expr: |
| out << "Expr\n"; |
| Storage.get<Expr*>(StoredKind)->dump(out); // FIXME: indent |
| out << "\n"; |
| return; |
| } |
| llvm_unreachable("bad kind"); |
| } |
| |
| PreparedArguments::PreparedArguments( |
| ArrayRef<AnyFunctionType::Param> params, |
| Expr *arg) : PreparedArguments(params) { |
| if (auto *PE = dyn_cast<ParenExpr>(arg)) |
| addArbitrary(PE->getSubExpr()); |
| else if (auto *TE = dyn_cast<TupleExpr>(arg)) { |
| for (auto *elt : TE->getElements()) |
| addArbitrary(elt); |
| } else { |
| // FIXME: All ApplyExprs should have a ParenExpr or TupleExpr as their argument |
| addArbitrary(arg); |
| } |
| } |
| |
| PreparedArguments |
| PreparedArguments::copy(SILGenFunction &SGF, SILLocation loc) const { |
| if (isNull()) return PreparedArguments(); |
| |
| assert(isValid()); |
| PreparedArguments result(getParams()); |
| for (auto &elt : Arguments) { |
| assert(elt.isRValue()); |
| result.add(elt.getKnownRValueLocation(), |
| elt.asKnownRValue().copy(SGF, loc)); |
| } |
| assert(isValid()); |
| return result; |
| } |
| |
| bool PreparedArguments::isObviouslyEqual(const PreparedArguments &other) const { |
| if (isNull() != other.isNull()) |
| return false; |
| if (isNull()) |
| return true; |
| |
| assert(isValid() && other.isValid()); |
| if (Arguments.size() != other.Arguments.size()) |
| return false; |
| for (auto i : indices(Arguments)) { |
| if (!Arguments[i].isObviouslyEqual(other.Arguments[i])) |
| return false; |
| } |
| return true; |
| } |
| |
| bool ArgumentSource::isObviouslyEqual(const ArgumentSource &other) const { |
| if (StoredKind != other.StoredKind) |
| return false; |
| |
| switch (StoredKind) { |
| case Kind::Invalid: |
| llvm_unreachable("argument source is invalid"); |
| case Kind::RValue: |
| return asKnownRValue().isObviouslyEqual(other.asKnownRValue()); |
| case Kind::LValue: |
| return false; // TODO? |
| case Kind::Expr: |
| return false; // TODO? |
| } |
| llvm_unreachable("bad kind"); |
| } |
| |
| PreparedArguments PreparedArguments::copyForDiagnostics() const { |
| if (isNull()) |
| return PreparedArguments(); |
| |
| assert(isValid()); |
| PreparedArguments result(getParams()); |
| for (auto &arg : Arguments) { |
| result.Arguments.push_back(arg.copyForDiagnostics()); |
| } |
| return result; |
| } |
| |
| ArgumentSource ArgumentSource::copyForDiagnostics() const { |
| switch (StoredKind) { |
| case Kind::Invalid: |
| return ArgumentSource(); |
| case Kind::LValue: |
| // We have no way to copy an l-value for diagnostics. |
| return {getKnownLValueLocation(), LValue()}; |
| case Kind::RValue: |
| return {getKnownRValueLocation(), asKnownRValue().copyForDiagnostics()}; |
| case Kind::Expr: |
| return asKnownExpr(); |
| } |
| llvm_unreachable("bad kind"); |
| } |