Skip to content

Commit ff03f23

Browse files
authored
[WebAssembly] remove instruction after builtin trap (#90207)
`llvm.trap` will be convert as `unreachable` which is terminator. Instruction after terminator will cause validation failed. This PR introduces a pass to clean instruction after terminator. Fixes: #68770.
1 parent 7b5b521 commit ff03f23

File tree

6 files changed

+102
-8
lines changed

6 files changed

+102
-8
lines changed

llvm/lib/Target/WebAssembly/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ add_llvm_target(WebAssemblyCodeGen
1919
WebAssemblyArgumentMove.cpp
2020
WebAssemblyAsmPrinter.cpp
2121
WebAssemblyCFGStackify.cpp
22+
WebAssemblyCleanCodeAfterTrap.cpp
2223
WebAssemblyCFGSort.cpp
2324
WebAssemblyDebugFixup.cpp
2425
WebAssemblyDebugValueManager.cpp

llvm/lib/Target/WebAssembly/WebAssembly.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ FunctionPass *createWebAssemblyISelDag(WebAssemblyTargetMachine &TM,
3737
CodeGenOptLevel OptLevel);
3838
FunctionPass *createWebAssemblyArgumentMove();
3939
FunctionPass *createWebAssemblySetP2AlignOperands();
40+
FunctionPass *createWebAssemblyCleanCodeAfterTrap();
4041

4142
// Late passes.
4243
FunctionPass *createWebAssemblyReplacePhysRegs();
@@ -63,6 +64,7 @@ void initializeOptimizeReturnedPass(PassRegistry &);
6364
void initializeWebAssemblyRefTypeMem2LocalPass(PassRegistry &);
6465
void initializeWebAssemblyAddMissingPrototypesPass(PassRegistry &);
6566
void initializeWebAssemblyArgumentMovePass(PassRegistry &);
67+
void initializeWebAssemblyCleanCodeAfterTrapPass(PassRegistry &);
6668
void initializeWebAssemblyCFGSortPass(PassRegistry &);
6769
void initializeWebAssemblyCFGStackifyPass(PassRegistry &);
6870
void initializeWebAssemblyDAGToDAGISelPass(PassRegistry &);
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//===-- WebAssemblyCleanCodeAfterTrap.cpp - Clean Code After Trap ---------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
///
9+
/// \file
10+
/// This file remove instruction after trap.
11+
/// ``llvm.trap`` will be convert as ``unreachable`` which is terminator.
12+
/// Instruction after terminator will cause validation failed.
13+
///
14+
//===----------------------------------------------------------------------===//
15+
16+
#include "WebAssembly.h"
17+
#include "WebAssemblyUtilities.h"
18+
#include "llvm/ADT/SmallVector.h"
19+
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
20+
#include "llvm/CodeGen/Passes.h"
21+
#include "llvm/MC/MCInstrDesc.h"
22+
#include "llvm/Support/Debug.h"
23+
#include "llvm/Support/raw_ostream.h"
24+
using namespace llvm;
25+
26+
#define DEBUG_TYPE "wasm-clean-code-after-trap"
27+
28+
namespace {
29+
class WebAssemblyCleanCodeAfterTrap final : public MachineFunctionPass {
30+
public:
31+
static char ID; // Pass identification, replacement for typeid
32+
WebAssemblyCleanCodeAfterTrap() : MachineFunctionPass(ID) {}
33+
34+
StringRef getPassName() const override {
35+
return "WebAssembly Clean Code After Trap";
36+
}
37+
38+
bool runOnMachineFunction(MachineFunction &MF) override;
39+
};
40+
} // end anonymous namespace
41+
42+
char WebAssemblyCleanCodeAfterTrap::ID = 0;
43+
INITIALIZE_PASS(WebAssemblyCleanCodeAfterTrap, DEBUG_TYPE,
44+
"WebAssembly Clean Code After Trap", false, false)
45+
46+
FunctionPass *llvm::createWebAssemblyCleanCodeAfterTrap() {
47+
return new WebAssemblyCleanCodeAfterTrap();
48+
}
49+
50+
bool WebAssemblyCleanCodeAfterTrap::runOnMachineFunction(MachineFunction &MF) {
51+
LLVM_DEBUG({
52+
dbgs() << "********** CleanCodeAfterTrap **********\n"
53+
<< "********** Function: " << MF.getName() << '\n';
54+
});
55+
56+
bool Changed = false;
57+
58+
for (MachineBasicBlock &BB : MF) {
59+
bool HasTerminator = false;
60+
llvm::SmallVector<MachineInstr *> RemoveMI{};
61+
for (MachineInstr &MI : BB) {
62+
if (HasTerminator)
63+
RemoveMI.push_back(&MI);
64+
if (MI.hasProperty(MCID::Trap) && MI.isTerminator())
65+
HasTerminator = true;
66+
}
67+
if (!RemoveMI.empty()) {
68+
Changed = true;
69+
LLVM_DEBUG({
70+
for (MachineInstr *MI : RemoveMI) {
71+
llvm::dbgs() << "* remove ";
72+
MI->print(llvm::dbgs());
73+
}
74+
});
75+
for (MachineInstr *MI : RemoveMI)
76+
MI->eraseFromParent();
77+
}
78+
}
79+
return Changed;
80+
}

llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,10 @@ bool WebAssemblyPassConfig::addInstSelector() {
512512
// Eliminate range checks and add default targets to br_table instructions.
513513
addPass(createWebAssemblyFixBrTableDefaults());
514514

515+
// unreachable is terminator, non-terminator instruction after it is not
516+
// allowed.
517+
addPass(createWebAssemblyCleanCodeAfterTrap());
518+
515519
return false;
516520
}
517521

llvm/test/CodeGen/WebAssembly/unreachable.ll

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ define void @trap_ret_void() {
3030
; CHECK: .functype trap_ret_void () -> ()
3131
; CHECK-NEXT: # %bb.0:
3232
; CHECK-NEXT: unreachable
33-
; CHECK-NEXT: # fallthrough-return
3433
; CHECK-NEXT: end_function
3534
call void @llvm.trap()
3635
ret void
@@ -54,7 +53,6 @@ define void @trap_unreacheable() {
5453
; CHECK: .functype trap_unreacheable () -> ()
5554
; CHECK-NEXT: # %bb.0:
5655
; CHECK-NEXT: unreachable
57-
; CHECK-NEXT: unreachable
5856
; CHECK-NEXT: end_function
5957
call void @llvm.trap()
6058
unreachable
@@ -94,3 +92,12 @@ define i32 @missing_ret_noreturn_unreachable() {
9492
call void @ext_never_return()
9593
unreachable
9694
}
95+
96+
define i32 @no_crash_for_other_instruction_after_trap(ptr %p, i32 %b) {
97+
; CHECK-LABEL: no_crash_for_other_instruction_after_trap:
98+
; CHECK: unreachable
99+
; CHECK-NEXT: end_function
100+
%a = load i32, ptr %p
101+
call void @llvm.trap()
102+
ret i32 %a
103+
}

llvm/test/MC/WebAssembly/global-ctor-dtor.ll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,29 +80,29 @@ declare void @func3()
8080
; CHECK-NEXT: Offset: 0x1D
8181
; CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB
8282
; CHECK-NEXT: Index: 6
83-
; CHECK-NEXT: Offset: 0x2C
83+
; CHECK-NEXT: Offset: 0x2B
8484
; CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_SLEB
8585
; CHECK-NEXT: Index: 5
86-
; CHECK-NEXT: Offset: 0x37
86+
; CHECK-NEXT: Offset: 0x36
8787
; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB
8888
; CHECK-NEXT: Index: 3
89-
; CHECK-NEXT: Offset: 0x3F
89+
; CHECK-NEXT: Offset: 0x3E
9090
; CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB
9191
; CHECK-NEXT: Index: 4
92-
; CHECK-NEXT: Offset: 0x45
92+
; CHECK-NEXT: Offset: 0x44
9393
; CHECK-NEXT: Functions:
9494
; CHECK-NEXT: - Index: 5
9595
; CHECK-NEXT: Locals:
9696
; CHECK-NEXT: Body: 1080808080000B
9797
; CHECK-NEXT: - Index: 6
9898
; CHECK-NEXT: Locals:
99-
; CHECK-NEXT: Body: 02404181808080004100418080808000108180808000450D0000000B0B
99+
; CHECK-NEXT: Body: 02404181808080004100418080808000108180808000450D00000B0B
100100
; CHECK-NEXT: - Index: 7
101101
; CHECK-NEXT: Locals:
102102
; CHECK-NEXT: Body: 1082808080000B
103103
; CHECK-NEXT: - Index: 8
104104
; CHECK-NEXT: Locals:
105-
; CHECK-NEXT: Body: 02404182808080004100418080808000108180808000450D0000000B0B
105+
; CHECK-NEXT: Body: 02404182808080004100418080808000108180808000450D00000B0B
106106
; CHECK-NEXT: - Type: DATA
107107
; CHECK-NEXT: Segments:
108108
; CHECK-NEXT: - SectionOffset: 6

0 commit comments

Comments
 (0)