Line data Source code
1 : //===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : ///
10 : /// \file
11 : /// This file implements several utility functions for WebAssembly.
12 : ///
13 : //===----------------------------------------------------------------------===//
14 :
15 : #include "WebAssemblyUtilities.h"
16 : #include "WebAssemblyMachineFunctionInfo.h"
17 : #include "llvm/CodeGen/MachineInstr.h"
18 : #include "llvm/CodeGen/MachineLoopInfo.h"
19 : using namespace llvm;
20 :
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";
27 :
28 156741 : bool WebAssembly::isArgument(const MachineInstr &MI) {
29 313482 : 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:
50 : return true;
51 119530 : default:
52 119530 : return false;
53 : }
54 : }
55 :
56 3879 : bool WebAssembly::isCopy(const MachineInstr &MI) {
57 7758 : 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:
68 : return true;
69 3840 : default:
70 3840 : return false;
71 : }
72 : }
73 :
74 3981 : bool WebAssembly::isTee(const MachineInstr &MI) {
75 3981 : 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:
86 : return true;
87 : default:
88 : return false;
89 : }
90 : }
91 :
92 : /// Test whether MI is a child of some other node in an expression tree.
93 709 : bool WebAssembly::isChild(const MachineInstr &MI,
94 : const WebAssemblyFunctionInfo &MFI) {
95 709 : if (MI.getNumOperands() == 0)
96 : return false;
97 709 : const MachineOperand &MO = MI.getOperand(0);
98 709 : if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
99 : return false;
100 527 : unsigned Reg = MO.getReg();
101 1047 : return TargetRegisterInfo::isVirtualRegister(Reg) &&
102 : MFI.isVRegStackified(Reg);
103 : }
104 :
105 0 : bool WebAssembly::isCallDirect(const MachineInstr &MI) {
106 0 : 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:
131 : return true;
132 : default:
133 : return false;
134 : }
135 : }
136 :
137 33 : bool WebAssembly::isCallIndirect(const MachineInstr &MI) {
138 66 : 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:
163 : return true;
164 0 : default:
165 0 : return false;
166 : }
167 : }
168 :
169 237 : unsigned WebAssembly::getCalleeOpNo(const MachineInstr &MI) {
170 237 : 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:
175 : return 0;
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:
220 : return 1;
221 0 : default:
222 0 : llvm_unreachable("Not a call instruction");
223 : }
224 : }
225 :
226 0 : bool WebAssembly::isMarker(const MachineInstr &MI) {
227 0 : 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:
240 : return true;
241 0 : default:
242 0 : return false;
243 : }
244 : }
245 :
246 0 : bool WebAssembly::isThrow(const MachineInstr &MI) {
247 0 : 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:
252 : return true;
253 0 : default:
254 0 : return false;
255 : }
256 : }
257 :
258 546 : bool WebAssembly::isRethrow(const MachineInstr &MI) {
259 1092 : 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:
264 : return true;
265 546 : default:
266 546 : return false;
267 : }
268 : }
269 :
270 339 : bool WebAssembly::isCatch(const MachineInstr &MI) {
271 678 : 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:
278 : return true;
279 306 : default:
280 306 : return false;
281 : }
282 : }
283 :
284 0 : bool WebAssembly::mayThrow(const MachineInstr &MI) {
285 0 : 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:
292 : return true;
293 : }
294 0 : if (isCallIndirect(MI))
295 : return true;
296 0 : if (!MI.isCall())
297 : return false;
298 :
299 0 : const MachineOperand &MO = MI.getOperand(getCalleeOpNo(MI));
300 : assert(MO.isGlobal());
301 0 : const auto *F = dyn_cast<Function>(MO.getGlobal());
302 : if (!F)
303 : return true;
304 0 : if (F->doesNotThrow())
305 : return false;
306 : // These functions never throw
307 0 : if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
308 0 : F->getName() == ClangCallTerminateFn || F->getName() == StdTerminateFn)
309 0 : return false;
310 : return true;
311 : }
312 :
313 149 : bool WebAssembly::isCatchTerminatePad(const MachineBasicBlock &MBB) {
314 149 : if (!MBB.isEHPad())
315 : return false;
316 : bool SeenCatch = false;
317 601 : for (auto &MI : MBB) {
318 540 : if (MI.getOpcode() == WebAssembly::CATCH_I32 ||
319 501 : MI.getOpcode() == WebAssembly::CATCH_I64 ||
320 1041 : MI.getOpcode() == WebAssembly::CATCH_I32_S ||
321 : MI.getOpcode() == WebAssembly::CATCH_I64_S)
322 : SeenCatch = true;
323 885 : if (SeenCatch && MI.isCall()) {
324 45 : const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI));
325 45 : if (CalleeOp.isGlobal() &&
326 45 : CalleeOp.getGlobal()->getName() == ClangCallTerminateFn)
327 : return true;
328 : }
329 : }
330 : return false;
331 : }
332 :
333 62 : bool WebAssembly::isCatchAllTerminatePad(const MachineBasicBlock &MBB) {
334 62 : if (!MBB.isEHPad())
335 : return false;
336 : bool SeenCatchAll = false;
337 507 : for (auto &MI : MBB) {
338 900 : if (MI.getOpcode() == WebAssembly::CATCH_ALL ||
339 : MI.getOpcode() == WebAssembly::CATCH_ALL_S)
340 : SeenCatchAll = true;
341 546 : if (SeenCatchAll && MI.isCall()) {
342 21 : const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI));
343 21 : if (CalleeOp.isGlobal() &&
344 21 : CalleeOp.getGlobal()->getName() == StdTerminateFn)
345 : return true;
346 : }
347 : }
348 : return false;
349 : }
|