diff --git a/llvm/include/llvm/CodeGen/WasmEHFuncInfo.h b/llvm/include/llvm/CodeGen/WasmEHFuncInfo.h --- a/llvm/include/llvm/CodeGen/WasmEHFuncInfo.h +++ b/llvm/include/llvm/CodeGen/WasmEHFuncInfo.h @@ -15,6 +15,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/SmallPtrSet.h" namespace llvm { @@ -32,41 +33,58 @@ // When there is an entry , if an exception is not caught by A, it // should next unwind to the EH pad B. DenseMap SrcToUnwindDest; - DenseMap UnwindDestToSrc; // reverse map + DenseMap> UnwindDestToSrcs; // reverse map // Helper functions const BasicBlock *getUnwindDest(const BasicBlock *BB) const { + assert(hasUnwindDest(BB)); return SrcToUnwindDest.lookup(BB).get(); } - const BasicBlock *getUnwindSrc(const BasicBlock *BB) const { - return UnwindDestToSrc.lookup(BB).get(); + SmallPtrSet getUnwindSrcs(const BasicBlock *BB) const { + assert(hasUnwindSrcs(BB)); + const auto &Set = UnwindDestToSrcs.lookup(BB); + SmallPtrSet Ret; + for (const auto &P : Set) + Ret.insert(P.get()); + return Ret; } void setUnwindDest(const BasicBlock *BB, const BasicBlock *Dest) { SrcToUnwindDest[BB] = Dest; - UnwindDestToSrc[Dest] = BB; + if (!UnwindDestToSrcs.count(Dest)) + UnwindDestToSrcs[Dest] = SmallPtrSet(); + UnwindDestToSrcs[Dest].insert(BB); } bool hasUnwindDest(const BasicBlock *BB) const { return SrcToUnwindDest.count(BB); } - bool hasUnwindSrc(const BasicBlock *BB) const { - return UnwindDestToSrc.count(BB); + bool hasUnwindSrcs(const BasicBlock *BB) const { + return UnwindDestToSrcs.count(BB); } MachineBasicBlock *getUnwindDest(MachineBasicBlock *MBB) const { + assert(hasUnwindDest(MBB)); return SrcToUnwindDest.lookup(MBB).get(); } - MachineBasicBlock *getUnwindSrc(MachineBasicBlock *MBB) const { - return UnwindDestToSrc.lookup(MBB).get(); + SmallPtrSet + getUnwindSrcs(MachineBasicBlock *MBB) const { + assert(hasUnwindSrcs(MBB)); + const auto &Set = UnwindDestToSrcs.lookup(MBB); + SmallPtrSet Ret; + for (const auto &P : Set) + Ret.insert(P.get()); + return Ret; } void setUnwindDest(MachineBasicBlock *MBB, MachineBasicBlock *Dest) { SrcToUnwindDest[MBB] = Dest; - UnwindDestToSrc[Dest] = MBB; + if (!UnwindDestToSrcs.count(Dest)) + UnwindDestToSrcs[Dest] = SmallPtrSet(); + UnwindDestToSrcs[Dest].insert(MBB); } bool hasUnwindDest(MachineBasicBlock *MBB) const { return SrcToUnwindDest.count(MBB); } - bool hasUnwindSrc(MachineBasicBlock *MBB) const { - return UnwindDestToSrc.count(MBB); + bool hasUnwindSrcs(MachineBasicBlock *MBB) const { + return UnwindDestToSrcs.count(MBB); } }; diff --git a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp --- a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -333,21 +333,23 @@ else if (Personality == EHPersonality::Wasm_CXX) { WasmEHFuncInfo &EHInfo = *MF->getWasmEHFuncInfo(); - // Map all BB references in the WinEH data to MBBs. - DenseMap NewMap; + // Map all BB references in the Wasm EH data to MBBs. + DenseMap SrcToUnwindDest; for (auto &KV : EHInfo.SrcToUnwindDest) { const auto *Src = KV.first.get(); - const auto *Dst = KV.second.get(); - NewMap[MBBMap[Src]] = MBBMap[Dst]; + const auto *Dest = KV.second.get(); + SrcToUnwindDest[MBBMap[Src]] = MBBMap[Dest]; } - EHInfo.SrcToUnwindDest = std::move(NewMap); - NewMap.clear(); - for (auto &KV : EHInfo.UnwindDestToSrc) { - const auto *Src = KV.first.get(); - const auto *Dst = KV.second.get(); - NewMap[MBBMap[Src]] = MBBMap[Dst]; + EHInfo.SrcToUnwindDest = std::move(SrcToUnwindDest); + DenseMap> UnwindDestToSrcs; + for (auto &KV : EHInfo.UnwindDestToSrcs) { + const auto *Dest = KV.first.get(); + UnwindDestToSrcs[MBBMap[Dest]] = SmallPtrSet(); + for (const auto &P : KV.second) + UnwindDestToSrcs[MBBMap[Dest]].insert( + MBBMap[P.get()]); } - EHInfo.UnwindDestToSrc = std::move(NewMap); + EHInfo.UnwindDestToSrcs = std::move(UnwindDestToSrcs); } } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGSort.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGSort.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyCFGSort.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyCFGSort.cpp @@ -259,11 +259,12 @@ // incorrect because we may end up delegating/rethrowing to an inner // scope in CFGStackify. So here we make sure those unwind destinations // are deferred until their unwind source's exception is sorted. - if (EHInfo && EHInfo->hasUnwindSrc(Succ)) { - auto *UnwindSrc = EHInfo->getUnwindSrc(Succ); + if (EHInfo && EHInfo->hasUnwindSrcs(Succ)) { + SmallPtrSet UnwindSrcs = + EHInfo->getUnwindSrcs(Succ); bool IsDeferred = false; - for (Entry &E : reverse(Entries)) { - if (E.TheRegion->getHeader() == UnwindSrc) { + for (Entry &E : Entries) { + if (UnwindSrcs.count(E.TheRegion->getHeader())) { E.Deferred.push_back(Succ); IsDeferred = true; break; diff --git a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll --- a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll +++ b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll @@ -1222,7 +1222,7 @@ ; end_block ; <- (b) The br destination should be remapped to here ; -; The test was reduced by bugpoint and should not crash. +; The test was reduced by bugpoint and should not crash in CFGStackify. define void @test21() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { entry: br i1 undef, label %if.then, label %if.end12 @@ -1298,6 +1298,65 @@ unreachable } +; Regression test for WasmEHFuncInfo's reverse mapping bug. 'UnwindDestToSrc' +; should return a vector and not a single BB, which was incorrect. +; This was reduced by bugpoint and should not crash in CFGStackify. +define void @test22() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { +entry: + invoke void @foo() + to label %invoke.cont unwind label %catch.dispatch + +catch.dispatch: ; preds = %entry + %0 = catchswitch within none [label %catch.start] unwind label %ehcleanup22 + +catch.start: ; preds = %catch.dispatch + %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)] + %2 = call i8* @llvm.wasm.get.exception(token %1) + %3 = call i32 @llvm.wasm.get.ehselector(token %1) + invoke void @__cxa_throw() #1 [ "funclet"(token %1) ] + to label %unreachable unwind label %catch.dispatch2 + +catch.dispatch2: ; preds = %catch.start + %4 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup + +catch.start3: ; preds = %catch.dispatch2 + %5 = catchpad within %4 [i8* bitcast (i8** @_ZTIi to i8*)] + %6 = call i8* @llvm.wasm.get.exception(token %5) + %7 = call i32 @llvm.wasm.get.ehselector(token %5) + catchret from %5 to label %try.cont + +try.cont: ; preds = %catch.start3 + invoke void @foo() [ "funclet"(token %1) ] + to label %invoke.cont8 unwind label %ehcleanup + +invoke.cont8: ; preds = %try.cont + invoke void @__cxa_throw() #1 [ "funclet"(token %1) ] + to label %unreachable unwind label %catch.dispatch11 + +catch.dispatch11: ; preds = %invoke.cont8 + %8 = catchswitch within %1 [label %catch.start12] unwind label %ehcleanup + +catch.start12: ; preds = %catch.dispatch11 + %9 = catchpad within %8 [i8* bitcast (i8** @_ZTIi to i8*)] + %10 = call i8* @llvm.wasm.get.exception(token %9) + %11 = call i32 @llvm.wasm.get.ehselector(token %9) + unreachable + +invoke.cont: ; preds = %entry + unreachable + +ehcleanup: ; preds = %try.cont, %catch.dispatch11, %catch.dispatch2 + %12 = cleanuppad within %1 [] + cleanupret from %12 unwind label %ehcleanup22 + +ehcleanup22: ; preds = %ehcleanup, %catch.dispatch + %13 = cleanuppad within none [] + cleanupret from %13 unwind to caller + +unreachable: ; preds = %catch.start, %invoke.cont8 + unreachable +} + ; Check if the unwind destination mismatch stats are correct ; NOSORT: 20 wasm-cfg-stackify - Number of call unwind mismatches found ; NOSORT: 4 wasm-cfg-stackify - Number of catch unwind mismatches found