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 #include "llvm/MC/MCContext.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 28 /// Test whether MI is a child of some other node in an expression tree. 29 bool WebAssembly::isChild(const MachineInstr &MI, 30 const WebAssemblyFunctionInfo &MFI) { 31 if (MI.getNumOperands() == 0) 32 return false; 33 const MachineOperand &MO = MI.getOperand(0); 34 if (!MO.isReg() || MO.isImplicit() || !MO.isDef()) 35 return false; 36 Register Reg = MO.getReg(); 37 return Register::isVirtualRegister(Reg) && MFI.isVRegStackified(Reg); 38 } 39 40 bool WebAssembly::mayThrow(const MachineInstr &MI) { 41 switch (MI.getOpcode()) { 42 case WebAssembly::THROW: 43 case WebAssembly::THROW_S: 44 case WebAssembly::RETHROW: 45 case WebAssembly::RETHROW_S: 46 return true; 47 } 48 if (isCallIndirect(MI.getOpcode())) 49 return true; 50 if (!MI.isCall()) 51 return false; 52 53 const MachineOperand &MO = getCalleeOp(MI); 54 assert(MO.isGlobal() || MO.isSymbol()); 55 56 if (MO.isSymbol()) { 57 // Some intrinsics are lowered to calls to external symbols, which are then 58 // lowered to calls to library functions. Most of libcalls don't throw, but 59 // we only list some of them here now. 60 // TODO Consider adding 'nounwind' info in TargetLowering::CallLoweringInfo 61 // instead for more accurate info. 62 const char *Name = MO.getSymbolName(); 63 if (strcmp(Name, "memcpy") == 0 || strcmp(Name, "memmove") == 0 || 64 strcmp(Name, "memset") == 0) 65 return false; 66 return true; 67 } 68 69 const auto *F = dyn_cast<Function>(MO.getGlobal()); 70 if (!F) 71 return true; 72 if (F->doesNotThrow()) 73 return false; 74 // These functions never throw 75 if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn || 76 F->getName() == ClangCallTerminateFn || F->getName() == StdTerminateFn) 77 return false; 78 79 // TODO Can we exclude call instructions that are marked as 'nounwind' in the 80 // original LLVm IR? (Even when the callee may throw) 81 return true; 82 } 83 84 const MachineOperand &WebAssembly::getCalleeOp(const MachineInstr &MI) { 85 switch (MI.getOpcode()) { 86 case WebAssembly::CALL: 87 case WebAssembly::CALL_S: 88 case WebAssembly::RET_CALL: 89 case WebAssembly::RET_CALL_S: 90 return MI.getOperand(MI.getNumExplicitDefs()); 91 case WebAssembly::CALL_INDIRECT: 92 case WebAssembly::CALL_INDIRECT_S: 93 case WebAssembly::RET_CALL_INDIRECT: 94 case WebAssembly::RET_CALL_INDIRECT_S: 95 return MI.getOperand(MI.getNumOperands() - 1); 96 default: 97 llvm_unreachable("Not a call instruction"); 98 } 99 } 100 101 MCSymbolWasm * 102 WebAssembly::getOrCreateFunctionTableSymbol(MCContext &Ctx, 103 const StringRef &Name) { 104 // FIXME: Duplicates functionality from 105 // MC/WasmObjectWriter::recordRelocation. 106 MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name)); 107 if (Sym) { 108 if (!Sym->isFunctionTable()) 109 Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table"); 110 } else { 111 Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name)); 112 Sym->setFunctionTable(); 113 // The default function table is synthesized by the linker. 114 Sym->setUndefined(); 115 } 116 return Sym; 117 } 118 119 // Find a catch instruction from an EH pad. 120 MachineInstr *WebAssembly::findCatch(MachineBasicBlock *EHPad) { 121 assert(EHPad->isEHPad()); 122 auto Pos = EHPad->begin(); 123 // Skip any label or debug instructions. Also skip 'end' marker instructions 124 // that may exist after marker placement in CFGStackify. 125 while (Pos != EHPad->end() && 126 (Pos->isLabel() || Pos->isDebugInstr() || isMarker(Pos->getOpcode()))) 127 Pos++; 128 if (Pos != EHPad->end() && WebAssembly::isCatch(Pos->getOpcode())) 129 return &*Pos; 130 return nullptr; 131 } 132