Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
fbfa46a
[SimplifyCFG] precommit tests for simplify switch with duplicate arms
michaelmaitland Oct 30, 2024
2db9f00
[SimplifyCFG] Simplify switch instruction that has duplicate arms
michaelmaitland Oct 30, 2024
4e56067
fixup! respond to review
michaelmaitland Oct 30, 2024
9e10655
fixup! refactor for general approach
michaelmaitland Oct 30, 2024
64ddee6
fixup! move PHI checks
michaelmaitland Oct 30, 2024
c8eecb6
fixup! make it O(n)
michaelmaitland Oct 31, 2024
9e9afc2
fixup! use successor BBs in hash
michaelmaitland Oct 31, 2024
ef1bc74
fixup! use hasNPredsOrMore for early exit capability
michaelmaitland Oct 31, 2024
794d4e8
fixup! don't add to Cases if size() != 1 to improve performance
michaelmaitland Oct 31, 2024
32b627f
fixup! precompute getIncomingValueForBlock
michaelmaitland Nov 1, 2024
4190352
fixup! only support unconditional branches
michaelmaitland Nov 1, 2024
f04d67f
fixup! try improving getHashValue
michaelmaitland Nov 1, 2024
4ca2777
fixup! nitty cleanup
michaelmaitland Nov 1, 2024
28620df
fixup! don't reproccess map for same BB
michaelmaitland Nov 1, 2024
9dcf124
fixup! avoid calls to getIncomingValueForBlock
michaelmaitland Nov 1, 2024
41edd15
fixup! drop Seen vector since we no longer build phi map in loop
michaelmaitland Nov 1, 2024
5c247db
fixup! respond to review
michaelmaitland Nov 2, 2024
c3a1361
fixup! some cleanup and add Seen checks
michaelmaitland Nov 2, 2024
b563080
fixup! try and avoid some resizes
michaelmaitland Nov 5, 2024
67b3c80
fixup! presize PhiPredIVs based on first pass data
michaelmaitland Nov 5, 2024
94ff86e
fixup! use reserve instead of resize
michaelmaitland Nov 5, 2024
c6a5e52
fixup! precompute incoming values from BB
michaelmaitland Nov 5, 2024
241fef5
fixup! don't hash an empty set of values
michaelmaitland Nov 5, 2024
aa4cf43
fixup! add some comments
michaelmaitland Nov 5, 2024
8153c4b
fixup! simplify getHashValue
michaelmaitland Nov 5, 2024
d1cd111
fixup! another attempt at fixing hashing
michaelmaitland Nov 5, 2024
4949890
fixup! fix crashes
michaelmaitland Nov 5, 2024
e91253c
fixup~ Revert changes that precompute for getHashValue.
michaelmaitland Nov 5, 2024
d87ea1d
fixup! use SmallVector instead of vector
michaelmaitland Nov 7, 2024
be55920
fixup! update dom tree
michaelmaitland Nov 11, 2024
085b048
fixup! use get/set Sucessor
michaelmaitland Nov 11, 2024
3f0b020
fixup! avoid extra insert
michaelmaitland Nov 12, 2024
3430a66
fixup! respond to review
michaelmaitland Nov 14, 2024
852f3f0
fixup! respond to review
michaelmaitland Nov 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ class SimplifyCFGOpt {
bool simplifyCleanupReturn(CleanupReturnInst *RI);
bool simplifyUnreachable(UnreachableInst *UI);
bool simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder);
bool simplifyDuplicateSwitchArms(SwitchInst *SI);
bool simplifyIndirectBr(IndirectBrInst *IBI);
bool simplifyBranch(BranchInst *Branch, IRBuilder<> &Builder);
bool simplifyUncondBranch(BranchInst *BI, IRBuilder<> &Builder);
Expand Down Expand Up @@ -7436,6 +7437,94 @@ static bool simplifySwitchOfCmpIntrinsic(SwitchInst *SI, IRBuilderBase &Builder,
return true;
}

bool SimplifyCFGOpt::simplifyDuplicateSwitchArms(SwitchInst *SI) {
// Simplify the case where multiple arms contain only a terminator, the
// terminators are the same, and their sucessor PHIS incoming values are the
// same.

// Find BBs that are candidates for simplification.
SmallPtrSet<BasicBlock *, 8> BBs;
for (auto &Case : SI->cases()) {
BasicBlock *BB = Case.getCaseSuccessor();

// FIXME: This case needs some extra care because the terminators other than
// SI need to be updated.
if (!BB->hasNPredecessors(1))
continue;

// FIXME: Relax that the terminator is a BranchInst by checking for equality
// on other kinds of terminators.
Instruction *T = BB->getTerminator();
if (T && BB->size() == 1 && isa<BranchInst>(T))
BBs.insert(BB);
}

auto IsBranchEq = [](BranchInst *A, BranchInst *B) {
if (A->isConditional() != B->isConditional())
return false;

if (A->isConditional() && A->getCondition() != B->getCondition())
return false;

if (A->getNumSuccessors() != B->getNumSuccessors())
return false;

for (unsigned I = 0; I < A->getNumSuccessors(); ++I)
if (A->getSuccessor(I) != B->getSuccessor(I))
return false;

// Need to check that PHIs in sucessors have matching values
for (auto *Succ : A->successors()) {
for (PHINode &Phi : Succ->phis())
if (Phi.getIncomingValueForBlock(A->getParent()) !=
Phi.getIncomingValueForBlock(B->getParent()))
return false;
}

return true;
};

// Construct a map from candidate basic block to an equivalent basic block
// to replace it with. All equivalent basic blocks should be replaced with
// the same basic block. To do this, if there is no equivalent BB in the map,
// then insert into the map BB -> BB. Otherwise, we should check only elements
// in the map for equivalence to ensure that all equivalent BB get replaced
// by the BB in the map. Replacing BB with BB has no impact, so we skip
// a call to setSuccessor when we do the actual replacement.
DenseMap<BasicBlock *, BasicBlock *> ReplaceWith;
for (BasicBlock *BB : BBs) {
bool Inserted = false;
for (auto KV : ReplaceWith) {
if (IsBranchEq(cast<BranchInst>(BB->getTerminator()),
cast<BranchInst>(KV.first->getTerminator()))) {
ReplaceWith[BB] = KV.first;
Inserted = true;
break;
}
}
if (!Inserted)
ReplaceWith[BB] = BB;
}

// Do the replacement in SI.
bool MadeChange = false;
// There is no fast lookup of BasicBlock -> Cases, so we iterate over cases
// and check that the case was a candidate. BBs is already filtered, so
// hopefully calling contains on it is not too expensive.
for (auto &Case : SI->cases()) {
BasicBlock *OldSucc = Case.getCaseSuccessor();
if (!BBs.contains(OldSucc))
continue;
BasicBlock *NewSucc = ReplaceWith[OldSucc];
if (OldSucc != NewSucc) {
Case.setSuccessor(NewSucc);
MadeChange = true;
}
}

return MadeChange;
}

bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
BasicBlock *BB = SI->getParent();

Expand Down Expand Up @@ -7496,6 +7585,9 @@ bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
hoistCommonCodeFromSuccessors(SI, !Options.HoistCommonInsts))
return requestResimplify();

if (simplifyDuplicateSwitchArms(SI))
return requestResimplify();

return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,16 +139,14 @@ define i32 @PR34471(i32 %x) {
; NO_FWD-NEXT: switch i32 [[X:%.*]], label [[ELSE3:%.*]] [
; NO_FWD-NEXT: i32 17, label [[RETURN:%.*]]
; NO_FWD-NEXT: i32 19, label [[IF19:%.*]]
; NO_FWD-NEXT: i32 42, label [[IF42:%.*]]
; NO_FWD-NEXT: i32 42, label [[IF19]]
; NO_FWD-NEXT: ]
; NO_FWD: if19:
; NO_FWD-NEXT: br label [[RETURN]]
; NO_FWD: if42:
; NO_FWD-NEXT: br label [[RETURN]]
; NO_FWD: else3:
; NO_FWD-NEXT: br label [[RETURN]]
; NO_FWD: return:
; NO_FWD-NEXT: [[R:%.*]] = phi i32 [ [[X]], [[IF19]] ], [ [[X]], [[IF42]] ], [ 0, [[ELSE3]] ], [ 17, [[ENTRY:%.*]] ]
; NO_FWD-NEXT: [[R:%.*]] = phi i32 [ [[X]], [[IF19]] ], [ 0, [[ELSE3]] ], [ 17, [[ENTRY:%.*]] ]
; NO_FWD-NEXT: ret i32 [[R]]
;
; FWD-LABEL: @PR34471(
Expand Down
6 changes: 2 additions & 4 deletions llvm/test/Transforms/SimplifyCFG/HoistCode.ll
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,12 @@ define float @PR39535min_switch(i64 %i, float %x) {
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i64 [[I:%.*]], label [[END:%.*]] [
; CHECK-NEXT: i64 1, label [[BB1:%.*]]
; CHECK-NEXT: i64 2, label [[BB2:%.*]]
; CHECK-NEXT: i64 2, label [[BB1]]
; CHECK-NEXT: ]
; CHECK: bb1:
; CHECK-NEXT: br label [[END]]
; CHECK: bb2:
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: [[COND:%.*]] = phi fast float [ [[X:%.*]], [[BB1]] ], [ [[X]], [[BB2]] ], [ 0.000000e+00, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[COND:%.*]] = phi fast float [ [[X:%.*]], [[BB1]] ], [ 0.000000e+00, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret float [[COND]]
;
entry:
Expand Down
140 changes: 140 additions & 0 deletions llvm/test/Transforms/SimplifyCFG/switch-dup-bbs.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt < %s -passes=simplifycfg -S | FileCheck %s -check-prefix=SIMPLIFY-CFG
; RUN: opt < %s -O3 -S | FileCheck %s -check-prefix=O3

define i32 @switch_all_duplicate_arms(i32 %0, i32 %1, i32 %2, i32 %3) {
; SIMPLIFY-CFG-LABEL: define i32 @switch_all_duplicate_arms(
; SIMPLIFY-CFG-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]], i32 [[TMP3:%.*]]) {
; SIMPLIFY-CFG-NEXT: switch i32 [[TMP1]], label %[[BB6:.*]] [
; SIMPLIFY-CFG-NEXT: i32 0, label %[[BB5:.*]]
; SIMPLIFY-CFG-NEXT: i32 1, label %[[BB5]]
; SIMPLIFY-CFG-NEXT: ]
; SIMPLIFY-CFG: [[BB5]]:
; SIMPLIFY-CFG-NEXT: br label %[[BB6]]
; SIMPLIFY-CFG: [[BB6]]:
; SIMPLIFY-CFG-NEXT: [[TMP8:%.*]] = phi i32 [ [[TMP3]], [[TMP4:%.*]] ], [ [[TMP2]], %[[BB5]] ]
; SIMPLIFY-CFG-NEXT: ret i32 [[TMP8]]
;
; O3-LABEL: define i32 @switch_all_duplicate_arms(
; O3-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]], i32 [[TMP3:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
; O3-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[TMP1]], 2
; O3-NEXT: [[TMP8:%.*]] = select i1 [[SWITCH]], i32 [[TMP2]], i32 [[TMP3]]
; O3-NEXT: ret i32 [[TMP8]]
;
switch i32 %1, label %7 [
i32 0, label %5
i32 1, label %6
]

5:
br label %7

6:
br label %7

7:
%8 = phi i32 [ %3, %4 ], [ %2, %6 ], [ %2, %5 ]
ret i32 %8
}

define i32 @switch_some_duplicate_arms(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4) {
; SIMPLIFY-CFG-LABEL: define i32 @switch_some_duplicate_arms(
; SIMPLIFY-CFG-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]], i32 [[TMP3:%.*]], i32 [[TMP4:%.*]]) {
; SIMPLIFY-CFG-NEXT: switch i32 [[TMP1]], label %[[BB8:.*]] [
; SIMPLIFY-CFG-NEXT: i32 0, label %[[BB6:.*]]
; SIMPLIFY-CFG-NEXT: i32 1, label %[[BB6]]
; SIMPLIFY-CFG-NEXT: i32 2, label %[[BB7:.*]]
; SIMPLIFY-CFG-NEXT: ]
; SIMPLIFY-CFG: [[BB6]]:
; SIMPLIFY-CFG-NEXT: br label %[[BB8]]
; SIMPLIFY-CFG: [[BB7]]:
; SIMPLIFY-CFG-NEXT: br label %[[BB8]]
; SIMPLIFY-CFG: [[BB8]]:
; SIMPLIFY-CFG-NEXT: [[TMP10:%.*]] = phi i32 [ [[TMP3]], [[TMP5:%.*]] ], [ [[TMP4]], %[[BB7]] ], [ [[TMP2]], %[[BB6]] ]
; SIMPLIFY-CFG-NEXT: ret i32 [[TMP10]]
;
; O3-LABEL: define i32 @switch_some_duplicate_arms(
; O3-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]], i32 [[TMP3:%.*]], i32 [[TMP4:%.*]]) local_unnamed_addr #[[ATTR0]] {
; O3-NEXT: switch i32 [[TMP1]], label %[[BB8:.*]] [
; O3-NEXT: i32 0, label %[[BB6:.*]]
; O3-NEXT: i32 1, label %[[BB6]]
; O3-NEXT: i32 2, label %[[BB7:.*]]
; O3-NEXT: ]
; O3: [[BB6]]:
; O3-NEXT: br label %[[BB8]]
; O3: [[BB7]]:
; O3-NEXT: br label %[[BB8]]
; O3: [[BB8]]:
; O3-NEXT: [[TMP10:%.*]] = phi i32 [ [[TMP3]], [[TMP5:%.*]] ], [ [[TMP4]], %[[BB7]] ], [ [[TMP2]], %[[BB6]] ]
; O3-NEXT: ret i32 [[TMP10]]
;
switch i32 %1, label %9 [
i32 0, label %6
i32 1, label %7
i32 2, label %8
]

6:
br label %9

7:
br label %9

8:
br label %9

9:
%10 = phi i32 [ %3, %5 ], [ %4, %8 ], [ %2, %7 ], [ %2, %6 ]
ret i32 %10
}

define i32 @switch_duplicate_arms_multipred(i1 %0, i32 %1, i32 %2, i32 %3, i32 %4) {
; SIMPLIFY-CFG-LABEL: define i32 @switch_duplicate_arms_multipred(
; SIMPLIFY-CFG-SAME: i1 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]], i32 [[TMP3:%.*]], i32 [[TMP4:%.*]]) {
; SIMPLIFY-CFG-NEXT: br i1 [[TMP0]], label %[[BB6:.*]], label %[[BB7:.*]]
; SIMPLIFY-CFG: [[BB6]]:
; SIMPLIFY-CFG-NEXT: switch i32 [[TMP2]], label %[[BB9:.*]] [
; SIMPLIFY-CFG-NEXT: i32 0, label %[[BB7]]
; SIMPLIFY-CFG-NEXT: i32 1, label %[[BB8:.*]]
; SIMPLIFY-CFG-NEXT: ]
; SIMPLIFY-CFG: [[BB7]]:
; SIMPLIFY-CFG-NEXT: br label %[[BB9]]
; SIMPLIFY-CFG: [[BB8]]:
; SIMPLIFY-CFG-NEXT: br label %[[BB9]]
; SIMPLIFY-CFG: [[BB9]]:
; SIMPLIFY-CFG-NEXT: [[TMP10:%.*]] = phi i32 [ [[TMP4]], %[[BB6]] ], [ [[TMP3]], %[[BB8]] ], [ [[TMP3]], %[[BB7]] ]
; SIMPLIFY-CFG-NEXT: ret i32 [[TMP10]]
;
; O3-LABEL: define i32 @switch_duplicate_arms_multipred(
; O3-SAME: i1 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]], i32 [[TMP3:%.*]], i32 [[TMP4:%.*]]) local_unnamed_addr #[[ATTR0]] {
; O3-NEXT: br i1 [[TMP0]], label %[[BB6:.*]], label %[[BB7:.*]]
; O3: [[BB6]]:
; O3-NEXT: switch i32 [[TMP2]], label %[[BB9:.*]] [
; O3-NEXT: i32 0, label %[[BB7]]
; O3-NEXT: i32 1, label %[[BB8:.*]]
; O3-NEXT: ]
; O3: [[BB7]]:
; O3-NEXT: br label %[[BB9]]
; O3: [[BB8]]:
; O3-NEXT: br label %[[BB9]]
; O3: [[BB9]]:
; O3-NEXT: [[TMP10:%.*]] = phi i32 [ [[TMP4]], %[[BB6]] ], [ [[TMP3]], %[[BB8]] ], [ [[TMP3]], %[[BB7]] ]
; O3-NEXT: ret i32 [[TMP10]]
;
br i1 %0, label %6, label %7
6:
switch i32 %2, label %9 [
i32 0, label %7
i32 1, label %8
]

7:
br label %9

8:
br label %9

9:
%10 = phi i32 [ %4, %6 ], [ %3, %8 ], [ %3, %7 ]
ret i32 %10
}
6 changes: 2 additions & 4 deletions llvm/test/Transforms/SimplifyCFG/switch-to-select-two-case.ll
Original file line number Diff line number Diff line change
Expand Up @@ -272,16 +272,14 @@ define i8 @switch_to_select_two_case_results_no_default(i32 %i) {
; CHECK-NEXT: i32 0, label [[END:%.*]]
; CHECK-NEXT: i32 2, label [[END]]
; CHECK-NEXT: i32 4, label [[CASE3:%.*]]
; CHECK-NEXT: i32 6, label [[CASE4:%.*]]
; CHECK-NEXT: i32 6, label [[CASE3]]
; CHECK-NEXT: ]
; CHECK: case3:
; CHECK-NEXT: br label [[END]]
; CHECK: case4:
; CHECK-NEXT: br label [[END]]
; CHECK: default:
; CHECK-NEXT: unreachable
; CHECK: end:
; CHECK-NEXT: [[T0:%.*]] = phi i8 [ 44, [[CASE3]] ], [ 44, [[CASE4]] ], [ 42, [[ENTRY:%.*]] ], [ 42, [[ENTRY]] ]
; CHECK-NEXT: [[T0:%.*]] = phi i8 [ 44, [[CASE3]] ], [ 42, [[ENTRY:%.*]] ], [ 42, [[ENTRY]] ]
; CHECK-NEXT: ret i8 [[T0]]
;
entry:
Expand Down
Loading