Skip to content

Commit ffa143c

Browse files
committed
[WebAssembly] Support 'unreachable' expression
Lower LLVM's 'unreachable' terminator to ISD::TRAP, and lower ISD::TRAP to wasm's 'unreachable' expression. WebAssembly type-checks expressions, but a noreturn function with a return type that doesn't match the context will cause a check failure. So we lower LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's 'unreachable' expression, which typechecks in any context and causes a trap if executed. Differential Revision: http://reviews.llvm.org/D14515 llvm-svn: 252566
1 parent 6d87f28 commit ffa143c

File tree

4 files changed

+49
-2
lines changed

4 files changed

+49
-2
lines changed

llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
172172
for (auto T : MVT::integer_valuetypes())
173173
for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
174174
setLoadExtAction(Ext, T, MVT::i1, Promote);
175+
176+
// Trap lowers to wasm unreachable
177+
setOperationAction(ISD::TRAP, MVT::Other, Legal);
175178
}
176179

177180
FastISel *WebAssemblyTargetLowering::createFastISel(

llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,14 @@ multiclass RETURN<WebAssemblyRegClass vt> {
5454
def RETURN_#vt : I<(outs), (ins vt:$val), [(WebAssemblyreturn vt:$val)],
5555
"return $val">;
5656
}
57-
let isReturn = 1, isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in {
57+
58+
let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in {
59+
let isReturn = 1 in {
5860
defm : RETURN<I32>;
5961
defm : RETURN<I64>;
6062
defm : RETURN<F32>;
6163
defm : RETURN<F64>;
6264
def RETURN_VOID : I<(outs), (ins), [(WebAssemblyreturn)], "return">;
63-
} // isReturn = 1, isTerminator = 1, hasCtrlDep = 1, isBarrier = 1
65+
} // isReturn = 1
66+
def UNREACHABLE : I<(outs), (ins), [(trap)], "unreachable">;
67+
} // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1

llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ WebAssemblyTargetMachine::WebAssemblyTargetMachine(
5050
: "e-p:32:32-i64:64-n32:64-S128",
5151
TT, CPU, FS, Options, RM, CM, OL),
5252
TLOF(make_unique<WebAssemblyTargetObjectFile>()) {
53+
// WebAssembly type-checks expressions, but a noreturn function with a return
54+
// type that doesn't match the context will cause a check failure. So we lower
55+
// LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's
56+
// 'unreachable' expression which is meant for that case.
57+
this->Options.TrapUnreachable = true;
58+
5359
initAsmInfo();
5460

5561
// We need a reducible CFG, so disable some optimizations which tend to
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
; RUN: llc < %s -asm-verbose=false | FileCheck %s
2+
; RUN: llc < %s -asm-verbose=false -fast-isel | FileCheck %s
3+
4+
; Test that LLVM unreachable instruction and trap intrinsic are lowered to
5+
; wasm unreachable
6+
7+
target datalayout = "e-p:32:32-i64:64-n32:64-S128"
8+
target triple = "wasm32-unknown-unknown"
9+
10+
declare void @llvm.trap()
11+
declare void @llvm.debugtrap()
12+
declare void @abort()
13+
14+
; CHECK-LABEL: f1:
15+
; CHECK: call $abort
16+
; CHECK: unreachable
17+
define i32 @f1() {
18+
call void @abort()
19+
unreachable
20+
}
21+
22+
; CHECK-LABEL: f2:
23+
; CHECK: unreachable
24+
define void @f2() {
25+
call void @llvm.trap()
26+
ret void
27+
}
28+
29+
; CHECK-LABEL: f3:
30+
; CHECK: unreachable
31+
define void @f3() {
32+
call void @llvm.debugtrap()
33+
ret void
34+
}

0 commit comments

Comments
 (0)