Skip to content

Commit

Permalink
[WebAssembly] Support 'unreachable' expression
Browse files Browse the repository at this point in the history
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
  • Loading branch information
dschuff committed Nov 10, 2015
1 parent 6d87f28 commit ffa143c
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 2 deletions.
3 changes: 3 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
for (auto T : MVT::integer_valuetypes())
for (auto Ext : {ISD::EXTLOAD, ISD::ZEXTLOAD, ISD::SEXTLOAD})
setLoadExtAction(Ext, T, MVT::i1, Promote);

// Trap lowers to wasm unreachable
setOperationAction(ISD::TRAP, MVT::Other, Legal);
}

FastISel *WebAssemblyTargetLowering::createFastISel(
Expand Down
8 changes: 6 additions & 2 deletions llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,14 @@ multiclass RETURN<WebAssemblyRegClass vt> {
def RETURN_#vt : I<(outs), (ins vt:$val), [(WebAssemblyreturn vt:$val)],
"return $val">;
}
let isReturn = 1, isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in {

let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in {
let isReturn = 1 in {
defm : RETURN<I32>;
defm : RETURN<I64>;
defm : RETURN<F32>;
defm : RETURN<F64>;
def RETURN_VOID : I<(outs), (ins), [(WebAssemblyreturn)], "return">;
} // isReturn = 1, isTerminator = 1, hasCtrlDep = 1, isBarrier = 1
} // isReturn = 1
def UNREACHABLE : I<(outs), (ins), [(trap)], "unreachable">;
} // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1
6 changes: 6 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ WebAssemblyTargetMachine::WebAssemblyTargetMachine(
: "e-p:32:32-i64:64-n32:64-S128",
TT, CPU, FS, Options, RM, CM, OL),
TLOF(make_unique<WebAssemblyTargetObjectFile>()) {
// 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 is meant for that case.
this->Options.TrapUnreachable = true;

initAsmInfo();

// We need a reducible CFG, so disable some optimizations which tend to
Expand Down
34 changes: 34 additions & 0 deletions llvm/test/CodeGen/WebAssembly/unreachable.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
; RUN: llc < %s -asm-verbose=false | FileCheck %s
; RUN: llc < %s -asm-verbose=false -fast-isel | FileCheck %s

; Test that LLVM unreachable instruction and trap intrinsic are lowered to
; wasm unreachable

target datalayout = "e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-unknown"

declare void @llvm.trap()
declare void @llvm.debugtrap()
declare void @abort()

; CHECK-LABEL: f1:
; CHECK: call $abort
; CHECK: unreachable
define i32 @f1() {
call void @abort()
unreachable
}

; CHECK-LABEL: f2:
; CHECK: unreachable
define void @f2() {
call void @llvm.trap()
ret void
}

; CHECK-LABEL: f3:
; CHECK: unreachable
define void @f3() {
call void @llvm.debugtrap()
ret void
}

0 comments on commit ffa143c

Please sign in to comment.