Skip to content

Commit 211e656

Browse files
committed
[SILOptimizer] Added MandatoryCombiner.
Minimal commit to get the mandatory combiner rolling. The intent of the mandatory combiner is to do basic transformations after the diagnostics passes have run at the beginning of both the Onone and the performance pipelines. For now, it simply visits reachable instructions and does no work. In a subsequent commit, apply instructions will be processed and replaced if they are calls to partial applies defined in the same function. At that point an attempt will be made to eliminate the partial apply altogether. For now, the pass does no work and is not part of any pipeline.
1 parent 568f615 commit 211e656

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)