1717#define DEBUG_TYPE " cow-opts"
1818#include " swift/SILOptimizer/PassManager/Transforms.h"
1919#include " swift/SILOptimizer/Analysis/AliasAnalysis.h"
20+ #include " swift/SIL/NodeBits.h"
2021#include " swift/SIL/SILFunction.h"
2122#include " swift/SIL/SILBasicBlock.h"
2223#include " swift/SIL/SILArgument.h"
2324#include " swift/SIL/SILBuilder.h"
25+ #include " swift/SIL/StackList.h"
2426#include " llvm/Support/Debug.h"
2527
2628using namespace swift ;
@@ -65,16 +67,13 @@ class COWOptsPass : public SILFunctionTransform {
6567 void run () override ;
6668
6769private:
68- using InstructionSet = SmallPtrSet<SILInstruction *, 8 >;
69- using VoidPointerSet = SmallPtrSet<void *, 8 >;
70-
7170 AliasAnalysis *AA = nullptr ;
7271
7372 bool optimizeBeginCOW (BeginCOWMutationInst *BCM);
7473
7574 static void collectEscapePoints (SILValue v,
76- InstructionSet &escapePoints,
77- VoidPointerSet &handled);
75+ InstructionSetWithSize &escapePoints,
76+ ValueSet &handled);
7877};
7978
8079void COWOptsPass::run () {
@@ -120,37 +119,44 @@ static SILValue skipStructAndExtract(SILValue value) {
120119}
121120
122121bool COWOptsPass::optimizeBeginCOW (BeginCOWMutationInst *BCM) {
123- VoidPointerSet handled ;
124- SmallVector<SILValue, 8 > workList ;
125- SmallPtrSet<EndCOWMutationInst *, 4 > endCOWMutationInsts ;
122+ SILFunction *function = BCM-> getFunction () ;
123+ StackList<EndCOWMutationInst *> endCOWMutationInsts (function) ;
124+ InstructionSet endCOWMutationsFound (function) ;
126125
127- // Collect all end_cow_mutation instructions, used by the begin_cow_mutation,
128- // looking through block phi-arguments.
129- workList.push_back (BCM->getOperand ());
130- while (!workList.empty ()) {
131- SILValue v = skipStructAndExtract (workList.pop_back_val ());
132- if (SILPhiArgument *arg = dyn_cast<SILPhiArgument>(v)) {
133- if (handled.insert (arg).second ) {
134- SmallVector<SILValue, 4 > incomingVals;
135- if (!arg->getIncomingPhiValues (incomingVals))
136- return false ;
137- for (SILValue incomingVal : incomingVals) {
138- workList.push_back (incomingVal);
126+ {
127+ // Collect all end_cow_mutation instructions, used by the begin_cow_mutation,
128+ // looking through block phi-arguments.
129+ StackList<SILValue> workList (function);
130+ ValueSet handled (function);
131+ workList.push_back (BCM->getOperand ());
132+ while (!workList.empty ()) {
133+ SILValue v = skipStructAndExtract (workList.pop_back_val ());
134+ if (SILPhiArgument *arg = dyn_cast<SILPhiArgument>(v)) {
135+ if (handled.insert (arg)) {
136+ SmallVector<SILValue, 4 > incomingVals;
137+ if (!arg->getIncomingPhiValues (incomingVals))
138+ return false ;
139+ for (SILValue incomingVal : incomingVals) {
140+ workList.push_back (incomingVal);
141+ }
139142 }
143+ } else if (auto *ECM = dyn_cast<EndCOWMutationInst>(v)) {
144+ if (endCOWMutationsFound.insert (ECM))
145+ endCOWMutationInsts.push_back (ECM);
146+ } else {
147+ return false ;
140148 }
141- } else if (auto *ECM = dyn_cast<EndCOWMutationInst>(v)) {
142- endCOWMutationInsts.insert (ECM);
143- } else {
144- return false ;
145149 }
146150 }
147151
148152 // Collect all uses of the end_cow_instructions, where the buffer can
149153 // potentially escape.
150- handled.clear ();
151- InstructionSet potentialEscapePoints;
152- for (EndCOWMutationInst *ECM : endCOWMutationInsts) {
153- collectEscapePoints (ECM, potentialEscapePoints, handled);
154+ InstructionSetWithSize potentialEscapePoints (function);
155+ {
156+ ValueSet handled (function);
157+ for (EndCOWMutationInst *ECM : endCOWMutationInsts) {
158+ collectEscapePoints (ECM, potentialEscapePoints, handled);
159+ }
154160 }
155161
156162 if (!potentialEscapePoints.empty ()) {
@@ -161,10 +167,13 @@ bool COWOptsPass::optimizeBeginCOW(BeginCOWMutationInst *BCM) {
161167 // For store instructions we do a little bit more: only count a store as an
162168 // escape if there is a (potential) load from the same address within the
163169 // liverange.
164- handled.clear ();
165- SmallVector<SILInstruction *, 8 > instWorkList;
166- SmallVector<SILInstruction *, 8 > potentialLoadInsts;
167- llvm::DenseSet<SILValue> storeAddrs;
170+ StackList<SILInstruction *> instWorkList (function);
171+ StackList<SILInstruction *> potentialLoadInsts (function);
172+ StackList<SILValue> storeAddrs (function);
173+ ValueSet storeAddrsFound (function);
174+ BasicBlockSet handled (function);
175+ int numStoresFound = 0 ;
176+ int numLoadsFound = 0 ;
168177
169178 // This is a simple worklist-based backward dataflow analysis.
170179 // Start at the initial begin_cow_mutation and go backward.
@@ -173,27 +182,32 @@ bool COWOptsPass::optimizeBeginCOW(BeginCOWMutationInst *BCM) {
173182 while (!instWorkList.empty ()) {
174183 SILInstruction *inst = instWorkList.pop_back_val ();
175184 for (;;) {
176- if (potentialEscapePoints.count (inst) != 0 ) {
185+ if (potentialEscapePoints.contains (inst)) {
177186 if (auto *store = dyn_cast<StoreInst>(inst)) {
178187 // Don't immediately bail on a store instruction. Instead, remember
179188 // it and check if it interfers with any (potential) load.
180- storeAddrs.insert (store->getDest ());
189+ if (storeAddrsFound.insert (store->getDest ())) {
190+ storeAddrs.push_back (store->getDest ());
191+ numStoresFound += 1 ;
192+ }
181193 } else {
182194 return false ;
183195 }
184196 }
185- if (inst->mayReadFromMemory ())
197+ if (inst->mayReadFromMemory ()) {
186198 potentialLoadInsts.push_back (inst);
199+ numLoadsFound += 1 ;
200+ }
187201
188202 // An end_cow_mutation marks the begin of the liverange. It's the end
189203 // point of the dataflow analysis.
190204 auto *ECM = dyn_cast<EndCOWMutationInst>(inst);
191- if (ECM && endCOWMutationInsts. count (ECM) != 0 )
205+ if (ECM && endCOWMutationsFound. contains (ECM))
192206 break ;
193207
194208 if (inst == &inst->getParent ()->front ()) {
195209 for (SILBasicBlock *pred : inst->getParent ()->getPredecessorBlocks ()) {
196- if (handled.insert (pred). second )
210+ if (handled.insert (pred))
197211 instWorkList.push_back (pred->getTerminator ());
198212 }
199213 break ;
@@ -205,9 +219,9 @@ bool COWOptsPass::optimizeBeginCOW(BeginCOWMutationInst *BCM) {
205219
206220 // Check if there is any (potential) load from a memory location where the
207221 // buffer is stored to.
208- if (!storeAddrs. empty () ) {
222+ if (numStoresFound != 0 ) {
209223 // Avoid quadratic behavior. Usually this limit is not exceeded.
210- if (storeAddrs. size () * potentialLoadInsts. size () > 128 )
224+ if (numStoresFound * numLoadsFound > 128 )
211225 return false ;
212226 for (SILInstruction *load : potentialLoadInsts) {
213227 for (SILValue storeAddr : storeAddrs) {
@@ -235,9 +249,9 @@ bool COWOptsPass::optimizeBeginCOW(BeginCOWMutationInst *BCM) {
235249}
236250
237251void COWOptsPass::collectEscapePoints (SILValue v,
238- InstructionSet &escapePoints,
239- VoidPointerSet &handled) {
240- if (!handled.insert (v. getOpaqueValue ()). second )
252+ InstructionSetWithSize &escapePoints,
253+ ValueSet &handled) {
254+ if (!handled.insert (v) )
241255 return ;
242256
243257 for (Operand *use : v->getUses ()) {
0 commit comments