1 //===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// This file implements several utility functions for WebAssembly.
13 //===----------------------------------------------------------------------===//
15 #include "WebAssemblyUtilities.h"
16 #include "WebAssemblyMachineFunctionInfo.h"
17 #include "llvm/CodeGen/MachineInstr.h"
18 #include "llvm/CodeGen/MachineLoopInfo.h"
21 const char *const WebAssembly::ClangCallTerminateFn = "__clang_call_terminate";
22 const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch";
23 const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow";
24 const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev";
25 const char *const WebAssembly::PersonalityWrapperFn =
26 "_Unwind_Wasm_CallPersonality";
28 bool WebAssembly::isArgument(const MachineInstr &MI) {
29 switch (MI.getOpcode()) {
30 case WebAssembly::ARGUMENT_i32:
31 case WebAssembly::ARGUMENT_i32_S:
32 case WebAssembly::ARGUMENT_i64:
33 case WebAssembly::ARGUMENT_i64_S:
34 case WebAssembly::ARGUMENT_f32:
35 case WebAssembly::ARGUMENT_f32_S:
36 case WebAssembly::ARGUMENT_f64:
37 case WebAssembly::ARGUMENT_f64_S:
38 case WebAssembly::ARGUMENT_v16i8:
39 case WebAssembly::ARGUMENT_v16i8_S:
40 case WebAssembly::ARGUMENT_v8i16:
41 case WebAssembly::ARGUMENT_v8i16_S:
42 case WebAssembly::ARGUMENT_v4i32:
43 case WebAssembly::ARGUMENT_v4i32_S:
44 case WebAssembly::ARGUMENT_v2i64:
45 case WebAssembly::ARGUMENT_v2i64_S:
46 case WebAssembly::ARGUMENT_v4f32:
47 case WebAssembly::ARGUMENT_v4f32_S:
48 case WebAssembly::ARGUMENT_v2f64:
49 case WebAssembly::ARGUMENT_v2f64_S:
56 bool WebAssembly::isCopy(const MachineInstr &MI) {
57 switch (MI.getOpcode()) {
58 case WebAssembly::COPY_I32:
59 case WebAssembly::COPY_I32_S:
60 case WebAssembly::COPY_I64:
61 case WebAssembly::COPY_I64_S:
62 case WebAssembly::COPY_F32:
63 case WebAssembly::COPY_F32_S:
64 case WebAssembly::COPY_F64:
65 case WebAssembly::COPY_F64_S:
66 case WebAssembly::COPY_V128:
67 case WebAssembly::COPY_V128_S:
74 bool WebAssembly::isTee(const MachineInstr &MI) {
75 switch (MI.getOpcode()) {
76 case WebAssembly::TEE_I32:
77 case WebAssembly::TEE_I32_S:
78 case WebAssembly::TEE_I64:
79 case WebAssembly::TEE_I64_S:
80 case WebAssembly::TEE_F32:
81 case WebAssembly::TEE_F32_S:
82 case WebAssembly::TEE_F64:
83 case WebAssembly::TEE_F64_S:
84 case WebAssembly::TEE_V128:
85 case WebAssembly::TEE_V128_S:
92 /// Test whether MI is a child of some other node in an expression tree.
93 bool WebAssembly::isChild(const MachineInstr &MI,
94 const WebAssemblyFunctionInfo &MFI) {
95 if (MI.getNumOperands() == 0)
97 const MachineOperand &MO = MI.getOperand(0);
98 if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
100 unsigned Reg = MO.getReg();
101 return TargetRegisterInfo::isVirtualRegister(Reg) &&
102 MFI.isVRegStackified(Reg);
105 bool WebAssembly::isCallDirect(const MachineInstr &MI) {
106 switch (MI.getOpcode()) {
107 case WebAssembly::CALL_VOID:
108 case WebAssembly::CALL_VOID_S:
109 case WebAssembly::CALL_I32:
110 case WebAssembly::CALL_I32_S:
111 case WebAssembly::CALL_I64:
112 case WebAssembly::CALL_I64_S:
113 case WebAssembly::CALL_F32:
114 case WebAssembly::CALL_F32_S:
115 case WebAssembly::CALL_F64:
116 case WebAssembly::CALL_F64_S:
117 case WebAssembly::CALL_v16i8:
118 case WebAssembly::CALL_v16i8_S:
119 case WebAssembly::CALL_v8i16:
120 case WebAssembly::CALL_v8i16_S:
121 case WebAssembly::CALL_v4i32:
122 case WebAssembly::CALL_v4i32_S:
123 case WebAssembly::CALL_v2i64:
124 case WebAssembly::CALL_v2i64_S:
125 case WebAssembly::CALL_v4f32:
126 case WebAssembly::CALL_v4f32_S:
127 case WebAssembly::CALL_v2f64:
128 case WebAssembly::CALL_v2f64_S:
129 case WebAssembly::CALL_EXCEPT_REF:
130 case WebAssembly::CALL_EXCEPT_REF_S:
137 bool WebAssembly::isCallIndirect(const MachineInstr &MI) {
138 switch (MI.getOpcode()) {
139 case WebAssembly::CALL_INDIRECT_VOID:
140 case WebAssembly::CALL_INDIRECT_VOID_S:
141 case WebAssembly::CALL_INDIRECT_I32:
142 case WebAssembly::CALL_INDIRECT_I32_S:
143 case WebAssembly::CALL_INDIRECT_I64:
144 case WebAssembly::CALL_INDIRECT_I64_S:
145 case WebAssembly::CALL_INDIRECT_F32:
146 case WebAssembly::CALL_INDIRECT_F32_S:
147 case WebAssembly::CALL_INDIRECT_F64:
148 case WebAssembly::CALL_INDIRECT_F64_S:
149 case WebAssembly::CALL_INDIRECT_v16i8:
150 case WebAssembly::CALL_INDIRECT_v16i8_S:
151 case WebAssembly::CALL_INDIRECT_v8i16:
152 case WebAssembly::CALL_INDIRECT_v8i16_S:
153 case WebAssembly::CALL_INDIRECT_v4i32:
154 case WebAssembly::CALL_INDIRECT_v4i32_S:
155 case WebAssembly::CALL_INDIRECT_v2i64:
156 case WebAssembly::CALL_INDIRECT_v2i64_S:
157 case WebAssembly::CALL_INDIRECT_v4f32:
158 case WebAssembly::CALL_INDIRECT_v4f32_S:
159 case WebAssembly::CALL_INDIRECT_v2f64:
160 case WebAssembly::CALL_INDIRECT_v2f64_S:
161 case WebAssembly::CALL_INDIRECT_EXCEPT_REF:
162 case WebAssembly::CALL_INDIRECT_EXCEPT_REF_S:
169 unsigned WebAssembly::getCalleeOpNo(const MachineInstr &MI) {
170 switch (MI.getOpcode()) {
171 case WebAssembly::CALL_VOID:
172 case WebAssembly::CALL_VOID_S:
173 case WebAssembly::CALL_INDIRECT_VOID:
174 case WebAssembly::CALL_INDIRECT_VOID_S:
176 case WebAssembly::CALL_I32:
177 case WebAssembly::CALL_I32_S:
178 case WebAssembly::CALL_I64:
179 case WebAssembly::CALL_I64_S:
180 case WebAssembly::CALL_F32:
181 case WebAssembly::CALL_F32_S:
182 case WebAssembly::CALL_F64:
183 case WebAssembly::CALL_F64_S:
184 case WebAssembly::CALL_v16i8:
185 case WebAssembly::CALL_v16i8_S:
186 case WebAssembly::CALL_v8i16:
187 case WebAssembly::CALL_v8i16_S:
188 case WebAssembly::CALL_v4i32:
189 case WebAssembly::CALL_v4i32_S:
190 case WebAssembly::CALL_v2i64:
191 case WebAssembly::CALL_v2i64_S:
192 case WebAssembly::CALL_v4f32:
193 case WebAssembly::CALL_v4f32_S:
194 case WebAssembly::CALL_v2f64:
195 case WebAssembly::CALL_v2f64_S:
196 case WebAssembly::CALL_EXCEPT_REF:
197 case WebAssembly::CALL_EXCEPT_REF_S:
198 case WebAssembly::CALL_INDIRECT_I32:
199 case WebAssembly::CALL_INDIRECT_I32_S:
200 case WebAssembly::CALL_INDIRECT_I64:
201 case WebAssembly::CALL_INDIRECT_I64_S:
202 case WebAssembly::CALL_INDIRECT_F32:
203 case WebAssembly::CALL_INDIRECT_F32_S:
204 case WebAssembly::CALL_INDIRECT_F64:
205 case WebAssembly::CALL_INDIRECT_F64_S:
206 case WebAssembly::CALL_INDIRECT_v16i8:
207 case WebAssembly::CALL_INDIRECT_v16i8_S:
208 case WebAssembly::CALL_INDIRECT_v8i16:
209 case WebAssembly::CALL_INDIRECT_v8i16_S:
210 case WebAssembly::CALL_INDIRECT_v4i32:
211 case WebAssembly::CALL_INDIRECT_v4i32_S:
212 case WebAssembly::CALL_INDIRECT_v2i64:
213 case WebAssembly::CALL_INDIRECT_v2i64_S:
214 case WebAssembly::CALL_INDIRECT_v4f32:
215 case WebAssembly::CALL_INDIRECT_v4f32_S:
216 case WebAssembly::CALL_INDIRECT_v2f64:
217 case WebAssembly::CALL_INDIRECT_v2f64_S:
218 case WebAssembly::CALL_INDIRECT_EXCEPT_REF:
219 case WebAssembly::CALL_INDIRECT_EXCEPT_REF_S:
222 llvm_unreachable("Not a call instruction");
226 bool WebAssembly::isMarker(const MachineInstr &MI) {
227 switch (MI.getOpcode()) {
228 case WebAssembly::BLOCK:
229 case WebAssembly::BLOCK_S:
230 case WebAssembly::END_BLOCK:
231 case WebAssembly::END_BLOCK_S:
232 case WebAssembly::LOOP:
233 case WebAssembly::LOOP_S:
234 case WebAssembly::END_LOOP:
235 case WebAssembly::END_LOOP_S:
236 case WebAssembly::TRY:
237 case WebAssembly::TRY_S:
238 case WebAssembly::END_TRY:
239 case WebAssembly::END_TRY_S:
246 bool WebAssembly::isThrow(const MachineInstr &MI) {
247 switch (MI.getOpcode()) {
248 case WebAssembly::THROW_I32:
249 case WebAssembly::THROW_I32_S:
250 case WebAssembly::THROW_I64:
251 case WebAssembly::THROW_I64_S:
258 bool WebAssembly::isRethrow(const MachineInstr &MI) {
259 switch (MI.getOpcode()) {
260 case WebAssembly::RETHROW:
261 case WebAssembly::RETHROW_S:
262 case WebAssembly::RETHROW_TO_CALLER:
263 case WebAssembly::RETHROW_TO_CALLER_S:
270 bool WebAssembly::isCatch(const MachineInstr &MI) {
271 switch (MI.getOpcode()) {
272 case WebAssembly::CATCH_I32:
273 case WebAssembly::CATCH_I32_S:
274 case WebAssembly::CATCH_I64:
275 case WebAssembly::CATCH_I64_S:
276 case WebAssembly::CATCH_ALL:
277 case WebAssembly::CATCH_ALL_S:
284 bool WebAssembly::mayThrow(const MachineInstr &MI) {
285 switch (MI.getOpcode()) {
286 case WebAssembly::THROW_I32:
287 case WebAssembly::THROW_I32_S:
288 case WebAssembly::THROW_I64:
289 case WebAssembly::THROW_I64_S:
290 case WebAssembly::RETHROW:
291 case WebAssembly::RETHROW_S:
294 if (isCallIndirect(MI))
299 const MachineOperand &MO = MI.getOperand(getCalleeOpNo(MI));
300 assert(MO.isGlobal());
301 const auto *F = dyn_cast<Function>(MO.getGlobal());
304 if (F->doesNotThrow())
306 // These functions never throw
307 if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
308 F->getName() == ClangCallTerminateFn || F->getName() == StdTerminateFn)
313 bool WebAssembly::isCatchTerminatePad(const MachineBasicBlock &MBB) {
316 bool SeenCatch = false;
317 for (auto &MI : MBB) {
318 if (MI.getOpcode() == WebAssembly::CATCH_I32 ||
319 MI.getOpcode() == WebAssembly::CATCH_I64 ||
320 MI.getOpcode() == WebAssembly::CATCH_I32_S ||
321 MI.getOpcode() == WebAssembly::CATCH_I64_S)
323 if (SeenCatch && MI.isCall()) {
324 const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI));
325 if (CalleeOp.isGlobal() &&
326 CalleeOp.getGlobal()->getName() == ClangCallTerminateFn)
333 bool WebAssembly::isCatchAllTerminatePad(const MachineBasicBlock &MBB) {
336 bool SeenCatchAll = false;
337 for (auto &MI : MBB) {
338 if (MI.getOpcode() == WebAssembly::CATCH_ALL ||
339 MI.getOpcode() == WebAssembly::CATCH_ALL_S)
341 if (SeenCatchAll && MI.isCall()) {
342 const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI));
343 if (CalleeOp.isGlobal() &&
344 CalleeOp.getGlobal()->getName() == StdTerminateFn)