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