Skip to content

Commit cfb5ad8

Browse files
authored
Merge pull request #61779 from tshortli/break-cycle-loop-can-duplicate
SILOptimizer: Break circular dependency with SIL library by moving `canDuplicate()`
2 parents 812cc05 + 0921480 commit cfb5ad8

File tree

7 files changed

+111
-109
lines changed

7 files changed

+111
-109
lines changed

include/swift/SIL/LoopInfo.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,6 @@ class SILLoop : public llvm::LoopBase<SILBasicBlock, SILLoop> {
4646
return make_range(begin(), end());
4747
}
4848

49-
/// Check whether it is safe to duplicate this instruction when duplicating
50-
/// this loop by unrolling or versioning.
51-
bool canDuplicate(SILInstruction *Inst) const;
52-
5349
void getExitingAndLatchBlocks(
5450
SmallVectorImpl<SILBasicBlock *> &ExitingAndLatchBlocks) const {
5551
this->getExitingBlocks(ExitingAndLatchBlocks);

include/swift/SILOptimizer/Utils/LoopUtils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ namespace swift {
2424

2525
class SILFunction;
2626
class SILBasicBlock;
27+
class SILInstruction;
2728
class SILLoop;
2829
class DominanceInfo;
2930
class SILLoopInfo;
@@ -37,6 +38,10 @@ bool canonicalizeLoop(SILLoop *L, DominanceInfo *DT, SILLoopInfo *LI);
3738
/// information. We update loop info and dominance info while we do this.
3839
bool canonicalizeAllLoops(DominanceInfo *DT, SILLoopInfo *LI);
3940

41+
/// Check whether it is safe to duplicate this instruction when duplicating
42+
/// this loop by unrolling or versioning.
43+
bool canDuplicateLoopInstruction(SILLoop *L, SILInstruction *Inst);
44+
4045
/// A visitor that visits loops in a function in a bottom up order. It only
4146
/// performs the visit.
4247
class SILLoopVisitor {

lib/SIL/Utils/LoopInfo.cpp

Lines changed: 0 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "swift/SIL/LoopInfo.h"
14-
#include "swift/SIL/SILBasicBlock.h"
1514
#include "swift/SIL/Dominance.h"
16-
#include "swift/SIL/SILFunction.h"
17-
#include "swift/SIL/CFG.h"
18-
#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h"
1915
#include "llvm/Analysis/LoopInfoImpl.h"
2016
#include "llvm/Support/Debug.h"
2117

@@ -36,105 +32,6 @@ SILLoopInfo::SILLoopInfo(SILFunction *F, DominanceInfo *DT) : Dominance(DT) {
3632
LI.analyze(*Dominance);
3733
}
3834

39-
bool SILLoop::canDuplicate(SILInstruction *I) const {
40-
SinkAddressProjections sinkProj;
41-
for (auto res : I->getResults()) {
42-
if (!res->getType().isAddress()) {
43-
continue;
44-
}
45-
auto canSink = sinkProj.analyzeAddressProjections(I);
46-
if (!canSink) {
47-
return false;
48-
}
49-
}
50-
51-
// The deallocation of a stack allocation must be in the loop, otherwise the
52-
// deallocation will be fed by a phi node of two allocations.
53-
if (I->isAllocatingStack()) {
54-
for (auto *UI : cast<SingleValueInstruction>(I)->getUses()) {
55-
if (UI->getUser()->isDeallocatingStack()) {
56-
if (!contains(UI->getUser()->getParent()))
57-
return false;
58-
}
59-
}
60-
return true;
61-
}
62-
if (I->isDeallocatingStack()) {
63-
SILInstruction *alloc = nullptr;
64-
if (auto *dealloc = dyn_cast<DeallocStackInst>(I)) {
65-
SILValue address = dealloc->getOperand();
66-
if (isa<AllocStackInst>(address) || isa<PartialApplyInst>(address))
67-
alloc = cast<SingleValueInstruction>(address);
68-
}
69-
if (auto *dealloc = dyn_cast<DeallocStackRefInst>(I))
70-
alloc = dealloc->getAllocRef();
71-
72-
return alloc && contains(alloc);
73-
}
74-
75-
// CodeGen can't build ssa for objc methods.
76-
if (auto *Method = dyn_cast<MethodInst>(I)) {
77-
if (Method->getMember().isForeign) {
78-
for (auto *UI : Method->getUses()) {
79-
if (!contains(UI->getUser()))
80-
return false;
81-
}
82-
}
83-
return true;
84-
}
85-
86-
// We can't have a phi of two openexistential instructions of different UUID.
87-
if (isa<OpenExistentialAddrInst>(I) || isa<OpenExistentialRefInst>(I) ||
88-
isa<OpenExistentialMetatypeInst>(I) ||
89-
isa<OpenExistentialValueInst>(I) || isa<OpenExistentialBoxInst>(I) ||
90-
isa<OpenExistentialBoxValueInst>(I)) {
91-
SingleValueInstruction *OI = cast<SingleValueInstruction>(I);
92-
for (auto *UI : OI->getUses())
93-
if (!contains(UI->getUser()))
94-
return false;
95-
return true;
96-
}
97-
98-
if (isa<ThrowInst>(I))
99-
return false;
100-
101-
// The entire access must be within the loop.
102-
if (auto BAI = dyn_cast<BeginAccessInst>(I)) {
103-
for (auto *UI : BAI->getUses()) {
104-
if (!contains(UI->getUser()))
105-
return false;
106-
}
107-
return true;
108-
}
109-
// The entire coroutine execution must be within the loop.
110-
// Note that we don't have to worry about the reverse --- a loop which
111-
// contains an end_apply or abort_apply of an external begin_apply ---
112-
// because that wouldn't be structurally valid in the first place.
113-
if (auto BAI = dyn_cast<BeginApplyInst>(I)) {
114-
for (auto UI : BAI->getTokenResult()->getUses()) {
115-
auto User = UI->getUser();
116-
assert(isa<EndApplyInst>(User) || isa<AbortApplyInst>(User));
117-
if (!contains(User))
118-
return false;
119-
}
120-
return true;
121-
}
122-
123-
if (isa<DynamicMethodBranchInst>(I))
124-
return false;
125-
126-
// Can't duplicate get/await_async_continuation.
127-
if (isa<AwaitAsyncContinuationInst>(I) ||
128-
isa<GetAsyncContinuationAddrInst>(I) || isa<GetAsyncContinuationInst>(I))
129-
return false;
130-
131-
// Some special cases above that aren't considered isTriviallyDuplicatable
132-
// return true early.
133-
assert(I->isTriviallyDuplicatable() &&
134-
"Code here must match isTriviallyDuplicatable in SILInstruction");
135-
return true;
136-
}
137-
13835
void SILLoopInfo::verify() const {
13936
LI.verify(*Dominance);
14037
}

lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include "swift/SILOptimizer/Analysis/LoopAnalysis.h"
5858
#include "swift/SILOptimizer/PassManager/Transforms.h"
5959
#include "swift/SILOptimizer/Utils/CFGOptUtils.h"
60+
#include "swift/SILOptimizer/Utils/LoopUtils.h"
6061
#include "swift/SILOptimizer/Utils/SILSSAUpdater.h"
6162
#include "swift/SIL/CFG.h"
6263
#include "swift/SIL/DebugUtils.h"
@@ -172,7 +173,7 @@ class ArrayPropertiesAnalysis {
172173
for (auto &Inst : *BB) {
173174
// Can't clone alloc_stack instructions whose dealloc_stack is outside
174175
// the loop.
175-
if (!Loop->canDuplicate(&Inst))
176+
if (!canDuplicateLoopInstruction(Loop, &Inst))
176177
return false;
177178

178179
ArraySemanticsCall ArrayPropsInst(&Inst, "array.props", true);

lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/SILOptimizer/PassManager/Passes.h"
2121
#include "swift/SILOptimizer/PassManager/Transforms.h"
2222
#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h"
23+
#include "swift/SILOptimizer/Utils/LoopUtils.h"
2324
#include "swift/SILOptimizer/Utils/PerformanceInlinerUtils.h"
2425
#include "swift/SILOptimizer/Utils/SILInliner.h"
2526
#include "swift/SILOptimizer/Utils/SILSSAUpdater.h"
@@ -213,7 +214,7 @@ static bool canAndShouldUnrollLoop(SILLoop *Loop, uint64_t TripCount) {
213214
(Loop->getBlocks())[0]->getParent()->getModule().getOptions().UnrollThreshold;
214215
for (auto *BB : Loop->getBlocks()) {
215216
for (auto &Inst : *BB) {
216-
if (!Loop->canDuplicate(&Inst))
217+
if (!canDuplicateLoopInstruction(Loop, &Inst))
217218
return false;
218219
if (instructionInlineCost(Inst) != InlineCost::Free)
219220
++Cost;

lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
1616
#include "swift/SILOptimizer/Utils/OwnershipOptUtils.h"
1717
#include "swift/SILOptimizer/Utils/SILSSAUpdater.h"
18+
#include "swift/SIL/LoopInfo.h"
1819

1920
using namespace swift;
2021

lib/SILOptimizer/Utils/LoopUtils.cpp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#define DEBUG_TYPE "sil-loop-utils"
1414
#include "swift/SILOptimizer/Utils/LoopUtils.h"
15+
#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h"
1516
#include "swift/SIL/BasicBlockUtils.h"
1617
#include "swift/SIL/Dominance.h"
1718
#include "swift/SIL/LoopInfo.h"
@@ -215,6 +216,106 @@ bool swift::canonicalizeAllLoops(DominanceInfo *DT, SILLoopInfo *LI) {
215216
return MadeChange;
216217
}
217218

219+
bool swift::canDuplicateLoopInstruction(SILLoop *L, SILInstruction *I) {
220+
SinkAddressProjections sinkProj;
221+
for (auto res : I->getResults()) {
222+
if (!res->getType().isAddress()) {
223+
continue;
224+
}
225+
auto canSink = sinkProj.analyzeAddressProjections(I);
226+
if (!canSink) {
227+
return false;
228+
}
229+
}
230+
231+
// The deallocation of a stack allocation must be in the loop, otherwise the
232+
// deallocation will be fed by a phi node of two allocations.
233+
if (I->isAllocatingStack()) {
234+
for (auto *UI : cast<SingleValueInstruction>(I)->getUses()) {
235+
if (UI->getUser()->isDeallocatingStack()) {
236+
if (!L->contains(UI->getUser()->getParent()))
237+
return false;
238+
}
239+
}
240+
return true;
241+
}
242+
if (I->isDeallocatingStack()) {
243+
SILInstruction *alloc = nullptr;
244+
if (auto *dealloc = dyn_cast<DeallocStackInst>(I)) {
245+
SILValue address = dealloc->getOperand();
246+
if (isa<AllocStackInst>(address) || isa<PartialApplyInst>(address))
247+
alloc = cast<SingleValueInstruction>(address);
248+
}
249+
if (auto *dealloc = dyn_cast<DeallocStackRefInst>(I))
250+
alloc = dealloc->getAllocRef();
251+
252+
return alloc && L->contains(alloc);
253+
}
254+
255+
// CodeGen can't build ssa for objc methods.
256+
if (auto *Method = dyn_cast<MethodInst>(I)) {
257+
if (Method->getMember().isForeign) {
258+
for (auto *UI : Method->getUses()) {
259+
if (!L->contains(UI->getUser()))
260+
return false;
261+
}
262+
}
263+
return true;
264+
}
265+
266+
// We can't have a phi of two openexistential instructions of different UUID.
267+
if (isa<OpenExistentialAddrInst>(I) || isa<OpenExistentialRefInst>(I) ||
268+
isa<OpenExistentialMetatypeInst>(I) ||
269+
isa<OpenExistentialValueInst>(I) || isa<OpenExistentialBoxInst>(I) ||
270+
isa<OpenExistentialBoxValueInst>(I)) {
271+
SingleValueInstruction *OI = cast<SingleValueInstruction>(I);
272+
for (auto *UI : OI->getUses())
273+
if (!L->contains(UI->getUser()))
274+
return false;
275+
return true;
276+
}
277+
278+
if (isa<ThrowInst>(I))
279+
return false;
280+
281+
// The entire access must be within the loop.
282+
if (auto BAI = dyn_cast<BeginAccessInst>(I)) {
283+
for (auto *UI : BAI->getUses()) {
284+
if (!L->contains(UI->getUser()))
285+
return false;
286+
}
287+
return true;
288+
}
289+
// The entire coroutine execution must be within the loop.
290+
// Note that we don't have to worry about the reverse --- a loop which
291+
// contains an end_apply or abort_apply of an external begin_apply ---
292+
// because that wouldn't be structurally valid in the first place.
293+
if (auto BAI = dyn_cast<BeginApplyInst>(I)) {
294+
for (auto UI : BAI->getTokenResult()->getUses()) {
295+
auto User = UI->getUser();
296+
assert(isa<EndApplyInst>(User) || isa<AbortApplyInst>(User));
297+
if (!L->contains(User))
298+
return false;
299+
}
300+
return true;
301+
}
302+
303+
if (isa<DynamicMethodBranchInst>(I))
304+
return false;
305+
306+
// Can't duplicate get/await_async_continuation.
307+
if (isa<AwaitAsyncContinuationInst>(I) ||
308+
isa<GetAsyncContinuationAddrInst>(I) || isa<GetAsyncContinuationInst>(I))
309+
return false;
310+
311+
// Some special cases above that aren't considered isTriviallyDuplicatable
312+
// return true early.
313+
assert(I->isTriviallyDuplicatable() &&
314+
"Code here must match isTriviallyDuplicatable in SILInstruction");
315+
return true;
316+
}
317+
318+
218319
//===----------------------------------------------------------------------===//
219320
// Loop Visitor
220321
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)