Skip to content

Commit 21d9b68

Browse files
aheejinmorehouse
authored andcommitted
[WebAssembly] Remap branch dests after fixCatchUnwindMismatches
Fixing catch unwind mismatches can sometimes invalidate existing branch destinations. This CL remaps those destinations after placing try-delegates. Fixes emscripten-core/emscripten#13515. Reviewed By: dschuff Differential Revision: https://reviews.llvm.org/D97178
1 parent 91e2949 commit 21d9b68

File tree

2 files changed

+133
-2
lines changed

2 files changed

+133
-2
lines changed

llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,13 +1368,76 @@ bool WebAssemblyCFGStackify::fixCatchUnwindMismatches(MachineFunction &MF) {
13681368
if (EHPadToUnwindDest.empty())
13691369
return false;
13701370
NumCatchUnwindMismatches += EHPadToUnwindDest.size();
1371+
// <current branch dest, future branch dest> map, because fixing catch unwind
1372+
// mismatches can invalidate branch destinations
1373+
DenseMap<MachineBasicBlock *, MachineBasicBlock *> BrDestMap;
13711374

13721375
for (auto &P : EHPadToUnwindDest) {
13731376
MachineBasicBlock *EHPad = P.first;
13741377
MachineBasicBlock *UnwindDest = P.second;
13751378
MachineInstr *Try = EHPadToTry[EHPad];
13761379
MachineInstr *EndTry = BeginToEnd[Try];
13771380
addTryDelegate(Try, EndTry, UnwindDest);
1381+
BrDestMap[EndTry->getParent()] =
1382+
EndTry->getParent()->getNextNode()->getNextNode();
1383+
}
1384+
1385+
// Adding a try-delegate wrapping an existing try-catch-end can make existing
1386+
// branch destination BBs invalid. For example,
1387+
//
1388+
// - Before:
1389+
// bb0:
1390+
// block
1391+
// br bb3
1392+
// bb1:
1393+
// try
1394+
// ...
1395+
// bb2: (ehpad)
1396+
// catch
1397+
// bb3:
1398+
// end_try
1399+
// end_block ;; 'br bb3' targets here
1400+
//
1401+
// Suppose this try-catch-end has a catch unwind mismatch, so we need to wrap
1402+
// this with a try-delegate. Then this becomes:
1403+
//
1404+
// - After:
1405+
// bb0:
1406+
// block
1407+
// br bb3 ;; invalid destination!
1408+
// bb1:
1409+
// try ;; (new instruction)
1410+
// try
1411+
// ...
1412+
// bb2: (ehpad)
1413+
// catch
1414+
// bb3:
1415+
// end_try ;; 'br bb3' still incorrectly targets here!
1416+
// delegate_bb: ;; (new BB)
1417+
// delegate ;; (new instruction)
1418+
// split_bb: ;; (new BB)
1419+
// end_block
1420+
//
1421+
// Now 'br bb3' incorrectly branches to an inner scope.
1422+
//
1423+
// As we can see in this case, when branches target a BB that has both
1424+
// 'end_try' and 'end_block' and the BB is split to insert a 'delegate', we
1425+
// have to remap existing branch destinations so that they target not the
1426+
// 'end_try' BB but the new 'end_block' BB, which should be the second next BB
1427+
// of 'end_try' (because there is a 'delegate' BB in between). In this
1428+
// example, the 'br bb3' instruction should be remapped to 'br split_bb'.
1429+
for (auto &MBB : MF) {
1430+
for (auto &MI : MBB) {
1431+
if (MI.isTerminator()) {
1432+
for (auto &MO : MI.operands()) {
1433+
if (MO.isMBB()) {
1434+
auto It = BrDestMap.find(MO.getMBB());
1435+
if (It != BrDestMap.end())
1436+
MO.setMBB(It->second);
1437+
}
1438+
}
1439+
}
1440+
}
13781441
}
13791442

13801443
return true;

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

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,9 +1126,77 @@ invoke.cont: ; preds = %entry
11261126
unreachable
11271127
}
11281128

1129+
; This tests if invalidated branch destinations after fixing catch unwind
1130+
; mismatches are correctly remapped. For example, we have this code and suppose
1131+
; we need to wrap this try-catch-end in this code with a try-delegate to fix a
1132+
; catch unwind mismatch:
1133+
; - Before:
1134+
; block
1135+
; br (a)
1136+
; try
1137+
; catch
1138+
; end_try
1139+
; end_block
1140+
; <- (a)
1141+
;
1142+
; - After
1143+
; block
1144+
; br (a)
1145+
; try
1146+
; try
1147+
; catch
1148+
; end_try
1149+
; <- (a)
1150+
; delegate
1151+
; end_block
1152+
; <- (b)
1153+
; After adding a try-delegate, the 'br's destination BB, where (a) points,
1154+
; becomes invalid because it incorrectly branches into an inner scope. The
1155+
; destination should change to the BB where (b) points.
1156+
1157+
; NOSORT-LABEL: test20
1158+
; NOSORT: try
1159+
; NOSORT: br_if 0
1160+
define void @test20(i1 %arg) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1161+
entry:
1162+
br i1 %arg, label %bb0, label %dest
1163+
1164+
bb0: ; preds = %entry
1165+
invoke void @foo()
1166+
to label %bb1 unwind label %catch.dispatch0
1167+
1168+
bb1: ; preds = %bb0
1169+
invoke void @bar()
1170+
to label %try.cont unwind label %catch.dispatch1
1171+
1172+
catch.dispatch0: ; preds = %bb0
1173+
%0 = catchswitch within none [label %catch.start0] unwind to caller
1174+
1175+
catch.start0: ; preds = %catch.dispatch0
1176+
%1 = catchpad within %0 [i8* null]
1177+
%2 = call i8* @llvm.wasm.get.exception(token %1)
1178+
%3 = call i32 @llvm.wasm.get.ehselector(token %1)
1179+
catchret from %1 to label %try.cont
1180+
1181+
dest: ; preds = %entry
1182+
ret void
1183+
1184+
catch.dispatch1: ; preds = %bb1
1185+
%4 = catchswitch within none [label %catch.start1] unwind to caller
1186+
1187+
catch.start1: ; preds = %catch.dispatch1
1188+
%5 = catchpad within %4 [i8* null]
1189+
%6 = call i8* @llvm.wasm.get.exception(token %5)
1190+
%7 = call i32 @llvm.wasm.get.ehselector(token %5)
1191+
catchret from %5 to label %try.cont
1192+
1193+
try.cont: ; preds = %catch.start1, %catch.start0, %bb1
1194+
ret void
1195+
}
1196+
11291197
; Check if the unwind destination mismatch stats are correct
1130-
; NOSORT: 19 wasm-cfg-stackify - Number of call unwind mismatches found
1131-
; NOSORT: 3 wasm-cfg-stackify - Number of catch unwind mismatches found
1198+
; NOSORT: 20 wasm-cfg-stackify - Number of call unwind mismatches found
1199+
; NOSORT: 4 wasm-cfg-stackify - Number of catch unwind mismatches found
11321200

11331201
declare void @foo()
11341202
declare void @bar()

0 commit comments

Comments
 (0)