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 "WebAssemblySubtarget.h"
17 #include "llvm/CodeGen/Analysis.h"
18 #include "llvm/CodeGen/MachineFrameInfo.h"
19 #include "llvm/CodeGen/MachineInstr.h"
20 #include "llvm/CodeGen/MachineLoopInfo.h"
21 #include "llvm/IR/Instructions.h"
22 #include "llvm/MC/MCContext.h"
23 using namespace llvm;
24 
25 const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch";
26 const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow";
27 const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev";
28 const char *const WebAssembly::PersonalityWrapperFn =
29     "_Unwind_Wasm_CallPersonality";
30 
31 // In an ideal world, when objects are added to the MachineFrameInfo by
32 // FunctionLoweringInfo::set, we could somehow hook into target-specific code to
33 // ensure they are assigned the right stack ID.  However there isn't a hook that
34 // runs between then and DAG building time, though, so instead we hoist stack
35 // objects lazily when they are first used, and comprehensively after the DAG is
36 // built via the PreprocessISelDAG hook, called by the
37 // SelectionDAGISel::runOnMachineFunction.  We have to do it in two places
38 // because we want to do it while building the selection DAG for uses of alloca,
39 // but not all alloca instructions are used so we have to follow up afterwards.
40 Optional<unsigned> WebAssembly::getLocalForStackObject(MachineFunction &MF,
41                                                        int FrameIndex) {
42   auto &MFI = MF.getFrameInfo();
43 
44   // If already hoisted to a local, done.
45   if (MFI.getStackID(FrameIndex) == TargetStackID::WasmLocal)
46     return static_cast<unsigned>(MFI.getObjectOffset(FrameIndex));
47 
48   // If not allocated in the object address space, this object will be in
49   // linear memory.
50   const AllocaInst *AI = MFI.getObjectAllocation(FrameIndex);
51   if (!AI || !isWasmVarAddressSpace(AI->getType()->getAddressSpace()))
52     return None;
53 
54   // Otherwise, allocate this object in the named value stack, outside of linear
55   // memory.
56   SmallVector<EVT, 4> ValueVTs;
57   const WebAssemblyTargetLowering &TLI =
58       *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering();
59   WebAssemblyFunctionInfo *FuncInfo = MF.getInfo<WebAssemblyFunctionInfo>();
60   ComputeValueVTs(TLI, MF.getDataLayout(), AI->getAllocatedType(), ValueVTs);
61   MFI.setStackID(FrameIndex, TargetStackID::WasmLocal);
62   // Abuse SP offset to record the index of the first local in the object.
63   unsigned Local = FuncInfo->getParams().size() + FuncInfo->getLocals().size();
64   MFI.setObjectOffset(FrameIndex, Local);
65   // Allocate WebAssembly locals for each non-aggregate component of the
66   // allocation.
67   for (EVT ValueVT : ValueVTs)
68     FuncInfo->addLocal(ValueVT.getSimpleVT());
69   // Abuse object size to record number of WebAssembly locals allocated to
70   // this object.
71   MFI.setObjectSize(FrameIndex, ValueVTs.size());
72   return static_cast<unsigned>(Local);
73 }
74 
75 /// Test whether MI is a child of some other node in an expression tree.
76 bool WebAssembly::isChild(const MachineInstr &MI,
77                           const WebAssemblyFunctionInfo &MFI) {
78   if (MI.getNumOperands() == 0)
79     return false;
80   const MachineOperand &MO = MI.getOperand(0);
81   if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
82     return false;
83   Register Reg = MO.getReg();
84   return Register::isVirtualRegister(Reg) && MFI.isVRegStackified(Reg);
85 }
86 
87 bool WebAssembly::mayThrow(const MachineInstr &MI) {
88   switch (MI.getOpcode()) {
89   case WebAssembly::THROW:
90   case WebAssembly::THROW_S:
91   case WebAssembly::RETHROW:
92   case WebAssembly::RETHROW_S:
93     return true;
94   }
95   if (isCallIndirect(MI.getOpcode()))
96     return true;
97   if (!MI.isCall())
98     return false;
99 
100   const MachineOperand &MO = getCalleeOp(MI);
101   assert(MO.isGlobal() || MO.isSymbol());
102 
103   if (MO.isSymbol()) {
104     // Some intrinsics are lowered to calls to external symbols, which are then
105     // lowered to calls to library functions. Most of libcalls don't throw, but
106     // we only list some of them here now.
107     // TODO Consider adding 'nounwind' info in TargetLowering::CallLoweringInfo
108     // instead for more accurate info.
109     const char *Name = MO.getSymbolName();
110     if (strcmp(Name, "memcpy") == 0 || strcmp(Name, "memmove") == 0 ||
111         strcmp(Name, "memset") == 0)
112       return false;
113     return true;
114   }
115 
116   const auto *F = dyn_cast<Function>(MO.getGlobal());
117   if (!F)
118     return true;
119   if (F->doesNotThrow())
120     return false;
121   // These functions never throw
122   if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
123       F->getName() == StdTerminateFn)
124     return false;
125 
126   // TODO Can we exclude call instructions that are marked as 'nounwind' in the
127   // original LLVm IR? (Even when the callee may throw)
128   return true;
129 }
130 
131 const MachineOperand &WebAssembly::getCalleeOp(const MachineInstr &MI) {
132   switch (MI.getOpcode()) {
133   case WebAssembly::CALL:
134   case WebAssembly::CALL_S:
135   case WebAssembly::RET_CALL:
136   case WebAssembly::RET_CALL_S:
137     return MI.getOperand(MI.getNumExplicitDefs());
138   case WebAssembly::CALL_INDIRECT:
139   case WebAssembly::CALL_INDIRECT_S:
140   case WebAssembly::RET_CALL_INDIRECT:
141   case WebAssembly::RET_CALL_INDIRECT_S:
142     return MI.getOperand(MI.getNumExplicitOperands() - 1);
143   default:
144     llvm_unreachable("Not a call instruction");
145   }
146 }
147 
148 MCSymbolWasm *WebAssembly::getOrCreateFunctionTableSymbol(
149     MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
150   StringRef Name = "__indirect_function_table";
151   MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
152   if (Sym) {
153     if (!Sym->isFunctionTable())
154       Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
155   } else {
156     Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
157     Sym->setFunctionTable();
158     // The default function table is synthesized by the linker.
159     Sym->setUndefined();
160   }
161   // MVP object files can't have symtab entries for tables.
162   if (!(Subtarget && Subtarget->hasReferenceTypes()))
163     Sym->setOmitFromLinkingSection();
164   return Sym;
165 }
166 
167 // Find a catch instruction from an EH pad.
168 MachineInstr *WebAssembly::findCatch(MachineBasicBlock *EHPad) {
169   assert(EHPad->isEHPad());
170   auto Pos = EHPad->begin();
171   // Skip any label or debug instructions. Also skip 'end' marker instructions
172   // that may exist after marker placement in CFGStackify.
173   while (Pos != EHPad->end() &&
174          (Pos->isLabel() || Pos->isDebugInstr() || isMarker(Pos->getOpcode())))
175     Pos++;
176   if (Pos != EHPad->end() && WebAssembly::isCatch(Pos->getOpcode()))
177     return &*Pos;
178   return nullptr;
179 }
180