//===--- ArgumentSource.cpp - Latent value representation -----------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://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 "Initialization.h" using namespace swift; using namespace Lowering; RValue &ArgumentSource::forceAndPeekRValue(SILGenFunction &gen) & { if (isRValue()) { return peekRValue(); } auto expr = asKnownExpr(); StoredKind = Kind::RValue; new (&Storage.TheRV.Value) RValue(gen.emitRValue(expr)); Storage.TheRV.Loc = expr; return Storage.TheRV.Value; } RValue &ArgumentSource::peekRValue() & { assert(isRValue() && "Undefined behavior to call this method without the " "ArgumentSource actually being an RValue"); return Storage.TheRV.Value; } void ArgumentSource::rewriteType(CanType newType) & { assert(!isLValue()); if (isRValue()) { Storage.TheRV.Value.rewriteType(newType); } else { Expr *expr = Storage.TheExpr; if (expr->getType()->isEqual(newType)) return; llvm_unreachable("unimplemented! hope it doesn't happen"); } } RValue ArgumentSource::getAsRValue(SILGenFunction &gen, SGFContext C) && { assert(!isLValue()); if (isRValue()) return std::move(*this).asKnownRValue(); return gen.emitRValue(std::move(*this).asKnownExpr(), C); } ManagedValue ArgumentSource::getAsSingleValue(SILGenFunction &gen, SGFContext C) && { if (isRValue()) { auto loc = getKnownRValueLocation(); return std::move(*this).asKnownRValue().getAsSingleValue(gen, loc); } if (isLValue()) { auto loc = getKnownLValueLocation(); return gen.emitAddressOfLValue(loc, std::move(*this).asKnownLValue(), AccessKind::ReadWrite); } auto e = std::move(*this).asKnownExpr(); if (e->getType()->is()) { return gen.emitAddressOfLValue(e, gen.emitLValue(e, AccessKind::ReadWrite), AccessKind::ReadWrite); } else { return gen.emitRValueAsSingleValue(e, C); } } ManagedValue ArgumentSource::getAsSingleValue(SILGenFunction &gen, AbstractionPattern origFormalType, SGFContext C) && { auto loc = getLocation(); auto substFormalType = getSubstType(); ManagedValue outputValue = std::move(*this).getAsSingleValue(gen); return gen.emitSubstToOrigValue(loc, outputValue, origFormalType, substFormalType, C); } void ArgumentSource::forwardInto(SILGenFunction &gen, Initialization *dest) && { assert(!isLValue()); if (isRValue()) { auto loc = getKnownRValueLocation(); return std::move(*this).asKnownRValue().forwardInto(gen, loc, dest); } auto e = std::move(*this).asKnownExpr(); return gen.emitExprInto(e, dest); } ManagedValue ArgumentSource::materialize(SILGenFunction &gen) && { assert(!isLValue()); if (isRValue()) { auto loc = getKnownRValueLocation(); return std::move(*this).asKnownRValue().materialize(gen, loc); } auto expr = std::move(*this).asKnownExpr(); auto temp = gen.emitTemporary(expr, gen.getTypeLowering(expr->getType())); gen.emitExprInto(expr, temp.get()); return temp->getManagedAddress(); } ManagedValue ArgumentSource::materialize(SILGenFunction &SGF, AbstractionPattern origFormalType, SILType destType) && { auto substFormalType = CanType(getSubstType()->getInOutObjectType()); assert(!destType || destType.getObjectType() == SGF.SGM.Types.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 = getSubstType(); 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, 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().getSwiftRValueType(); RValue(SGF, loc, substLoweredType, outputValue).forwardInto(SGF, loc, dest); }