diff --git a/lld/test/wasm/init-fini.ll b/lld/test/wasm/init-fini.ll index 3d2e9a78043ee4..ef2f41f96e89b4 100644 --- a/lld/test/wasm/init-fini.ll +++ b/lld/test/wasm/init-fini.ll @@ -78,7 +78,7 @@ entry: ; CHECK-NEXT: Body: 10041005100A100F1012100F10141004100C100F10161002100E0B ; CHECK: - Index: 22 ; CHECK-NEXT: Locals: -; CHECK-NEXT: Body: 02404186808080004100418088808000108080808000450D0000000B0B +; CHECK-NEXT: Body: 02404186808080004100418088808000108080808000450D00000B0B ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: name ; CHECK-NEXT: FunctionNames: diff --git a/llvm/lib/Target/WebAssembly/CMakeLists.txt b/llvm/lib/Target/WebAssembly/CMakeLists.txt index f430be2653b4ee..1e83cbeac50d6d 100644 --- a/llvm/lib/Target/WebAssembly/CMakeLists.txt +++ b/llvm/lib/Target/WebAssembly/CMakeLists.txt @@ -19,6 +19,7 @@ add_llvm_target(WebAssemblyCodeGen WebAssemblyArgumentMove.cpp WebAssemblyAsmPrinter.cpp WebAssemblyCFGStackify.cpp + WebAssemblyCleanCodeAfterTrap.cpp WebAssemblyCFGSort.cpp WebAssemblyDebugFixup.cpp WebAssemblyDebugValueManager.cpp diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.h b/llvm/lib/Target/WebAssembly/WebAssembly.h index 1c40addb6d6f78..7fc8546248f164 100644 --- a/llvm/lib/Target/WebAssembly/WebAssembly.h +++ b/llvm/lib/Target/WebAssembly/WebAssembly.h @@ -37,6 +37,7 @@ FunctionPass *createWebAssemblyISelDag(WebAssemblyTargetMachine &TM, CodeGenOptLevel OptLevel); FunctionPass *createWebAssemblyArgumentMove(); FunctionPass *createWebAssemblySetP2AlignOperands(); +FunctionPass *createWebAssemblyCleanCodeAfterTrap(); // Late passes. FunctionPass *createWebAssemblyReplacePhysRegs(); @@ -63,6 +64,7 @@ void initializeOptimizeReturnedPass(PassRegistry &); void initializeWebAssemblyRefTypeMem2LocalPass(PassRegistry &); void initializeWebAssemblyAddMissingPrototypesPass(PassRegistry &); void initializeWebAssemblyArgumentMovePass(PassRegistry &); +void initializeWebAssemblyCleanCodeAfterTrapPass(PassRegistry &); void initializeWebAssemblyCFGSortPass(PassRegistry &); void initializeWebAssemblyCFGStackifyPass(PassRegistry &); void initializeWebAssemblyDAGToDAGISelPass(PassRegistry &); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCleanCodeAfterTrap.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCleanCodeAfterTrap.cpp new file mode 100644 index 00000000000000..e5cba3c485473c --- /dev/null +++ b/llvm/lib/Target/WebAssembly/WebAssemblyCleanCodeAfterTrap.cpp @@ -0,0 +1,80 @@ +//===-- WebAssemblyCleanCodeAfterTrap.cpp - Clean Code After Trap ---------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file remove instruction after trap. +/// ``llvm.trap`` will be convert as ``unreachable`` which is terminator. +/// Instruction after terminator will cause validation failed. +/// +//===----------------------------------------------------------------------===// + +#include "WebAssembly.h" +#include "WebAssemblyUtilities.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/MachineBlockFrequencyInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/MC/MCInstrDesc.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define DEBUG_TYPE "wasm-clean-code-after-trap" + +namespace { +class WebAssemblyCleanCodeAfterTrap final : public MachineFunctionPass { +public: + static char ID; // Pass identification, replacement for typeid + WebAssemblyCleanCodeAfterTrap() : MachineFunctionPass(ID) {} + + StringRef getPassName() const override { + return "WebAssembly Clean Code After Trap"; + } + + bool runOnMachineFunction(MachineFunction &MF) override; +}; +} // end anonymous namespace + +char WebAssemblyCleanCodeAfterTrap::ID = 0; +INITIALIZE_PASS(WebAssemblyCleanCodeAfterTrap, DEBUG_TYPE, + "WebAssembly Clean Code After Trap", false, false) + +FunctionPass *llvm::createWebAssemblyCleanCodeAfterTrap() { + return new WebAssemblyCleanCodeAfterTrap(); +} + +bool WebAssemblyCleanCodeAfterTrap::runOnMachineFunction(MachineFunction &MF) { + LLVM_DEBUG({ + dbgs() << "********** CleanCodeAfterTrap **********\n" + << "********** Function: " << MF.getName() << '\n'; + }); + + bool Changed = false; + + for (MachineBasicBlock &BB : MF) { + bool HasTerminator = false; + llvm::SmallVector RemoveMI{}; + for (MachineInstr &MI : BB) { + if (HasTerminator) + RemoveMI.push_back(&MI); + if (MI.hasProperty(MCID::Trap) && MI.isTerminator()) + HasTerminator = true; + } + if (!RemoveMI.empty()) { + Changed = true; + LLVM_DEBUG({ + for (MachineInstr *MI : RemoveMI) { + llvm::dbgs() << "* remove "; + MI->print(llvm::dbgs()); + } + }); + for (MachineInstr *MI : RemoveMI) + MI->eraseFromParent(); + } + } + return Changed; +} diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index cdd39eeb6bbbc2..de342e89657367 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -512,6 +512,10 @@ bool WebAssemblyPassConfig::addInstSelector() { // Eliminate range checks and add default targets to br_table instructions. addPass(createWebAssemblyFixBrTableDefaults()); + // unreachable is terminator, non-terminator instruction after it is not + // allowed. + addPass(createWebAssemblyCleanCodeAfterTrap()); + return false; } diff --git a/llvm/test/CodeGen/WebAssembly/unreachable.ll b/llvm/test/CodeGen/WebAssembly/unreachable.ll index 5368c2ba5b8dc1..ccac31a9af4a3d 100644 --- a/llvm/test/CodeGen/WebAssembly/unreachable.ll +++ b/llvm/test/CodeGen/WebAssembly/unreachable.ll @@ -30,7 +30,6 @@ define void @trap_ret_void() { ; CHECK: .functype trap_ret_void () -> () ; CHECK-NEXT: # %bb.0: ; CHECK-NEXT: unreachable -; CHECK-NEXT: # fallthrough-return ; CHECK-NEXT: end_function call void @llvm.trap() ret void @@ -54,7 +53,6 @@ define void @trap_unreacheable() { ; CHECK: .functype trap_unreacheable () -> () ; CHECK-NEXT: # %bb.0: ; CHECK-NEXT: unreachable -; CHECK-NEXT: unreachable ; CHECK-NEXT: end_function call void @llvm.trap() unreachable @@ -94,3 +92,12 @@ define i32 @missing_ret_noreturn_unreachable() { call void @ext_never_return() unreachable } + +define i32 @no_crash_for_other_instruction_after_trap(ptr %p, i32 %b) { +; CHECK-LABEL: no_crash_for_other_instruction_after_trap: +; CHECK: unreachable +; CHECK-NEXT: end_function + %a = load i32, ptr %p + call void @llvm.trap() + ret i32 %a +} diff --git a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll index bc1be793134969..f1ec71da1ebb64 100644 --- a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll +++ b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll @@ -80,29 +80,29 @@ declare void @func3() ; CHECK-NEXT: Offset: 0x1D ; CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB ; CHECK-NEXT: Index: 6 -; CHECK-NEXT: Offset: 0x2C +; CHECK-NEXT: Offset: 0x2B ; CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_SLEB ; CHECK-NEXT: Index: 5 -; CHECK-NEXT: Offset: 0x37 +; CHECK-NEXT: Offset: 0x36 ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB ; CHECK-NEXT: Index: 3 -; CHECK-NEXT: Offset: 0x3F +; CHECK-NEXT: Offset: 0x3E ; CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB ; CHECK-NEXT: Index: 4 -; CHECK-NEXT: Offset: 0x45 +; CHECK-NEXT: Offset: 0x44 ; CHECK-NEXT: Functions: ; CHECK-NEXT: - Index: 5 ; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 1080808080000B ; CHECK-NEXT: - Index: 6 ; CHECK-NEXT: Locals: -; CHECK-NEXT: Body: 02404181808080004100418080808000108180808000450D0000000B0B +; CHECK-NEXT: Body: 02404181808080004100418080808000108180808000450D00000B0B ; CHECK-NEXT: - Index: 7 ; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 1082808080000B ; CHECK-NEXT: - Index: 8 ; CHECK-NEXT: Locals: -; CHECK-NEXT: Body: 02404182808080004100418080808000108180808000450D0000000B0B +; CHECK-NEXT: Body: 02404182808080004100418080808000108180808000450D00000B0B ; CHECK-NEXT: - Type: DATA ; CHECK-NEXT: Segments: ; CHECK-NEXT: - SectionOffset: 6