Skip to content

Commit cd1d1f8

Browse files
authored
Merge pull request #61650 from meg-gupta/canonswitchenum
Enable canonicalizing switch_enums in OSSA
2 parents 86642fa + c515db2 commit cd1d1f8

File tree

5 files changed

+350
-242
lines changed

5 files changed

+350
-242
lines changed
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
//===-------------------- SimplifyCFG.h -----------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 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+
14+
#ifndef SWIFT_SILOPTIMIZER_SIMPLIFYCFG_H
15+
#define SWIFT_SILOPTIMIZER_SIMPLIFYCFG_H
16+
17+
#include "swift/SILOptimizer/Utils/ConstantFolding.h"
18+
#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h"
19+
#include "llvm/ADT/SmallPtrSet.h"
20+
#include "llvm/ADT/SmallVector.h"
21+
#include "llvm/ADT/Statistic.h"
22+
23+
using namespace swift;
24+
25+
struct ThreadInfo;
26+
27+
class SimplifyCFG {
28+
SILOptFunctionBuilder FuncBuilder;
29+
SILFunction &Fn;
30+
SILFunctionTransform &transform;
31+
SILPassManager *PM = nullptr;
32+
33+
// DeadEndBlocks remains conservatively valid across updates that rewrite
34+
// branches and remove edges. Any transformation that adds a block must call
35+
// updateForReachableBlock(). Removing a block causes a dangling pointer
36+
// within DeadEndBlocks, but this pointer can't be accessed by queries.
37+
DeadEndBlocks *deBlocks = nullptr;
38+
39+
// WorklistList is the actual list that we iterate over (for determinism).
40+
// Slots may be null, which should be ignored.
41+
SmallVector<SILBasicBlock *, 32> WorklistList;
42+
// WorklistMap keeps track of which slot a BB is in, allowing efficient
43+
// containment query, and allows efficient removal.
44+
llvm::SmallDenseMap<SILBasicBlock *, unsigned, 32> WorklistMap;
45+
// Keep track of loop headers - we don't want to jump-thread through them.
46+
SmallPtrSet<SILBasicBlock *, 32> LoopHeaders;
47+
// The set of cloned loop headers to avoid infinite loop peeling. Blocks in
48+
// this set may or may not still be LoopHeaders.
49+
// (ultimately this can be used to eliminate findLoopHeaders)
50+
SmallPtrSet<SILBasicBlock *, 4> ClonedLoopHeaders;
51+
// The cost (~ number of copied instructions) of jump threading per basic
52+
// block. Used to prevent infinite jump threading loops.
53+
llvm::SmallDenseMap<SILBasicBlock *, int, 8> JumpThreadingCost;
54+
55+
// Dominance and post-dominance info for the current function
56+
DominanceInfo *DT = nullptr;
57+
58+
ConstantFolder ConstFolder;
59+
60+
// True if the function has a large amount of blocks. In this case we turn off
61+
// some expensive optimizations.
62+
bool isVeryLargeFunction = false;
63+
64+
void constFoldingCallback(SILInstruction *I) {
65+
// If a terminal instruction gets constant folded (like cond_br), it
66+
// enables further simplify-CFG optimizations.
67+
if (isa<TermInst>(I))
68+
addToWorklist(I->getParent());
69+
}
70+
71+
bool ShouldVerify;
72+
bool EnableJumpThread;
73+
74+
public:
75+
SimplifyCFG(SILFunction &Fn, SILFunctionTransform &T, bool Verify,
76+
bool EnableJumpThread)
77+
: FuncBuilder(T), Fn(Fn), transform(T), PM(T.getPassManager()),
78+
ConstFolder(FuncBuilder, PM->getOptions().AssertConfig,
79+
/* EnableDiagnostics */ false,
80+
[&](SILInstruction *I) { constFoldingCallback(I); }),
81+
ShouldVerify(Verify), EnableJumpThread(EnableJumpThread) {}
82+
83+
bool run();
84+
85+
bool simplifyBlockArgs();
86+
bool simplifyBlocks();
87+
bool canonicalizeSwitchEnums();
88+
bool simplifyThreadedTerminators();
89+
bool dominatorBasedSimplifications(SILFunction &Fn, DominanceInfo *DT);
90+
bool dominatorBasedSimplify(DominanceAnalysis *DA);
91+
bool threadEdge(const ThreadInfo &ti);
92+
93+
/// Remove the basic block if it has no predecessors. Returns true
94+
/// If the block was removed.
95+
bool removeIfDead(SILBasicBlock *BB);
96+
97+
bool tryJumpThreading(BranchInst *BI);
98+
bool tailDuplicateObjCMethodCallSuccessorBlocks();
99+
bool simplifyAfterDroppingPredecessor(SILBasicBlock *BB);
100+
101+
bool simplifyBranchOperands(OperandValueArrayRef Operands);
102+
bool simplifyBranchBlock(BranchInst *BI);
103+
bool simplifyCondBrBlock(CondBranchInst *BI);
104+
bool simplifyCheckedCastBranchBlock(CheckedCastBranchInst *CCBI);
105+
bool simplifyCheckedCastAddrBranchBlock(CheckedCastAddrBranchInst *CCABI);
106+
bool simplifyTryApplyBlock(TryApplyInst *TAI);
107+
bool simplifySwitchValueBlock(SwitchValueInst *SVI);
108+
bool simplifyTermWithIdenticalDestBlocks(SILBasicBlock *BB);
109+
bool simplifySwitchEnumUnreachableBlocks(SwitchEnumInst *SEI);
110+
bool simplifySwitchEnumBlock(SwitchEnumInst *SEI);
111+
bool simplifyUnreachableBlock(UnreachableInst *UI);
112+
bool simplifyProgramTerminationBlock(SILBasicBlock *BB);
113+
bool simplifyArgument(SILBasicBlock *BB, unsigned i);
114+
bool simplifyArgs(SILBasicBlock *BB);
115+
bool simplifySwitchEnumOnObjcClassOptional(SwitchEnumInst *SEI);
116+
117+
private:
118+
// Called when \p newBlock inherits the former predecessors of \p
119+
// oldBlock. e.g. if \p oldBlock was a loop header, then newBlock is now a
120+
// loop header.
121+
void substitutedBlockPreds(SILBasicBlock *oldBlock, SILBasicBlock *newBlock) {
122+
if (LoopHeaders.count(oldBlock))
123+
LoopHeaders.insert(newBlock);
124+
if (ClonedLoopHeaders.count(oldBlock))
125+
ClonedLoopHeaders.insert(newBlock);
126+
}
127+
128+
void clearWorklist() {
129+
WorklistMap.clear();
130+
WorklistList.clear();
131+
}
132+
133+
/// popWorklist - Return the next basic block to look at, or null if the
134+
/// worklist is empty. This handles skipping over null entries in the
135+
/// worklist.
136+
SILBasicBlock *popWorklist() {
137+
while (!WorklistList.empty())
138+
if (auto *BB = WorklistList.pop_back_val()) {
139+
WorklistMap.erase(BB);
140+
return BB;
141+
}
142+
143+
return nullptr;
144+
}
145+
146+
/// addToWorklist - Add the specified block to the work list if it isn't
147+
/// already present.
148+
void addToWorklist(SILBasicBlock *BB) {
149+
unsigned &Entry = WorklistMap[BB];
150+
if (Entry != 0)
151+
return;
152+
WorklistList.push_back(BB);
153+
Entry = WorklistList.size();
154+
}
155+
156+
/// removeFromWorklist - Remove the specified block from the worklist if
157+
/// present.
158+
void removeFromWorklist(SILBasicBlock *BB) {
159+
assert(BB && "Cannot add null pointer to the worklist");
160+
auto It = WorklistMap.find(BB);
161+
if (It == WorklistMap.end())
162+
return;
163+
164+
// If the BB is in the worklist, null out its entry.
165+
if (It->second) {
166+
assert(WorklistList[It->second - 1] == BB && "Consistency error");
167+
WorklistList[It->second - 1] = nullptr;
168+
}
169+
170+
// Remove it from the map as well.
171+
WorklistMap.erase(It);
172+
173+
if (LoopHeaders.count(BB)) {
174+
LoopHeaders.erase(BB);
175+
ClonedLoopHeaders.erase(BB);
176+
}
177+
}
178+
179+
void findLoopHeaders();
180+
bool addToWorklistAfterSplittingEdges(SILBasicBlock *BB);
181+
};
182+
183+
#endif

0 commit comments

Comments
 (0)