Skip to content

Commit eb7f705

Browse files
committed
[DFAJumpThreading] Unify equivalent states
1 parent f6eb2f8 commit eb7f705

File tree

2 files changed

+97
-101
lines changed

2 files changed

+97
-101
lines changed

llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp

Lines changed: 85 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,22 @@ inline raw_ostream &operator<<(raw_ostream &OS, const PathType &Path) {
384384
return OS;
385385
}
386386

387+
/// Helper to get the successor corresponding to a particular case value for
388+
/// a switch statement.
389+
static BasicBlock *getNextCaseSuccessor(SwitchInst *Switch,
390+
const APInt &NextState) {
391+
BasicBlock *NextCase = nullptr;
392+
for (auto Case : Switch->cases()) {
393+
if (Case.getCaseValue()->getValue() == NextState) {
394+
NextCase = Case.getCaseSuccessor();
395+
break;
396+
}
397+
}
398+
if (!NextCase)
399+
NextCase = Switch->getDefaultDest();
400+
return NextCase;
401+
}
402+
387403
namespace {
388404
/// ThreadingPath is a path in the control flow of a loop that can be threaded
389405
/// by cloning necessary basic blocks and replacing conditional branches with
@@ -396,6 +412,10 @@ struct ThreadingPath {
396412
ExitVal = V->getValue();
397413
IsExitValSet = true;
398414
}
415+
void setExitValue(const APInt &V) {
416+
ExitVal = V;
417+
IsExitValSet = true;
418+
}
399419
bool isExitValueSet() const { return IsExitValSet; }
400420

401421
/// Determinator is the basic block that determines the next state of the DFA.
@@ -578,44 +598,8 @@ struct AllSwitchPaths {
578598
BasicBlock *getSwitchBlock() { return SwitchBlock; }
579599

580600
void run() {
581-
StateDefMap StateDef = getStateDefMap();
582-
if (StateDef.empty()) {
583-
ORE->emit([&]() {
584-
return OptimizationRemarkMissed(DEBUG_TYPE, "SwitchNotPredictable",
585-
Switch)
586-
<< "Switch instruction is not predictable.";
587-
});
588-
return;
589-
}
590-
591-
auto *SwitchPhi = cast<PHINode>(Switch->getOperand(0));
592-
auto *SwitchPhiDefBB = SwitchPhi->getParent();
593-
VisitedBlocks VB;
594-
// Get paths from the determinator BBs to SwitchPhiDefBB
595-
std::vector<ThreadingPath> PathsToPhiDef =
596-
getPathsFromStateDefMap(StateDef, SwitchPhi, VB, MaxNumPaths);
597-
if (SwitchPhiDefBB == SwitchBlock || PathsToPhiDef.empty()) {
598-
TPaths = std::move(PathsToPhiDef);
599-
return;
600-
}
601-
602-
assert(MaxNumPaths >= PathsToPhiDef.size() && !PathsToPhiDef.empty());
603-
auto PathsLimit = MaxNumPaths / PathsToPhiDef.size();
604-
// Find and append paths from SwitchPhiDefBB to SwitchBlock.
605-
PathsType PathsToSwitchBB =
606-
paths(SwitchPhiDefBB, SwitchBlock, VB, /* PathDepth = */ 1, PathsLimit);
607-
if (PathsToSwitchBB.empty())
608-
return;
609-
610-
std::vector<ThreadingPath> TempList;
611-
for (const ThreadingPath &Path : PathsToPhiDef) {
612-
for (const PathType &PathToSw : PathsToSwitchBB) {
613-
ThreadingPath PathCopy(Path);
614-
PathCopy.appendExcludingFirst(PathToSw);
615-
TempList.push_back(PathCopy);
616-
}
617-
}
618-
TPaths = std::move(TempList);
601+
findTPaths();
602+
unifyTPaths();
619603
}
620604

621605
private:
@@ -807,6 +791,69 @@ struct AllSwitchPaths {
807791
return Res;
808792
}
809793

794+
// Find all threadable paths.
795+
void findTPaths() {
796+
StateDefMap StateDef = getStateDefMap();
797+
if (StateDef.empty()) {
798+
ORE->emit([&]() {
799+
return OptimizationRemarkMissed(DEBUG_TYPE, "SwitchNotPredictable",
800+
Switch)
801+
<< "Switch instruction is not predictable.";
802+
});
803+
return;
804+
}
805+
806+
auto *SwitchPhi = cast<PHINode>(Switch->getOperand(0));
807+
auto *SwitchPhiDefBB = SwitchPhi->getParent();
808+
VisitedBlocks VB;
809+
// Get paths from the determinator BBs to SwitchPhiDefBB
810+
std::vector<ThreadingPath> PathsToPhiDef =
811+
getPathsFromStateDefMap(StateDef, SwitchPhi, VB, MaxNumPaths);
812+
if (SwitchPhiDefBB == SwitchBlock || PathsToPhiDef.empty()) {
813+
TPaths = std::move(PathsToPhiDef);
814+
return;
815+
}
816+
817+
assert(MaxNumPaths >= PathsToPhiDef.size() && !PathsToPhiDef.empty());
818+
auto PathsLimit = MaxNumPaths / PathsToPhiDef.size();
819+
// Find and append paths from SwitchPhiDefBB to SwitchBlock.
820+
PathsType PathsToSwitchBB =
821+
paths(SwitchPhiDefBB, SwitchBlock, VB, /* PathDepth = */ 1, PathsLimit);
822+
if (PathsToSwitchBB.empty())
823+
return;
824+
825+
std::vector<ThreadingPath> TempList;
826+
for (const ThreadingPath &Path : PathsToPhiDef) {
827+
for (const PathType &PathToSw : PathsToSwitchBB) {
828+
ThreadingPath PathCopy(Path);
829+
PathCopy.appendExcludingFirst(PathToSw);
830+
TempList.push_back(PathCopy);
831+
}
832+
}
833+
TPaths = std::move(TempList);
834+
}
835+
836+
// Two states are equivalent if they have the same switch destination.
837+
// Unify the states in different threading path if the states are equivalent.
838+
void unifyTPaths() {
839+
llvm::SmallDenseMap<BasicBlock *, APInt> DestToState;
840+
for (ThreadingPath &Path : TPaths) {
841+
APInt NextState = Path.getExitValue();
842+
BasicBlock *Dest = getNextCaseSuccessor(Switch, NextState);
843+
auto StateIt = DestToState.find(Dest);
844+
if (StateIt == DestToState.end()) {
845+
DestToState.insert({Dest, NextState});
846+
continue;
847+
}
848+
849+
if (NextState != StateIt->second) {
850+
LLVM_DEBUG(dbgs() << "Next state in " << Path << " is equivalent to "
851+
<< StateIt->second << "\n");
852+
Path.setExitValue(StateIt->second);
853+
}
854+
}
855+
}
856+
810857
unsigned NumVisited = 0;
811858
SwitchInst *Switch;
812859
BasicBlock *SwitchBlock;
@@ -1339,21 +1386,6 @@ struct TransformDFA {
13391386
return It != ClonedBBs.end() ? (*It).BB : nullptr;
13401387
}
13411388

1342-
/// Helper to get the successor corresponding to a particular case value for
1343-
/// a switch statement.
1344-
BasicBlock *getNextCaseSuccessor(SwitchInst *Switch, const APInt &NextState) {
1345-
BasicBlock *NextCase = nullptr;
1346-
for (auto Case : Switch->cases()) {
1347-
if (Case.getCaseValue()->getValue() == NextState) {
1348-
NextCase = Case.getCaseSuccessor();
1349-
break;
1350-
}
1351-
}
1352-
if (!NextCase)
1353-
NextCase = Switch->getDefaultDest();
1354-
return NextCase;
1355-
}
1356-
13571389
/// Returns true if IncomingBB is a predecessor of BB.
13581390
bool isPredecessor(BasicBlock *BB, BasicBlock *IncomingBB) {
13591391
return llvm::is_contained(predecessors(BB), IncomingBB);

llvm/test/Transforms/DFAJumpThreading/equivalent-states.ll

Lines changed: 12 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ define void @equivalent_on_default(i1 %c1) {
1515
; CHECK-NEXT: i32 0, label [[CASE1:%.*]]
1616
; CHECK-NEXT: i32 1, label [[CASE2:%.*]]
1717
; CHECK-NEXT: ]
18-
; CHECK: switch_bb.jt3:
19-
; CHECK-NEXT: [[PHI_JT3:%.*]] = phi i32 [ [[PHI_CASE2_JT3:%.*]], [[CASE2END_JT3:%.*]] ]
20-
; CHECK-NEXT: br label [[DEFAULT_DEST]]
2118
; CHECK: switch_bb.jt2:
2219
; CHECK-NEXT: [[PHI_JT2:%.*]] = phi i32 [ [[PHI_CASE2_JT2:%.*]], [[CASE2END_JT2:%.*]] ]
2320
; CHECK-NEXT: br label [[DEFAULT_DEST]]
@@ -29,16 +26,12 @@ define void @equivalent_on_default(i1 %c1) {
2926
; CHECK: case2:
3027
; CHECK-NEXT: br i1 [[C1]], label [[CASE2THEN:%.*]], label [[CASE2END_JT2]]
3128
; CHECK: case2then:
32-
; CHECK-NEXT: br label [[CASE2END_JT3]]
29+
; CHECK-NEXT: br label [[CASE2END_JT2]]
3330
; CHECK: case2end:
3431
; CHECK-NEXT: call void @do_something()
3532
; CHECK-NEXT: br label [[SWITCH_BB]]
36-
; CHECK: case2end.jt3:
37-
; CHECK-NEXT: [[PHI_CASE2_JT3]] = phi i32 [ 3, [[CASE2THEN]] ]
38-
; CHECK-NEXT: call void @do_something()
39-
; CHECK-NEXT: br label [[SWITCH_BB_JT3:%.*]]
4033
; CHECK: case2end.jt2:
41-
; CHECK-NEXT: [[PHI_CASE2_JT2]] = phi i32 [ 2, [[CASE2]] ]
34+
; CHECK-NEXT: [[PHI_CASE2_JT2]] = phi i32 [ 2, [[CASE2]] ], [ 3, [[CASE2THEN]] ]
4235
; CHECK-NEXT: call void @do_something()
4336
; CHECK-NEXT: br label [[SWITCH_BB_JT2:%.*]]
4437
; CHECK: default_dest:
@@ -83,9 +76,6 @@ define void @equivalent_on_default_user(i1 %c1) {
8376
; CHECK-NEXT: i32 0, label [[CASE1:%.*]]
8477
; CHECK-NEXT: i32 1, label [[CASE2:%.*]]
8578
; CHECK-NEXT: ]
86-
; CHECK: switch_bb.jt3:
87-
; CHECK-NEXT: [[PHI_JT3:%.*]] = phi i32 [ [[PHI_CASE2_JT3:%.*]], [[CASE2END_JT3:%.*]] ]
88-
; CHECK-NEXT: br label [[DEFAULT_DEST]]
8979
; CHECK: switch_bb.jt2:
9080
; CHECK-NEXT: [[PHI_JT2:%.*]] = phi i32 [ [[PHI_CASE2_JT2:%.*]], [[CASE2END_JT2:%.*]] ]
9181
; CHECK-NEXT: br label [[DEFAULT_DEST]]
@@ -97,18 +87,13 @@ define void @equivalent_on_default_user(i1 %c1) {
9787
; CHECK: case2:
9888
; CHECK-NEXT: br i1 [[C1]], label [[CASE2THEN:%.*]], label [[CASE2END_JT2]]
9989
; CHECK: case2then:
100-
; CHECK-NEXT: br label [[CASE2END_JT3]]
90+
; CHECK-NEXT: br label [[CASE2END_JT2]]
10191
; CHECK: case2end:
10292
; CHECK-NEXT: call void @do_something()
10393
; CHECK-NEXT: call void @user(i32 poison)
10494
; CHECK-NEXT: br label [[SWITCH_BB]]
105-
; CHECK: case2end.jt3:
106-
; CHECK-NEXT: [[PHI_CASE2_JT3]] = phi i32 [ 3, [[CASE2THEN]] ]
107-
; CHECK-NEXT: call void @do_something()
108-
; CHECK-NEXT: call void @user(i32 [[PHI_CASE2_JT3]])
109-
; CHECK-NEXT: br label [[SWITCH_BB_JT3:%.*]]
11095
; CHECK: case2end.jt2:
111-
; CHECK-NEXT: [[PHI_CASE2_JT2]] = phi i32 [ 2, [[CASE2]] ]
96+
; CHECK-NEXT: [[PHI_CASE2_JT2]] = phi i32 [ 2, [[CASE2]] ], [ 3, [[CASE2THEN]] ]
11297
; CHECK-NEXT: call void @do_something()
11398
; CHECK-NEXT: call void @user(i32 [[PHI_CASE2_JT2]])
11499
; CHECK-NEXT: br label [[SWITCH_BB_JT2:%.*]]
@@ -157,9 +142,6 @@ define void @equivalent_only_cases(i1 %c1) {
157142
; CHECK-NEXT: i32 2, label [[CASE1]]
158143
; CHECK-NEXT: i32 3, label [[CASE1]]
159144
; CHECK-NEXT: ]
160-
; CHECK: switch_bb.jt3:
161-
; CHECK-NEXT: [[PHI_JT3:%.*]] = phi i32 [ [[PHI_CASE2_JT3:%.*]], [[CASE2END_JT3:%.*]] ]
162-
; CHECK-NEXT: br label [[CASE1]]
163145
; CHECK: switch_bb.jt2:
164146
; CHECK-NEXT: [[PHI_JT2:%.*]] = phi i32 [ [[PHI_CASE2_JT2:%.*]], [[CASE2END_JT2:%.*]] ]
165147
; CHECK-NEXT: br label [[CASE1]]
@@ -172,16 +154,12 @@ define void @equivalent_only_cases(i1 %c1) {
172154
; CHECK: case2:
173155
; CHECK-NEXT: br i1 [[C1]], label [[CASE2THEN:%.*]], label [[CASE2END_JT2]]
174156
; CHECK: case2then:
175-
; CHECK-NEXT: br label [[CASE2END_JT3]]
157+
; CHECK-NEXT: br label [[CASE2END_JT2]]
176158
; CHECK: case2end:
177159
; CHECK-NEXT: call void @do_something()
178160
; CHECK-NEXT: br label [[SWITCH_BB]]
179-
; CHECK: case2end.jt3:
180-
; CHECK-NEXT: [[PHI_CASE2_JT3]] = phi i32 [ 3, [[CASE2THEN]] ]
181-
; CHECK-NEXT: call void @do_something()
182-
; CHECK-NEXT: br label [[SWITCH_BB_JT3:%.*]]
183161
; CHECK: case2end.jt2:
184-
; CHECK-NEXT: [[PHI_CASE2_JT2]] = phi i32 [ 2, [[CASE2]] ]
162+
; CHECK-NEXT: [[PHI_CASE2_JT2]] = phi i32 [ 2, [[CASE2]] ], [ 3, [[CASE2THEN]] ]
185163
; CHECK-NEXT: call void @do_something()
186164
; CHECK-NEXT: br label [[SWITCH_BB_JT2:%.*]]
187165
; CHECK: default_dest:
@@ -231,15 +209,9 @@ define void @equivalent_both_case_and_default(i1 %c1, i1 %c2) {
231209
; CHECK-NEXT: i32 2, label [[CASE1]]
232210
; CHECK-NEXT: i32 3, label [[CASE1]]
233211
; CHECK-NEXT: ]
234-
; CHECK: switch_bb.jt5:
235-
; CHECK-NEXT: [[PHI_JT5:%.*]] = phi i32 [ [[PHI_CASE2_JT5:%.*]], [[CASE2END_JT5:%.*]] ]
236-
; CHECK-NEXT: br label [[DEFAULT_DEST]]
237212
; CHECK: switch_bb.jt4:
238-
; CHECK-NEXT: [[PHI_JT4:%.*]] = phi i32 [ [[PHI_CASE2_JT4:%.*]], [[CASE2END_JT4:%.*]] ]
239-
; CHECK-NEXT: br label [[DEFAULT_DEST]]
240-
; CHECK: switch_bb.jt3:
241213
; CHECK-NEXT: [[PHI_JT3:%.*]] = phi i32 [ [[PHI_CASE2_JT3:%.*]], [[CASE2END_JT3:%.*]] ]
242-
; CHECK-NEXT: br label [[CASE1]]
214+
; CHECK-NEXT: br label [[DEFAULT_DEST]]
243215
; CHECK: switch_bb.jt2:
244216
; CHECK-NEXT: [[PHI_JT2:%.*]] = phi i32 [ [[PHI_CASE2_JT2:%.*]], [[CASE2END_JT2:%.*]] ]
245217
; CHECK-NEXT: br label [[CASE1]]
@@ -252,28 +224,20 @@ define void @equivalent_both_case_and_default(i1 %c1, i1 %c2) {
252224
; CHECK: case2:
253225
; CHECK-NEXT: br i1 [[C1]], label [[CASE2THEN:%.*]], label [[CASE2END_JT2]]
254226
; CHECK: case2then:
255-
; CHECK-NEXT: br i1 [[C2]], label [[CASE2THEN2:%.*]], label [[CASE2END_JT3]]
227+
; CHECK-NEXT: br i1 [[C2]], label [[CASE2THEN2:%.*]], label [[CASE2END_JT2]]
256228
; CHECK: case2then2:
257-
; CHECK-NEXT: br i1 [[C2]], label [[CASE2THEN3:%.*]], label [[CASE2END_JT4]]
229+
; CHECK-NEXT: br i1 [[C2]], label [[CASE2THEN3:%.*]], label [[CASE2END_JT3]]
258230
; CHECK: case2then3:
259-
; CHECK-NEXT: br label [[CASE2END_JT5]]
231+
; CHECK-NEXT: br label [[CASE2END_JT3]]
260232
; CHECK: case2end:
261233
; CHECK-NEXT: call void @do_something()
262234
; CHECK-NEXT: br label [[SWITCH_BB]]
263-
; CHECK: case2end.jt5:
264-
; CHECK-NEXT: [[PHI_CASE2_JT5]] = phi i32 [ 5, [[CASE2THEN3]] ]
265-
; CHECK-NEXT: call void @do_something()
266-
; CHECK-NEXT: br label [[SWITCH_BB_JT5:%.*]]
267235
; CHECK: case2end.jt4:
268-
; CHECK-NEXT: [[PHI_CASE2_JT4]] = phi i32 [ 4, [[CASE2THEN2]] ]
269-
; CHECK-NEXT: call void @do_something()
270-
; CHECK-NEXT: br label [[SWITCH_BB_JT4:%.*]]
271-
; CHECK: case2end.jt3:
272-
; CHECK-NEXT: [[PHI_CASE2_JT3]] = phi i32 [ 3, [[CASE2THEN]] ]
236+
; CHECK-NEXT: [[PHI_CASE2_JT3]] = phi i32 [ 4, [[CASE2THEN2]] ], [ 5, [[CASE2THEN3]] ]
273237
; CHECK-NEXT: call void @do_something()
274238
; CHECK-NEXT: br label [[SWITCH_BB_JT3:%.*]]
275239
; CHECK: case2end.jt2:
276-
; CHECK-NEXT: [[PHI_CASE2_JT2]] = phi i32 [ 2, [[CASE2]] ]
240+
; CHECK-NEXT: [[PHI_CASE2_JT2]] = phi i32 [ 2, [[CASE2]] ], [ 3, [[CASE2THEN]] ]
277241
; CHECK-NEXT: call void @do_something()
278242
; CHECK-NEXT: br label [[SWITCH_BB_JT2:%.*]]
279243
; CHECK: default_dest:

0 commit comments

Comments
 (0)