WebAssemblyUtilities.cpp revision 341825
1311116Sdim//===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===//
2311116Sdim//
3311116Sdim//                     The LLVM Compiler Infrastructure
4311116Sdim//
5311116Sdim// This file is distributed under the University of Illinois Open Source
6311116Sdim// License. See LICENSE.TXT for details.
7311116Sdim//
8311116Sdim//===----------------------------------------------------------------------===//
9311116Sdim///
10311116Sdim/// \file
11341825Sdim/// This file implements several utility functions for WebAssembly.
12311116Sdim///
13311116Sdim//===----------------------------------------------------------------------===//
14311116Sdim
15311116Sdim#include "WebAssemblyUtilities.h"
16311116Sdim#include "WebAssemblyMachineFunctionInfo.h"
17311116Sdim#include "llvm/CodeGen/MachineInstr.h"
18321369Sdim#include "llvm/CodeGen/MachineLoopInfo.h"
19311116Sdimusing namespace llvm;
20311116Sdim
21341825Sdimconst char *const WebAssembly::ClangCallTerminateFn = "__clang_call_terminate";
22341825Sdimconst char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch";
23341825Sdimconst char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow";
24341825Sdimconst char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev";
25341825Sdimconst char *const WebAssembly::PersonalityWrapperFn =
26341825Sdim    "_Unwind_Wasm_CallPersonality";
27341825Sdim
28311116Sdimbool WebAssembly::isArgument(const MachineInstr &MI) {
29311116Sdim  switch (MI.getOpcode()) {
30311116Sdim  case WebAssembly::ARGUMENT_I32:
31311116Sdim  case WebAssembly::ARGUMENT_I64:
32311116Sdim  case WebAssembly::ARGUMENT_F32:
33311116Sdim  case WebAssembly::ARGUMENT_F64:
34311116Sdim  case WebAssembly::ARGUMENT_v16i8:
35311116Sdim  case WebAssembly::ARGUMENT_v8i16:
36311116Sdim  case WebAssembly::ARGUMENT_v4i32:
37311116Sdim  case WebAssembly::ARGUMENT_v4f32:
38311116Sdim    return true;
39311116Sdim  default:
40311116Sdim    return false;
41311116Sdim  }
42311116Sdim}
43311116Sdim
44311116Sdimbool WebAssembly::isCopy(const MachineInstr &MI) {
45311116Sdim  switch (MI.getOpcode()) {
46311116Sdim  case WebAssembly::COPY_I32:
47311116Sdim  case WebAssembly::COPY_I64:
48311116Sdim  case WebAssembly::COPY_F32:
49311116Sdim  case WebAssembly::COPY_F64:
50311116Sdim    return true;
51311116Sdim  default:
52311116Sdim    return false;
53311116Sdim  }
54311116Sdim}
55311116Sdim
56311116Sdimbool WebAssembly::isTee(const MachineInstr &MI) {
57311116Sdim  switch (MI.getOpcode()) {
58311116Sdim  case WebAssembly::TEE_I32:
59311116Sdim  case WebAssembly::TEE_I64:
60311116Sdim  case WebAssembly::TEE_F32:
61311116Sdim  case WebAssembly::TEE_F64:
62311116Sdim    return true;
63311116Sdim  default:
64311116Sdim    return false;
65311116Sdim  }
66311116Sdim}
67311116Sdim
68311116Sdim/// Test whether MI is a child of some other node in an expression tree.
69311116Sdimbool WebAssembly::isChild(const MachineInstr &MI,
70311116Sdim                          const WebAssemblyFunctionInfo &MFI) {
71311116Sdim  if (MI.getNumOperands() == 0)
72311116Sdim    return false;
73311116Sdim  const MachineOperand &MO = MI.getOperand(0);
74311116Sdim  if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
75311116Sdim    return false;
76311116Sdim  unsigned Reg = MO.getReg();
77311116Sdim  return TargetRegisterInfo::isVirtualRegister(Reg) &&
78311116Sdim         MFI.isVRegStackified(Reg);
79311116Sdim}
80321369Sdim
81341825Sdimbool WebAssembly::isCallDirect(const MachineInstr &MI) {
82341825Sdim  switch (MI.getOpcode()) {
83341825Sdim  case WebAssembly::CALL_VOID:
84341825Sdim  case WebAssembly::CALL_I32:
85341825Sdim  case WebAssembly::CALL_I64:
86341825Sdim  case WebAssembly::CALL_F32:
87341825Sdim  case WebAssembly::CALL_F64:
88341825Sdim  case WebAssembly::CALL_v16i8:
89341825Sdim  case WebAssembly::CALL_v8i16:
90341825Sdim  case WebAssembly::CALL_v4i32:
91341825Sdim  case WebAssembly::CALL_v4f32:
92341825Sdim  case WebAssembly::CALL_EXCEPT_REF:
93341825Sdim    return true;
94341825Sdim  default:
95341825Sdim    return false;
96341825Sdim  }
97341825Sdim}
98341825Sdim
99321369Sdimbool WebAssembly::isCallIndirect(const MachineInstr &MI) {
100321369Sdim  switch (MI.getOpcode()) {
101321369Sdim  case WebAssembly::CALL_INDIRECT_VOID:
102321369Sdim  case WebAssembly::CALL_INDIRECT_I32:
103321369Sdim  case WebAssembly::CALL_INDIRECT_I64:
104321369Sdim  case WebAssembly::CALL_INDIRECT_F32:
105321369Sdim  case WebAssembly::CALL_INDIRECT_F64:
106321369Sdim  case WebAssembly::CALL_INDIRECT_v16i8:
107321369Sdim  case WebAssembly::CALL_INDIRECT_v8i16:
108321369Sdim  case WebAssembly::CALL_INDIRECT_v4i32:
109321369Sdim  case WebAssembly::CALL_INDIRECT_v4f32:
110341825Sdim  case WebAssembly::CALL_INDIRECT_EXCEPT_REF:
111321369Sdim    return true;
112321369Sdim  default:
113321369Sdim    return false;
114321369Sdim  }
115321369Sdim}
116321369Sdim
117341825Sdimunsigned WebAssembly::getCalleeOpNo(const MachineInstr &MI) {
118341825Sdim  switch (MI.getOpcode()) {
119341825Sdim  case WebAssembly::CALL_VOID:
120341825Sdim  case WebAssembly::CALL_INDIRECT_VOID:
121341825Sdim    return 0;
122341825Sdim  case WebAssembly::CALL_I32:
123341825Sdim  case WebAssembly::CALL_I64:
124341825Sdim  case WebAssembly::CALL_F32:
125341825Sdim  case WebAssembly::CALL_F64:
126341825Sdim  case WebAssembly::CALL_EXCEPT_REF:
127341825Sdim  case WebAssembly::CALL_INDIRECT_I32:
128341825Sdim  case WebAssembly::CALL_INDIRECT_I64:
129341825Sdim  case WebAssembly::CALL_INDIRECT_F32:
130341825Sdim  case WebAssembly::CALL_INDIRECT_F64:
131341825Sdim  case WebAssembly::CALL_INDIRECT_EXCEPT_REF:
132341825Sdim    return 1;
133341825Sdim  default:
134341825Sdim    llvm_unreachable("Not a call instruction");
135341825Sdim  }
136321369Sdim}
137341825Sdim
138341825Sdimbool WebAssembly::isMarker(const MachineInstr &MI) {
139341825Sdim  switch (MI.getOpcode()) {
140341825Sdim  case WebAssembly::BLOCK:
141341825Sdim  case WebAssembly::END_BLOCK:
142341825Sdim  case WebAssembly::LOOP:
143341825Sdim  case WebAssembly::END_LOOP:
144341825Sdim  case WebAssembly::TRY:
145341825Sdim  case WebAssembly::END_TRY:
146341825Sdim    return true;
147341825Sdim  default:
148341825Sdim    return false;
149341825Sdim  }
150341825Sdim}
151341825Sdim
152341825Sdimbool WebAssembly::isThrow(const MachineInstr &MI) {
153341825Sdim  switch (MI.getOpcode()) {
154341825Sdim  case WebAssembly::THROW_I32:
155341825Sdim  case WebAssembly::THROW_I64:
156341825Sdim    return true;
157341825Sdim  default:
158341825Sdim    return false;
159341825Sdim  }
160341825Sdim}
161341825Sdim
162341825Sdimbool WebAssembly::isRethrow(const MachineInstr &MI) {
163341825Sdim  switch (MI.getOpcode()) {
164341825Sdim  case WebAssembly::RETHROW:
165341825Sdim  case WebAssembly::RETHROW_TO_CALLER:
166341825Sdim    return true;
167341825Sdim  default:
168341825Sdim    return false;
169341825Sdim  }
170341825Sdim}
171341825Sdim
172341825Sdimbool WebAssembly::isCatch(const MachineInstr &MI) {
173341825Sdim  switch (MI.getOpcode()) {
174341825Sdim  case WebAssembly::CATCH_I32:
175341825Sdim  case WebAssembly::CATCH_I64:
176341825Sdim  case WebAssembly::CATCH_ALL:
177341825Sdim    return true;
178341825Sdim  default:
179341825Sdim    return false;
180341825Sdim  }
181341825Sdim}
182341825Sdim
183341825Sdimbool WebAssembly::mayThrow(const MachineInstr &MI) {
184341825Sdim  switch (MI.getOpcode()) {
185341825Sdim  case WebAssembly::THROW_I32:
186341825Sdim  case WebAssembly::THROW_I64:
187341825Sdim  case WebAssembly::RETHROW:
188341825Sdim    return true;
189341825Sdim  }
190341825Sdim  if (isCallIndirect(MI))
191341825Sdim    return true;
192341825Sdim  if (!MI.isCall())
193341825Sdim    return false;
194341825Sdim
195341825Sdim  const MachineOperand &MO = MI.getOperand(getCalleeOpNo(MI));
196341825Sdim  assert(MO.isGlobal());
197341825Sdim  const auto *F = dyn_cast<Function>(MO.getGlobal());
198341825Sdim  if (!F)
199341825Sdim    return true;
200341825Sdim  if (F->doesNotThrow())
201341825Sdim    return false;
202341825Sdim  // These functions never throw
203341825Sdim  if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
204341825Sdim      F->getName() == ClangCallTerminateFn || F->getName() == StdTerminateFn)
205341825Sdim    return false;
206341825Sdim  return true;
207341825Sdim}
208341825Sdim
209341825Sdimbool WebAssembly::isCatchTerminatePad(const MachineBasicBlock &MBB) {
210341825Sdim  if (!MBB.isEHPad())
211341825Sdim    return false;
212341825Sdim  bool SeenCatch = false;
213341825Sdim  for (auto &MI : MBB) {
214341825Sdim    if (MI.getOpcode() == WebAssembly::CATCH_I32 ||
215341825Sdim        MI.getOpcode() == WebAssembly::CATCH_I64)
216341825Sdim      SeenCatch = true;
217341825Sdim    if (SeenCatch && MI.isCall()) {
218341825Sdim      const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI));
219341825Sdim      if (CalleeOp.isGlobal() &&
220341825Sdim          CalleeOp.getGlobal()->getName() == ClangCallTerminateFn)
221341825Sdim        return true;
222341825Sdim    }
223341825Sdim  }
224341825Sdim  return false;
225341825Sdim}
226341825Sdim
227341825Sdimbool WebAssembly::isCatchAllTerminatePad(const MachineBasicBlock &MBB) {
228341825Sdim  if (!MBB.isEHPad())
229341825Sdim    return false;
230341825Sdim  bool SeenCatchAll = false;
231341825Sdim  for (auto &MI : MBB) {
232341825Sdim    if (MI.getOpcode() == WebAssembly::CATCH_ALL)
233341825Sdim      SeenCatchAll = true;
234341825Sdim    if (SeenCatchAll && MI.isCall()) {
235341825Sdim      const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI));
236341825Sdim      if (CalleeOp.isGlobal() &&
237341825Sdim          CalleeOp.getGlobal()->getName() == StdTerminateFn)
238341825Sdim        return true;
239341825Sdim    }
240341825Sdim  }
241341825Sdim  return false;
242341825Sdim}
243