xref: /llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp (revision c4ac74fb4987c083fa8e7e10f0f978ecee9402c0)
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_EXCEPT_REF:
131   case WebAssembly::CALL_EXCEPT_REF_S:
132     return true;
133   default:
134     return false;
135   }
136 }
137 
138 bool WebAssembly::isCallIndirect(const MachineInstr &MI) {
139   switch (MI.getOpcode()) {
140   case WebAssembly::CALL_INDIRECT_VOID:
141   case WebAssembly::CALL_INDIRECT_VOID_S:
142   case WebAssembly::CALL_INDIRECT_I32:
143   case WebAssembly::CALL_INDIRECT_I32_S:
144   case WebAssembly::CALL_INDIRECT_I64:
145   case WebAssembly::CALL_INDIRECT_I64_S:
146   case WebAssembly::CALL_INDIRECT_F32:
147   case WebAssembly::CALL_INDIRECT_F32_S:
148   case WebAssembly::CALL_INDIRECT_F64:
149   case WebAssembly::CALL_INDIRECT_F64_S:
150   case WebAssembly::CALL_INDIRECT_v16i8:
151   case WebAssembly::CALL_INDIRECT_v16i8_S:
152   case WebAssembly::CALL_INDIRECT_v8i16:
153   case WebAssembly::CALL_INDIRECT_v8i16_S:
154   case WebAssembly::CALL_INDIRECT_v4i32:
155   case WebAssembly::CALL_INDIRECT_v4i32_S:
156   case WebAssembly::CALL_INDIRECT_v2i64:
157   case WebAssembly::CALL_INDIRECT_v2i64_S:
158   case WebAssembly::CALL_INDIRECT_v4f32:
159   case WebAssembly::CALL_INDIRECT_v4f32_S:
160   case WebAssembly::CALL_INDIRECT_v2f64:
161   case WebAssembly::CALL_INDIRECT_v2f64_S:
162   case WebAssembly::CALL_INDIRECT_EXCEPT_REF:
163   case WebAssembly::CALL_INDIRECT_EXCEPT_REF_S:
164     return true;
165   default:
166     return false;
167   }
168 }
169 
170 unsigned WebAssembly::getCalleeOpNo(const MachineInstr &MI) {
171   switch (MI.getOpcode()) {
172   case WebAssembly::CALL_VOID:
173   case WebAssembly::CALL_VOID_S:
174   case WebAssembly::CALL_INDIRECT_VOID:
175   case WebAssembly::CALL_INDIRECT_VOID_S:
176     return 0;
177   case WebAssembly::CALL_I32:
178   case WebAssembly::CALL_I32_S:
179   case WebAssembly::CALL_I64:
180   case WebAssembly::CALL_I64_S:
181   case WebAssembly::CALL_F32:
182   case WebAssembly::CALL_F32_S:
183   case WebAssembly::CALL_F64:
184   case WebAssembly::CALL_F64_S:
185   case WebAssembly::CALL_v16i8:
186   case WebAssembly::CALL_v16i8_S:
187   case WebAssembly::CALL_v8i16:
188   case WebAssembly::CALL_v8i16_S:
189   case WebAssembly::CALL_v4i32:
190   case WebAssembly::CALL_v4i32_S:
191   case WebAssembly::CALL_v2i64:
192   case WebAssembly::CALL_v2i64_S:
193   case WebAssembly::CALL_v4f32:
194   case WebAssembly::CALL_v4f32_S:
195   case WebAssembly::CALL_v2f64:
196   case WebAssembly::CALL_v2f64_S:
197   case WebAssembly::CALL_EXCEPT_REF:
198   case WebAssembly::CALL_EXCEPT_REF_S:
199   case WebAssembly::CALL_INDIRECT_I32:
200   case WebAssembly::CALL_INDIRECT_I32_S:
201   case WebAssembly::CALL_INDIRECT_I64:
202   case WebAssembly::CALL_INDIRECT_I64_S:
203   case WebAssembly::CALL_INDIRECT_F32:
204   case WebAssembly::CALL_INDIRECT_F32_S:
205   case WebAssembly::CALL_INDIRECT_F64:
206   case WebAssembly::CALL_INDIRECT_F64_S:
207   case WebAssembly::CALL_INDIRECT_v16i8:
208   case WebAssembly::CALL_INDIRECT_v16i8_S:
209   case WebAssembly::CALL_INDIRECT_v8i16:
210   case WebAssembly::CALL_INDIRECT_v8i16_S:
211   case WebAssembly::CALL_INDIRECT_v4i32:
212   case WebAssembly::CALL_INDIRECT_v4i32_S:
213   case WebAssembly::CALL_INDIRECT_v2i64:
214   case WebAssembly::CALL_INDIRECT_v2i64_S:
215   case WebAssembly::CALL_INDIRECT_v4f32:
216   case WebAssembly::CALL_INDIRECT_v4f32_S:
217   case WebAssembly::CALL_INDIRECT_v2f64:
218   case WebAssembly::CALL_INDIRECT_v2f64_S:
219   case WebAssembly::CALL_INDIRECT_EXCEPT_REF:
220   case WebAssembly::CALL_INDIRECT_EXCEPT_REF_S:
221     return 1;
222   default:
223     llvm_unreachable("Not a call instruction");
224   }
225 }
226 
227 bool WebAssembly::isMarker(const MachineInstr &MI) {
228   switch (MI.getOpcode()) {
229   case WebAssembly::BLOCK:
230   case WebAssembly::BLOCK_S:
231   case WebAssembly::END_BLOCK:
232   case WebAssembly::END_BLOCK_S:
233   case WebAssembly::LOOP:
234   case WebAssembly::LOOP_S:
235   case WebAssembly::END_LOOP:
236   case WebAssembly::END_LOOP_S:
237   case WebAssembly::TRY:
238   case WebAssembly::TRY_S:
239   case WebAssembly::END_TRY:
240   case WebAssembly::END_TRY_S:
241     return true;
242   default:
243     return false;
244   }
245 }
246 
247 bool WebAssembly::mayThrow(const MachineInstr &MI) {
248   switch (MI.getOpcode()) {
249   case WebAssembly::THROW:
250   case WebAssembly::THROW_S:
251   case WebAssembly::RETHROW:
252   case WebAssembly::RETHROW_S:
253     return true;
254   }
255   if (isCallIndirect(MI))
256     return true;
257   if (!MI.isCall())
258     return false;
259 
260   const MachineOperand &MO = MI.getOperand(getCalleeOpNo(MI));
261   assert(MO.isGlobal());
262   const auto *F = dyn_cast<Function>(MO.getGlobal());
263   if (!F)
264     return true;
265   if (F->doesNotThrow())
266     return false;
267   // These functions never throw
268   if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
269       F->getName() == ClangCallTerminateFn || F->getName() == StdTerminateFn)
270     return false;
271 
272   // TODO Can we exclude call instructions that are marked as 'nounwind' in the
273   // original LLVm IR? (Even when the callee may throw)
274   return true;
275 }
276