Index: lib/Target/WebAssembly/WebAssemblyISelLowering.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -172,6 +172,9 @@ 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: lib/Target/WebAssembly/WebAssemblyInstrControl.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrControl.td +++ lib/Target/WebAssembly/WebAssemblyInstrControl.td @@ -54,10 +54,14 @@ 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 Index: lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -50,6 +50,12 @@ : "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 Index: test/CodeGen/WebAssembly/unreachable.ll =================================================================== --- /dev/null +++ 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 +}