From e07994c9c8f47b85c13f2bc9accedb1dba936de5 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sat, 7 Dec 2013 21:30:38 +0000 Subject: [PATCH] Two changes: - Fix a misunderstanding I had about ownership requirements in my previous patch: now any references to value-promoted self do a retain and use a ManagedValue, just like the semantic load path used to. This is the change to visitLoadExpr - Second, change argument lowering to drop the "self" argument of normal class methods into a constant reference, instead of making a box for it. This greatly reduces the amount of SIL generated for class methods. The argument lowering piece is somewhat hacky because initializations really want to be dealing with memory, but it seemed like the best approach given the current design. Review appreciated. Swift SVN r10984 --- lib/SILGen/SILGenDecl.cpp | 69 +++++++++++++++++++++++++++------------ lib/SILGen/SILGenExpr.cpp | 34 +++++++++++-------- 2 files changed, 68 insertions(+), 35 deletions(-) diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp index 70aaddc3176..e9b507f641e 100644 --- a/lib/SILGen/SILGenDecl.cpp +++ b/lib/SILGen/SILGenDecl.cpp @@ -414,6 +414,14 @@ struct InitializationForPattern if (isa(varType)) return InitializationPtr(new InOutInitialization(vd)); + // If this is a 'self' argument for a class method (not struct method), emit + // it as a constant value. Since it is a constant value, there is no memory + // location associated with it, and thus we don't need an initialization - + // the store will provide the value directly into the VarLocs map. + if (vd->isImplicit() && vd->getName().str() == "self" && + vd->getType()->hasReferenceSemantics()) + return InitializationPtr(new BlackHoleInitialization()); + // Otherwise, we have a normal local-variable initialization. auto varInit = Gen.emitLocalVariableWithCleanup(vd); @@ -484,6 +492,26 @@ CleanupHandle SILGenFunction::enterDeallocStackCleanup(SILLocation loc, return Cleanups.getTopCleanup(); } + +class CleanupCaptureBox : public Cleanup { + SILValue box; +public: + CleanupCaptureBox(SILValue box) : box(box) {} + void emit(SILGenFunction &gen, CleanupLocation l) override { + gen.B.emitStrongRelease(l, box); + } +}; + +class CleanupCaptureValue : public Cleanup { + SILValue v; +public: + CleanupCaptureValue(SILValue v) : v(v) {} + void emit(SILGenFunction &gen, CleanupLocation l) override { + gen.B.emitDestroyValueOperation(l, v); + } +}; + + namespace { /// A visitor for traversing a pattern, creating @@ -608,8 +636,25 @@ struct ArgumentInitVisitor : } SILValue visitNamedPattern(NamedPattern *P, Initialization *I) { - return makeArgumentInto(P->getType(), f.begin(), - P->getDecl(), I); + VarDecl *vd = P->getDecl(); + + // If this is a 'self' argument for a class method (not struct method), emit + // it as a constant value. Since it is a constant value, there is no memory + // location associated with it, and thus we don't need an initialization - + // the store will provide the value directly into the VarLocs map. + if (vd->isImplicit() && vd->getName().str() == "self" && + vd->getType()->hasReferenceSemantics()) { + SILLocation loc = vd; + loc.markAsPrologue(); + SILValue arg = makeArgument(P->getType(), f.begin(), loc); + assert(!gen.VarLocs.count(vd) && "Already emitted a this vardecl?"); + gen.VarLocs[vd] = SILGenFunction::VarLoc::getConstant(arg); + gen.Cleanups.pushCleanup(arg); + I->finishInitialization(gen); + return arg; + } + + return makeArgumentInto(P->getType(), f.begin(), vd, I); } #define PATTERN(Id, Parent) @@ -621,25 +666,7 @@ struct ArgumentInitVisitor : }; -class CleanupCaptureBox : public Cleanup { - SILValue box; -public: - CleanupCaptureBox(SILValue box) : box(box) {} - void emit(SILGenFunction &gen, CleanupLocation l) override { - gen.B.emitStrongRelease(l, box); - } -}; - -class CleanupCaptureValue : public Cleanup { - SILValue v; -public: - CleanupCaptureValue(SILValue v) : v(v) {} - void emit(SILGenFunction &gen, CleanupLocation l) override { - gen.B.emitDestroyValueOperation(l, v); - } -}; - -static void emitCaptureArguments(SILGenFunction &gen, ValueDecl *capture) { +static void emitCaptureArguments(SILGenFunction & gen, ValueDecl *capture) { ASTContext &c = capture->getASTContext(); switch (getDeclCaptureKind(capture)) { case CaptureKind::None: diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 309ed10948c..536d87fda69 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -139,40 +139,38 @@ static void destroyRValue(SILGenFunction &SGF, CleanupLocation loc, } } -/// getLoadPropagatedValue - If a LoadExpr of the specified subexpression will -/// be folded into a constant, return that value. Otherwise, it returns a null -/// SILValue. -static SILValue getLoadPropagatedValue(Expr *SubExpr, SILGenFunction &SGF) { - - // Look through parens. +static VarDecl *isLoadPropagatedValue(Expr *SubExpr, SILGenFunction &SGF) { + // Look through parens. while (auto *PE = dyn_cast(SubExpr)) SubExpr = PE->getSubExpr(); // If this is a load of a local constant decl, just produce the value. if (auto *DRE = dyn_cast(SubExpr)) { if (auto *VD = dyn_cast(DRE->getDecl())) { + // FIXME: This should be a bit on vardecl, not presence in VarLocs. auto It = SGF.VarLocs.find(VD); if (It != SGF.VarLocs.end() && It->second.isConstant()) - return It->second.getConstant(); + return VD; } } // If this is a use of super that is a constant, just produce the value. if (auto *SRE = dyn_cast(SubExpr)) { if (auto *VD = dyn_cast(SRE->getSelf())) { + // FIXME: This should be a bit on vardecl, not presence in VarLocs. auto It = SGF.VarLocs.find(VD); if (It != SGF.VarLocs.end() && It->second.isConstant()) - return It->second.getConstant(); + return VD; } } - - return SILValue(); + return nullptr; } + void SILGenFunction::emitExprInto(Expr *E, Initialization *I) { // Handle the special case of copying an lvalue. if (auto load = dyn_cast(E)) - if (!getLoadPropagatedValue(load->getSubExpr(), *this)) { + if (!isLoadPropagatedValue(load->getSubExpr(), *this)) { auto lv = emitLValue(load->getSubExpr()); emitCopyLValueInto(E, lv, I); return; @@ -578,8 +576,16 @@ RValue RValueEmitter::visitStringLiteralExpr(StringLiteralExpr *E, RValue RValueEmitter::visitLoadExpr(LoadExpr *E, SGFContext C) { // If we can and must fold this, do so. - if (SILValue V = getLoadPropagatedValue(E->getSubExpr(), SGF)) - return RValue(SGF, E, ManagedValue(V, ManagedValue::Unmanaged)); + if (VarDecl *VD = isLoadPropagatedValue(E->getSubExpr(), SGF)) { + auto &Entry = SGF.VarLocs[VD]; + assert(Entry.isConstant() && "Not a load propagated vardecl"); + SILValue V = Entry.getConstant(); + + auto &TL = SGF.getTypeLowering(VD->getType()); + // The value must be copied for the duration of the expression. + V = TL.emitLoweredCopyValue(SGF.B, E, V, false); + return RValue(SGF, E, SGF.emitManagedRValueWithCleanup(V, TL)); + } LValue lv = SGF.emitLValue(E->getSubExpr()); auto result = SGF.emitLoadOfLValue(E, lv, C); @@ -3036,7 +3042,7 @@ RValue RValueEmitter::visitAssignExpr(AssignExpr *E, SGFContext C) { if (auto *LE = dyn_cast(E->getSrc())) { if (!isa(E->getDest()) && E->getDest()->getType()->isEqual(LE->getSubExpr()->getType()) && - !getLoadPropagatedValue(LE->getSubExpr(), SGF)) { + !isLoadPropagatedValue(LE->getSubExpr(), SGF)) { SGF.emitAssignLValueToLValue(E, SGF.emitLValue(cast(E->getSrc())->getSubExpr()), SGF.emitLValue(E->getDest()));