From 537330de8268f3592b5f98987da5f74a808d2670 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Tue, 10 Nov 2015 00:30:57 +0000 Subject: [PATCH] [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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252566 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../WebAssembly/WebAssemblyISelLowering.cpp | 3 ++ .../WebAssembly/WebAssemblyInstrControl.td | 8 +++-- .../WebAssembly/WebAssemblyTargetMachine.cpp | 6 ++++ test/CodeGen/WebAssembly/unreachable.ll | 34 +++++++++++++++++++ 4 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 test/CodeGen/WebAssembly/unreachable.ll diff --git a/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index 1c7d86b293a..baf5b2554bb 100644 --- a/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -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( diff --git a/lib/Target/WebAssembly/WebAssemblyInstrControl.td b/lib/Target/WebAssembly/WebAssemblyInstrControl.td index a7e87f9d04d..6aae5d38d0b 100644 --- a/lib/Target/WebAssembly/WebAssemblyInstrControl.td +++ b/lib/Target/WebAssembly/WebAssemblyInstrControl.td @@ -54,10 +54,14 @@ multiclass RETURN { 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; defm : RETURN; defm : RETURN; defm : RETURN; 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 diff --git a/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index 18e2e5057db..99a24266686 100644 --- a/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -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()) { + // 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 index 00000000000..a16e4529033 --- /dev/null +++ b/test/CodeGen/WebAssembly/unreachable.ll @@ -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 +} -- 2.34.1