Skip to content

Commit 8779ce7

Browse files
authored
Merge pull request #27049 from nate-chandler/add-mandatory-combiner-frame
[SILOptimizer] Added MandatoryCombiner.
2 parents edf2e3b + 211e656 commit 8779ce7

File tree

3 files changed

+233
-0
lines changed

3 files changed

+233
-0
lines changed

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@ PASS(SerializeSILPass, "serialize-sil",
312312
PASS(YieldOnceCheck, "yield-once-check",
313313
"Check correct usage of yields in yield-once coroutines")
314314
PASS(OSLogOptimization, "os-log-optimization", "Optimize os log calls")
315+
PASS(MandatoryCombine, "mandatory-combine",
316+
"Perform mandatory peephole combines")
315317
PASS(BugReducerTester, "bug-reducer-tester",
316318
"sil-bug-reducer Tool Testing by Asserting on a Sentinel Function")
317319
PASS_RANGE(AllPasses, AADumper, BugReducerTester)

lib/SILOptimizer/Mandatory/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ silopt_register_sources(
2121
SemanticARCOpts.cpp
2222
SILGenCleanup.cpp
2323
YieldOnceCheck.cpp
24+
MandatoryCombine.cpp
2425
OSLogOptimization.cpp
2526
)
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
//===------- MandatoryCombiner.cpp ----------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
///
13+
/// \file
14+
///
15+
/// Defines the MandatoryCombiner function transform. The pass contains basic
16+
/// instruction combines to be performed at the begining of both the Onone and
17+
/// also the performance pass pipelines, after the diagnostics passes have been
18+
/// run. It is intended to be run before and to be independent of other
19+
/// transforms.
20+
///
21+
/// The intention of this pass is to be a place for mandatory peepholes that
22+
/// are not needed for diagnostics. Please put any such peepholes here instead
23+
/// of in the diagnostic passes.
24+
///
25+
//===----------------------------------------------------------------------===//
26+
27+
#define DEBUG_TYPE "sil-mandatory-combiner"
28+
#include "swift/Basic/LLVM.h"
29+
#include "swift/Basic/STLExtras.h"
30+
#include "swift/SIL/SILInstructionWorklist.h"
31+
#include "swift/SIL/SILVisitor.h"
32+
#include "swift/SILOptimizer/PassManager/Passes.h"
33+
#include "swift/SILOptimizer/PassManager/Transforms.h"
34+
#include "swift/SILOptimizer/Utils/Local.h"
35+
#include "llvm/ADT/STLExtras.h"
36+
#include "llvm/ADT/Statistic.h"
37+
#include "llvm/Support/raw_ostream.h"
38+
#include <algorithm>
39+
40+
using namespace swift;
41+
42+
namespace {
43+
44+
class MandatoryCombiner final
45+
: public SILInstructionVisitor<MandatoryCombiner, SILInstruction *> {
46+
47+
using Worklist = SmallSILInstructionWorklist<256>;
48+
49+
/// The list of instructions remaining to visit, perhaps to combine.
50+
Worklist worklist;
51+
52+
/// Whether any changes have been made.
53+
bool madeChange;
54+
55+
/// The number of times that the worklist has been processed.
56+
unsigned iteration;
57+
58+
InstModCallbacks instModCallbacks;
59+
SmallVectorImpl<SILInstruction *> &createdInstructions;
60+
SmallVector<SILInstruction *, 16> instructionsPendingDeletion;
61+
62+
public:
63+
MandatoryCombiner(
64+
SmallVectorImpl<SILInstruction *> &createdInstructions)
65+
: worklist("MC"), madeChange(false), iteration(0),
66+
instModCallbacks(
67+
[&](SILInstruction *instruction) {
68+
worklist.erase(instruction);
69+
instructionsPendingDeletion.push_back(instruction);
70+
},
71+
[&](SILInstruction *instruction) { worklist.add(instruction); }),
72+
createdInstructions(createdInstructions){};
73+
74+
/// Base visitor that does not do anything.
75+
SILInstruction *visitSILInstruction(SILInstruction *) { return nullptr; }
76+
77+
void addReachableCodeToWorklist(SILFunction &function) {
78+
SmallBlotSetVector<SILBasicBlock *, 32> blockWorklist;
79+
SmallBlotSetVector<SILBasicBlock *, 32> blocksVisited;
80+
SmallVector<SILInstruction *, 128> instructions;
81+
82+
blockWorklist.insert(&*function.begin());
83+
while (!blockWorklist.empty()) {
84+
auto *block = blockWorklist.pop_back_val().getValueOr(nullptr);
85+
if (block == nullptr) {
86+
continue;
87+
}
88+
89+
if (!blocksVisited.insert(block).second) {
90+
continue;
91+
}
92+
93+
for (auto iterator = block->begin(), end = block->end(); iterator != end;) {
94+
auto *instruction = &*iterator;
95+
++iterator;
96+
97+
if (isInstructionTriviallyDead(instruction)) {
98+
continue;
99+
}
100+
101+
instructions.push_back(instruction);
102+
}
103+
104+
for_each(block->getSuccessorBlocks(), [&](SILBasicBlock *block) {
105+
blockWorklist.insert(block);
106+
});
107+
}
108+
109+
worklist.addInitialGroup(instructions);
110+
}
111+
112+
/// \return whether a change was made.
113+
bool doOneIteration(SILFunction &function, unsigned iteration) {
114+
madeChange = false;
115+
116+
addReachableCodeToWorklist(function);
117+
118+
while (!worklist.isEmpty()) {
119+
auto *instruction = worklist.pop_back_val();
120+
if (instruction == nullptr) {
121+
continue;
122+
}
123+
124+
#ifndef NDEBUG
125+
std::string instructionDescription;
126+
#endif
127+
LLVM_DEBUG(llvm::raw_string_ostream SS(instructionDescription);
128+
instruction->print(SS); instructionDescription = SS.str(););
129+
LLVM_DEBUG(llvm::dbgs()
130+
<< "MC: Visiting: " << instructionDescription << '\n');
131+
132+
if (auto replacement = visit(instruction)) {
133+
worklist.replaceInstructionWithInstruction(instruction, replacement
134+
#ifndef NDEBUG
135+
, instructionDescription
136+
#endif
137+
);
138+
}
139+
140+
for (SILInstruction *instruction : instructionsPendingDeletion) {
141+
worklist.eraseInstFromFunction(*instruction);
142+
}
143+
instructionsPendingDeletion.clear();
144+
145+
// Our tracking list has been accumulating instructions created by the
146+
// SILBuilder during this iteration. Go through the tracking list and add
147+
// its contents to the worklist and then clear said list in preparation
148+
// for the next iteration.
149+
for (SILInstruction *instruction : createdInstructions) {
150+
LLVM_DEBUG(llvm::dbgs() << "MC: add " << *instruction
151+
<< " from tracking list to worklist\n");
152+
worklist.add(instruction);
153+
}
154+
createdInstructions.clear();
155+
}
156+
157+
worklist.resetChecked();
158+
return madeChange;
159+
}
160+
161+
void clear() {
162+
iteration = 0;
163+
worklist.resetChecked();
164+
madeChange = false;
165+
}
166+
167+
168+
/// Applies the MandatoryCombiner to the provided function.
169+
///
170+
/// \param function the function to which to apply the MandatoryCombiner.
171+
///
172+
/// \return whether a change was made.
173+
bool runOnFunction(SILFunction &function) {
174+
bool changed = false;
175+
176+
while (doOneIteration(function, iteration)) {
177+
changed = true;
178+
++iteration;
179+
}
180+
181+
return changed;
182+
}
183+
};
184+
185+
} // end anonymous namespace
186+
187+
//===----------------------------------------------------------------------===//
188+
// Top Level Entrypoint
189+
//===----------------------------------------------------------------------===//
190+
191+
namespace {
192+
193+
class MandatoryCombine final : public SILFunctionTransform {
194+
195+
SmallVector<SILInstruction *, 64> createdInstructions;
196+
197+
void run() override {
198+
auto *function = getFunction();
199+
200+
MandatoryCombiner combiner(createdInstructions);
201+
bool madeChange = combiner.runOnFunction(*function);
202+
203+
if (madeChange) {
204+
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
205+
}
206+
}
207+
208+
void handleDeleteNotification(SILNode *node) override {
209+
// Remove instructions that were both created and deleted from the list of
210+
// created instructions which will eventually be added to the worklist.
211+
212+
auto *instruction = dyn_cast<SILInstruction>(node);
213+
if (instruction == nullptr) {
214+
return;
215+
}
216+
217+
// Linear searching the tracking list doesn't hurt because usually it only
218+
// contains a few elements.
219+
auto iterator = find(createdInstructions, instruction);
220+
if (createdInstructions.end() != iterator) {
221+
createdInstructions.erase(iterator);
222+
}
223+
}
224+
225+
bool needsNotifications() override { return true; }
226+
};
227+
228+
} // end anonymous namespace
229+
230+
SILTransform *swift::createMandatoryCombine() { return new MandatoryCombine(); }

0 commit comments

Comments
 (0)