blob: 5944cea5abd156a52fd79e972db7551e84b8bcb3 [file] [log] [blame]
Dan Gohman4fc4e422016-10-24 19:49:43 +00001//===-- 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
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000011/// This file implements several utility functions for WebAssembly.
Dan Gohman4fc4e422016-10-24 19:49:43 +000012///
13//===----------------------------------------------------------------------===//
14
15#include "WebAssemblyUtilities.h"
16#include "WebAssemblyMachineFunctionInfo.h"
17#include "llvm/CodeGen/MachineInstr.h"
Dan Gohmanf52ee172017-02-27 22:38:58 +000018#include "llvm/CodeGen/MachineLoopInfo.h"
Dan Gohman4fc4e422016-10-24 19:49:43 +000019using namespace llvm;
20
Heejin Ahn817811ca2018-06-19 00:32:03 +000021const 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
Dan Gohman4fc4e422016-10-24 19:49:43 +000028bool WebAssembly::isArgument(const MachineInstr &MI) {
29 switch (MI.getOpcode()) {
30 case WebAssembly::ARGUMENT_I32:
31 case WebAssembly::ARGUMENT_I64:
32 case WebAssembly::ARGUMENT_F32:
33 case WebAssembly::ARGUMENT_F64:
34 case WebAssembly::ARGUMENT_v16i8:
35 case WebAssembly::ARGUMENT_v8i16:
36 case WebAssembly::ARGUMENT_v4i32:
37 case WebAssembly::ARGUMENT_v4f32:
38 return true;
39 default:
40 return false;
41 }
42}
43
44bool WebAssembly::isCopy(const MachineInstr &MI) {
45 switch (MI.getOpcode()) {
46 case WebAssembly::COPY_I32:
47 case WebAssembly::COPY_I64:
48 case WebAssembly::COPY_F32:
49 case WebAssembly::COPY_F64:
50 return true;
51 default:
52 return false;
53 }
54}
55
56bool WebAssembly::isTee(const MachineInstr &MI) {
57 switch (MI.getOpcode()) {
58 case WebAssembly::TEE_I32:
59 case WebAssembly::TEE_I64:
60 case WebAssembly::TEE_F32:
61 case WebAssembly::TEE_F64:
62 return true;
63 default:
64 return false;
65 }
66}
67
68/// Test whether MI is a child of some other node in an expression tree.
69bool WebAssembly::isChild(const MachineInstr &MI,
70 const WebAssemblyFunctionInfo &MFI) {
71 if (MI.getNumOperands() == 0)
72 return false;
73 const MachineOperand &MO = MI.getOperand(0);
74 if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
75 return false;
76 unsigned Reg = MO.getReg();
77 return TargetRegisterInfo::isVirtualRegister(Reg) &&
78 MFI.isVRegStackified(Reg);
79}
Dan Gohmand934cb82017-02-24 23:18:00 +000080
Heejin Ahn817811ca2018-06-19 00:32:03 +000081bool WebAssembly::isCallDirect(const MachineInstr &MI) {
82 switch (MI.getOpcode()) {
83 case WebAssembly::CALL_VOID:
84 case WebAssembly::CALL_I32:
85 case WebAssembly::CALL_I64:
86 case WebAssembly::CALL_F32:
87 case WebAssembly::CALL_F64:
88 case WebAssembly::CALL_v16i8:
89 case WebAssembly::CALL_v8i16:
90 case WebAssembly::CALL_v4i32:
91 case WebAssembly::CALL_v4f32:
92 case WebAssembly::CALL_EXCEPT_REF:
93 return true;
94 default:
95 return false;
96 }
97}
98
Dan Gohmand934cb82017-02-24 23:18:00 +000099bool WebAssembly::isCallIndirect(const MachineInstr &MI) {
100 switch (MI.getOpcode()) {
101 case WebAssembly::CALL_INDIRECT_VOID:
102 case WebAssembly::CALL_INDIRECT_I32:
103 case WebAssembly::CALL_INDIRECT_I64:
104 case WebAssembly::CALL_INDIRECT_F32:
105 case WebAssembly::CALL_INDIRECT_F64:
106 case WebAssembly::CALL_INDIRECT_v16i8:
107 case WebAssembly::CALL_INDIRECT_v8i16:
108 case WebAssembly::CALL_INDIRECT_v4i32:
109 case WebAssembly::CALL_INDIRECT_v4f32:
Heejin Ahn817811ca2018-06-19 00:32:03 +0000110 case WebAssembly::CALL_INDIRECT_EXCEPT_REF:
Dan Gohmand934cb82017-02-24 23:18:00 +0000111 return true;
112 default:
113 return false;
114 }
115}
Dan Gohmanf52ee172017-02-27 22:38:58 +0000116
Heejin Ahn817811ca2018-06-19 00:32:03 +0000117unsigned WebAssembly::getCalleeOpNo(const MachineInstr &MI) {
118 switch (MI.getOpcode()) {
119 case WebAssembly::CALL_VOID:
120 case WebAssembly::CALL_INDIRECT_VOID:
121 return 0;
122 case WebAssembly::CALL_I32:
123 case WebAssembly::CALL_I64:
124 case WebAssembly::CALL_F32:
125 case WebAssembly::CALL_F64:
126 case WebAssembly::CALL_EXCEPT_REF:
127 case WebAssembly::CALL_INDIRECT_I32:
128 case WebAssembly::CALL_INDIRECT_I64:
129 case WebAssembly::CALL_INDIRECT_F32:
130 case WebAssembly::CALL_INDIRECT_F64:
131 case WebAssembly::CALL_INDIRECT_EXCEPT_REF:
132 return 1;
133 default:
134 llvm_unreachable("Not a call instruction");
135 }
136}
137
138bool WebAssembly::isMarker(const MachineInstr &MI) {
139 switch (MI.getOpcode()) {
140 case WebAssembly::BLOCK:
141 case WebAssembly::END_BLOCK:
142 case WebAssembly::LOOP:
143 case WebAssembly::END_LOOP:
144 case WebAssembly::TRY:
145 case WebAssembly::END_TRY:
146 return true;
147 default:
148 return false;
149 }
150}
151
152bool WebAssembly::isThrow(const MachineInstr &MI) {
153 switch (MI.getOpcode()) {
154 case WebAssembly::THROW_I32:
155 case WebAssembly::THROW_I64:
156 return true;
157 default:
158 return false;
159 }
160}
161
162bool WebAssembly::isRethrow(const MachineInstr &MI) {
163 switch (MI.getOpcode()) {
164 case WebAssembly::RETHROW:
165 case WebAssembly::RETHROW_TO_CALLER:
166 return true;
167 default:
168 return false;
169 }
170}
171
172bool WebAssembly::isCatch(const MachineInstr &MI) {
173 switch (MI.getOpcode()) {
174 case WebAssembly::CATCH_I32:
175 case WebAssembly::CATCH_I64:
176 case WebAssembly::CATCH_ALL:
177 return true;
178 default:
179 return false;
180 }
181}
182
183bool WebAssembly::mayThrow(const MachineInstr &MI) {
184 switch (MI.getOpcode()) {
185 case WebAssembly::THROW_I32:
186 case WebAssembly::THROW_I64:
187 case WebAssembly::RETHROW:
188 return true;
189 }
190 if (isCallIndirect(MI))
191 return true;
192 if (!MI.isCall())
193 return false;
194
195 const MachineOperand &MO = MI.getOperand(getCalleeOpNo(MI));
196 assert(MO.isGlobal());
197 const auto *F = dyn_cast<Function>(MO.getGlobal());
198 if (!F)
199 return true;
200 if (F->doesNotThrow())
201 return false;
202 // These functions never throw
203 if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
204 F->getName() == ClangCallTerminateFn || F->getName() == StdTerminateFn)
205 return false;
206 return true;
207}
208
209bool WebAssembly::isCatchTerminatePad(const MachineBasicBlock &MBB) {
210 if (!MBB.isEHPad())
211 return false;
212 bool SeenCatch = false;
213 for (auto &MI : MBB) {
214 if (MI.getOpcode() == WebAssembly::CATCH_I32 ||
215 MI.getOpcode() == WebAssembly::CATCH_I64)
216 SeenCatch = true;
217 if (SeenCatch && MI.isCall()) {
218 const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI));
219 if (CalleeOp.isGlobal() &&
220 CalleeOp.getGlobal()->getName() == ClangCallTerminateFn)
221 return true;
222 }
223 }
224 return false;
225}
226
227bool WebAssembly::isCatchAllTerminatePad(const MachineBasicBlock &MBB) {
228 if (!MBB.isEHPad())
229 return false;
230 bool SeenCatchAll = false;
231 for (auto &MI : MBB) {
232 if (MI.getOpcode() == WebAssembly::CATCH_ALL)
233 SeenCatchAll = true;
234 if (SeenCatchAll && MI.isCall()) {
235 const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI));
236 if (CalleeOp.isGlobal() &&
237 CalleeOp.getGlobal()->getName() == StdTerminateFn)
238 return true;
239 }
240 }
241 return false;
Dan Gohmanf52ee172017-02-27 22:38:58 +0000242}