Skip to content

Commit aa097ef

Browse files
committed
[WebAssembly] Fix reverse mapping in WasmEHFuncInfo
D97247 added the reverse mapping from unwind destination to their source, but it had a critical bug; sources can be multiple, because multiple BBs can have a single BB as their unwind destination. This changes `WasmEHFuncInfo::getUnwindSrc` to `getUnwindSrcs` and makes it return a vector rather than a single BB. It does not return the const reference to the existing vector but creates a new vector because `WasmEHFuncInfo` stores not `BasicBlock*` or `MachineBasicBlock*` but `PointerUnion` of them. Also I hoped to unify those methods for `BasicBlock` and `MachineBasicBlock` into one using templates to reduce duplication, but failed because various usages require `BasicBlock*` to be `const` but it's hard to make it `const` for `MachineBasicBlock` usages. Fixes emscripten-core/emscripten#13514. (More precisely, fixes emscripten-core/emscripten#13514 (comment)) Reviewed By: dschuff, tlively Differential Revision: https://reviews.llvm.org/D97583
1 parent 14ffbb8 commit aa097ef

File tree

4 files changed

+107
-27
lines changed

4 files changed

+107
-27
lines changed

llvm/include/llvm/CodeGen/WasmEHFuncInfo.h

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "llvm/ADT/DenseMap.h"
1717
#include "llvm/ADT/PointerUnion.h"
18+
#include "llvm/ADT/SmallPtrSet.h"
1819

1920
namespace llvm {
2021

@@ -32,41 +33,58 @@ struct WasmEHFuncInfo {
3233
// When there is an entry <A, B>, if an exception is not caught by A, it
3334
// should next unwind to the EH pad B.
3435
DenseMap<BBOrMBB, BBOrMBB> SrcToUnwindDest;
35-
DenseMap<BBOrMBB, BBOrMBB> UnwindDestToSrc; // reverse map
36+
DenseMap<BBOrMBB, SmallPtrSet<BBOrMBB, 4>> UnwindDestToSrcs; // reverse map
3637

3738
// Helper functions
3839
const BasicBlock *getUnwindDest(const BasicBlock *BB) const {
40+
assert(hasUnwindDest(BB));
3941
return SrcToUnwindDest.lookup(BB).get<const BasicBlock *>();
4042
}
41-
const BasicBlock *getUnwindSrc(const BasicBlock *BB) const {
42-
return UnwindDestToSrc.lookup(BB).get<const BasicBlock *>();
43+
SmallPtrSet<const BasicBlock *, 4> getUnwindSrcs(const BasicBlock *BB) const {
44+
assert(hasUnwindSrcs(BB));
45+
const auto &Set = UnwindDestToSrcs.lookup(BB);
46+
SmallPtrSet<const BasicBlock *, 4> Ret;
47+
for (const auto &P : Set)
48+
Ret.insert(P.get<const BasicBlock *>());
49+
return Ret;
4350
}
4451
void setUnwindDest(const BasicBlock *BB, const BasicBlock *Dest) {
4552
SrcToUnwindDest[BB] = Dest;
46-
UnwindDestToSrc[Dest] = BB;
53+
if (!UnwindDestToSrcs.count(Dest))
54+
UnwindDestToSrcs[Dest] = SmallPtrSet<BBOrMBB, 4>();
55+
UnwindDestToSrcs[Dest].insert(BB);
4756
}
4857
bool hasUnwindDest(const BasicBlock *BB) const {
4958
return SrcToUnwindDest.count(BB);
5059
}
51-
bool hasUnwindSrc(const BasicBlock *BB) const {
52-
return UnwindDestToSrc.count(BB);
60+
bool hasUnwindSrcs(const BasicBlock *BB) const {
61+
return UnwindDestToSrcs.count(BB);
5362
}
5463

5564
MachineBasicBlock *getUnwindDest(MachineBasicBlock *MBB) const {
65+
assert(hasUnwindDest(MBB));
5666
return SrcToUnwindDest.lookup(MBB).get<MachineBasicBlock *>();
5767
}
58-
MachineBasicBlock *getUnwindSrc(MachineBasicBlock *MBB) const {
59-
return UnwindDestToSrc.lookup(MBB).get<MachineBasicBlock *>();
68+
SmallPtrSet<MachineBasicBlock *, 4>
69+
getUnwindSrcs(MachineBasicBlock *MBB) const {
70+
assert(hasUnwindSrcs(MBB));
71+
const auto &Set = UnwindDestToSrcs.lookup(MBB);
72+
SmallPtrSet<MachineBasicBlock *, 4> Ret;
73+
for (const auto &P : Set)
74+
Ret.insert(P.get<MachineBasicBlock *>());
75+
return Ret;
6076
}
6177
void setUnwindDest(MachineBasicBlock *MBB, MachineBasicBlock *Dest) {
6278
SrcToUnwindDest[MBB] = Dest;
63-
UnwindDestToSrc[Dest] = MBB;
79+
if (!UnwindDestToSrcs.count(Dest))
80+
UnwindDestToSrcs[Dest] = SmallPtrSet<BBOrMBB, 4>();
81+
UnwindDestToSrcs[Dest].insert(MBB);
6482
}
6583
bool hasUnwindDest(MachineBasicBlock *MBB) const {
6684
return SrcToUnwindDest.count(MBB);
6785
}
68-
bool hasUnwindSrc(MachineBasicBlock *MBB) const {
69-
return UnwindDestToSrc.count(MBB);
86+
bool hasUnwindSrcs(MachineBasicBlock *MBB) const {
87+
return UnwindDestToSrcs.count(MBB);
7088
}
7189
};
7290

llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -333,21 +333,23 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
333333

334334
else if (Personality == EHPersonality::Wasm_CXX) {
335335
WasmEHFuncInfo &EHInfo = *MF->getWasmEHFuncInfo();
336-
// Map all BB references in the WinEH data to MBBs.
337-
DenseMap<BBOrMBB, BBOrMBB> NewMap;
336+
// Map all BB references in the Wasm EH data to MBBs.
337+
DenseMap<BBOrMBB, BBOrMBB> SrcToUnwindDest;
338338
for (auto &KV : EHInfo.SrcToUnwindDest) {
339339
const auto *Src = KV.first.get<const BasicBlock *>();
340-
const auto *Dst = KV.second.get<const BasicBlock *>();
341-
NewMap[MBBMap[Src]] = MBBMap[Dst];
340+
const auto *Dest = KV.second.get<const BasicBlock *>();
341+
SrcToUnwindDest[MBBMap[Src]] = MBBMap[Dest];
342342
}
343-
EHInfo.SrcToUnwindDest = std::move(NewMap);
344-
NewMap.clear();
345-
for (auto &KV : EHInfo.UnwindDestToSrc) {
346-
const auto *Src = KV.first.get<const BasicBlock *>();
347-
const auto *Dst = KV.second.get<const BasicBlock *>();
348-
NewMap[MBBMap[Src]] = MBBMap[Dst];
343+
EHInfo.SrcToUnwindDest = std::move(SrcToUnwindDest);
344+
DenseMap<BBOrMBB, SmallPtrSet<BBOrMBB, 4>> UnwindDestToSrcs;
345+
for (auto &KV : EHInfo.UnwindDestToSrcs) {
346+
const auto *Dest = KV.first.get<const BasicBlock *>();
347+
UnwindDestToSrcs[MBBMap[Dest]] = SmallPtrSet<BBOrMBB, 4>();
348+
for (const auto &P : KV.second)
349+
UnwindDestToSrcs[MBBMap[Dest]].insert(
350+
MBBMap[P.get<const BasicBlock *>()]);
349351
}
350-
EHInfo.UnwindDestToSrc = std::move(NewMap);
352+
EHInfo.UnwindDestToSrcs = std::move(UnwindDestToSrcs);
351353
}
352354
}
353355

llvm/lib/Target/WebAssembly/WebAssemblyCFGSort.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -259,11 +259,12 @@ static void sortBlocks(MachineFunction &MF, const MachineLoopInfo &MLI,
259259
// incorrect because we may end up delegating/rethrowing to an inner
260260
// scope in CFGStackify. So here we make sure those unwind destinations
261261
// are deferred until their unwind source's exception is sorted.
262-
if (EHInfo && EHInfo->hasUnwindSrc(Succ)) {
263-
auto *UnwindSrc = EHInfo->getUnwindSrc(Succ);
262+
if (EHInfo && EHInfo->hasUnwindSrcs(Succ)) {
263+
SmallPtrSet<MachineBasicBlock *, 4> UnwindSrcs =
264+
EHInfo->getUnwindSrcs(Succ);
264265
bool IsDeferred = false;
265-
for (Entry &E : reverse(Entries)) {
266-
if (E.TheRegion->getHeader() == UnwindSrc) {
266+
for (Entry &E : Entries) {
267+
if (UnwindSrcs.count(E.TheRegion->getHeader())) {
267268
E.Deferred.push_back(Succ);
268269
IsDeferred = true;
269270
break;

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

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1222,7 +1222,7 @@ try.cont: ; preds = %catch.start1, %catc
12221222
; end_block
12231223
; <- (b) The br destination should be remapped to here
12241224
;
1225-
; The test was reduced by bugpoint and should not crash.
1225+
; The test was reduced by bugpoint and should not crash in CFGStackify.
12261226
define void @test21() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
12271227
entry:
12281228
br i1 undef, label %if.then, label %if.end12
@@ -1298,6 +1298,65 @@ unreachable: ; preds = %if.then, %invoke.co
12981298
unreachable
12991299
}
13001300

1301+
; Regression test for WasmEHFuncInfo's reverse mapping bug. 'UnwindDestToSrc'
1302+
; should return a vector and not a single BB, which was incorrect.
1303+
; This was reduced by bugpoint and should not crash in CFGStackify.
1304+
define void @test22() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1305+
entry:
1306+
invoke void @foo()
1307+
to label %invoke.cont unwind label %catch.dispatch
1308+
1309+
catch.dispatch: ; preds = %entry
1310+
%0 = catchswitch within none [label %catch.start] unwind label %ehcleanup22
1311+
1312+
catch.start: ; preds = %catch.dispatch
1313+
%1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)]
1314+
%2 = call i8* @llvm.wasm.get.exception(token %1)
1315+
%3 = call i32 @llvm.wasm.get.ehselector(token %1)
1316+
invoke void @__cxa_throw() #1 [ "funclet"(token %1) ]
1317+
to label %unreachable unwind label %catch.dispatch2
1318+
1319+
catch.dispatch2: ; preds = %catch.start
1320+
%4 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup
1321+
1322+
catch.start3: ; preds = %catch.dispatch2
1323+
%5 = catchpad within %4 [i8* bitcast (i8** @_ZTIi to i8*)]
1324+
%6 = call i8* @llvm.wasm.get.exception(token %5)
1325+
%7 = call i32 @llvm.wasm.get.ehselector(token %5)
1326+
catchret from %5 to label %try.cont
1327+
1328+
try.cont: ; preds = %catch.start3
1329+
invoke void @foo() [ "funclet"(token %1) ]
1330+
to label %invoke.cont8 unwind label %ehcleanup
1331+
1332+
invoke.cont8: ; preds = %try.cont
1333+
invoke void @__cxa_throw() #1 [ "funclet"(token %1) ]
1334+
to label %unreachable unwind label %catch.dispatch11
1335+
1336+
catch.dispatch11: ; preds = %invoke.cont8
1337+
%8 = catchswitch within %1 [label %catch.start12] unwind label %ehcleanup
1338+
1339+
catch.start12: ; preds = %catch.dispatch11
1340+
%9 = catchpad within %8 [i8* bitcast (i8** @_ZTIi to i8*)]
1341+
%10 = call i8* @llvm.wasm.get.exception(token %9)
1342+
%11 = call i32 @llvm.wasm.get.ehselector(token %9)
1343+
unreachable
1344+
1345+
invoke.cont: ; preds = %entry
1346+
unreachable
1347+
1348+
ehcleanup: ; preds = %try.cont, %catch.dispatch11, %catch.dispatch2
1349+
%12 = cleanuppad within %1 []
1350+
cleanupret from %12 unwind label %ehcleanup22
1351+
1352+
ehcleanup22: ; preds = %ehcleanup, %catch.dispatch
1353+
%13 = cleanuppad within none []
1354+
cleanupret from %13 unwind to caller
1355+
1356+
unreachable: ; preds = %catch.start, %invoke.cont8
1357+
unreachable
1358+
}
1359+
13011360
; Check if the unwind destination mismatch stats are correct
13021361
; NOSORT: 20 wasm-cfg-stackify - Number of call unwind mismatches found
13031362
; NOSORT: 4 wasm-cfg-stackify - Number of catch unwind mismatches found

0 commit comments

Comments
 (0)