Skip to content

Commit 0b29a9b

Browse files
committed
---
yaml --- r: 346029 b: refs/heads/master c: b7e10c1 h: refs/heads/master i: 346027: a72188e
1 parent 339abad commit 0b29a9b

File tree

18 files changed

+199
-268
lines changed

18 files changed

+199
-268
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
refs/heads/master: c14c5c9af346299cfaecc2ceba85c1406c002a38
2+
refs/heads/master: b7e10c1b676b2fc4fdf7ef010c68eda8f9cbdc8f
33
refs/heads/master-next: 203b3026584ecad859eb328b2e12490099409cd5
44
refs/tags/osx-passed: b6b74147ef8a386f532cf9357a1bde006e552c54
55
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-a: 6bb18e013c2284f2b45f5f84f2df2887dc0f7dea

trunk/include/swift/Basic/Statistic.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
#include <thread>
2222
#include <tuple>
2323

24-
#define SWIFT_FUNC_STAT \
24+
#define SWIFT_FUNC_STAT SWIFT_FUNC_STAT_NAMED(DEBUG_TYPE)
25+
26+
#define SWIFT_FUNC_STAT_NAMED(DEBUG_TYPE) \
2527
do { \
2628
static llvm::Statistic FStat = \
2729
{DEBUG_TYPE, __func__, __func__, {0}, {false}}; \

trunk/include/swift/SIL/SILCloner.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
6767
/// Set of basic blocks where unreachable was inserted.
6868
SmallPtrSet<SILBasicBlock *, 32> BlocksWithUnreachables;
6969

70+
// Keep track of the last cloned block in function order. For single block
71+
// regions, this will be the start block.
72+
SILBasicBlock *lastClonedBB = nullptr;
73+
7074
public:
7175
using SILInstructionVisitor<ImplClass>::asImpl;
7276

@@ -102,6 +106,10 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
102106

103107
SILBuilder &getBuilder() { return Builder; }
104108

109+
// After cloning, returns a non-null pointer to the last cloned block in
110+
// function order. For single block regions, this will be the start block.
111+
SILBasicBlock *getLastClonedBB() { return lastClonedBB; }
112+
105113
/// Visit all blocks reachable from the given `StartBB` and all instructions
106114
/// in those blocks.
107115
///
@@ -655,7 +663,7 @@ void SILCloner<ImplClass>::visitBlocksDepthFirst(SILBasicBlock *startBB) {
655663
// order they are created, which differs from the order they are
656664
// cloned. Blocks are created in BFS order but cloned in DFS preorder (when no
657665
// critical edges are present).
658-
SILBasicBlock *lastClonedBB = BBMap[startBB];
666+
lastClonedBB = BBMap[startBB];
659667
while (!dfsWorklist.empty()) {
660668
auto *BB = dfsWorklist.pop_back_val();
661669
preorderBlocks.push_back(BB);

trunk/include/swift/SILOptimizer/Utils/CFG.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,16 @@ bool splitAllCondBrCriticalEdgesWithNonTrivialArgs(SILFunction &Fn,
127127
bool mergeBasicBlockWithSuccessor(SILBasicBlock *BB, DominanceInfo *DT,
128128
SILLoopInfo *LI);
129129

130+
/// Merge basic blocks in the given function by eliminating all unconditional
131+
/// branches to single-predecessor branch targets.
132+
///
133+
/// During optimization, SimplifyCFG also handles this, but this is a basic
134+
/// canonicalization after any pass that splits blocks, such as inlining. This
135+
/// is not done on-the-fly after splitting blocks because merging is linear in
136+
/// the number of instructions, so interleaved merging and splitting is
137+
/// quadratic.
138+
bool mergeBasicBlocks(SILFunction *F);
139+
130140
/// Given a list of \p UserBlocks and a list of \p DefBlocks, find a set of
131141
/// blocks that together with \p UserBlocks joint-postdominate \p
132142
/// DefBlocks. This is in a sense finding a set of blocks that "complete" \p

trunk/include/swift/SILOptimizer/Utils/SILInliner.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,18 +80,32 @@ class SILInliner {
8080
/// iterator to the first inlined instruction (or first instruction after the
8181
/// call for an empty function).
8282
///
83-
/// This may split basic blocks and delete instructions.
84-
///
8583
/// This only performs one step of inlining: it does not recursively
8684
/// inline functions called by the callee.
8785
///
86+
/// This may split basic blocks and delete instructions anywhere.
87+
///
88+
/// All inlined instructions must be either inside the original call block or
89+
/// inside new basic blocks laid out after the original call block.
90+
///
91+
/// Any instructions in the original call block after the inlined call must be
92+
/// in a new basic block laid out after all inlined blocks.
93+
///
94+
/// The above guarantees ensure that inlining is liner in the number of
95+
/// instructions and that inlined instructions are revisited exactly once.
96+
///
8897
/// *NOTE*: This attempts to perform inlining unconditionally and thus asserts
8998
/// if inlining will fail. All users /must/ check that a function is allowed
9099
/// to be inlined using SILInliner::canInlineApplySite before calling this
91100
/// function.
92-
SILBasicBlock::iterator inlineFunction(SILFunction *calleeFunction,
93-
FullApplySite apply,
94-
ArrayRef<SILValue> appliedArgs);
101+
///
102+
/// Returns an iterator to the first inlined instruction (or the end of the
103+
/// caller block for empty functions) and the last block in function order
104+
/// containing inlined instructions (the original caller block for
105+
/// single-block functions).
106+
std::pair<SILBasicBlock::iterator, SILBasicBlock *>
107+
inlineFunction(SILFunction *calleeFunction, FullApplySite apply,
108+
ArrayRef<SILValue> appliedArgs);
95109
};
96110

97111
} // end namespace swift

trunk/lib/SIL/SILInstruction.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,10 @@ transferNodesFromList(llvm::ilist_traits<SILInstruction> &L2,
8686
if (ThisParent == L2.getContainingBlock()) return;
8787

8888
// Update the parent fields in the instructions.
89-
for (; first != last; ++first)
89+
for (; first != last; ++first) {
90+
SWIFT_FUNC_STAT_NAMED("sil");
9091
first->ParentBB = ThisParent;
92+
}
9193
}
9294

9395
//===----------------------------------------------------------------------===//

trunk/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp

Lines changed: 58 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ static void diagnose(ASTContext &Context, SourceLoc loc, Diag<T...> diag,
4949
/// and that the function implementing the closure consumes its capture
5050
/// arguments.
5151
static void fixupReferenceCounts(
52-
SILBasicBlock::iterator I, SILValue CalleeValue,
52+
SILInstruction *I, SILValue CalleeValue,
5353
SmallVectorImpl<std::pair<SILValue, ParameterConvention>> &CaptureArgs,
5454
bool isCalleeGuaranteed) {
5555
// Add a copy of each non-address type capture argument to lifetime extend the
@@ -60,7 +60,7 @@ static void fixupReferenceCounts(
6060
if (!CaptureArg.first->getType().isAddress() &&
6161
CaptureArg.second != ParameterConvention::Direct_Guaranteed &&
6262
CaptureArg.second != ParameterConvention::Direct_Unowned) {
63-
createIncrementBefore(CaptureArg.first, &*I);
63+
createIncrementBefore(CaptureArg.first, I);
6464
} else {
6565
// FIXME: What about indirectly owned parameters? The invocation of the
6666
// closure would perform an indirect copy which we should mimick here.
@@ -190,35 +190,31 @@ namespace {
190190
class ClosureCleanup {
191191
using DeadInstSet = SmallBlotSetVector<SILInstruction *, 4>;
192192

193-
/// A helper class to update an instruction iterator if
194-
/// removal of instructions would invalidate it.
193+
/// A helper class to update the set of dead instructions.
195194
///
196195
/// Since this is called by the SILModule callback, the instruction may longer
197196
/// be well-formed. Do not visit its operands. However, it's position in the
198197
/// basic block is still valid.
199198
///
200-
/// FIXME: Using the Module's callback mechanism is undesirable. Instead,
201-
/// cleanupCalleeValue could be easily rewritten to use its own instruction
202-
/// deletion helper and pass a callback to tryDeleteDeadClosure and
203-
/// recursivelyDeleteTriviallyDeadInstructions.
204-
class IteratorUpdateHandler : public DeleteNotificationHandler {
199+
/// FIXME: Using the Module's callback mechanism for this is terrible.
200+
/// Instead, cleanupCalleeValue could be easily rewritten to use its own
201+
/// instruction deletion helper and pass a callback to tryDeleteDeadClosure
202+
/// and recursivelyDeleteTriviallyDeadInstructions.
203+
class DeleteUpdateHandler : public DeleteNotificationHandler {
205204
SILModule &Module;
206-
SILBasicBlock::iterator CurrentI;
207205
DeadInstSet &DeadInsts;
208206

209207
public:
210-
IteratorUpdateHandler(SILBasicBlock::iterator I, DeadInstSet &DeadInsts)
211-
: Module(I->getModule()), CurrentI(I), DeadInsts(DeadInsts) {
208+
DeleteUpdateHandler(SILModule &M, DeadInstSet &DeadInsts)
209+
: Module(M), DeadInsts(DeadInsts) {
212210
Module.registerDeleteNotificationHandler(this);
213211
}
214212

215-
~IteratorUpdateHandler() override {
213+
~DeleteUpdateHandler() override {
216214
// Unregister the handler.
217215
Module.removeDeleteNotificationHandler(this);
218216
}
219217

220-
SILBasicBlock::iterator getIterator() const { return CurrentI; }
221-
222218
// Handling of instruction removal notifications.
223219
bool needsNotifications() override { return true; }
224220

@@ -229,9 +225,6 @@ class ClosureCleanup {
229225
return;
230226

231227
DeadInsts.erase(deletedI);
232-
233-
if (CurrentI == SILBasicBlock::iterator(deletedI))
234-
++CurrentI;
235228
}
236229
};
237230

@@ -260,16 +253,15 @@ class ClosureCleanup {
260253
// Note: instructions in the `deadFunctionVals` set may use each other, so the
261254
// set needs to continue to be updated (by this handler) when deleting
262255
// instructions. This assumes that DeadFunctionValSet::erase() is stable.
263-
SILBasicBlock::iterator cleanupDeadClosures(SILBasicBlock::iterator II) {
264-
IteratorUpdateHandler iteratorUpdate(II, deadFunctionVals);
256+
void cleanupDeadClosures(SILFunction *F) {
257+
DeleteUpdateHandler deleteUpdate(F->getModule(), deadFunctionVals);
265258
for (Optional<SILInstruction *> I : deadFunctionVals) {
266259
if (!I.hasValue())
267260
continue;
268261

269262
if (auto *SVI = dyn_cast<SingleValueInstruction>(I.getValue()))
270263
cleanupCalleeValue(SVI);
271264
}
272-
return iteratorUpdate.getIterator();
273265
}
274266
};
275267
} // end of namespace
@@ -472,21 +464,21 @@ static SILFunction *getCalleeFunction(
472464
return CalleeFunction;
473465
}
474466

475-
static std::tuple<FullApplySite, SILBasicBlock::iterator>
476-
tryDevirtualizeApplyHelper(FullApplySite InnerAI, SILBasicBlock::iterator I,
477-
ClassHierarchyAnalysis *CHA) {
467+
static SILInstruction *tryDevirtualizeApplyHelper(FullApplySite InnerAI,
468+
ClassHierarchyAnalysis *CHA) {
478469
auto NewInst = tryDevirtualizeApply(InnerAI, CHA);
479-
if (!NewInst) {
480-
return std::make_tuple(InnerAI, I);
481-
}
470+
if (!NewInst)
471+
return InnerAI.getInstruction();
482472

483473
deleteDevirtualizedApply(InnerAI);
484474

475+
// FIXME: Comments at the use of this helper indicate that devirtualization
476+
// may return SILArgument. Yet here we assert that it must return an
477+
// instruction.
485478
auto newApplyAI = NewInst.getInstruction();
486479
assert(newApplyAI && "devirtualized but removed apply site?");
487480

488-
return std::make_tuple(FullApplySite::isa(newApplyAI),
489-
newApplyAI->getIterator());
481+
return newApplyAI;
490482
}
491483

492484
/// \brief Inlines all mandatory inlined functions into the body of a function,
@@ -532,23 +524,34 @@ runOnFunctionRecursively(SILOptFunctionBuilder &FuncBuilder,
532524
SmallVector<std::pair<SILValue, ParameterConvention>, 16> CaptureArgs;
533525
SmallVector<SILValue, 32> FullArgs;
534526

535-
for (auto BI = F->begin(), BE = F->end(); BI != BE; ++BI) {
536-
// While iterating over this block, instructions are inserted and deleted.
537-
for (auto II = BI->begin(), nextI = II; II != BI->end(); II = nextI) {
538-
nextI = std::next(II);
527+
// Visiting blocks in reverse order avoids revisiting instructions after block
528+
// splitting, which would be quadratic.
529+
for (auto BI = F->rbegin(), BE = F->rend(), nextBB = BI; BI != BE;
530+
BI = nextBB) {
531+
// After inlining, the block iterator will be adjusted to point to the last
532+
// block containing inlined instructions. This way, the inlined function
533+
// body will be reprocessed within the caller's context without revisiting
534+
// any original instructions.
535+
nextBB = std::next(BI);
539536

537+
// While iterating over this block, instructions are inserted and deleted.
538+
// To avoid quadratic block splitting, instructions must be processed in
539+
// reverse order (block splitting reassigned the parent pointer of all
540+
// instructions below the split point).
541+
for (auto II = BI->rbegin(); II != BI->rend(); ++II) {
540542
FullApplySite InnerAI = FullApplySite::isa(&*II);
541-
542543
if (!InnerAI)
543544
continue;
544545

545-
auto *ApplyBlock = InnerAI.getParent();
546-
547-
// *NOTE* If devirtualization succeeds, sometimes II will not be InnerAI,
546+
// *NOTE* If devirtualization succeeds, devirtInst may not be InnerAI,
548547
// but a casted result of InnerAI or even a block argument due to
549-
// abstraction changes when calling the witness or class method. We still
550-
// know that InnerAI dominates II though.
551-
std::tie(InnerAI, II) = tryDevirtualizeApplyHelper(InnerAI, II, CHA);
548+
// abstraction changes when calling the witness or class method.
549+
auto *devirtInst = tryDevirtualizeApplyHelper(InnerAI, CHA);
550+
// Restore II to the current apply site.
551+
II = devirtInst->getReverseIterator();
552+
// If the devirtualized call result is no longer a invalid FullApplySite,
553+
// then it has succeeded, but the result is not immediately inlinable.
554+
InnerAI = FullApplySite::isa(devirtInst);
552555
if (!InnerAI)
553556
continue;
554557

@@ -597,13 +600,8 @@ runOnFunctionRecursively(SILOptFunctionBuilder &FuncBuilder,
597600

598601
SILInliner Inliner(FuncBuilder, SILInliner::InlineKind::MandatoryInline,
599602
Subs, OpenedArchetypesTracker);
600-
if (!Inliner.canInlineApplySite(InnerAI)) {
601-
// See comment above about casting when devirtualizing and how this
602-
// sometimes causes II and InnerAI to be different and even in different
603-
// blocks.
604-
II = InnerAI.getInstruction()->getIterator();
603+
if (!Inliner.canInlineApplySite(InnerAI))
605604
continue;
606-
}
607605

608606
// Inline function at I, which also changes I to refer to the first
609607
// instruction inlined in the case that it succeeds. We purposely
@@ -620,7 +618,8 @@ runOnFunctionRecursively(SILOptFunctionBuilder &FuncBuilder,
620618
bool IsCalleeGuaranteed =
621619
PAI &&
622620
PAI->getType().castTo<SILFunctionType>()->isCalleeGuaranteed();
623-
fixupReferenceCounts(II, CalleeValue, CaptureArgs, IsCalleeGuaranteed);
621+
fixupReferenceCounts(InnerAI.getInstruction(), CalleeValue, CaptureArgs,
622+
IsCalleeGuaranteed);
624623
}
625624

626625
// Register a callback to record potentially unused function values after
@@ -632,20 +631,23 @@ runOnFunctionRecursively(SILOptFunctionBuilder &FuncBuilder,
632631

633632
// Inlining deletes the apply, and can introduce multiple new basic
634633
// blocks. After this, CalleeValue and other instructions may be invalid.
635-
nextI = Inliner.inlineFunction(CalleeFunction, InnerAI, FullArgs);
634+
// nextBB will point to the last inlined block
635+
auto firstInlinedInstAndLastBB =
636+
Inliner.inlineFunction(CalleeFunction, InnerAI, FullArgs);
637+
nextBB = firstInlinedInstAndLastBB.second->getReverseIterator();
636638
++NumMandatoryInlines;
637639

638640
// The IR is now valid, and trivial dead arguments are removed. However,
639641
// we may be able to remove dead callee computations (e.g. dead
640642
// partial_apply closures).
641-
nextI = closureCleanup.cleanupDeadClosures(nextI);
643+
closureCleanup.cleanupDeadClosures(F);
642644

643-
assert(nextI == ApplyBlock->end()
644-
|| nextI->getParent() == ApplyBlock
645-
&& "Mismatch between the instruction and basic block");
645+
// Resume inlining within nextBB, which contains only the inlined
646+
// instructions and possibly instructions in the original call block that
647+
// have not yet been visited.
648+
break;
646649
}
647650
}
648-
649651
// Keep track of full inlined functions so we don't waste time recursively
650652
// reprocessing them.
651653
FullyInlinedSet.insert(F);
@@ -680,6 +682,9 @@ class MandatoryInlining : public SILModuleTransform {
680682
runOnFunctionRecursively(FuncBuilder, &F,
681683
FullApplySite(), FullyInlinedSet, SetFactory,
682684
SetFactory.getEmptySet(), CHA);
685+
// The inliner splits blocks at call sites. Re-merge trivial branches
686+
// to reestablish a canonical CFG.
687+
mergeBasicBlocks(&F);
683688
}
684689

685690
if (!ShouldCleanup)

trunk/lib/SILOptimizer/Transforms/PerformanceInliner.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h"
1818
#include "swift/SILOptimizer/PassManager/Passes.h"
1919
#include "swift/SILOptimizer/PassManager/Transforms.h"
20+
#include "swift/SILOptimizer/Utils/CFG.h"
2021
#include "swift/SILOptimizer/Utils/Devirtualize.h"
2122
#include "swift/SILOptimizer/Utils/Generics.h"
2223
#include "swift/SILOptimizer/Utils/PerformanceInlinerUtils.h"
@@ -903,6 +904,9 @@ bool SILPerformanceInliner::inlineCallsIntoFunction(SILFunction *Caller) {
903904
Inliner.inlineFunction(Callee, AI, Args);
904905
NumFunctionsInlined++;
905906
}
907+
// The inliner splits blocks at call sites. Re-merge trivial branches to
908+
// reestablish a canonical CFG.
909+
mergeBasicBlocks(Caller);
906910
return true;
907911
}
908912

trunk/lib/SILOptimizer/Utils/CFG.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,19 @@ bool swift::mergeBasicBlockWithSuccessor(SILBasicBlock *BB, DominanceInfo *DT,
493493
return true;
494494
}
495495

496+
bool swift::mergeBasicBlocks(SILFunction *F) {
497+
bool merged = false;
498+
for (auto BBIter = F->begin(); BBIter != F->end();) {
499+
if (mergeBasicBlockWithSuccessor(&*BBIter, /*DT*/ nullptr, /*LI*/ nullptr)) {
500+
merged = true;
501+
// Continue to merge the current block without advancing.
502+
continue;
503+
}
504+
++BBIter;
505+
}
506+
return merged;
507+
}
508+
496509
/// Splits the critical edges between from and to. This code assumes there is
497510
/// only one edge between the two basic blocks.
498511
SILBasicBlock *swift::splitIfCriticalEdge(SILBasicBlock *From,

0 commit comments

Comments
 (0)