xref: /llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp (revision 9d37f5afac4a3b9194b9001bed84f58ca8bd6c02)
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 /// Test whether MI is a child of some other node in an expression tree.
28 bool WebAssembly::isChild(const MachineInstr &MI,
29                           const WebAssemblyFunctionInfo &MFI) {
30   if (MI.getNumOperands() == 0)
31     return false;
32   const MachineOperand &MO = MI.getOperand(0);
33   if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
34     return false;
35   Register Reg = MO.getReg();
36   return Register::isVirtualRegister(Reg) && MFI.isVRegStackified(Reg);
37 }
38 
39 bool WebAssembly::mayThrow(const MachineInstr &MI) {
40   switch (MI.getOpcode()) {
41   case WebAssembly::THROW:
42   case WebAssembly::THROW_S:
43   case WebAssembly::RETHROW:
44   case WebAssembly::RETHROW_S:
45     return true;
46   }
47   if (isCallIndirect(MI.getOpcode()))
48     return true;
49   if (!MI.isCall())
50     return false;
51 
52   const MachineOperand &MO = getCalleeOp(MI);
53   assert(MO.isGlobal() || MO.isSymbol());
54 
55   if (MO.isSymbol()) {
56     // Some intrinsics are lowered to calls to external symbols, which are then
57     // lowered to calls to library functions. Most of libcalls don't throw, but
58     // we only list some of them here now.
59     // TODO Consider adding 'nounwind' info in TargetLowering::CallLoweringInfo
60     // instead for more accurate info.
61     const char *Name = MO.getSymbolName();
62     if (strcmp(Name, "memcpy") == 0 || strcmp(Name, "memmove") == 0 ||
63         strcmp(Name, "memset") == 0)
64       return false;
65     return true;
66   }
67 
68   const auto *F = dyn_cast<Function>(MO.getGlobal());
69   if (!F)
70     return true;
71   if (F->doesNotThrow())
72     return false;
73   // These functions never throw
74   if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
75       F->getName() == ClangCallTerminateFn || F->getName() == StdTerminateFn)
76     return false;
77 
78   // TODO Can we exclude call instructions that are marked as 'nounwind' in the
79   // original LLVm IR? (Even when the callee may throw)
80   return true;
81 }
82 
83 const MachineOperand &WebAssembly::getCalleeOp(const MachineInstr &MI) {
84   switch (MI.getOpcode()) {
85   case WebAssembly::CALL_VOID:
86   case WebAssembly::CALL_VOID_S:
87   case WebAssembly::CALL_INDIRECT_VOID:
88   case WebAssembly::CALL_INDIRECT_VOID_S:
89   case WebAssembly::RET_CALL:
90   case WebAssembly::RET_CALL_S:
91   case WebAssembly::RET_CALL_INDIRECT:
92   case WebAssembly::RET_CALL_INDIRECT_S:
93     return MI.getOperand(0);
94   case WebAssembly::CALL_i32:
95   case WebAssembly::CALL_i32_S:
96   case WebAssembly::CALL_i64:
97   case WebAssembly::CALL_i64_S:
98   case WebAssembly::CALL_f32:
99   case WebAssembly::CALL_f32_S:
100   case WebAssembly::CALL_f64:
101   case WebAssembly::CALL_f64_S:
102   case WebAssembly::CALL_v16i8:
103   case WebAssembly::CALL_v16i8_S:
104   case WebAssembly::CALL_v8i16:
105   case WebAssembly::CALL_v8i16_S:
106   case WebAssembly::CALL_v4i32:
107   case WebAssembly::CALL_v4i32_S:
108   case WebAssembly::CALL_v2i64:
109   case WebAssembly::CALL_v2i64_S:
110   case WebAssembly::CALL_v4f32:
111   case WebAssembly::CALL_v4f32_S:
112   case WebAssembly::CALL_v2f64:
113   case WebAssembly::CALL_v2f64_S:
114   case WebAssembly::CALL_exnref:
115   case WebAssembly::CALL_exnref_S:
116   case WebAssembly::CALL_INDIRECT_i32:
117   case WebAssembly::CALL_INDIRECT_i32_S:
118   case WebAssembly::CALL_INDIRECT_i64:
119   case WebAssembly::CALL_INDIRECT_i64_S:
120   case WebAssembly::CALL_INDIRECT_f32:
121   case WebAssembly::CALL_INDIRECT_f32_S:
122   case WebAssembly::CALL_INDIRECT_f64:
123   case WebAssembly::CALL_INDIRECT_f64_S:
124   case WebAssembly::CALL_INDIRECT_v16i8:
125   case WebAssembly::CALL_INDIRECT_v16i8_S:
126   case WebAssembly::CALL_INDIRECT_v8i16:
127   case WebAssembly::CALL_INDIRECT_v8i16_S:
128   case WebAssembly::CALL_INDIRECT_v4i32:
129   case WebAssembly::CALL_INDIRECT_v4i32_S:
130   case WebAssembly::CALL_INDIRECT_v2i64:
131   case WebAssembly::CALL_INDIRECT_v2i64_S:
132   case WebAssembly::CALL_INDIRECT_v4f32:
133   case WebAssembly::CALL_INDIRECT_v4f32_S:
134   case WebAssembly::CALL_INDIRECT_v2f64:
135   case WebAssembly::CALL_INDIRECT_v2f64_S:
136   case WebAssembly::CALL_INDIRECT_exnref:
137   case WebAssembly::CALL_INDIRECT_exnref_S:
138     return MI.getOperand(1);
139   case WebAssembly::CALL:
140   case WebAssembly::CALL_S:
141     return MI.getOperand(MI.getNumExplicitDefs());
142   case WebAssembly::CALL_INDIRECT:
143   case WebAssembly::CALL_INDIRECT_S:
144     return MI.getOperand(MI.getNumOperands() - 1);
145   default:
146     llvm_unreachable("Not a call instruction");
147   }
148 }
149