//===--- SILGenLValue.cpp - Constructs logical lvalues for SILGen ---------===// // // 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 // //===----------------------------------------------------------------------===// // // Emission of l-value expressions and basic operations on them. // //===----------------------------------------------------------------------===// #include "SILGen.h" #include "ArgumentSource.h" #include "LValue.h" #include "RValue.h" #include "Scope.h" #include "Initialization.h" #include "swift/AST/AST.h" #include "swift/AST/DiagnosticsSIL.h" #include "swift/AST/Decl.h" #include "swift/AST/Types.h" #include "swift/AST/DiagnosticsCommon.h" #include "swift/AST/Mangle.h" #include "swift/SIL/PrettyStackTrace.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILUndef.h" #include "swift/SIL/TypeLowering.h" #include "llvm/Support/raw_ostream.h" #include "ASTVisitor.h" using namespace swift; using namespace Lowering; //===----------------------------------------------------------------------===// /// A pending writeback. namespace swift { namespace Lowering { struct LLVM_LIBRARY_VISIBILITY LValueWriteback { SILLocation loc; std::unique_ptr component; ManagedValue base; MaterializedLValue materialized; CleanupHandle cleanup; ~LValueWriteback() {} LValueWriteback(LValueWriteback&&) = default; LValueWriteback &operator=(LValueWriteback&&) = default; LValueWriteback() = default; LValueWriteback(SILLocation loc, std::unique_ptr &&comp, ManagedValue base, MaterializedLValue materialized, CleanupHandle cleanup) : loc(loc), component(std::move(comp)), base(base), materialized(materialized), cleanup(cleanup) { } void diagnoseConflict(const LValueWriteback &rhs, SILGenFunction &SGF) const { // If the two writebacks we're comparing are of different kinds (e.g. // ownership conversion vs a computed property) then they aren't the // same and thus cannot conflict. if (component->getKind() != rhs.component->getKind()) return; // If the lvalues don't have the same base value, then they aren't the same. // Note that this is the primary source of false negative for this // diagnostic. if (base.getValue() != rhs.base.getValue()) return; component->diagnoseWritebackConflict(rhs.component.get(), loc, rhs.loc,SGF); } void performWriteback(SILGenFunction &gen, bool isFinal) { Scope S(gen.Cleanups, CleanupLocation::get(loc)); component->writeback(gen, loc, base, materialized, isFinal); } }; } } namespace { class LValueWritebackCleanup : public Cleanup { unsigned Depth; public: LValueWritebackCleanup(unsigned depth) : Depth(depth) {} void emit(SILGenFunction &gen, CleanupLocation loc) override { gen.getWritebackStack()[Depth].performWriteback(gen, /*isFinal*/ false); } }; } std::vector &SILGenFunction::getWritebackStack() { if (!WritebackStack) WritebackStack = new std::vector(); return *WritebackStack; } void SILGenFunction::freeWritebackStack() { assert((!WritebackStack || WritebackStack->empty()) && "entries remaining on writeback stack at end of function!"); delete WritebackStack; } /// Push a writeback onto the current LValueWriteback stack. static void pushWriteback(SILGenFunction &gen, SILLocation loc, std::unique_ptr &&comp, ManagedValue base, MaterializedLValue materialized) { assert(gen.InWritebackScope); // Push a cleanup to execute the writeback consistently. auto &stack = gen.getWritebackStack(); gen.Cleanups.pushCleanup(stack.size()); auto cleanup = gen.Cleanups.getTopCleanup(); stack.emplace_back(loc, std::move(comp), base, materialized, cleanup); } //===----------------------------------------------------------------------===// static CanType getSubstFormalRValueType(Expr *expr) { return expr->getType()->getRValueType()->getCanonicalType(); } static LValueTypeData getLogicalStorageTypeData(SILGenModule &SGM, CanType substFormalType) { AbstractionPattern origFormalType( substFormalType.getReferenceStorageReferent()); return { origFormalType, substFormalType, SGM.Types.getLoweredType(origFormalType, substFormalType).getObjectType() }; } static LValueTypeData getPhysicalStorageTypeData(SILGenModule &SGM, AbstractStorageDecl *storage, CanType substFormalType) { auto origFormalType = SGM.Types.getAbstractionPattern(storage) .getReferenceStorageReferentType(); return { origFormalType, substFormalType, SGM.Types.getLoweredType(origFormalType, substFormalType).getObjectType() }; } /// SILGenLValue - An ASTVisitor for building logical lvalues. class LLVM_LIBRARY_VISIBILITY SILGenLValue : public Lowering::ExprVisitor { /// A mapping from opaque value expressions to the open-existential /// expression that determines them. llvm::SmallDenseMap openedExistentials; public: SILGenFunction &gen; SILGenLValue(SILGenFunction &gen) : gen(gen) {} LValue visitRec(Expr *e, AccessKind accessKind); /// Dummy handler to log unimplemented nodes. LValue visitExpr(Expr *e, AccessKind accessKind); // Nodes that form the root of lvalue paths LValue visitDiscardAssignmentExpr(DiscardAssignmentExpr *e, AccessKind accessKind); LValue visitDeclRefExpr(DeclRefExpr *e, AccessKind accessKind); LValue visitOpaqueValueExpr(OpaqueValueExpr *e, AccessKind accessKind); // Nodes that make up components of lvalue paths LValue visitMemberRefExpr(MemberRefExpr *e, AccessKind accessKind); LValue visitSubscriptExpr(SubscriptExpr *e, AccessKind accessKind); LValue visitTupleElementExpr(TupleElementExpr *e, AccessKind accessKind); LValue visitForceValueExpr(ForceValueExpr *e, AccessKind accessKind); LValue visitBindOptionalExpr(BindOptionalExpr *e, AccessKind accessKind); LValue visitOpenExistentialExpr(OpenExistentialExpr *e, AccessKind accessKind); // Expressions that wrap lvalues LValue visitInOutExpr(InOutExpr *e, AccessKind accessKind); LValue visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *e, AccessKind accessKind); }; static ManagedValue emitGetIntoTemporary(SILGenFunction &gen, SILLocation loc, ManagedValue base, LogicalPathComponent &&component) { // Create a temporary. auto temporaryInit = gen.emitTemporary(loc, gen.getTypeLowering(component.getTypeOfRValue())); // Emit a 'get' into the temporary. RValue value = std::move(component).get(gen, loc, base, SGFContext(temporaryInit.get())); // Force the value into the temporary if necessary. if (!value.isInContext()) { std::move(value).forwardInto(gen, loc, temporaryInit.get()); } return temporaryInit->getManagedAddress(); } ManagedValue LogicalPathComponent::getMaterialized(SILGenFunction &gen, SILLocation loc, ManagedValue base, AccessKind kind) && { // If this is just for a read, emit a load into a temporary memory // location. if (kind == AccessKind::Read) { return emitGetIntoTemporary(gen, loc, base, std::move(*this)); } assert(gen.InWritebackScope && "materializing l-value for modification without writeback scope"); // Otherwise, we need to emit a get and set. Borrow the base for // the getter. ManagedValue getterBase = (base ? base.borrow() : ManagedValue()); // Clone anything else about the component that we might need in the // writeback. auto clonedComponent = clone(gen, loc); // Emit a 'get' into a temporary. ManagedValue temporary = emitGetIntoTemporary(gen, loc, getterBase, std::move(*this)); // Push a writeback for the temporary. pushWriteback(gen, loc, std::move(clonedComponent), base, MaterializedLValue(temporary)); return temporary.borrow(); } void LogicalPathComponent::writeback(SILGenFunction &gen, SILLocation loc, ManagedValue base, MaterializedLValue materialized, bool isFinal) { assert(!materialized.callback && "unexpected materialized lvalue with callback!"); // Load the value from the temporary unless the type is address-only // and this is the final use, in which case we can just consume the // value as-is. auto temporary = materialized.temporary; assert(temporary.getType().isAddress()); auto &tempTL = gen.getTypeLowering(temporary.getType()); if (!tempTL.isAddressOnly() || !isFinal) { if (isFinal) temporary.forward(gen); temporary = gen.emitLoad(loc, temporary.getValue(), tempTL, SGFContext(), IsTake_t(isFinal)); } RValue rvalue(gen, loc, getSubstFormalType(), temporary); // Don't consume cleanups on the base if this isn't final. if (!isFinal) { base = ManagedValue::forUnmanaged(base.getValue()); } // Clone the component if this isn't final. std::unique_ptr clonedComponent = (isFinal ? nullptr : clone(gen, loc)); LogicalPathComponent *component = (isFinal ? this : &*clonedComponent); std::move(*component).set(gen, loc, std::move(rvalue), base); } WritebackScope::WritebackScope(SILGenFunction &g) : gen(&g), wasInWritebackScope(g.InWritebackScope), savedDepth(g.getWritebackStack().size()) { // If we're in an inout conversion scope, disable nested writeback scopes. if (g.InInOutConversionScope) { gen = nullptr; return; } g.InWritebackScope = true; } void WritebackScope::popImpl() { // Pop the InWritebackScope bit. gen->InWritebackScope = wasInWritebackScope; // Check to see if there is anything going on here. auto &stack = gen->getWritebackStack(); size_t depthAtPop = stack.size(); if (depthAtPop == savedDepth) return; size_t prevIndex = depthAtPop; while (prevIndex-- > savedDepth) { auto index = prevIndex; // Deactivate the cleanup. gen->Cleanups.setCleanupState(stack[index].cleanup, CleanupState::Dead); // Attempt to diagnose problems where obvious aliasing introduces illegal // code. We do a simple N^2 comparison here to detect this because it is // extremely unlikely more than a few writebacks are active at once. for (auto j = index; j > savedDepth; --j) stack[index].diagnoseConflict(stack[j-1], *gen); // Claim the address of each and then perform the writeback from the // temporary allocation to the source we copied from. // // This evaluates arbitrary code, so it's best to be paranoid // about iterators on the stack. stack[index].performWriteback(*gen, /*isFinal*/ true); } assert(depthAtPop == stack.size() && "more writebacks left on stack during writeback scope pop?"); stack.erase(stack.begin() + savedDepth, stack.end()); } WritebackScope::WritebackScope(WritebackScope &&o) : gen(o.gen), wasInWritebackScope(o.wasInWritebackScope), savedDepth(o.savedDepth) { o.gen = nullptr; } WritebackScope &WritebackScope::operator=(WritebackScope &&o) { gen = o.gen; wasInWritebackScope = o.wasInWritebackScope; savedDepth = o.savedDepth; o.gen = nullptr; return *this; } InOutConversionScope::InOutConversionScope(SILGenFunction &gen) : gen(gen) { assert(gen.InWritebackScope && "inout conversions should happen in writeback scopes"); assert(!gen.InInOutConversionScope && "inout conversions should not be nested"); gen.InInOutConversionScope = true; } InOutConversionScope::~InOutConversionScope() { assert(gen.InInOutConversionScope && "already exited conversion scope?!"); gen.InInOutConversionScope = false; } void PathComponent::_anchor() {} void PhysicalPathComponent::_anchor() {} void LogicalPathComponent::_anchor() {} void PathComponent::dump() const { print(llvm::errs()); } /// Return the LValueTypeData for a SIL value with the given AST formal type. static LValueTypeData getValueTypeData(CanType formalType, SILValue value) { return { AbstractionPattern(formalType), formalType, value->getType().getObjectType() }; } static LValueTypeData getValueTypeData(SILGenFunction &gen, Expr *e) { CanType formalType = getSubstFormalRValueType(e); SILType loweredType = gen.getLoweredType(formalType).getObjectType(); return { AbstractionPattern(formalType), formalType, loweredType }; } /// Given the address of an optional value, unsafely project out the /// address of the value. static ManagedValue getAddressOfOptionalValue(SILGenFunction &gen, SILLocation loc, ManagedValue optAddr, const LValueTypeData &valueTypeData) { // Project out the 'Some' payload. OptionalTypeKind otk; auto valueTy = optAddr.getType().getSwiftRValueType().getAnyOptionalObjectType(otk); assert(valueTy && "base was not optional?"); (void) valueTy; EnumElementDecl *someDecl = gen.getASTContext().getOptionalSomeDecl(otk); // If the base is +1, we want to forward the cleanup. bool hadCleanup = optAddr.hasCleanup(); // UncheckedTakeEnumDataAddr is safe to apply to Optional, because it is // a single-payload enum. There will (currently) never be spare bits // embedded in the payload. SILValue valueAddr = gen.B.createUncheckedTakeEnumDataAddr(loc, optAddr.forward(gen), someDecl, valueTypeData.TypeOfRValue.getAddressType()); // Return the value as +1 if the optional was +1. if (hadCleanup) { return gen.emitManagedBufferWithCleanup(valueAddr); } else { return ManagedValue::forLValue(valueAddr); } } namespace { class RefElementComponent : public PhysicalPathComponent { VarDecl *Field; SILType SubstFieldType; public: RefElementComponent(VarDecl *field, SILType substFieldType, LValueTypeData typeData) : PhysicalPathComponent(typeData, RefElementKind), Field(field), SubstFieldType(substFieldType) {} ManagedValue offset(SILGenFunction &gen, SILLocation loc, ManagedValue base, AccessKind accessKind) && override { assert(base.getType().isObject() && "base for ref element component must be an object"); assert(base.getType().hasReferenceSemantics() && "base for ref element component must be a reference type"); auto Res = gen.B.createRefElementAddr(loc, base.getValue(), Field, SubstFieldType); return ManagedValue::forLValue(Res); } void print(raw_ostream &OS) const override { OS << "RefElementComponent(" << Field->getName() << ")\n"; } }; class TupleElementComponent : public PhysicalPathComponent { unsigned ElementIndex; public: TupleElementComponent(unsigned elementIndex, LValueTypeData typeData) : PhysicalPathComponent(typeData, TupleElementKind), ElementIndex(elementIndex) {} ManagedValue offset(SILGenFunction &gen, SILLocation loc, ManagedValue base, AccessKind accessKind) && override { assert(base && "invalid value for element base"); // TODO: if the base is +1, break apart its cleanup. auto Res = gen.B.createTupleElementAddr(loc, base.getValue(), ElementIndex, getTypeOfRValue().getAddressType()); return ManagedValue::forLValue(Res); } void print(raw_ostream &OS) const override { OS << "TupleElementComponent(" << ElementIndex << ")\n"; } }; class StructElementComponent : public PhysicalPathComponent { VarDecl *Field; SILType SubstFieldType; public: StructElementComponent(VarDecl *field, SILType substFieldType, LValueTypeData typeData) : PhysicalPathComponent(typeData, StructElementKind), Field(field), SubstFieldType(substFieldType) {} ManagedValue offset(SILGenFunction &gen, SILLocation loc, ManagedValue base, AccessKind accessKind) && override { assert(base && "invalid value for element base"); // TODO: if the base is +1, break apart its cleanup. auto Res = gen.B.createStructElementAddr(loc, base.getValue(), Field, SubstFieldType); return ManagedValue::forLValue(Res); } void print(raw_ostream &OS) const override { OS << "StructElementComponent(" << Field->getName() << ")\n"; } }; /// A physical path component which force-projects the address of /// the value of an optional l-value. class ForceOptionalObjectComponent : public PhysicalPathComponent { public: ForceOptionalObjectComponent(LValueTypeData typeData) : PhysicalPathComponent(typeData, OptionalObjectKind) {} ManagedValue offset(SILGenFunction &gen, SILLocation loc, ManagedValue base, AccessKind accessKind) && override { // Assert that the optional value is present. gen.emitPreconditionOptionalHasValue(loc, base.getValue()); // Project out the payload. return getAddressOfOptionalValue(gen, loc, base, getTypeData()); } void print(raw_ostream &OS) const override { OS << "ForceOptionalObjectComponent()\n"; } }; /// A physical path component which projects out an opened archetype /// from an existential. class OpenOpaqueExistentialComponent : public PhysicalPathComponent { static LValueTypeData getOpenedArchetypeTypeData(CanArchetypeType type) { return { AbstractionPattern::getOpaque(), type, SILType::getPrimitiveObjectType(type) }; } public: OpenOpaqueExistentialComponent(CanArchetypeType openedArchetype) : PhysicalPathComponent(getOpenedArchetypeTypeData(openedArchetype), OpenedExistentialKind) {} ManagedValue offset(SILGenFunction &gen, SILLocation loc, ManagedValue base, AccessKind accessKind) && override { assert(base.getType().isExistentialType() && "base for open existential component must be an existential"); auto addr = gen.B.createOpenExistentialAddr(loc, base.getLValueAddress(), getTypeOfRValue().getAddressType()); if (base.hasCleanup()) { // Leave a cleanup to deinit the existential container. gen.enterDeinitExistentialCleanup(base.getValue(), CanType(), ExistentialRepresentation::Opaque); } gen.setArchetypeOpeningSite(cast(getSubstFormalType()), addr); return ManagedValue::forLValue(addr); } void print(raw_ostream &OS) const override { OS << "OpenOpaqueExistentialComponent(" << getSubstFormalType() << ")\n"; } }; /// A physical path component which returns a literal address. class ValueComponent : public PhysicalPathComponent { ManagedValue Value; public: ValueComponent(ManagedValue value, LValueTypeData typeData) : PhysicalPathComponent(typeData, ValueKind), Value(value) { } ManagedValue offset(SILGenFunction &gen, SILLocation loc, ManagedValue base, AccessKind accessKind) && override { assert(!base && "value component must be root of lvalue path"); return Value; } void print(raw_ostream &OS) const override { OS << "ValueComponent()\n"; } }; } // end anonymous namespace. static bool isReadNoneFunction(const Expr *e) { // If this is a curried call to an integer literal conversion operations, then // we can "safely" assume it is readnone (btw, yes this is totally gross). // This is better to be attribute driven, a la rdar://15587352. if (auto *dre = dyn_cast(e)) { DeclName name = dre->getDecl()->getFullName(); return (name.getArgumentNames().size() == 1 && name.getBaseName().str() == "init" && !name.getArgumentNames()[0].empty() && (name.getArgumentNames()[0].str() == "integerLiteral" || name.getArgumentNames()[0].str() == "_builtinIntegerLiteral")); } // Look through DotSyntaxCallExpr, since the literal functions are curried. if (auto *CRCE = dyn_cast(e)) return isReadNoneFunction(CRCE->getFn()); return false; } /// Given two expressions used as indexes to the same SubscriptDecl (and thus /// are guaranteed to have the same AST type) check to see if they are going to /// produce the same value. static bool areCertainlyEqualIndices(const Expr *e1, const Expr *e2) { if (e1->getKind() != e2->getKind()) return false; // Look through ParenExpr's. if (auto *pe1 = dyn_cast(e1)) { auto *pe2 = cast(e2); return areCertainlyEqualIndices(pe1->getSubExpr(), pe2->getSubExpr()); } // Calls are identical if the callee and operands are identical and we know // that the call is something that is "readnone". if (auto *ae1 = dyn_cast(e1)) { auto *ae2 = cast(e2); return areCertainlyEqualIndices(ae1->getFn(), ae2->getFn()) && areCertainlyEqualIndices(ae1->getArg(), ae2->getArg()) && isReadNoneFunction(ae1->getFn()); } // TypeExpr's that produce the same metatype type are identical. if (isa(e1)) return true; if (auto *dre1 = dyn_cast(e1)) { auto *dre2 = cast(e2); return dre1->getDecl() == dre2->getDecl() && dre1->getGenericArgs() == dre2->getGenericArgs(); } // Compare a variety of literals. if (auto *il1 = dyn_cast(e1)) return il1->getValue() == cast(e2)->getValue(); if (auto *il1 = dyn_cast(e1)) return il1->getValue().bitwiseIsEqual( cast(e2)->getValue()); if (auto *bl1 = dyn_cast(e1)) return bl1->getValue() == cast(e2)->getValue(); if (auto *sl1 = dyn_cast(e1)) return sl1->getValue() == cast(e2)->getValue(); // Compare tuple expressions. if (auto *te1 = dyn_cast(e1)) { auto *te2 = cast(e2); // Easy checks: # of elements, trailing closures, element names. if (te1->getNumElements() != te2->getNumElements() || te1->hasTrailingClosure() != te2->hasTrailingClosure() || te1->getElementNames() != te2->getElementNames()) { return false; } for (unsigned i = 0, n = te1->getNumElements(); i != n; ++i) { if (!areCertainlyEqualIndices(te1->getElement(i), te2->getElement(i))) return false; } return true; } // Otherwise, we have no idea if they are identical. return false; } namespace { /// A helper class for implementing a component that involves /// calling accessors. template class AccessorBasedComponent : public Base { protected: // The VarDecl or SubscriptDecl being get/set. AbstractStorageDecl *decl; bool IsSuper; bool IsDirectAccessorUse; std::vector substitutions; /// The subscript index expression. Useless Expr *subscriptIndexExpr; RValue subscripts; /// AST type of the base expression, in case the accessor call /// requires re-abstraction. CanType baseFormalType; struct AccessorArgs { ArgumentSource base; RValue subscripts; }; /// Returns a tuple of RValues holding the accessor value, base (retained if /// necessary), and subscript arguments, in that order. AccessorArgs prepareAccessorArgs(SILGenFunction &gen, SILLocation loc, ManagedValue base, SILDeclRef accessor) && { AccessorArgs result; if (base) result.base = gen.prepareAccessorBaseArg(loc, base, baseFormalType, accessor); if (subscripts) result.subscripts = std::move(subscripts); return result; } AccessorBasedComponent(PathComponent::KindTy kind, AbstractStorageDecl *decl, bool isSuper, bool isDirectAccessorUse, ArrayRef substitutions, CanType baseFormalType, LValueTypeData typeData, Expr *subscriptIndexExpr, RValue *optSubscripts) : Base(typeData, kind), decl(decl), IsSuper(isSuper), IsDirectAccessorUse(isDirectAccessorUse), substitutions(substitutions.begin(), substitutions.end()), subscriptIndexExpr(subscriptIndexExpr), baseFormalType(baseFormalType) { if (optSubscripts) subscripts = std::move(*optSubscripts); } AccessorBasedComponent(const AccessorBasedComponent &copied, SILGenFunction &gen, SILLocation loc) : Base(copied.getTypeData(), copied.getKind()), decl(copied.decl), IsSuper(copied.IsSuper), IsDirectAccessorUse(copied.IsDirectAccessorUse), substitutions(copied.substitutions), subscriptIndexExpr(copied.subscriptIndexExpr), subscripts(copied.subscripts.copy(gen, loc)) , baseFormalType(copied.baseFormalType) {} virtual SILDeclRef getAccessor(SILGenFunction &gen, AccessKind kind) const = 0; AccessKind getBaseAccessKind(SILGenFunction &gen, AccessKind kind) const override { SILDeclRef accessor = getAccessor(gen, kind); auto accessorType = gen.SGM.Types.getConstantFunctionType(accessor); if (accessorType->getSelfParameter().isIndirectMutating()) { return AccessKind::ReadWrite; } else { return AccessKind::Read; } } void printBase(raw_ostream &OS, StringRef name) const { OS << name << "(" << decl->getName() << ")"; if (IsSuper) OS << " isSuper"; if (IsDirectAccessorUse) OS << " isDirectAccessorUse"; if (subscriptIndexExpr) { OS << " subscript_index:\n"; subscriptIndexExpr->print(OS, 2); } OS << '\n'; } }; class GetterSetterComponent : public AccessorBasedComponent { public: GetterSetterComponent(AbstractStorageDecl *decl, bool isSuper, bool isDirectAccessorUse, ArrayRef substitutions, CanType baseFormalType, LValueTypeData typeData, Expr *subscriptIndexExpr = nullptr, RValue *subscriptIndex = nullptr) : AccessorBasedComponent(GetterSetterKind, decl, isSuper, isDirectAccessorUse, substitutions, baseFormalType, typeData, subscriptIndexExpr, subscriptIndex) { } GetterSetterComponent(const GetterSetterComponent &copied, SILGenFunction &gen, SILLocation loc) : AccessorBasedComponent(copied, gen, loc) { } SILDeclRef getAccessor(SILGenFunction &gen, AccessKind accessKind) const override { if (accessKind == AccessKind::Read) { return gen.getGetterDeclRef(decl, IsDirectAccessorUse); } else { return gen.getSetterDeclRef(decl, IsDirectAccessorUse); } } void set(SILGenFunction &gen, SILLocation loc, RValue &&value, ManagedValue base) && override { SILDeclRef setter = gen.getSetterDeclRef(decl, IsDirectAccessorUse); // Pass in just the setter. auto args = std::move(*this).prepareAccessorArgs(gen, loc, base, setter); return gen.emitSetAccessor(loc, setter, substitutions, std::move(args.base), IsSuper, IsDirectAccessorUse, std::move(args.subscripts), std::move(value)); } ManagedValue getMaterialized(SILGenFunction &gen, SILLocation loc, ManagedValue base, AccessKind accessKind) && override { // If this is just for a read, or the property is dynamic, or if // it doesn't have a materializeForSet, or if this is a direct // use of something defined in a protocol extension (see // maybeEmitMaterializeForSetThunk), just materialize to a // temporary directly. if (accessKind == AccessKind::Read || decl->getAttrs().hasAttribute() || !decl->getMaterializeForSetFunc() || isa(decl->getDeclContext()) || decl->getDeclContext()->getAsProtocolExtensionContext()) { return std::move(*this).LogicalPathComponent::getMaterialized(gen, loc, base, accessKind); } assert(gen.InWritebackScope && "materializing l-value for modification without writeback scope"); // Allocate opaque storage for the callback to use. SILValue callbackStorage = gen.emitTemporaryAllocation(loc, SILType::getPrimitiveObjectType( gen.getASTContext().TheUnsafeValueBufferType)); // Allocate a temporary. SILValue buffer = gen.emitTemporaryAllocation(loc, getTypeOfRValue()); // If the base is a +1 r-value, just borrow it for materializeForSet. // prepareAccessorArgs will copy it if necessary. ManagedValue borrowedBase = (base ? base.borrow() : ManagedValue()); // Clone the component without cloning the indices. We don't actually // consume them in writeback(). std::unique_ptr clonedComponent( [&]() -> LogicalPathComponent* { // Steal the subscript values without copying them so that we // can peek at them in diagnoseWritebackConflict. // // This is *amazingly* unprincipled. RValue borrowedSubscripts; RValue *optSubscripts = nullptr; if (subscripts) { CanType type = subscripts.getType(); SmallVector values; std::move(subscripts).getAll(values); subscripts = RValue(values, type); borrowedSubscripts = RValue(values, type); optSubscripts = &borrowedSubscripts; } return new GetterSetterComponent(decl, IsSuper, IsDirectAccessorUse, substitutions, baseFormalType, getTypeData(), subscriptIndexExpr, optSubscripts); }()); SILDeclRef materializeForSet = gen.getMaterializeForSetDeclRef(decl, IsDirectAccessorUse); auto args = std::move(*this).prepareAccessorArgs(gen, loc, borrowedBase, materializeForSet); MaterializedLValue materialized = gen.emitMaterializeForSetAccessor(loc, materializeForSet, substitutions, std::move(args.base), IsSuper, IsDirectAccessorUse, std::move(args.subscripts), buffer, callbackStorage); // Mark a value-dependence on the base. We do this regardless // of whether the base is trivial because even a trivial base // may be value-dependent on something non-trivial. if (base) { SILValue temporary = materialized.temporary.getValue(); materialized.temporary = ManagedValue::forUnmanaged( gen.B.createMarkDependence(loc, temporary, base.getValue())); } // TODO: maybe needsWriteback should be a thin function pointer // to which we pass the base? That would let us use direct // access for stored properties with didSet. pushWriteback(gen, loc, std::move(clonedComponent), base, materialized); return ManagedValue::forLValue(materialized.temporary.getValue()); } void writeback(SILGenFunction &gen, SILLocation loc, ManagedValue base, MaterializedLValue materialized, bool isFinal) override { // If we don't have a callback, we don't have to conditionalize // the writeback. if (!materialized.callback) { LogicalPathComponent::writeback(gen, loc, base, materialized, isFinal); return; } // Otherwise, 'materialized' holds an optional callback and the // callback storage. // Mark the writeback as auto-generated so that we don't get // warnings if we manage to devirtualize materializeForSet. loc.markAutoGenerated(); ASTContext &ctx = gen.getASTContext(); SILBasicBlock *contBB = gen.createBasicBlock(); SILBasicBlock *writebackBB = gen.createBasicBlock(gen.B.getInsertionBB()); gen.B.createSwitchEnum(loc, materialized.callback, /*defaultDest*/ nullptr, { { ctx.getOptionalSomeDecl(), writebackBB }, { ctx.getOptionalNoneDecl(), contBB } }); // The writeback block. gen.B.setInsertionPoint(writebackBB); { FullExpr scope(gen.Cleanups, CleanupLocation::get(loc)); auto emptyTupleTy = SILType::getPrimitiveObjectType(TupleType::getEmpty(ctx)); SILType callbackSILType = gen.getLoweredType( materialized.callback->getType().getSwiftRValueType() .getAnyOptionalObjectType()); // The callback is a BB argument from the switch_enum. SILValue callback = writebackBB->createBBArg(callbackSILType); auto callbackType = callbackSILType.castTo(); SILType metatypeType = callbackType->getParameters().back().getSILType(); // We need to borrow the base here. We can't just consume it // because we're in conditionally-executed code (and because // this might be a non-final use). We also need to pass it // indirectly. SILValue baseAddress; SILValue baseMetatype; if (base) { if (base.getType().isAddress()) { baseAddress = base.getValue(); } else { baseAddress = gen.emitTemporaryAllocation(loc, base.getType()); gen.B.createStore(loc, base.getValue(), baseAddress); } baseMetatype = gen.B.createMetatype(loc, metatypeType); // Otherwise, we have to pass something; use an empty tuple // and an undef metatype. } else { baseAddress = SILUndef::get(emptyTupleTy.getAddressType(), gen.SGM.M); baseMetatype = SILUndef::get(metatypeType, gen.SGM.M); } SILValue temporaryPointer = gen.B.createAddressToPointer(loc, materialized.temporary.getValue(), SILType::getRawPointerType(ctx)); // Apply the callback. gen.B.createApply(loc, callback, { temporaryPointer, materialized.callbackStorage, baseAddress, baseMetatype }, false); } // Continue. gen.B.emitBlock(contBB, loc); } RValue get(SILGenFunction &gen, SILLocation loc, ManagedValue base, SGFContext c) && override { SILDeclRef getter = gen.getGetterDeclRef(decl, IsDirectAccessorUse); auto args = std::move(*this).prepareAccessorArgs(gen, loc, base, getter); return gen.emitGetAccessor(loc, getter, substitutions, std::move(args.base), IsSuper, IsDirectAccessorUse, std::move(args.subscripts), c); } std::unique_ptr clone(SILGenFunction &gen, SILLocation loc) const override { LogicalPathComponent *clone = new GetterSetterComponent(*this, gen, loc); return std::unique_ptr(clone); } void print(raw_ostream &OS) const override { printBase(OS, "GetterSetterComponent"); } /// Compare 'this' lvalue and the 'rhs' lvalue (which is guaranteed to have /// the same dynamic PathComponent type as the receiver) to see if they are /// identical. If so, there is a conflicting writeback happening, so emit a /// diagnostic. void diagnoseWritebackConflict(LogicalPathComponent *RHS, SILLocation loc1, SILLocation loc2, SILGenFunction &gen) override { auto &rhs = (GetterSetterComponent&)*RHS; // If the decls match, then this could conflict. if (decl != rhs.decl || IsSuper != rhs.IsSuper) return; // If the decl is monomorphically a stored property, allow aliases. // It could be overridden by a computed property in a subclass, but // that's not likely enough to be worth the strictness here. if (auto storage = dyn_cast(decl)) { switch (storage->getStorageKind()) { case AbstractStorageDecl::Stored: case AbstractStorageDecl::StoredWithTrivialAccessors: case AbstractStorageDecl::Addressed: case AbstractStorageDecl::AddressedWithTrivialAccessors: return; // TODO: Stored properties with didSet accessors that don't look at the // oldValue could also be addressed. case AbstractStorageDecl::StoredWithObservers: case AbstractStorageDecl::AddressedWithObservers: break; case AbstractStorageDecl::InheritedWithObservers: case AbstractStorageDecl::Computed: case AbstractStorageDecl::ComputedWithMutableAddress: break; } } // If the property is a generic requirement, allow aliases, because // it may be conformed to using a stored property. if (isa(decl->getDeclContext())) return; // If this is a simple property access, then we must have a conflict. if (!subscripts) { assert(isa(decl)); gen.SGM.diagnose(loc1, diag::writeback_overlap_property,decl->getName()) .highlight(loc1.getSourceRange()); gen.SGM.diagnose(loc2, diag::writebackoverlap_note) .highlight(loc2.getSourceRange()); return; } // Otherwise, it is a subscript, check the index values. // If the indices are literally identical SILValue's, then there is // clearly a conflict. if (!subscripts.isObviouslyEqual(rhs.subscripts)) { // If the index value doesn't lower to literally the same SILValue's, // do some fuzzy matching to catch the common case. if (!subscriptIndexExpr || !rhs.subscriptIndexExpr || !areCertainlyEqualIndices(subscriptIndexExpr, rhs.subscriptIndexExpr)) return; } // The locations for the subscripts are almost certainly SubscriptExprs. // If so, dig into them to produce better location info in the // diagnostics and be able to do more precise analysis. auto expr1 = loc1.getAsASTNode(); auto expr2 = loc2.getAsASTNode(); if (expr1 && expr2) { gen.SGM.diagnose(loc1, diag::writeback_overlap_subscript) .highlight(expr1->getBase()->getSourceRange()); gen.SGM.diagnose(loc2, diag::writebackoverlap_note) .highlight(expr2->getBase()->getSourceRange()); } else { gen.SGM.diagnose(loc1, diag::writeback_overlap_subscript) .highlight(loc1.getSourceRange()); gen.SGM.diagnose(loc2, diag::writebackoverlap_note) .highlight(loc2.getSourceRange()); } } }; class UnpinPseudoComponent : public LogicalPathComponent { public: UnpinPseudoComponent(const LValueTypeData &typeData) : LogicalPathComponent(typeData, WritebackPseudoKind) {} private: AccessKind getBaseAccessKind(SILGenFunction &SGF, AccessKind accessKind) const override { llvm_unreachable("called getBaseAccessKind on pseudo-component"); } std::unique_ptr clone(SILGenFunction &gen, SILLocation l) const override { llvm_unreachable("called clone on pseudo-component"); } RValue get(SILGenFunction &gen, SILLocation loc, ManagedValue base, SGFContext c) && override { llvm_unreachable("called get on a pseudo-component"); } void set(SILGenFunction &gen, SILLocation loc, RValue &&value, ManagedValue base) && override { llvm_unreachable("called set on a pseudo-component"); } ManagedValue getMaterialized(SILGenFunction &gen, SILLocation loc, ManagedValue base, AccessKind accessKind) && override { llvm_unreachable("called getMaterialized on a pseudo-component"); } void diagnoseWritebackConflict(LogicalPathComponent *rhs, SILLocation loc1, SILLocation loc2, SILGenFunction &gen) override { // do nothing } void writeback(SILGenFunction &gen, SILLocation loc, ManagedValue base, MaterializedLValue materialized, bool isFinal) override { // If this is final, we can consume the owner (stored as // 'base'). If it isn't, we actually need to retain it, because // we've still got a release active. SILValue baseValue = (isFinal ? base.forward(gen) : base.getValue()); if (!isFinal) gen.B.createRetainValue(loc, baseValue); gen.B.createStrongUnpin(loc, baseValue); } void print(raw_ostream &OS) const override { OS << "UnpinPseudoComponent"; } }; /// A physical component which involves calling addressors. class AddressorComponent : public AccessorBasedComponent { SILType SubstFieldType; public: AddressorComponent(AbstractStorageDecl *decl, bool isSuper, bool isDirectAccessorUse, ArrayRef substitutions, CanType baseFormalType, LValueTypeData typeData, SILType substFieldType, Expr *subscriptIndexExpr = nullptr, RValue *subscriptIndex = nullptr) : AccessorBasedComponent(AddressorKind, decl, isSuper, isDirectAccessorUse, substitutions, baseFormalType, typeData, subscriptIndexExpr, subscriptIndex), SubstFieldType(substFieldType) { } SILDeclRef getAccessor(SILGenFunction &gen, AccessKind accessKind) const override { return gen.getAddressorDeclRef(decl, accessKind, IsDirectAccessorUse); } ManagedValue offset(SILGenFunction &gen, SILLocation loc, ManagedValue base, AccessKind accessKind) && override { assert(gen.InWritebackScope && "offsetting l-value for modification without writeback scope"); SILDeclRef addressor = gen.getAddressorDeclRef(decl, accessKind, IsDirectAccessorUse); auto args = std::move(*this).prepareAccessorArgs(gen, loc, base, addressor); auto result = gen.emitAddressorAccessor(loc, addressor, substitutions, std::move(args.base), IsSuper, IsDirectAccessorUse, std::move(args.subscripts), SubstFieldType); switch (cast(addressor.getDecl())->getAddressorKind()) { case AddressorKind::NotAddressor: llvm_unreachable("not an addressor!"); // For unsafe addressors, we have no owner pointer to manage. case AddressorKind::Unsafe: assert(!result.second); return result.first; // For owning addressors, we can just let the owner get released // at an appropriate point. case AddressorKind::Owning: case AddressorKind::NativeOwning: return result.first; // For pinning addressors, we have to push a writeback. case AddressorKind::NativePinning: { std::unique_ptr component(new UnpinPseudoComponent(getTypeData())); pushWriteback(gen, loc, std::move(component), result.second, MaterializedLValue()); return result.first; } } llvm_unreachable("bad addressor kind"); } void print(raw_ostream &OS) const override { printBase(OS, "AddressorComponent"); } }; } // end anonymous namespace. RValue TranslationPathComponent::get(SILGenFunction &gen, SILLocation loc, ManagedValue base, SGFContext c) && { // Load the original value. RValue baseVal(gen, loc, getSubstFormalType(), gen.emitLoad(loc, base.getValue(), gen.getTypeLowering(base.getType()), SGFContext(), IsNotTake)); // Map the base value to its substituted representation. return std::move(*this).translate(gen, loc, std::move(baseVal), c); } void TranslationPathComponent::set(SILGenFunction &gen, SILLocation loc, RValue &&value, ManagedValue base) && { // Map the value to the original pattern. RValue newValue = std::move(*this).untranslate(gen, loc, std::move(value)); // Store to the base. std::move(newValue).assignInto(gen, loc, base.getValue()); } namespace { /// Remap an lvalue referencing a generic type to an lvalue of its /// substituted type in a concrete context. class OrigToSubstComponent : public TranslationPathComponent { AbstractionPattern OrigType; public: OrigToSubstComponent(AbstractionPattern origType, CanType substFormalType, SILType loweredSubstType) : TranslationPathComponent({ AbstractionPattern(substFormalType), substFormalType, loweredSubstType }, OrigToSubstKind), OrigType(origType) {} RValue untranslate(SILGenFunction &gen, SILLocation loc, RValue &&rv, SGFContext c) && override { return gen.emitSubstToOrigValue(loc, std::move(rv), OrigType, getSubstFormalType(), c); } RValue translate(SILGenFunction &gen, SILLocation loc, RValue &&rv, SGFContext c) && override { return gen.emitOrigToSubstValue(loc, std::move(rv), OrigType, getSubstFormalType(), c); } std::unique_ptr clone(SILGenFunction &gen, SILLocation loc) const override { LogicalPathComponent *clone = new OrigToSubstComponent(OrigType, getSubstFormalType(), getTypeOfRValue()); return std::unique_ptr(clone); } void print(raw_ostream &OS) const override { OS << "OrigToSubstComponent(" << getOrigFormalType() << ", " << getSubstFormalType() << ", " << getTypeOfRValue() << ")\n"; } }; /// Remap an lvalue referencing a concrete type to an lvalue of a /// generically-reabstracted type. class SubstToOrigComponent : public TranslationPathComponent { public: SubstToOrigComponent(AbstractionPattern origType, CanType substFormalType, SILType loweredSubstType) : TranslationPathComponent({ origType, substFormalType, loweredSubstType }, SubstToOrigKind) {} RValue untranslate(SILGenFunction &gen, SILLocation loc, RValue &&rv, SGFContext c) && override { return gen.emitOrigToSubstValue(loc, std::move(rv), getOrigFormalType(), getSubstFormalType(), c); } RValue translate(SILGenFunction &gen, SILLocation loc, RValue &&rv, SGFContext c) && override { return gen.emitSubstToOrigValue(loc, std::move(rv), getOrigFormalType(), getSubstFormalType(), c); } std::unique_ptr clone(SILGenFunction &gen, SILLocation loc) const override { LogicalPathComponent *clone = new SubstToOrigComponent(getOrigFormalType(), getSubstFormalType(), getTypeOfRValue()); return std::unique_ptr(clone); } void print(raw_ostream &OS) const override { OS << "SubstToOrigComponent(" << getOrigFormalType() << ", " << getSubstFormalType() << ", " << getTypeOfRValue() << ")\n"; } }; /// Remap a weak value to Optional*, or unowned pointer to T*. class OwnershipComponent : public LogicalPathComponent { public: OwnershipComponent(LValueTypeData typeData) : LogicalPathComponent(typeData, OwnershipKind) { } AccessKind getBaseAccessKind(SILGenFunction &gen, AccessKind kind) const override { // Always use the same access kind for the base. return kind; } void diagnoseWritebackConflict(LogicalPathComponent *RHS, SILLocation loc1, SILLocation loc2, SILGenFunction &gen) override { // no useful writeback diagnostics at this point } RValue get(SILGenFunction &gen, SILLocation loc, ManagedValue base, SGFContext c) && override { assert(base && "ownership component must not be root of lvalue path"); auto &TL = gen.getTypeLowering(getTypeOfRValue()); // Load the original value. ManagedValue result = gen.emitLoad(loc, base.getValue(), TL, SGFContext(), IsNotTake); return RValue(gen, loc, getSubstFormalType(), result); } void set(SILGenFunction &gen, SILLocation loc, RValue &&value, ManagedValue base) && override { assert(base && "ownership component must not be root of lvalue path"); auto &TL = gen.getTypeLowering(base.getType()); gen.emitSemanticStore(loc, std::move(value).forwardAsSingleValue(gen, loc), base.getValue(), TL, IsNotInitialization); } std::unique_ptr clone(SILGenFunction &gen, SILLocation loc) const override { LogicalPathComponent *clone = new OwnershipComponent(getTypeData()); return std::unique_ptr(clone); } void print(raw_ostream &OS) const override { OS << "OwnershipComponent(...)\n"; } }; } // end anonymous namespace. LValue LValue::forValue(ManagedValue value, CanType substFormalType) { assert(value.getType().isObject()); LValueTypeData typeData = getValueTypeData(substFormalType, value.getValue()); LValue lv; lv.add(value, typeData); return lv; } LValue LValue::forAddress(ManagedValue address, AbstractionPattern origFormalType, CanType substFormalType) { assert(address.isLValue()); LValueTypeData typeData = { origFormalType, substFormalType, address.getType().getObjectType() }; LValue lv; lv.add(address, typeData); return lv; } LValue LValue::forClassReference(ManagedValue ref) { assert(ref.isPlusZeroRValueOrTrivial()); assert(ref.getType().isObject()); assert(ref.getType().getSwiftRValueType()->mayHaveSuperclass()); CanType classType = ref.getType().getSwiftRValueType(); LValueTypeData typeData = { AbstractionPattern(classType), classType, ref.getType() }; LValue lv; lv.add(ref, typeData); return lv; } void LValue::addMemberComponent(SILGenFunction &gen, SILLocation loc, AbstractStorageDecl *storage, ArrayRef subs, bool isSuper, AccessKind accessKind, AccessSemantics accessSemantics, AccessStrategy accessStrategy, CanType formalRValueType, RValue &&indices) { if (auto var = dyn_cast(storage)) { assert(!indices); addMemberVarComponent(gen, loc, var, subs, isSuper, accessKind, accessSemantics, accessStrategy, formalRValueType); } else { auto subscript = cast(storage); addMemberSubscriptComponent(gen, loc, subscript, subs, isSuper, accessKind, accessSemantics, accessStrategy, formalRValueType, std::move(indices)); } } void LValue::addOrigToSubstComponent(SILType loweredSubstType) { loweredSubstType = loweredSubstType.getObjectType(); assert(getTypeOfRValue() != loweredSubstType && "reabstraction component is unnecessary!"); // Peephole away complementary reabstractions. assert(!Path.empty() && "adding translation component to empty l-value"); if (Path.back()->getKind() == PathComponent::SubstToOrigKind) { // But only if the lowered type matches exactly. if (Path[Path.size()-2]->getTypeOfRValue() == loweredSubstType) { Path.pop_back(); return; } // TODO: combine reabstractions; this doesn't matter all that much // for most things, but it can be dramatically better for function // reabstraction. } add(getOrigFormalType(), getSubstFormalType(), loweredSubstType); } void LValue::addSubstToOrigComponent(AbstractionPattern origType, SILType loweredSubstType) { loweredSubstType = loweredSubstType.getObjectType(); assert(getTypeOfRValue() != loweredSubstType && "reabstraction component is unnecessary!"); // Peephole away complementary reabstractions. assert(!Path.empty() && "adding translation component to empty l-value"); if (Path.back()->getKind() == PathComponent::OrigToSubstKind) { // But only if the lowered type matches exactly. if (Path[Path.size()-2]->getTypeOfRValue() == loweredSubstType) { Path.pop_back(); return; } // TODO: combine reabstractions; this doesn't matter all that much // for most things, but it can be dramatically better for function // reabstraction. } add(origType, getSubstFormalType(), loweredSubstType); } void LValue::dump() const { print(llvm::errs()); } void LValue::print(raw_ostream &OS) const { for (const auto &component : *this) { component->print(OS); } } LValue SILGenFunction::emitLValue(Expr *e, AccessKind accessKind) { LValue r = SILGenLValue(*this).visit(e, accessKind); // If the final component has an abstraction change, introduce a // reabstraction component. auto substFormalType = r.getSubstFormalType(); auto loweredSubstType = getLoweredType(substFormalType); if (r.getTypeOfRValue() != loweredSubstType.getObjectType()) { // Logical components always re-abstract back to the substituted // type. assert(r.isLastComponentPhysical()); r.addOrigToSubstComponent(loweredSubstType); } return r; } LValue SILGenLValue::visitRec(Expr *e, AccessKind accessKind) { // Non-lvalue types (references, values, metatypes, etc) form the root of a // logical l-value. if (!e->getType()->is() && !e->getType()->is()) { // Decide if we can evaluate this expression at +0 for the rest of the // lvalue. SGFContext Ctx; // Calls through opaque protocols can be done with +0 rvalues. This allows // us to avoid materializing copies of existentials. if (gen.SGM.Types.isIndirectPlusZeroSelfParameter(e->getType())) Ctx = SGFContext::AllowGuaranteedPlusZero; else if (auto *DRE = dyn_cast(e)) { // Any reference to "self" can be done at +0 so long as it is a direct // access, since we know it is guaranteed. // TODO: it would be great to factor this even lower into SILGen to the // point where we can see that the parameter is +0 guaranteed. Note that // this handles the case in initializers where there is actually a stack // allocation for it as well. if (isa(DRE->getDecl()) && DRE->getDecl()->getName().str() == "self" && DRE->getDecl()->isImplicit()) { Ctx = SGFContext::AllowGuaranteedPlusZero; } else if (auto *VD = dyn_cast(DRE->getDecl())) { // All let values are guaranteed to be held alive across their lifetime, // and won't change once initialized. Any loaded value is good for the // duration of this expression evaluation. if (VD->isLet()) Ctx = SGFContext::AllowGuaranteedPlusZero; } } ManagedValue rv = gen.emitRValueAsSingleValue(e, Ctx); CanType formalType = getSubstFormalRValueType(e); auto typeData = getValueTypeData(formalType, rv.getValue()); LValue lv; lv.add(rv, typeData); return lv; } return visit(e, accessKind); } LValue SILGenLValue::visitExpr(Expr *e, AccessKind accessKind) { e->dump(llvm::errs()); llvm_unreachable("unimplemented lvalue expr"); } static ArrayRef getNonMemberVarDeclSubstitutions(SILGenModule &SGM, VarDecl *var) { ArrayRef substitutions; if (auto genericParams = var->getDeclContext()->getGenericParamsOfContext()) substitutions = genericParams->getForwardingSubstitutions(SGM.getASTContext()); return substitutions; } // For now, we don't need either an AccessKind or an // AccessSemantics, because addressors are always directly // dispatched. static void addNonMemberVarDeclAddressorComponent(SILGenModule &SGM, VarDecl *var, CanType formalRValueType, LValue &lvalue) { assert(!lvalue.isValid()); auto typeData = getPhysicalStorageTypeData(SGM, var, formalRValueType); SILType storageType = SGM.Types.getLoweredType(var->getType()).getAddressType(); lvalue.add(var, /*isSuper=*/ false, /*direct*/ true, getNonMemberVarDeclSubstitutions(SGM, var), CanType(), typeData, storageType); } LValue SILGenFunction::emitLValueForAddressedNonMemberVarDecl(SILLocation loc, VarDecl *var, CanType formalRValueType, AccessKind accessKind, AccessSemantics semantics) { LValue lv; addNonMemberVarDeclAddressorComponent(SGM, var, formalRValueType, lv); return lv; } static LValue emitLValueForNonMemberVarDecl(SILGenFunction &gen, SILLocation loc, VarDecl *var, CanType formalRValueType, AccessKind accessKind, AccessSemantics semantics) { LValue lv; switch (var->getAccessStrategy(semantics, accessKind)) { case AccessStrategy::DispatchToAccessor: llvm_unreachable("can't polymorphically access non-member variable"); // If it's a computed variable, push a reference to the getter and setter. case AccessStrategy::DirectToAccessor: { auto typeData = getLogicalStorageTypeData(gen.SGM, formalRValueType); lv.add(var, /*isSuper=*/false, /*direct*/ true, getNonMemberVarDeclSubstitutions(gen.SGM, var), CanType(), typeData); break; } case AccessStrategy::Addressor: { addNonMemberVarDeclAddressorComponent(gen.SGM, var, formalRValueType, lv); break; } case AccessStrategy::Storage: { // If it's a physical value (e.g. a local variable in memory), push its // address. auto address = gen.emitLValueForDecl(loc, var, formalRValueType, accessKind, semantics); assert(address.isLValue() && "physical lvalue decl ref must evaluate to an address"); auto typeData = getPhysicalStorageTypeData(gen.SGM, var, formalRValueType); lv.add(address, typeData); if (address.getType().is()) lv.add(typeData); break; } } return lv; } LValue SILGenLValue::visitDiscardAssignmentExpr(DiscardAssignmentExpr *e, AccessKind accessKind) { LValueTypeData typeData = getValueTypeData(gen, e); SILValue address = gen.emitTemporaryAllocation(e, typeData.TypeOfRValue); address = gen.B.createMarkUninitialized(e, address, MarkUninitializedInst::Var); gen.enterDestroyCleanup(address); LValue lv; lv.add(ManagedValue::forUnmanaged(address), typeData); return lv; } LValue SILGenLValue::visitDeclRefExpr(DeclRefExpr *e, AccessKind accessKind) { // The only non-member decl that can be an lvalue is VarDecl. return emitLValueForNonMemberVarDecl(gen, e, cast(e->getDecl()), getSubstFormalRValueType(e), accessKind, e->getAccessSemantics()); } LValue SILGenLValue::visitOpaqueValueExpr(OpaqueValueExpr *e, AccessKind accessKind) { // Handle an opaque lvalue that refers to an opened existential. auto known = openedExistentials.find(e); if (known != openedExistentials.end()) { // Dig the open-existential expression out of the list. OpenExistentialExpr *opened = known->second; openedExistentials.erase(known); // Do formal evaluation of the underlying existential lvalue. LValue existentialLV = visitRec(opened->getExistentialValue(), accessKind); ManagedValue existentialAddr = gen.emitAddressOfLValue(e, std::move(existentialLV), accessKind); // Open up the existential. LValue lv; lv.add(existentialAddr, existentialLV.getTypeData()); lv.add( cast(opened->getOpenedArchetype()->getCanonicalType())); return lv; } assert(gen.OpaqueValues.count(e) && "Didn't bind OpaqueValueExpr"); auto &entry = gen.OpaqueValues.find(e)->second; assert(!entry.HasBeenConsumed && "opaque value already consumed"); entry.HasBeenConsumed = true; LValue lv; lv.add(entry.Value.borrow(), getValueTypeData(gen, e)); return lv; } LValue SILGenLValue::visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *e, AccessKind accessKind) { gen.emitIgnoredExpr(e->getLHS()); return visitRec(e->getRHS(), accessKind); } static AccessKind getBaseAccessKindForAccessor(FuncDecl *accessor) { if (accessor->isMutating()) { return AccessKind::ReadWrite; } else { return AccessKind::Read; } } /// Return the appropriate access kind for the base l-value of a /// particular member, which is being accessed in a particular way. static AccessKind getBaseAccessKind(AbstractStorageDecl *member, AccessKind accessKind, AccessStrategy strategy) { switch (strategy) { // Assume that the member only partially projects the enclosing value. case AccessStrategy::Storage: return (accessKind == AccessKind::Read ? AccessKind::Read : AccessKind::ReadWrite); case AccessStrategy::Addressor: return getBaseAccessKindForAccessor( member->getAddressorForAccess(accessKind)); case AccessStrategy::DirectToAccessor: case AccessStrategy::DispatchToAccessor: if (accessKind == AccessKind::Read) { return getBaseAccessKindForAccessor(member->getGetter()); } else { return getBaseAccessKindForAccessor(member->getSetter()); } } llvm_unreachable("bad access strategy"); } LValue SILGenLValue::visitMemberRefExpr(MemberRefExpr *e, AccessKind accessKind) { // MemberRefExpr can refer to type and function members, but the only case // that can be an lvalue is a VarDecl. VarDecl *var = cast(e->getMember().getDecl()); AccessStrategy strategy = var->getAccessStrategy(e->getAccessSemantics(), accessKind); LValue lv = visitRec(e->getBase(), getBaseAccessKind(var, accessKind, strategy)); assert(lv.isValid()); CanType substFormalRValueType = getSubstFormalRValueType(e); lv.addMemberVarComponent(gen, e, var, e->getMember().getSubstitutions(), e->isSuper(), accessKind, e->getAccessSemantics(), strategy, substFormalRValueType); return lv; } void LValue::addMemberVarComponent(SILGenFunction &gen, SILLocation loc, VarDecl *var, ArrayRef subs, bool isSuper, AccessKind accessKind, AccessSemantics accessSemantics, AccessStrategy strategy, CanType formalRValueType) { CanType baseFormalType = getSubstFormalType(); // Use the property accessors if the variable has accessors and this isn't a // direct access to underlying storage. if (strategy == AccessStrategy::DirectToAccessor || strategy == AccessStrategy::DispatchToAccessor) { auto typeData = getLogicalStorageTypeData(gen.SGM, formalRValueType); add(var, isSuper, strategy == AccessStrategy::DirectToAccessor, subs, baseFormalType, typeData); return; } assert(strategy == AccessStrategy::Addressor || strategy == AccessStrategy::Storage); // Otherwise, the lvalue access is performed with a fragile element reference. // Find the substituted storage type. SILType varStorageType = gen.SGM.Types.getSubstitutedStorageType(var, formalRValueType); // For static variables, emit a reference to the global variable backing // them. // FIXME: This has to be dynamically looked up for classes, and // dynamically instantiated for generics. if (strategy == AccessStrategy::Storage && var->isStatic()) { auto baseMeta = baseFormalType->castTo()->getInstanceType(); (void)baseMeta; assert(!baseMeta->is() && "generic static stored properties not implemented"); // FIXME: this implicitly drops the earlier components, but maybe // we ought to evaluate them for side-effects even during the // formal access? *this = emitLValueForNonMemberVarDecl(gen, loc, var, formalRValueType, accessKind, accessSemantics); return; } auto typeData = getPhysicalStorageTypeData(gen.SGM, var, formalRValueType); // For member variables, this access is done w.r.t. a base computation that // was already emitted. This member is accessed off of it. if (strategy == AccessStrategy::Addressor) { add(var, isSuper, /*direct*/ true, subs, baseFormalType, typeData, varStorageType); } else if (baseFormalType->mayHaveSuperclass()) { add(var, varStorageType, typeData); } else { assert(baseFormalType->getStructOrBoundGenericStruct()); add(var, varStorageType, typeData); } // If the member has weak or unowned storage, convert it away. if (varStorageType.is()) { add(typeData); } } LValue SILGenLValue::visitSubscriptExpr(SubscriptExpr *e, AccessKind accessKind) { auto decl = cast(e->getDecl().getDecl()); auto accessSemantics = e->getAccessSemantics(); auto strategy = decl->getAccessStrategy(accessSemantics, accessKind); LValue lv = visitRec(e->getBase(), getBaseAccessKind(decl, accessKind, strategy)); assert(lv.isValid()); Expr *indexExpr = e->getIndex(); // FIXME: This admits varargs tuples, which should only be handled as part of // argument emission. RValue index = gen.emitRValue(indexExpr); CanType formalRValueType = getSubstFormalRValueType(e); lv.addMemberSubscriptComponent(gen, e, decl, e->getDecl().getSubstitutions(), e->isSuper(), accessKind, accessSemantics, strategy, formalRValueType, std::move(index), indexExpr); return lv; } void LValue::addMemberSubscriptComponent(SILGenFunction &gen, SILLocation loc, SubscriptDecl *decl, ArrayRef subs, bool isSuper, AccessKind accessKind, AccessSemantics accessSemantics, AccessStrategy strategy, CanType formalRValueType, RValue &&indices, Expr *indexExprForDiagnostics) { CanType baseFormalType = getSubstFormalType(); if (strategy == AccessStrategy::DirectToAccessor || strategy == AccessStrategy::DispatchToAccessor) { auto typeData = getLogicalStorageTypeData(gen.SGM, formalRValueType); add(decl, isSuper, strategy == AccessStrategy::DirectToAccessor, subs, baseFormalType, typeData, indexExprForDiagnostics, &indices); } else { assert(strategy == AccessStrategy::Addressor); auto typeData = getPhysicalStorageTypeData(gen.SGM, decl, formalRValueType); auto storageType = gen.SGM.Types.getSubstitutedStorageType(decl, formalRValueType); add(decl, isSuper, /*direct*/ true, subs, baseFormalType, typeData, storageType, indexExprForDiagnostics, &indices); } } LValue SILGenLValue::visitTupleElementExpr(TupleElementExpr *e, AccessKind accessKind) { unsigned index = e->getFieldNumber(); LValue lv = visitRec(e->getBase(), accessKind == AccessKind::Read ? AccessKind::Read : AccessKind::ReadWrite); auto baseTypeData = lv.getTypeData(); LValueTypeData typeData = { baseTypeData.OrigFormalType.getTupleElementType(index), cast(baseTypeData.SubstFormalType).getElementType(index), baseTypeData.TypeOfRValue.getTupleElementType(index) }; lv.add(index, typeData); return lv; } LValue SILGenLValue::visitOpenExistentialExpr(OpenExistentialExpr *e, AccessKind accessKind) { // If the opaque value is not an lvalue, open the existential immediately. if (!e->getOpaqueValue()->getType()->is()) { return gen.emitOpenExistentialExpr(e, [&](Expr *subExpr) -> LValue { return visitRec(subExpr, accessKind); }); } // Record the fact that we're opening this existential. The actual // opening operation will occur when we see the OpaqueValueExpr. bool inserted = openedExistentials.insert({e->getOpaqueValue(), e}).second; (void)inserted; assert(inserted && "already have this opened existential?"); // Visit the subexpression. LValue lv = visitRec(e->getSubExpr(), accessKind); // Sanity check that we did see the OpaqueValueExpr. assert(openedExistentials.count(e->getOpaqueValue()) == 0 && "opened existential not removed?"); return lv; } static LValueTypeData getOptionalObjectTypeData(SILGenFunction &gen, const LValueTypeData &baseTypeData) { OptionalTypeKind otk; CanType objectTy = baseTypeData.SubstFormalType.getAnyOptionalObjectType(otk); assert(objectTy); EnumElementDecl *someDecl = gen.getASTContext().getOptionalSomeDecl(otk); return { gen.SGM.M.Types.getAbstractionPattern(someDecl), objectTy, baseTypeData.TypeOfRValue.getEnumElementType(someDecl, gen.SGM.M), }; } LValue SILGenLValue::visitForceValueExpr(ForceValueExpr *e, AccessKind accessKind) { LValue lv = visitRec(e->getSubExpr(), accessKind); LValueTypeData typeData = getOptionalObjectTypeData(gen, lv.getTypeData()); lv.add(typeData); return lv; } LValue SILGenLValue::visitBindOptionalExpr(BindOptionalExpr *e, AccessKind accessKind) { // Do formal evaluation of the base l-value. LValue optLV = visitRec(e->getSubExpr(), accessKind); LValueTypeData optTypeData = optLV.getTypeData(); LValueTypeData valueTypeData = getOptionalObjectTypeData(gen, optTypeData); // The chaining operator immediately begins a formal access to the // base l-value. In concrete terms, this means we can immediately // evaluate the base down to an address. ManagedValue optAddr = gen.emitAddressOfLValue(e, std::move(optLV), accessKind); // Bind the value, branching to the destination address if there's no // value there. gen.emitBindOptional(e, optAddr, e->getDepth()); // Project out the payload on the success branch. We can just use a // naked ValueComponent here; this is effectively a separate l-value. ManagedValue valueAddr = getAddressOfOptionalValue(gen, e, optAddr, valueTypeData); LValue valueLV; valueLV.add(valueAddr, valueTypeData); return valueLV; } LValue SILGenLValue::visitInOutExpr(InOutExpr *e, AccessKind accessKind) { return visitRec(e->getSubExpr(), accessKind); } /// Emit an lvalue that refers to the given property. This is /// designed to work with ManagedValue 'base's that are either +0 or +1. LValue SILGenFunction::emitPropertyLValue(SILLocation loc, ManagedValue base, CanType baseFormalType, VarDecl *ivar, AccessKind accessKind, AccessSemantics semantics) { SILGenLValue sgl(*this); LValue lv; ArrayRef subs; if (auto genericType = base.getType().getAs()) { subs = genericType->getSubstitutions(SGM.SwiftModule, nullptr); } LValueTypeData baseTypeData = getValueTypeData(baseFormalType, base.getValue()); // Refer to 'self' as the base of the lvalue. lv.add(base, baseTypeData); auto substFormalType = base.getType().getSwiftRValueType() ->getTypeOfMember(F.getModule().getSwiftModule(), ivar, nullptr) ->getCanonicalType(); AccessStrategy strategy = ivar->getAccessStrategy(semantics, accessKind); // Use the property accessors if the variable has accessors and this // isn't a direct access to underlying storage. if (strategy == AccessStrategy::DirectToAccessor || strategy == AccessStrategy::DispatchToAccessor) { auto typeData = getLogicalStorageTypeData(SGM, substFormalType); lv.add(ivar, /*super*/ false, strategy == AccessStrategy::DirectToAccessor, subs, baseFormalType, typeData); return lv; } assert(strategy == AccessStrategy::Addressor || strategy == AccessStrategy::Storage); // Find the substituted storage type. SILType varStorageType = SGM.Types.getSubstitutedStorageType(ivar, substFormalType); auto typeData = getPhysicalStorageTypeData(SGM, ivar, substFormalType); if (strategy == AccessStrategy::Addressor) { lv.add(ivar, /*super*/ false, /*direct*/ true, subs, baseFormalType, typeData, varStorageType); } else if (baseFormalType->hasReferenceSemantics()) { lv.add(ivar, varStorageType, typeData); } else { lv.add(ivar, varStorageType, typeData); } if (varStorageType.is()) { auto formalRValueType = ivar->getType()->getRValueType()->getReferenceStorageReferent() ->getCanonicalType(); auto typeData = getPhysicalStorageTypeData(SGM, ivar, formalRValueType); lv.add(typeData); } return lv; } /// Load an r-value out of the given address. /// /// \param rvalueTL - the type lowering for the type-of-rvalue /// of the address /// \param isGuaranteedValid - true if the value in this address /// is guaranteed to be valid for the duration of the current /// evaluation (see SGFContext::AllowGuaranteedPlusZero) ManagedValue SILGenFunction::emitLoad(SILLocation loc, SILValue addr, const TypeLowering &rvalueTL, SGFContext C, IsTake_t isTake, bool isGuaranteedValid) { // Get the lowering for the address type. We can avoid a re-lookup // in the very common case of this being equivalent to the r-value // type. auto &addrTL = (addr->getType() == rvalueTL.getLoweredType().getAddressType() ? rvalueTL : getTypeLowering(addr->getType())); // Never do a +0 load together with a take. bool isPlusZeroOk = (isTake == IsNotTake && (isGuaranteedValid ? C.isGuaranteedPlusZeroOk() : C.isImmediatePlusZeroOk())); if (rvalueTL.isAddressOnly()) { // If the client is cool with a +0 rvalue, the decl has an address-only // type, and there are no conversions, then we can return this as a +0 // address RValue. if (isPlusZeroOk && rvalueTL.getLoweredType() == addrTL.getLoweredType()) return ManagedValue::forUnmanaged(addr); // Copy the address-only value. SILValue copy = getBufferForExprResult(loc, rvalueTL.getLoweredType(), C); emitSemanticLoadInto(loc, addr, addrTL, copy, rvalueTL, isTake, IsInitialization); return manageBufferForExprResult(copy, rvalueTL, C); } // Ok, this is something loadable. If this is a non-take access at plus zero, // we can perform a +0 load of the address instead of materializing a +1 // value. if (isPlusZeroOk && addrTL.getLoweredType() == rvalueTL.getLoweredType()) { return ManagedValue::forUnmanaged(B.createLoad(loc, addr)); } // Load the loadable value, and retain it if we aren't taking it. SILValue loadedV = emitSemanticLoad(loc, addr, addrTL, rvalueTL, isTake); return emitManagedRValueWithCleanup(loadedV, rvalueTL); } static void emitUnloweredStoreOfCopy(SILGenBuilder &B, SILLocation loc, SILValue value, SILValue addr, IsInitialization_t isInit) { if (isInit) B.createStore(loc, value, addr); else B.createAssign(loc, value, addr); } SILValue SILGenFunction::emitConversionToSemanticRValue(SILLocation loc, SILValue src, const TypeLowering &valueTL) { // Weak storage types are handled with their underlying type. assert(!src->getType().is() && "weak pointers are always the right optional types"); // For @unowned(safe) types, we need to generate a strong retain and // strip the unowned box. if (auto unownedType = src->getType().getAs()) { assert(unownedType->isLoadable(ResilienceExpansion::Maximal)); (void) unownedType; B.createStrongRetainUnowned(loc, src); return B.createUnownedToRef(loc, src, SILType::getPrimitiveObjectType(unownedType.getReferentType())); } // For @unowned(unsafe) types, we need to strip the unmanaged box // and then do an (unsafe) retain. if (auto unmanagedType = src->getType().getAs()) { auto result = B.createUnmanagedToRef(loc, src, SILType::getPrimitiveObjectType(unmanagedType.getReferentType())); B.createStrongRetain(loc, result); return result; } llvm_unreachable("unexpected storage type that differs from type-of-rvalue"); } /// Given that the type-of-rvalue differs from the type-of-storage, /// and given that the type-of-rvalue is loadable, produce a +1 scalar /// of the type-of-rvalue. static SILValue emitLoadOfSemanticRValue(SILGenFunction &gen, SILLocation loc, SILValue src, const TypeLowering &valueTL, IsTake_t isTake) { SILType storageType = src->getType(); // For @weak types, we need to create an Optional. // Optional is currently loadable, but it probably won't be forever. if (storageType.is()) return gen.B.createLoadWeak(loc, src, isTake); // For @unowned(safe) types, we need to strip the unowned box. if (auto unownedType = storageType.getAs()) { if (!unownedType->isLoadable(ResilienceExpansion::Maximal)) { return gen.B.createLoadUnowned(loc, src, isTake); } auto unownedValue = gen.B.createLoad(loc, src); gen.B.createStrongRetainUnowned(loc, unownedValue); if (isTake) gen.B.createUnownedRelease(loc, unownedValue); return gen.B.createUnownedToRef(loc, unownedValue, SILType::getPrimitiveObjectType(unownedType.getReferentType())); } // For @unowned(unsafe) types, we need to strip the unmanaged box. if (auto unmanagedType = src->getType().getAs()) { auto value = gen.B.createLoad(loc, src); auto result = gen.B.createUnmanagedToRef(loc, value, SILType::getPrimitiveObjectType(unmanagedType.getReferentType())); gen.B.createStrongRetain(loc, result); return result; } // NSString * must be bridged to String. if (storageType.getSwiftRValueType() == gen.SGM.Types.getNSStringType()) { auto nsstr = gen.B.createLoad(loc, src); auto str = gen.emitBridgedToNativeValue(loc, ManagedValue::forUnmanaged(nsstr), SILFunctionTypeRepresentation::CFunctionPointer, gen.SGM.Types.getStringType()); return str.forward(gen); } llvm_unreachable("unexpected storage type that differs from type-of-rvalue"); } /// Given that the type-of-rvalue differs from the type-of-storage, /// store a +1 value (possibly not a scalar) of the type-of-rvalue /// into the given address. static void emitStoreOfSemanticRValue(SILGenFunction &gen, SILLocation loc, SILValue value, SILValue dest, const TypeLowering &valueTL, IsInitialization_t isInit) { auto storageType = dest->getType(); // For @weak types, we need to break down an Optional and then // emit the storeWeak ourselves. if (storageType.is()) { gen.B.createStoreWeak(loc, value, dest, isInit); // store_weak doesn't take ownership of the input, so cancel it out. gen.B.emitReleaseValueAndFold(loc, value); return; } // For @unowned(safe) types, we need to enter the unowned box by // turning the strong retain into an unowned retain. if (auto unownedType = storageType.getAs()) { // FIXME: resilience if (!unownedType->isLoadable(ResilienceExpansion::Maximal)) { gen.B.createStoreUnowned(loc, value, dest, isInit); // store_unowned doesn't take ownership of the input, so cancel it out. gen.B.emitStrongReleaseAndFold(loc, value); return; } auto unownedValue = gen.B.createRefToUnowned(loc, value, storageType.getObjectType()); gen.B.createUnownedRetain(loc, unownedValue); emitUnloweredStoreOfCopy(gen.B, loc, unownedValue, dest, isInit); gen.B.emitStrongReleaseAndFold(loc, value); return; } // For @unowned(unsafe) types, we need to enter the unmanaged box and // release the strong retain. if (storageType.is()) { auto unmanagedValue = gen.B.createRefToUnmanaged(loc, value, storageType.getObjectType()); emitUnloweredStoreOfCopy(gen.B, loc, unmanagedValue, dest, isInit); gen.B.emitStrongReleaseAndFold(loc, value); return; } llvm_unreachable("unexpected storage type that differs from type-of-rvalue"); } /// Load a value of the type-of-rvalue out of the given address as a /// scalar. The type-of-rvalue must be loadable. SILValue SILGenFunction::emitSemanticLoad(SILLocation loc, SILValue src, const TypeLowering &srcTL, const TypeLowering &rvalueTL, IsTake_t isTake) { assert(srcTL.getLoweredType().getAddressType() == src->getType()); assert(rvalueTL.isLoadable()); // Easy case: the types match. if (srcTL.getLoweredType() == rvalueTL.getLoweredType()) { return srcTL.emitLoadOfCopy(B, loc, src, isTake); } return emitLoadOfSemanticRValue(*this, loc, src, rvalueTL, isTake); } /// Load a value of the type-of-reference out of the given address /// and into the destination address. void SILGenFunction::emitSemanticLoadInto(SILLocation loc, SILValue src, const TypeLowering &srcTL, SILValue dest, const TypeLowering &destTL, IsTake_t isTake, IsInitialization_t isInit) { assert(srcTL.getLoweredType().getAddressType() == src->getType()); assert(destTL.getLoweredType().getAddressType() == dest->getType()); // Easy case: the types match. if (srcTL.getLoweredType() == destTL.getLoweredType()) { B.createCopyAddr(loc, src, dest, isTake, isInit); return; } auto rvalue = emitLoadOfSemanticRValue(*this, loc, src, srcTL, isTake); emitUnloweredStoreOfCopy(B, loc, rvalue, dest, isInit); } /// Store an r-value into the given address as an initialization. void SILGenFunction::emitSemanticStore(SILLocation loc, SILValue rvalue, SILValue dest, const TypeLowering &destTL, IsInitialization_t isInit) { assert(destTL.getLoweredType().getAddressType() == dest->getType()); // Easy case: the types match. if (rvalue->getType() == destTL.getLoweredType()) { assert(destTL.isAddressOnly() == rvalue->getType().isAddress()); if (rvalue->getType().isAddress()) { B.createCopyAddr(loc, rvalue, dest, IsTake, isInit); } else { emitUnloweredStoreOfCopy(B, loc, rvalue, dest, isInit); } return; } auto &rvalueTL = getTypeLowering(rvalue->getType()); emitStoreOfSemanticRValue(*this, loc, rvalue, dest, rvalueTL, isInit); } /// Convert a semantic rvalue to a value of storage type. SILValue SILGenFunction::emitConversionFromSemanticValue(SILLocation loc, SILValue semanticValue, SILType storageType) { auto &destTL = getTypeLowering(storageType); (void)destTL; // Easy case: the types match. if (semanticValue->getType() == storageType) { return semanticValue; } // @weak types are never loadable, so we don't need to handle them here. // For @unowned types, place into an unowned box. if (auto unownedType = storageType.getAs()) { assert(unownedType->isLoadable(ResilienceExpansion::Maximal)); (void) unownedType; SILValue unowned = B.createRefToUnowned(loc, semanticValue, storageType); B.createUnownedRetain(loc, unowned); B.emitStrongReleaseAndFold(loc, semanticValue); return unowned; } // For @unmanaged types, place into an unmanaged box. if (storageType.is()) { SILValue unmanaged = B.createRefToUnmanaged(loc, semanticValue, storageType); B.emitStrongReleaseAndFold(loc, semanticValue); return unmanaged; } llvm_unreachable("unexpected storage type that differs from type-of-rvalue"); } /// Produce a physical address that corresponds to the given l-value /// component. static ManagedValue drillIntoComponent(SILGenFunction &SGF, SILLocation loc, PathComponent &&component, ManagedValue base, AccessKind accessKind) { ManagedValue addr; if (component.isPhysical()) { addr = std::move(component.asPhysical()).offset(SGF, loc, base, accessKind); } else { auto &lcomponent = component.asLogical(); addr = std::move(lcomponent).getMaterialized(SGF, loc, base, accessKind); } return addr; } /// Find the last component of the given lvalue and derive a base /// location for it. static PathComponent &&drillToLastComponent(SILGenFunction &SGF, SILLocation loc, LValue &&lv, ManagedValue &addr, AccessKind accessKind) { assert(lv.begin() != lv.end() && "lvalue must have at least one component"); // Remember all the access kinds we needed along the path. SmallVector pathAccessKinds; for (auto i = lv.end(), e = lv.begin() + 1; i != e; --i) { pathAccessKinds.push_back(accessKind); accessKind = (*(i-1))->getBaseAccessKind(SGF, accessKind); } for (auto i = lv.begin(), e = lv.end() - 1; i != e; ++i) { addr = drillIntoComponent(SGF, loc, std::move(**i), addr, accessKind); accessKind = pathAccessKinds.pop_back_val(); } return std::move(**(lv.end() - 1)); } RValue SILGenFunction::emitLoadOfLValue(SILLocation loc, LValue &&src, SGFContext C, bool isGuaranteedValid) { // Any writebacks should be scoped to after the load. WritebackScope scope(*this); ManagedValue addr; PathComponent &&component = drillToLastComponent(*this, loc, std::move(src), addr, AccessKind::Read); // If the last component is physical, just drill down and load from it. if (component.isPhysical()) { addr = std::move(component.asPhysical()) .offset(*this, loc, addr, AccessKind::Read); return RValue(*this, loc, src.getSubstFormalType(), emitLoad(loc, addr.getValue(), getTypeLowering(src.getTypeOfRValue()), C, IsNotTake, isGuaranteedValid)); } // If the last component is logical, just emit a get. return std::move(component.asLogical()).get(*this, loc, addr, C); } ManagedValue SILGenFunction::emitAddressOfLValue(SILLocation loc, LValue &&src, AccessKind accessKind) { ManagedValue addr; PathComponent &&component = drillToLastComponent(*this, loc, std::move(src), addr, accessKind); addr = drillIntoComponent(*this, loc, std::move(component), addr, accessKind); assert(addr.getType().isAddress() && "resolving lvalue did not give an address"); return ManagedValue::forLValue(addr.getValue()); } void SILGenFunction::emitAssignToLValue(SILLocation loc, RValue &&src, LValue &&dest) { WritebackScope scope(*this); // Peephole: instead of materializing and then assigning into a // translation component, untransform the value first. if (dest.isLastComponentTranslation()) { // Repeatedly reverse translation components. do { src = std::move(dest.getLastTranslationComponent()) .untranslate(*this, loc, std::move(src)); dest.dropLastTranslationComponent(); } while (dest.isLastComponentTranslation()); } // Resolve all components up to the last, keeping track of value-type logical // properties we need to write back to. ManagedValue destAddr; PathComponent &&component = drillToLastComponent(*this, loc, std::move(dest), destAddr, AccessKind::ReadWrite); // Write to the tail component. if (component.isPhysical()) { auto finalDestAddr = std::move(component.asPhysical()).offset(*this, loc, destAddr, AccessKind::Write); std::move(src).assignInto(*this, loc, finalDestAddr.getValue()); } else { std::move(component.asLogical()).set(*this, loc, std::move(src), destAddr); } // The writeback scope closing will propagate the value back up through the // writeback chain. } void SILGenFunction::emitCopyLValueInto(SILLocation loc, LValue &&src, Initialization *dest) { auto skipPeephole = [&]{ auto loaded = emitLoadOfLValue(loc, std::move(src), SGFContext(dest)); if (!loaded.isInContext()) std::move(loaded).forwardInto(*this, loc, dest); }; // If the source is a physical lvalue, the destination is a single address, // and there's no semantic conversion necessary, do a copy_addr from the // lvalue into the destination. if (!src.isPhysical()) return skipPeephole(); auto destAddr = dest->getAddressOrNull(); if (!destAddr) return skipPeephole(); if (src.getTypeOfRValue().getSwiftRValueType() != destAddr->getType().getSwiftRValueType()) return skipPeephole(); auto srcAddr = emitAddressOfLValue(loc, std::move(src), AccessKind::Read) .getUnmanagedValue(); B.createCopyAddr(loc, srcAddr, destAddr, IsNotTake, IsInitialization); dest->finishInitialization(*this); } void SILGenFunction::emitAssignLValueToLValue(SILLocation loc, LValue &&src, LValue &&dest) { auto skipPeephole = [&]{ RValue loaded = emitLoadOfLValue(loc, std::move(src), SGFContext()); emitAssignToLValue(loc, std::move(loaded), std::move(dest)); }; // Only perform the peephole if both operands are physical and there's no // semantic conversion necessary. if (!src.isPhysical()) return skipPeephole(); if (!dest.isPhysical()) return skipPeephole(); auto srcAddr = emitAddressOfLValue(loc, std::move(src), AccessKind::Read) .getUnmanagedValue(); auto destAddr = emitAddressOfLValue(loc, std::move(dest), AccessKind::Write) .getUnmanagedValue(); if (srcAddr->getType() == destAddr->getType()) { B.createCopyAddr(loc, srcAddr, destAddr, IsNotTake, IsNotInitialization); } else { // If there's a semantic conversion necessary, do a load then assign. auto loaded = emitLoad(loc, srcAddr, getTypeLowering(src.getTypeOfRValue()), SGFContext(), IsNotTake); loaded.assignInto(*this, loc, destAddr); } }