• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"
19 using namespace llvm;
20 
21 const char *const WebAssembly::ClangCallTerminateFn = "__clang_call_terminate";
22 const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch";
23 const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow";
24 const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev";
25 const char *const WebAssembly::PersonalityWrapperFn =
26     "_Unwind_Wasm_CallPersonality";
27 
isArgument(const MachineInstr & MI)28 bool 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 
isCopy(const MachineInstr & MI)44 bool 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 
isTee(const MachineInstr & MI)56 bool 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.
isChild(const MachineInstr & MI,const WebAssemblyFunctionInfo & MFI)69 bool 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 }
80 
isCallDirect(const MachineInstr & MI)81 bool 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 
isCallIndirect(const MachineInstr & MI)99 bool 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:
110   case WebAssembly::CALL_INDIRECT_EXCEPT_REF:
111     return true;
112   default:
113     return false;
114   }
115 }
116 
getCalleeOpNo(const MachineInstr & MI)117 unsigned 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 
isMarker(const MachineInstr & MI)138 bool 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 
isThrow(const MachineInstr & MI)152 bool 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 
isRethrow(const MachineInstr & MI)162 bool 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 
isCatch(const MachineInstr & MI)172 bool 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 
mayThrow(const MachineInstr & MI)183 bool 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 
isCatchTerminatePad(const MachineBasicBlock & MBB)209 bool 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 
isCatchAllTerminatePad(const MachineBasicBlock & MBB)227 bool 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;
242 }
243