[WebAssembly] Support 'unreachable' expression
authorDerek Schuff <dschuff@google.com>
Tue, 10 Nov 2015 00:30:57 +0000 (00:30 +0000)
committerDerek Schuff <dschuff@google.com>
Tue, 10 Nov 2015 00:30:57 +0000 (00:30 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252566 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
lib/Target/WebAssembly/WebAssemblyInstrControl.td
lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
test/CodeGen/WebAssembly/unreachable.ll [new file with mode: 0644]

index 1c7d86b..baf5b25 100644 (file)
@@ -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(
index a7e87f9..6aae5d3 100644 (file)
@@ -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
index 18e2e50..99a2426 100644 (file)
@@ -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
diff --git a/test/CodeGen/WebAssembly/unreachable.ll b/test/CodeGen/WebAssembly/unreachable.ll
new file mode 100644 (file)
index 0000000..a16e452
--- /dev/null
@@ -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
+}