[llvm] r347003 - [WebAssembly] Split BBs after throw instructions
Heejin Ahn via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 15 16:47:18 PST 2018
Author: aheejin
Date: Thu Nov 15 16:47:18 2018
New Revision: 347003
URL: http://llvm.org/viewvc/llvm-project?rev=347003&view=rev
Log:
[WebAssembly] Split BBs after throw instructions
Summary:
`throw` instruction is a terminator in wasm, but BBs were not splitted
after `throw` instructions, causing machine instruction verifier to
fail.
This patch
- Splits BBs after `throw` instructions in WasmEHPrepare and adding an
unreachable instruction after `throw`, which will be deleted in
LateEHPrepare pass
- Refactors WasmEHPrepare into two member functions
- Changes the semantics of `eraseBBsAndChildren` in LateEHPrepare pass
to match that of WasmEHPrepare pass, which is newly added. Now
`eraseBBsAndChildren` does not delete BBs with remaining predecessors.
- Fixes style nits, making static function names conform to clang-tidy
- Re-enables the test temporarily disabled by rL346840 && rL346845
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D54571
Modified:
llvm/trunk/lib/CodeGen/WasmEHPrepare.cpp
llvm/trunk/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
llvm/trunk/test/CodeGen/WebAssembly/exception.ll
llvm/trunk/test/CodeGen/WebAssembly/wasmehprepare.ll
llvm/trunk/test/MC/WebAssembly/event-section.ll
Modified: llvm/trunk/lib/CodeGen/WasmEHPrepare.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/WasmEHPrepare.cpp?rev=347003&r1=347002&r2=347003&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/WasmEHPrepare.cpp (original)
+++ llvm/trunk/lib/CodeGen/WasmEHPrepare.cpp Thu Nov 15 16:47:18 2018
@@ -137,6 +137,7 @@ class WasmEHPrepare : public FunctionPas
Value *LSDAField = nullptr; // lsda field
Value *SelectorField = nullptr; // selector
+ Function *ThrowF = nullptr; // wasm.throw() intrinsic
Function *CatchF = nullptr; // wasm.catch.extract() intrinsic
Function *LPadIndexF = nullptr; // wasm.landingpad.index() intrinsic
Function *LSDAF = nullptr; // wasm.lsda() intrinsic
@@ -145,6 +146,9 @@ class WasmEHPrepare : public FunctionPas
Function *CallPersonalityF = nullptr; // _Unwind_CallPersonality() wrapper
Function *ClangCallTermF = nullptr; // __clang_call_terminate() function
+ bool prepareEHPads(Function &F);
+ bool prepareThrows(Function &F);
+
void prepareEHPad(BasicBlock *BB, unsigned Index);
void prepareTerminateCleanupPad(BasicBlock *BB);
@@ -177,7 +181,62 @@ bool WasmEHPrepare::doInitialization(Mod
return false;
}
+// Erase the specified BBs if the BB does not have any remaining predecessors,
+// and also all its dead children.
+template <typename Container>
+static void eraseDeadBBsAndChildren(const Container &BBs) {
+ SmallVector<BasicBlock *, 8> WL(BBs.begin(), BBs.end());
+ while (!WL.empty()) {
+ auto *BB = WL.pop_back_val();
+ if (pred_begin(BB) != pred_end(BB))
+ continue;
+ WL.append(succ_begin(BB), succ_end(BB));
+ DeleteDeadBlock(BB);
+ }
+}
+
bool WasmEHPrepare::runOnFunction(Function &F) {
+ bool Changed = false;
+ Changed |= prepareThrows(F);
+ Changed |= prepareEHPads(F);
+ return Changed;
+}
+
+bool WasmEHPrepare::prepareThrows(Function &F) {
+ Module &M = *F.getParent();
+ IRBuilder<> IRB(F.getContext());
+ bool Changed = false;
+
+ // wasm.throw() intinsic, which will be lowered to wasm 'throw' instruction.
+ ThrowF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_throw);
+
+ // Insert an unreachable instruction after a call to @llvm.wasm.throw and
+ // delete all following instructions within the BB, and delete all the dead
+ // children of the BB as well.
+ for (User *U : ThrowF->users()) {
+ // A call to @llvm.wasm.throw() is only generated from
+ // __builtin_wasm_throw() builtin call within libcxxabi, and cannot be an
+ // InvokeInst.
+ auto *ThrowI = cast<CallInst>(U);
+ if (ThrowI->getFunction() != &F)
+ continue;
+ Changed = true;
+ auto *BB = ThrowI->getParent();
+ SmallVector<BasicBlock *, 4> Succs(succ_begin(BB), succ_end(BB));
+ auto &InstList = BB->getInstList();
+ InstList.erase(std::next(BasicBlock::iterator(ThrowI)), InstList.end());
+ IRB.SetInsertPoint(BB);
+ IRB.CreateUnreachable();
+ eraseDeadBBsAndChildren(Succs);
+ }
+
+ return Changed;
+}
+
+bool WasmEHPrepare::prepareEHPads(Function &F) {
+ Module &M = *F.getParent();
+ IRBuilder<> IRB(F.getContext());
+
SmallVector<BasicBlock *, 16> CatchPads;
SmallVector<BasicBlock *, 16> CleanupPads;
for (BasicBlock &BB : F) {
@@ -194,9 +253,6 @@ bool WasmEHPrepare::runOnFunction(Functi
return false;
assert(F.hasPersonalityFn() && "Personality function not found");
- Module &M = *F.getParent();
- IRBuilder<> IRB(F.getContext());
-
// __wasm_lpad_context global variable
LPadContextGV = cast<GlobalVariable>(
M.getOrInsertGlobal("__wasm_lpad_context", LPadContextTy));
Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp?rev=347003&r1=347002&r2=347003&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp Thu Nov 15 16:47:18 2018
@@ -31,6 +31,7 @@ class WebAssemblyLateEHPrepare final : p
bool runOnMachineFunction(MachineFunction &MF) override;
+ bool removeUnnecessaryUnreachables(MachineFunction &MF);
bool replaceFuncletReturns(MachineFunction &MF);
bool hoistCatches(MachineFunction &MF);
bool addCatchAlls(MachineFunction &MF);
@@ -59,7 +60,7 @@ FunctionPass *llvm::createWebAssemblyLat
// possible search paths should be the same.
// Returns nullptr in case it does not find any EH pad in the search, or finds
// multiple different EH pads.
-static MachineBasicBlock *GetMatchingEHPad(MachineInstr *MI) {
+static MachineBasicBlock *getMatchingEHPad(MachineInstr *MI) {
MachineFunction *MF = MI->getParent()->getParent();
SmallVector<MachineBasicBlock *, 2> WL;
SmallPtrSet<MachineBasicBlock *, 2> Visited;
@@ -83,18 +84,15 @@ static MachineBasicBlock *GetMatchingEHP
return EHPad;
}
-// Erases the given BBs and all their children from the function. If other BBs
-// have the BB as a successor, the successor relationships will be deleted as
-// well.
+// Erase the specified BBs if the BB does not have any remaining predecessors,
+// and also all its dead children.
template <typename Container>
-static void EraseBBsAndChildren(const Container &MBBs) {
+static void eraseDeadBBsAndChildren(const Container &MBBs) {
SmallVector<MachineBasicBlock *, 8> WL(MBBs.begin(), MBBs.end());
while (!WL.empty()) {
MachineBasicBlock *MBB = WL.pop_back_val();
- SmallVector<MachineBasicBlock *, 4> Preds(MBB->pred_begin(),
- MBB->pred_end());
- for (auto *Pred : Preds)
- Pred->removeSuccessor(MBB);
+ if (!MBB->pred_empty())
+ continue;
SmallVector<MachineBasicBlock *, 4> Succs(MBB->succ_begin(),
MBB->succ_end());
WL.append(MBB->succ_begin(), MBB->succ_end());
@@ -110,6 +108,7 @@ bool WebAssemblyLateEHPrepare::runOnMach
return false;
bool Changed = false;
+ Changed |= removeUnnecessaryUnreachables(MF);
Changed |= addRethrows(MF);
if (!MF.getFunction().hasPersonalityFn())
return Changed;
@@ -122,6 +121,31 @@ bool WebAssemblyLateEHPrepare::runOnMach
return Changed;
}
+bool WebAssemblyLateEHPrepare::removeUnnecessaryUnreachables(
+ MachineFunction &MF) {
+ bool Changed = false;
+ for (auto &MBB : MF) {
+ for (auto &MI : MBB) {
+ if (!WebAssembly::isThrow(MI))
+ continue;
+ Changed = true;
+
+ // The instruction after the throw should be an unreachable or a branch to
+ // another BB that should eventually lead to an unreachable. Delete it
+ // because throw itself is a terminator, and also delete successors if
+ // any.
+ MBB.erase(std::next(MachineBasicBlock::iterator(MI)), MBB.end());
+ SmallVector<MachineBasicBlock *, 8> Succs(MBB.succ_begin(),
+ MBB.succ_end());
+ for (auto *Succ : Succs)
+ MBB.removeSuccessor(Succ);
+ eraseDeadBBsAndChildren(Succs);
+ }
+ }
+
+ return Changed;
+}
+
bool WebAssemblyLateEHPrepare::replaceFuncletReturns(MachineFunction &MF) {
bool Changed = false;
const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
@@ -183,7 +207,7 @@ bool WebAssemblyLateEHPrepare::hoistCatc
Catches.push_back(&MI);
for (auto *Catch : Catches) {
- MachineBasicBlock *EHPad = GetMatchingEHPad(Catch);
+ MachineBasicBlock *EHPad = getMatchingEHPad(Catch);
assert(EHPad && "No matching EH pad for catch");
if (EHPad->begin() == Catch)
continue;
@@ -242,7 +266,7 @@ bool WebAssemblyLateEHPrepare::addRethro
Rethrow = BuildMI(MBB, InsertPt, MI.getDebugLoc(),
TII.get(WebAssembly::RETHROW_TO_CALLER));
- // Becasue __cxa_rethrow does not return, the instruction after the
+ // Because __cxa_rethrow does not return, the instruction after the
// rethrow should be an unreachable or a branch to another BB that should
// eventually lead to an unreachable. Delete it because rethrow itself is
// a terminator, and also delete non-EH pad successors if any.
@@ -251,7 +275,9 @@ bool WebAssemblyLateEHPrepare::addRethro
for (auto *Succ : MBB.successors())
if (!Succ->isEHPad())
NonPadSuccessors.push_back(Succ);
- EraseBBsAndChildren(NonPadSuccessors);
+ for (auto *Succ : NonPadSuccessors)
+ MBB.removeSuccessor(Succ);
+ eraseDeadBBsAndChildren(NonPadSuccessors);
}
return Changed;
}
@@ -283,7 +309,7 @@ bool WebAssemblyLateEHPrepare::ensureSin
bool Changed = false;
for (auto *Call : ClangCallTerminateCalls) {
- MachineBasicBlock *EHPad = GetMatchingEHPad(Call);
+ MachineBasicBlock *EHPad = getMatchingEHPad(Call);
assert(EHPad && "No matching EH pad for catch");
// If it is already the form we want, skip it
@@ -308,7 +334,11 @@ bool WebAssemblyLateEHPrepare::ensureSin
BuildMI(*EHPad, InsertPos, Call->getDebugLoc(),
TII.get(WebAssembly::UNREACHABLE));
EHPad->erase(InsertPos, EHPad->end());
- EraseBBsAndChildren(EHPad->successors());
+ SmallVector<MachineBasicBlock *, 8> Succs(EHPad->succ_begin(),
+ EHPad->succ_end());
+ for (auto *Succ : Succs)
+ EHPad->removeSuccessor(Succ);
+ eraseDeadBBsAndChildren(Succs);
}
return Changed;
}
Modified: llvm/trunk/test/CodeGen/WebAssembly/exception.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/exception.ll?rev=347003&r1=347002&r2=347003&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/exception.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/exception.ll Thu Nov 15 16:47:18 2018
@@ -1,5 +1,5 @@
; RUN: not llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -exception-model=wasm
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -exception-model=wasm -mattr=+exception-handling | FileCheck -allow-deprecated-dag-overlap %s
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs | FileCheck -allow-deprecated-dag-overlap %s
; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-keep-registers -exception-model=wasm -mattr=+exception-handling
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
@@ -12,10 +12,11 @@ target triple = "wasm32-unknown-unknown"
declare void @llvm.wasm.throw(i32, i8*)
; CHECK-LABEL: test_throw:
-; CHECK-NEXT: i32.const $push0=, 0
+; CHECK: get_local $push0=, 0
; CHECK-NEXT: throw __cpp_exception at EVENT, $pop0
-define void @test_throw() {
- call void @llvm.wasm.throw(i32 0, i8* null)
+; CHECK-NOT: unreachable
+define void @test_throw(i8* %p) {
+ call void @llvm.wasm.throw(i32 0, i8* %p)
ret void
}
Modified: llvm/trunk/test/CodeGen/WebAssembly/wasmehprepare.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/wasmehprepare.ll?rev=347003&r1=347002&r2=347003&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/wasmehprepare.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/wasmehprepare.ll Thu Nov 15 16:47:18 2018
@@ -298,6 +298,34 @@ try.cont10:
ret void
}
+; Tests if instructions after a call to @llvm.wasm.throw are deleted and the
+; BB's dead children are deleted.
+
+; CHECK-LABEL: @test6
+define i32 @test6(i1 %b, i8* %p) {
+entry:
+ br i1 %b, label %bb.true, label %bb.false
+
+; CHECK: bb.true:
+; CHECK-NEXT: call void @llvm.wasm.throw(i32 0, i8* %p)
+; CHECK-NEXT: unreachable
+bb.true: ; preds = %entry
+ call void @llvm.wasm.throw(i32 0, i8* %p)
+ br label %bb.true.0
+
+; CHECK-NOT: bb.true.0
+bb.true.0: ; preds = %bb.true
+ br label %merge
+
+; CHECK: bb.false
+bb.false: ; preds = %entry
+ br label %merge
+
+; CHECK: merge
+merge: ; preds = %bb.true.0, %bb.false
+ ret i32 0
+}
+
declare void @foo()
declare void @func(i32)
declare %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* returned)
@@ -305,6 +333,7 @@ declare i32 @__gxx_wasm_personality_v0(.
declare i8* @llvm.wasm.get.exception(token)
declare i32 @llvm.wasm.get.ehselector(token)
declare i32 @llvm.eh.typeid.for(i8*)
+declare void @llvm.wasm.throw(i32, i8*)
declare i8* @__cxa_begin_catch(i8*)
declare void @__cxa_end_catch()
declare void @__cxa_rethrow()
@@ -314,4 +343,3 @@ declare void @__clang_call_terminate(i8*
; CHECK-DAG: declare void @llvm.wasm.landingpad.index(token, i32)
; CHECK-DAG: declare i8* @llvm.wasm.lsda()
; CHECK-DAG: declare i32 @_Unwind_CallPersonality(i8*)
-
Modified: llvm/trunk/test/MC/WebAssembly/event-section.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/WebAssembly/event-section.ll?rev=347003&r1=347002&r2=347003&view=diff
==============================================================================
--- llvm/trunk/test/MC/WebAssembly/event-section.ll (original)
+++ llvm/trunk/test/MC/WebAssembly/event-section.ll Thu Nov 15 16:47:18 2018
@@ -1,6 +1,5 @@
-; XFAIL: *
-; RUN: llc -filetype=obj -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs %s -o - | obj2yaml | FileCheck %s
-; RUN: llc -filetype=obj -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs %s -o - | llvm-readobj -s | FileCheck -check-prefix=SEC %s
+; RUN: llc -filetype=obj -exception-model=wasm -mattr=+exception-handling %s -o - | obj2yaml | FileCheck %s
+; RUN: llc -filetype=obj -exception-model=wasm -mattr=+exception-handling %s -o - | llvm-readobj -s | FileCheck -check-prefix=SEC %s
target triple = "wasm32-unknown-unknown"
@@ -41,7 +40,7 @@ define i32 @test_throw1(i8* %p) {
; CHECK-NEXT: Offset: 0x00000006
; CHECK-NEXT: - Type: R_WEBASSEMBLY_EVENT_INDEX_LEB
; CHECK-NEXT: Index: 1
-; CHECK-NEXT: Offset: 0x00000013
+; CHECK-NEXT: Offset: 0x00000011
; CHECK: - Type: CUSTOM
; CHECK-NEXT: Name: linking
More information about the llvm-commits
mailing list