xref: /llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp (revision a1d97a960e622ee21550d92809512cb0870be499)
1 //===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file implements several utility functions for WebAssembly.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #include "WebAssemblyUtilities.h"
15 #include "WebAssemblyMachineFunctionInfo.h"
16 #include "llvm/CodeGen/MachineInstr.h"
17 #include "llvm/CodeGen/MachineLoopInfo.h"
18 using namespace llvm;
19 
20 const char *const WebAssembly::ClangCallTerminateFn = "__clang_call_terminate";
21 const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch";
22 const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow";
23 const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev";
24 const char *const WebAssembly::PersonalityWrapperFn =
25     "_Unwind_Wasm_CallPersonality";
26 
27 bool WebAssembly::isArgument(const MachineInstr &MI) {
28   switch (MI.getOpcode()) {
29   case WebAssembly::ARGUMENT_i32:
30   case WebAssembly::ARGUMENT_i32_S:
31   case WebAssembly::ARGUMENT_i64:
32   case WebAssembly::ARGUMENT_i64_S:
33   case WebAssembly::ARGUMENT_f32:
34   case WebAssembly::ARGUMENT_f32_S:
35   case WebAssembly::ARGUMENT_f64:
36   case WebAssembly::ARGUMENT_f64_S:
37   case WebAssembly::ARGUMENT_v16i8:
38   case WebAssembly::ARGUMENT_v16i8_S:
39   case WebAssembly::ARGUMENT_v8i16:
40   case WebAssembly::ARGUMENT_v8i16_S:
41   case WebAssembly::ARGUMENT_v4i32:
42   case WebAssembly::ARGUMENT_v4i32_S:
43   case WebAssembly::ARGUMENT_v2i64:
44   case WebAssembly::ARGUMENT_v2i64_S:
45   case WebAssembly::ARGUMENT_v4f32:
46   case WebAssembly::ARGUMENT_v4f32_S:
47   case WebAssembly::ARGUMENT_v2f64:
48   case WebAssembly::ARGUMENT_v2f64_S:
49     return true;
50   default:
51     return false;
52   }
53 }
54 
55 bool WebAssembly::isCopy(const MachineInstr &MI) {
56   switch (MI.getOpcode()) {
57   case WebAssembly::COPY_I32:
58   case WebAssembly::COPY_I32_S:
59   case WebAssembly::COPY_I64:
60   case WebAssembly::COPY_I64_S:
61   case WebAssembly::COPY_F32:
62   case WebAssembly::COPY_F32_S:
63   case WebAssembly::COPY_F64:
64   case WebAssembly::COPY_F64_S:
65   case WebAssembly::COPY_V128:
66   case WebAssembly::COPY_V128_S:
67   case WebAssembly::COPY_EXCEPT_REF:
68   case WebAssembly::COPY_EXCEPT_REF_S:
69     return true;
70   default:
71     return false;
72   }
73 }
74 
75 bool WebAssembly::isTee(const MachineInstr &MI) {
76   switch (MI.getOpcode()) {
77   case WebAssembly::TEE_I32:
78   case WebAssembly::TEE_I32_S:
79   case WebAssembly::TEE_I64:
80   case WebAssembly::TEE_I64_S:
81   case WebAssembly::TEE_F32:
82   case WebAssembly::TEE_F32_S:
83   case WebAssembly::TEE_F64:
84   case WebAssembly::TEE_F64_S:
85   case WebAssembly::TEE_V128:
86   case WebAssembly::TEE_V128_S:
87     return true;
88   default:
89     return false;
90   }
91 }
92 
93 /// Test whether MI is a child of some other node in an expression tree.
94 bool WebAssembly::isChild(const MachineInstr &MI,
95                           const WebAssemblyFunctionInfo &MFI) {
96   if (MI.getNumOperands() == 0)
97     return false;
98   const MachineOperand &MO = MI.getOperand(0);
99   if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
100     return false;
101   unsigned Reg = MO.getReg();
102   return TargetRegisterInfo::isVirtualRegister(Reg) &&
103          MFI.isVRegStackified(Reg);
104 }
105 
106 bool WebAssembly::isCallDirect(const MachineInstr &MI) {
107   switch (MI.getOpcode()) {
108   case WebAssembly::CALL_VOID:
109   case WebAssembly::CALL_VOID_S:
110   case WebAssembly::CALL_i32:
111   case WebAssembly::CALL_i32_S:
112   case WebAssembly::CALL_i64:
113   case WebAssembly::CALL_i64_S:
114   case WebAssembly::CALL_f32:
115   case WebAssembly::CALL_f32_S:
116   case WebAssembly::CALL_f64:
117   case WebAssembly::CALL_f64_S:
118   case WebAssembly::CALL_v16i8:
119   case WebAssembly::CALL_v16i8_S:
120   case WebAssembly::CALL_v8i16:
121   case WebAssembly::CALL_v8i16_S:
122   case WebAssembly::CALL_v4i32:
123   case WebAssembly::CALL_v4i32_S:
124   case WebAssembly::CALL_v2i64:
125   case WebAssembly::CALL_v2i64_S:
126   case WebAssembly::CALL_v4f32:
127   case WebAssembly::CALL_v4f32_S:
128   case WebAssembly::CALL_v2f64:
129   case WebAssembly::CALL_v2f64_S:
130   case WebAssembly::CALL_ExceptRef:
131   case WebAssembly::CALL_ExceptRef_S:
132   case WebAssembly::RET_CALL:
133   case WebAssembly::RET_CALL_S:
134     return true;
135   default:
136     return false;
137   }
138 }
139 
140 bool WebAssembly::isCallIndirect(const MachineInstr &MI) {
141   switch (MI.getOpcode()) {
142   case WebAssembly::CALL_INDIRECT_VOID:
143   case WebAssembly::CALL_INDIRECT_VOID_S:
144   case WebAssembly::CALL_INDIRECT_i32:
145   case WebAssembly::CALL_INDIRECT_i32_S:
146   case WebAssembly::CALL_INDIRECT_i64:
147   case WebAssembly::CALL_INDIRECT_i64_S:
148   case WebAssembly::CALL_INDIRECT_f32:
149   case WebAssembly::CALL_INDIRECT_f32_S:
150   case WebAssembly::CALL_INDIRECT_f64:
151   case WebAssembly::CALL_INDIRECT_f64_S:
152   case WebAssembly::CALL_INDIRECT_v16i8:
153   case WebAssembly::CALL_INDIRECT_v16i8_S:
154   case WebAssembly::CALL_INDIRECT_v8i16:
155   case WebAssembly::CALL_INDIRECT_v8i16_S:
156   case WebAssembly::CALL_INDIRECT_v4i32:
157   case WebAssembly::CALL_INDIRECT_v4i32_S:
158   case WebAssembly::CALL_INDIRECT_v2i64:
159   case WebAssembly::CALL_INDIRECT_v2i64_S:
160   case WebAssembly::CALL_INDIRECT_v4f32:
161   case WebAssembly::CALL_INDIRECT_v4f32_S:
162   case WebAssembly::CALL_INDIRECT_v2f64:
163   case WebAssembly::CALL_INDIRECT_v2f64_S:
164   case WebAssembly::CALL_INDIRECT_ExceptRef:
165   case WebAssembly::CALL_INDIRECT_ExceptRef_S:
166   case WebAssembly::RET_CALL_INDIRECT:
167   case WebAssembly::RET_CALL_INDIRECT_S:
168     return true;
169   default:
170     return false;
171   }
172 }
173 
174 unsigned WebAssembly::getCalleeOpNo(const MachineInstr &MI) {
175   switch (MI.getOpcode()) {
176   case WebAssembly::CALL_VOID:
177   case WebAssembly::CALL_VOID_S:
178   case WebAssembly::CALL_INDIRECT_VOID:
179   case WebAssembly::CALL_INDIRECT_VOID_S:
180   case WebAssembly::RET_CALL:
181   case WebAssembly::RET_CALL_S:
182   case WebAssembly::RET_CALL_INDIRECT:
183   case WebAssembly::RET_CALL_INDIRECT_S:
184     return 0;
185   case WebAssembly::CALL_i32:
186   case WebAssembly::CALL_i32_S:
187   case WebAssembly::CALL_i64:
188   case WebAssembly::CALL_i64_S:
189   case WebAssembly::CALL_f32:
190   case WebAssembly::CALL_f32_S:
191   case WebAssembly::CALL_f64:
192   case WebAssembly::CALL_f64_S:
193   case WebAssembly::CALL_v16i8:
194   case WebAssembly::CALL_v16i8_S:
195   case WebAssembly::CALL_v8i16:
196   case WebAssembly::CALL_v8i16_S:
197   case WebAssembly::CALL_v4i32:
198   case WebAssembly::CALL_v4i32_S:
199   case WebAssembly::CALL_v2i64:
200   case WebAssembly::CALL_v2i64_S:
201   case WebAssembly::CALL_v4f32:
202   case WebAssembly::CALL_v4f32_S:
203   case WebAssembly::CALL_v2f64:
204   case WebAssembly::CALL_v2f64_S:
205   case WebAssembly::CALL_ExceptRef:
206   case WebAssembly::CALL_ExceptRef_S:
207   case WebAssembly::CALL_INDIRECT_i32:
208   case WebAssembly::CALL_INDIRECT_i32_S:
209   case WebAssembly::CALL_INDIRECT_i64:
210   case WebAssembly::CALL_INDIRECT_i64_S:
211   case WebAssembly::CALL_INDIRECT_f32:
212   case WebAssembly::CALL_INDIRECT_f32_S:
213   case WebAssembly::CALL_INDIRECT_f64:
214   case WebAssembly::CALL_INDIRECT_f64_S:
215   case WebAssembly::CALL_INDIRECT_v16i8:
216   case WebAssembly::CALL_INDIRECT_v16i8_S:
217   case WebAssembly::CALL_INDIRECT_v8i16:
218   case WebAssembly::CALL_INDIRECT_v8i16_S:
219   case WebAssembly::CALL_INDIRECT_v4i32:
220   case WebAssembly::CALL_INDIRECT_v4i32_S:
221   case WebAssembly::CALL_INDIRECT_v2i64:
222   case WebAssembly::CALL_INDIRECT_v2i64_S:
223   case WebAssembly::CALL_INDIRECT_v4f32:
224   case WebAssembly::CALL_INDIRECT_v4f32_S:
225   case WebAssembly::CALL_INDIRECT_v2f64:
226   case WebAssembly::CALL_INDIRECT_v2f64_S:
227   case WebAssembly::CALL_INDIRECT_ExceptRef:
228   case WebAssembly::CALL_INDIRECT_ExceptRef_S:
229     return 1;
230   default:
231     llvm_unreachable("Not a call instruction");
232   }
233 }
234 
235 bool WebAssembly::isMarker(const MachineInstr &MI) {
236   switch (MI.getOpcode()) {
237   case WebAssembly::BLOCK:
238   case WebAssembly::BLOCK_S:
239   case WebAssembly::END_BLOCK:
240   case WebAssembly::END_BLOCK_S:
241   case WebAssembly::LOOP:
242   case WebAssembly::LOOP_S:
243   case WebAssembly::END_LOOP:
244   case WebAssembly::END_LOOP_S:
245   case WebAssembly::TRY:
246   case WebAssembly::TRY_S:
247   case WebAssembly::END_TRY:
248   case WebAssembly::END_TRY_S:
249     return true;
250   default:
251     return false;
252   }
253 }
254 
255 bool WebAssembly::mayThrow(const MachineInstr &MI) {
256   switch (MI.getOpcode()) {
257   case WebAssembly::THROW:
258   case WebAssembly::THROW_S:
259   case WebAssembly::RETHROW:
260   case WebAssembly::RETHROW_S:
261     return true;
262   }
263   if (isCallIndirect(MI))
264     return true;
265   if (!MI.isCall())
266     return false;
267 
268   const MachineOperand &MO = MI.getOperand(getCalleeOpNo(MI));
269   assert(MO.isGlobal());
270   const auto *F = dyn_cast<Function>(MO.getGlobal());
271   if (!F)
272     return true;
273   if (F->doesNotThrow())
274     return false;
275   // These functions never throw
276   if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
277       F->getName() == ClangCallTerminateFn || F->getName() == StdTerminateFn)
278     return false;
279 
280   // TODO Can we exclude call instructions that are marked as 'nounwind' in the
281   // original LLVm IR? (Even when the callee may throw)
282   return true;
283 }
284