WebAssemblyUtilities.cpp revision 344779
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"
19using namespace llvm;
20
21const char *const WebAssembly::ClangCallTerminateFn = "__clang_call_terminate";
22const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch";
23const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow";
24const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev";
25const char *const WebAssembly::PersonalityWrapperFn =
26    "_Unwind_Wasm_CallPersonality";
27
28bool 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:
50    return true;
51  default:
52    return false;
53  }
54}
55
56bool 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:
68    return true;
69  default:
70    return false;
71  }
72}
73
74bool 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:
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.
93bool WebAssembly::isChild(const MachineInstr &MI,
94                          const WebAssemblyFunctionInfo &MFI) {
95  if (MI.getNumOperands() == 0)
96    return false;
97  const MachineOperand &MO = MI.getOperand(0);
98  if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
99    return false;
100  unsigned Reg = MO.getReg();
101  return TargetRegisterInfo::isVirtualRegister(Reg) &&
102         MFI.isVRegStackified(Reg);
103}
104
105bool 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:
131    return true;
132  default:
133    return false;
134  }
135}
136
137bool 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:
163    return true;
164  default:
165    return false;
166  }
167}
168
169unsigned 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:
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  default:
222    llvm_unreachable("Not a call instruction");
223  }
224}
225
226bool 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:
240    return true;
241  default:
242    return false;
243  }
244}
245
246bool 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:
252    return true;
253  default:
254    return false;
255  }
256}
257
258bool 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:
264    return true;
265  default:
266    return false;
267  }
268}
269
270bool 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:
278    return true;
279  default:
280    return false;
281  }
282}
283
284bool 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:
292    return true;
293  }
294  if (isCallIndirect(MI))
295    return true;
296  if (!MI.isCall())
297    return false;
298
299  const MachineOperand &MO = MI.getOperand(getCalleeOpNo(MI));
300  assert(MO.isGlobal());
301  const auto *F = dyn_cast<Function>(MO.getGlobal());
302  if (!F)
303    return true;
304  if (F->doesNotThrow())
305    return false;
306  // These functions never throw
307  if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
308      F->getName() == ClangCallTerminateFn || F->getName() == StdTerminateFn)
309    return false;
310  return true;
311}
312
313bool WebAssembly::isCatchTerminatePad(const MachineBasicBlock &MBB) {
314  if (!MBB.isEHPad())
315    return false;
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)
322      SeenCatch = true;
323    if (SeenCatch && MI.isCall()) {
324      const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI));
325      if (CalleeOp.isGlobal() &&
326          CalleeOp.getGlobal()->getName() == ClangCallTerminateFn)
327        return true;
328    }
329  }
330  return false;
331}
332
333bool WebAssembly::isCatchAllTerminatePad(const MachineBasicBlock &MBB) {
334  if (!MBB.isEHPad())
335    return false;
336  bool SeenCatchAll = false;
337  for (auto &MI : MBB) {
338    if (MI.getOpcode() == WebAssembly::CATCH_ALL ||
339        MI.getOpcode() == WebAssembly::CATCH_ALL_S)
340      SeenCatchAll = true;
341    if (SeenCatchAll && MI.isCall()) {
342      const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI));
343      if (CalleeOp.isGlobal() &&
344          CalleeOp.getGlobal()->getName() == StdTerminateFn)
345        return true;
346    }
347  }
348  return false;
349}
350