Skip to content

Commit 3c8f3b9

Browse files
authored
[WebAssembly] Treat 'rethrow' as terminator in custom isel (#95967)
`rethrow` instruction is a terminator, but when when its DAG is built in `SelectionDAGBuilder` in a custom routine, it was NOT treated as such. ```ll rethrow: ; preds = %catch.start invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %1) ] to label %unreachable unwind label %ehcleanup ehcleanup: ; preds = %rethrow, %catch.dispatch %tmp = phi i32 [ 10, %catch.dispatch ], [ 20, %rethrow ] ... ``` In this bitcode, because of the `phi`, a `CONST_I32` will be created in the `rethrow` BB. Without this patch, the DAG for the `rethrow` BB looks like this: ``` t0: ch,glue = EntryToken t3: ch = CopyToReg t0, Register:i32 %9, Constant:i32<20> t5: ch = llvm.wasm.rethrow t0, TargetConstant:i32<12161> t6: ch = TokenFactor t3, t5 t8: ch = br t6, BasicBlock:ch<unreachable 0x562532e43c50> ``` Note that `CopyToReg` and `llvm.wasm.rethrow` don't have dependence so either can come first in the selected code, which can result in the code like ```mir bb.3.rethrow: RETHROW 0, implicit-def dead $arguments %9:i32 = CONST_I32 20, implicit-def dead $arguments BR %bb.6, implicit-def dead $arguments ``` After this patch, `llvm.wasm.rethrow` is treated as a terminator, and the DAG will look like ``` t0: ch,glue = EntryToken t3: ch = CopyToReg t0, Register:i32 %9, Constant:i32<20> t5: ch = llvm.wasm.rethrow t3, TargetConstant:i32<12161> t7: ch = br t5, BasicBlock:ch<unreachable 0x5555e3d32c70> ``` Note that now `rethrow` takes a token from `CopyToReg`, so `rethrow` has to come after `CopyToReg`. And the resulting code will be ```mir bb.3.rethrow: %9:i32 = CONST_I32 20, implicit-def dead $arguments RETHROW 0, implicit-def dead $arguments BR %bb.6, implicit-def dead $arguments ``` I'm not very familiar with the internals of `getRoot` vs. `getControlRoot`, but other terminator instructions seem to use the latter, and using it for `rethrow` too worked.
1 parent 728fb23 commit 3c8f3b9

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3355,7 +3355,7 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
33553355
// special because it can be invoked, so we manually lower it to a DAG
33563356
// node here.
33573357
SmallVector<SDValue, 8> Ops;
3358-
Ops.push_back(getRoot()); // inchain
3358+
Ops.push_back(getControlRoot()); // inchain for the terminator node
33593359
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
33603360
Ops.push_back(
33613361
DAG.getTargetConstant(Intrinsic::wasm_rethrow, getCurSDLoc(),

llvm/test/CodeGen/WebAssembly/exception-legacy.ll

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,8 +350,60 @@ ehcleanupret: ; preds = %catch.start, %ehcle
350350
cleanupret from %0 unwind to caller
351351
}
352352

353+
; Regression test for the bug that 'rethrow' was not treated correctly as a
354+
; terminator in isel.
355+
define void @test_rethrow_terminator() personality ptr @__gxx_wasm_personality_v0 {
356+
entry:
357+
invoke void @foo()
358+
to label %try.cont unwind label %catch.dispatch
359+
360+
catch.dispatch: ; preds = %entry
361+
%0 = catchswitch within none [label %catch.start] unwind label %ehcleanup
362+
363+
catch.start: ; preds = %catch.dispatch
364+
%1 = catchpad within %0 [ptr @_ZTIi]
365+
%2 = call ptr @llvm.wasm.get.exception(token %1)
366+
%3 = call i32 @llvm.wasm.get.ehselector(token %1)
367+
%4 = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi)
368+
%matches = icmp eq i32 %3, %4
369+
br i1 %matches, label %catch, label %rethrow
370+
371+
catch: ; preds = %catch.start
372+
%5 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
373+
%6 = load i32, ptr %5, align 4
374+
call void @__cxa_end_catch() [ "funclet"(token %1) ]
375+
catchret from %1 to label %try.cont
376+
377+
rethrow: ; preds = %catch.start
378+
invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %1) ]
379+
to label %unreachable unwind label %ehcleanup
380+
381+
try.cont: ; preds = %entry, %catch
382+
ret void
383+
384+
ehcleanup: ; preds = %rethrow, %catch.dispatch
385+
; 'rethrow' BB is this BB's predecessor, and its
386+
; 'invoke void @llvm.wasm.rethrow()' is lowered down to a 'RETHROW' in Wasm
387+
; MIR. And this 'phi' creates 'CONST_I32' instruction in the predecessor
388+
; 'rethrow' BB. If 'RETHROW' is not treated correctly as a terminator, it can
389+
; create a BB like
390+
; bb.3.rethrow:
391+
; RETHROW 0
392+
; %0 = CONST_I32 20
393+
; BR ...
394+
%tmp = phi i32 [ 10, %catch.dispatch ], [ 20, %rethrow ]
395+
%7 = cleanuppad within none []
396+
call void @take_i32(i32 %tmp) [ "funclet"(token %7) ]
397+
cleanupret from %7 unwind to caller
398+
399+
unreachable: ; preds = %rethrow
400+
unreachable
401+
}
402+
403+
353404
declare void @foo()
354405
declare void @bar(ptr)
406+
declare void @take_i32(i32)
355407
declare i32 @__gxx_wasm_personality_v0(...)
356408
; Function Attrs: noreturn
357409
declare void @llvm.wasm.throw(i32, ptr) #1

0 commit comments

Comments
 (0)