Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit 6596fa3

Browse files
committed
[WebAssembly] Remove unnecessary instructions after TRY marker placement
Summary: This removes unnecessary instructions after TRY marker placement. There are two cases: - `end`/`end_block` can be removed if they overlap with `try`/`end_try` and they have the same return types. - `br` right before `catch` that branches to after `end_try` can be deleted. Reviewers: dschuff Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D58591 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@354939 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 96e2795 commit 6596fa3

File tree

3 files changed

+207
-146
lines changed

3 files changed

+207
-146
lines changed

lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class WebAssemblyCFGStackify final : public MachineFunctionPass {
6464
void placeBlockMarker(MachineBasicBlock &MBB);
6565
void placeLoopMarker(MachineBasicBlock &MBB);
6666
void placeTryMarker(MachineBasicBlock &MBB);
67+
void removeUnnecessaryInstrs(MachineFunction &MF);
6768
void rewriteDepthImmediates(MachineFunction &MF);
6869
void fixEndsAtEndOfFunction(MachineFunction &MF);
6970

@@ -76,11 +77,12 @@ class WebAssemblyCFGStackify final : public MachineFunctionPass {
7677
// <EH pad, TRY marker> map
7778
DenseMap<const MachineBasicBlock *, MachineInstr *> EHPadToTry;
7879

79-
// Helper functions to register scope information created by marker
80-
// instructions.
80+
// Helper functions to register / unregister scope information created by
81+
// marker instructions.
8182
void registerScope(MachineInstr *Begin, MachineInstr *End);
8283
void registerTryScope(MachineInstr *Begin, MachineInstr *End,
8384
MachineBasicBlock *EHPad);
85+
void unregisterScope(MachineInstr *Begin);
8486

8587
public:
8688
static char ID; // Pass identification, replacement for typeid
@@ -175,6 +177,20 @@ void WebAssemblyCFGStackify::registerTryScope(MachineInstr *Begin,
175177
EHPadToTry[EHPad] = Begin;
176178
}
177179

180+
void WebAssemblyCFGStackify::unregisterScope(MachineInstr *Begin) {
181+
assert(BeginToEnd.count(Begin));
182+
MachineInstr *End = BeginToEnd[Begin];
183+
assert(EndToBegin.count(End));
184+
BeginToEnd.erase(Begin);
185+
EndToBegin.erase(End);
186+
MachineBasicBlock *EHPad = TryToEHPad.lookup(Begin);
187+
if (EHPad) {
188+
assert(EHPadToTry.count(EHPad));
189+
TryToEHPad.erase(Begin);
190+
EHPadToTry.erase(EHPad);
191+
}
192+
}
193+
178194
/// Insert a BLOCK marker for branches to MBB (if needed).
179195
void WebAssemblyCFGStackify::placeBlockMarker(MachineBasicBlock &MBB) {
180196
// This should have been handled in placeTryMarker.
@@ -585,6 +601,76 @@ void WebAssemblyCFGStackify::placeTryMarker(MachineBasicBlock &MBB) {
585601
ScopeTops[Number] = Header;
586602
}
587603

604+
void WebAssemblyCFGStackify::removeUnnecessaryInstrs(MachineFunction &MF) {
605+
const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
606+
607+
// When there is an unconditional branch right before a catch instruction and
608+
// it branches to the end of end_try marker, we don't need the branch, because
609+
// it there is no exception, the control flow transfers to that point anyway.
610+
// bb0:
611+
// try
612+
// ...
613+
// br bb2 <- Not necessary
614+
// bb1:
615+
// catch
616+
// ...
617+
// bb2:
618+
// end
619+
for (auto &MBB : MF) {
620+
if (!MBB.isEHPad())
621+
continue;
622+
623+
MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
624+
SmallVector<MachineOperand, 4> Cond;
625+
MachineBasicBlock *EHPadLayoutPred =
626+
&*std::prev(MachineFunction::iterator(&MBB));
627+
MachineBasicBlock *Cont = BeginToEnd[EHPadToTry[&MBB]]->getParent();
628+
bool Analyzable = !TII.analyzeBranch(*EHPadLayoutPred, TBB, FBB, Cond);
629+
if (Analyzable && ((Cond.empty() && TBB && TBB == Cont) ||
630+
(!Cond.empty() && FBB && FBB == Cont)))
631+
TII.removeBranch(*EHPadLayoutPred);
632+
}
633+
634+
// When there are block / end_block markers that overlap with try / end_try
635+
// markers, and the block and try markers' return types are the same, the
636+
// block /end_block markers are not necessary, because try / end_try markers
637+
// also can serve as boundaries for branches.
638+
// block <- Not necessary
639+
// try
640+
// ...
641+
// catch
642+
// ...
643+
// end
644+
// end <- Not necessary
645+
SmallVector<MachineInstr *, 32> ToDelete;
646+
for (auto &MBB : MF) {
647+
for (auto &MI : MBB) {
648+
if (MI.getOpcode() != WebAssembly::TRY)
649+
continue;
650+
651+
MachineInstr *Try = &MI, *EndTry = BeginToEnd[Try];
652+
MachineBasicBlock *TryBB = Try->getParent();
653+
MachineBasicBlock *Cont = EndTry->getParent();
654+
int64_t RetType = Try->getOperand(0).getImm();
655+
for (auto B = MachineBasicBlock::iterator(Try),
656+
E = std::next(MachineBasicBlock::iterator(EndTry));
657+
B != TryBB->begin() && E != Cont->end() &&
658+
std::prev(B)->getOpcode() == WebAssembly::BLOCK &&
659+
E->getOpcode() == WebAssembly::END_BLOCK &&
660+
std::prev(B)->getOperand(0).getImm() == RetType;
661+
--B, ++E) {
662+
ToDelete.push_back(&*std::prev(B));
663+
ToDelete.push_back(&*E);
664+
}
665+
}
666+
}
667+
for (auto *MI : ToDelete) {
668+
if (MI->getOpcode() == WebAssembly::BLOCK)
669+
unregisterScope(MI);
670+
MI->eraseFromParent();
671+
}
672+
}
673+
588674
static unsigned
589675
getDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack,
590676
const MachineBasicBlock *MBB) {
@@ -747,6 +833,7 @@ bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {
747833
LLVM_DEBUG(dbgs() << "********** CFG Stackifying **********\n"
748834
"********** Function: "
749835
<< MF.getName() << '\n');
836+
const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo();
750837

751838
releaseMemory();
752839

@@ -756,6 +843,11 @@ bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {
756843
// Place the BLOCK/LOOP/TRY markers to indicate the beginnings of scopes.
757844
placeMarkers(MF);
758845

846+
if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm &&
847+
MF.getFunction().hasPersonalityFn())
848+
// Remove unnecessary instructions.
849+
removeUnnecessaryInstrs(MF);
850+
759851
// Convert MBB operands in terminators to relative depth immediates.
760852
rewriteDepthImmediates(MF);
761853

test/CodeGen/WebAssembly/cfg-stackify-eh.ll

Lines changed: 40 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,23 @@ target triple = "wasm32-unknown-unknown"
1818
; }
1919

2020
; CHECK-LABEL: test0
21-
; CHECK: block
22-
; CHECK: try
23-
; CHECK: call foo
24-
; CHECK: br 0 # 0: down to label1
25-
; CHECK: catch
26-
; CHECK: block
27-
; CHECK: br_if 0, {{.*}} # 0: down to label3
28-
; CHECK: i32.call $drop=, __cxa_begin_catch
29-
; CHECK: call __cxa_end_catch
30-
; CHECK: br 1 # 1: down to label1
31-
; CHECK: end_block # label3:
32-
; CHECK: block
33-
; CHECK: br_if 0, {{.*}} # 0: down to label4
34-
; CHECK: i32.call $drop=, __cxa_begin_catch
35-
; CHECK: call __cxa_end_catch
36-
; CHECK: br 1 # 1: down to label1
37-
; CHECK: end_block # label4:
38-
; CHECK: call __cxa_rethrow
39-
; CHECK: end_try # label1:
40-
; CHECK: end_block
21+
; CHECK: try
22+
; CHECK: call foo
23+
; CHECK: catch
24+
; CHECK: block
25+
; CHECK: br_if 0, {{.*}} # 0: down to label2
26+
; CHECK: i32.call $drop=, __cxa_begin_catch
27+
; CHECK: call __cxa_end_catch
28+
; CHECK: br 1 # 1: down to label0
29+
; CHECK: end_block # label2:
30+
; CHECK: block
31+
; CHECK: br_if 0, {{.*}} # 0: down to label3
32+
; CHECK: i32.call $drop=, __cxa_begin_catch
33+
; CHECK: call __cxa_end_catch
34+
; CHECK: br 1 # 1: down to label0
35+
; CHECK: end_block # label3:
36+
; CHECK: call __cxa_rethrow
37+
; CHECK: end_try # label0:
4138
define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
4239
entry:
4340
invoke void @foo()
@@ -177,39 +174,33 @@ unreachable: ; preds = %rethrow5
177174
; }
178175

179176
; CHECK-LABEL: test2
180-
; CHECK: block
181-
; CHECK: try
182-
; CHECK: call foo
183-
; CHECK: br 0 # 0: down to label17
184-
; CHECK: catch
185-
; CHECK: i32.call $drop=, __cxa_begin_catch
186-
; CHECK: loop # label19:
177+
; CHECK: try
178+
; CHECK: call foo
179+
; CHECK: catch
180+
; CHECK: i32.call $drop=, __cxa_begin_catch
181+
; CHECK: loop # label15:
182+
; CHECK: block
187183
; CHECK: block
188-
; CHECK: block
189-
; CHECK: br_if 0, {{.*}} # 0: down to label21
184+
; CHECK: br_if 0, {{.*}} # 0: down to label17
185+
; CHECK: try
186+
; CHECK: call foo
187+
; CHECK: br 2 # 2: down to label16
188+
; CHECK: catch
190189
; CHECK: try
191-
; CHECK: call foo
192-
; CHECK: br 2 # 2: down to label20
190+
; CHECK: call __cxa_end_catch
193191
; CHECK: catch
194-
; CHECK: block
195-
; CHECK: try
196-
; CHECK: call __cxa_end_catch
197-
; CHECK: br 0 # 0: down to label24
198-
; CHECK: catch
199-
; CHECK: call __clang_call_terminate
200-
; CHECK: unreachable
201-
; CHECK: end_try # label24:
202-
; CHECK: end_block
203-
; CHECK: rethrow # to caller
192+
; CHECK: call __clang_call_terminate
193+
; CHECK: unreachable
204194
; CHECK: end_try
205-
; CHECK: end_block # label21:
206-
; CHECK: call __cxa_end_catch
207-
; CHECK: br 2 # 2: down to label17
208-
; CHECK: end_block # label20:
209-
; CHECK: br 0 # 0: up to label19
210-
; CHECK: end_loop
211-
; CHECK: end_try # label17:
212-
; CHECK: end_block
195+
; CHECK: rethrow # to caller
196+
; CHECK: end_try
197+
; CHECK: end_block # label17:
198+
; CHECK: call __cxa_end_catch
199+
; CHECK: br 2 # 2: down to label13
200+
; CHECK: end_block # label16:
201+
; CHECK: br 0 # 0: up to label15
202+
; CHECK: end_loop
203+
; CHECK: end_try # label13:
213204
define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
214205
entry:
215206
invoke void @foo()

0 commit comments

Comments
 (0)