22
22
#ifndef SWIFT_SILOPTIMIZER_UTILS_BASICBLOCKOPTUTILS_H
23
23
#define SWIFT_SILOPTIMIZER_UTILS_BASICBLOCKOPTUTILS_H
24
24
25
- #include " swift/SIL/SILInstruction.h"
26
25
#include " swift/SIL/SILBasicBlock.h"
27
26
#include " swift/SIL/SILCloner.h"
27
+ #include " swift/SIL/SILInstruction.h"
28
+ #include " swift/SILOptimizer/Utils/InstOptUtils.h"
28
29
29
30
namespace swift {
30
31
@@ -61,12 +62,65 @@ bool rotateLoop(SILLoop *loop, DominanceInfo *domInfo, SILLoopInfo *loopInfo,
61
62
bool rotateSingleBlockLoops, SILBasicBlock *upToBB,
62
63
bool shouldVerify);
63
64
64
- // / Helper function to perform SSA updates in case of jump threading.
65
- void updateSSAAfterCloning (BasicBlockCloner &cloner, SILBasicBlock *srcBB,
66
- SILBasicBlock *destBB);
65
+ // / Sink address projections to their out-of-block uses. This is
66
+ // / required after cloning a block and before calling
67
+ // / updateSSAAfterCloning to avoid address-type phis.
68
+ // /
69
+ // / This clones address projections at their use points, but does not
70
+ // / mutate the block containing the projections.
71
+ // /
72
+ // / BasicBlockCloner handles this internally.
73
+ class SinkAddressProjections {
74
+ // Projections ordered from last to first in the chain.
75
+ SmallVector<SingleValueInstruction *, 4 > projections;
76
+ SmallSetVector<SILValue, 4 > inBlockDefs;
77
+
78
+ // Transient per-projection data for use during cloning.
79
+ SmallVector<Operand *, 4 > usesToReplace;
80
+ llvm::SmallDenseMap<SILBasicBlock *, Operand *, 4 > firstBlockUse;
81
+
82
+ public:
83
+ // / Check for an address projection chain ending at \p inst. Return true if
84
+ // / the given instruction is successfully analyzed.
85
+ // /
86
+ // / If \p inst does not produce an address, then return
87
+ // / true. getInBlockDefs() will contain \p inst if any of its
88
+ // / (non-address) values are used outside its block.
89
+ // /
90
+ // / If \p inst does produce an address, return true only of the
91
+ // / chain of address projections within this block is clonable at
92
+ // / their use sites. getInBlockDefs will return all non-address
93
+ // / operands in the chain that are also defined in this block. These
94
+ // / may require phis after cloning the projections.
95
+ bool analyzeAddressProjections (SILInstruction *inst);
96
+
97
+ // / After analyzing projections, returns the list of (non-address) values
98
+ // / defined in the same block as the projections which will have uses outside
99
+ // / the block after cloning.
100
+ ArrayRef<SILValue> getInBlockDefs () const {
101
+ return inBlockDefs.getArrayRef ();
102
+ }
103
+ // / Clone the chain of projections at their use sites.
104
+ // /
105
+ // / Return true if anything was done.
106
+ // /
107
+ // / getInBlockProjectionOperandValues() can be called before or after cloning.
108
+ bool cloneProjections ();
109
+ };
67
110
68
111
// / Clone a single basic block and any required successor edges within the same
69
112
// / function.
113
+ // /
114
+ // / Before cloning, call either canCloneBlock or call canCloneInstruction for
115
+ // / every instruction in the original block.
116
+ // /
117
+ // / To clone just the block, call cloneBlock. To also update the original
118
+ // / block's branch to jump to the newly cloned block, call cloneBranchTarget
119
+ // / instead.
120
+ // /
121
+ // / After cloning, call splitCriticalEdges, then updateSSAAfterCloning. This is
122
+ // / decoupled from cloning becaused some clients perform CFG edges updates after
123
+ // / cloning but before splitting CFG edges.
70
124
class BasicBlockCloner : public SILCloner <BasicBlockCloner> {
71
125
using SuperTy = SILCloner<BasicBlockCloner>;
72
126
friend class SILCloner <BasicBlockCloner>;
@@ -75,18 +129,56 @@ class BasicBlockCloner : public SILCloner<BasicBlockCloner> {
75
129
// / The original block to be cloned.
76
130
SILBasicBlock *origBB;
77
131
132
+ // / Will cloning require an SSA update?
133
+ bool needsSSAUpdate = false ;
134
+
135
+ // / Transient object for analyzing a single address projction chain. It's
136
+ // / state is reset each time analyzeAddressProjections is called.
137
+ SinkAddressProjections sinkProj;
138
+
78
139
public:
79
140
// / An ordered list of old to new available value pairs.
80
141
// /
81
142
// / updateSSAAfterCloning() expects this public field to hold values that may
82
143
// / be remapped in the cloned block and live out.
83
- SmallVector<std::pair<SILValue, SILValue>, 16 > AvailVals ;
144
+ SmallVector<std::pair<SILValue, SILValue>, 16 > availVals ;
84
145
85
146
// Clone blocks starting at `origBB`, within the same function.
86
147
BasicBlockCloner (SILBasicBlock *origBB)
87
148
: SILCloner(*origBB->getParent ()), origBB(origBB) {}
88
149
150
+ bool canCloneBlock () {
151
+ for (auto &inst : *origBB) {
152
+ if (!canCloneInstruction (&inst))
153
+ return false ;
154
+ }
155
+ return true ;
156
+ }
157
+
158
+ // / Returns true if \p inst can be cloned.
159
+ // /
160
+ // / If canCloneBlock is not called, then this must be called for every
161
+ // / instruction in origBB, both to ensure clonability and to handle internal
162
+ // / book-keeping (needsSSAUpdate).
163
+ bool canCloneInstruction (SILInstruction *inst) {
164
+ assert (inst->getParent () == origBB);
165
+
166
+ if (!inst->isTriviallyDuplicatable ())
167
+ return false ;
168
+
169
+ if (!sinkProj.analyzeAddressProjections (inst))
170
+ return false ;
171
+
172
+ // Check if any of the non-address defs in the cloned block (including the
173
+ // current instruction) will still have uses outside the block after sinking
174
+ // address projections.
175
+ needsSSAUpdate |= !sinkProj.getInBlockDefs ().empty ();
176
+ return true ;
177
+ }
178
+
89
179
void cloneBlock (SILBasicBlock *insertAfterBB = nullptr ) {
180
+ sinkAddressProjections ();
181
+
90
182
SmallVector<SILBasicBlock *, 4 > successorBBs;
91
183
successorBBs.reserve (origBB->getSuccessors ().size ());
92
184
llvm::copy (origBB->getSuccessors (), std::back_inserter (successorBBs));
@@ -95,6 +187,9 @@ class BasicBlockCloner : public SILCloner<BasicBlockCloner> {
95
187
96
188
// / Clone the given branch instruction's destination block, splitting
97
189
// / its successors, and rewrite the branch instruction.
190
+ // /
191
+ // / Return false if the branch's destination block cannot be cloned. When
192
+ // / false is returned, no changes have been made.
98
193
void cloneBranchTarget (BranchInst *bi) {
99
194
assert (origBB == bi->getDestBB ());
100
195
@@ -110,10 +205,16 @@ class BasicBlockCloner : public SILCloner<BasicBlockCloner> {
110
205
return remapBasicBlock (origBB);
111
206
}
112
207
208
+ bool wasCloned () { return isBlockCloned (origBB); }
209
+
113
210
// / Call this after processing all instructions to fix the control flow
114
211
// / graph. The branch cloner may have left critical edges.
115
212
bool splitCriticalEdges (DominanceInfo *domInfo, SILLoopInfo *loopInfo);
116
213
214
+ // / Helper function to perform SSA updates after calling both
215
+ // / cloneBranchTarget and splitCriticalEdges.
216
+ void updateSSAAfterCloning ();
217
+
117
218
protected:
118
219
// MARK: CRTP overrides.
119
220
@@ -137,8 +238,10 @@ class BasicBlockCloner : public SILCloner<BasicBlockCloner> {
137
238
138
239
void mapValue (SILValue origValue, SILValue mappedValue) {
139
240
SuperTy::mapValue (origValue, mappedValue);
140
- AvailVals .emplace_back (origValue, mappedValue);
241
+ availVals .emplace_back (origValue, mappedValue);
141
242
}
243
+
244
+ void sinkAddressProjections ();
142
245
};
143
246
144
247
// Helper class that provides a callback that can be used in
@@ -173,46 +276,6 @@ class CloneCollector {
173
276
}
174
277
};
175
278
176
- // / Sink address projections to their out-of-block uses. This is
177
- // / required after cloning a block and before calling
178
- // / updateSSAAfterCloning to avoid address-type phis.
179
- // /
180
- // / This clones address projections at their use points, but does not
181
- // / mutate the block containing the projections.
182
- class SinkAddressProjections {
183
- // Projections ordered from last to first in the chain.
184
- SmallVector<SingleValueInstruction *, 4 > projections;
185
- SmallSetVector<SILValue, 4 > inBlockDefs;
186
-
187
- public:
188
- // / Check for an address projection chain ending at \p inst. Return true if
189
- // / the given instruction is successfully analyzed.
190
- // /
191
- // / If \p inst does not produce an address, then return
192
- // / true. getInBlockDefs() will contain \p inst if any of its
193
- // / (non-address) values are used outside its block.
194
- // /
195
- // / If \p inst does produce an address, return true only of the
196
- // / chain of address projections within this block is clonable at
197
- // / their use sites. getInBlockDefs will return all non-address
198
- // / operands in the chain that are also defined in this block. These
199
- // / may require phis after cloning the projections.
200
- bool analyzeAddressProjections (SILInstruction *inst);
201
-
202
- // / After analyzing projections, returns the list of (non-address) values
203
- // / defined in the same block as the projections which will have uses outside
204
- // / the block after cloning.
205
- ArrayRef<SILValue> getInBlockDefs () const {
206
- return inBlockDefs.getArrayRef ();
207
- }
208
- // / Clone the chain of projections at their use sites.
209
- // /
210
- // / Return true if anything was done.
211
- // /
212
- // / getInBlockProjectionOperandValues() can be called before or after cloning.
213
- bool cloneProjections ();
214
- };
215
-
216
279
// / Utility class for cloning init values into the static initializer of a
217
280
// / SILGlobalVariable.
218
281
class StaticInitCloner : public SILCloner <StaticInitCloner> {
0 commit comments