WebAssemblyUtilities.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. #include "WebAssemblyUtilities.h"
  14. #include "WebAssemblyMachineFunctionInfo.h"
  15. #include "llvm/CodeGen/MachineInstr.h"
  16. #include "llvm/CodeGen/MachineLoopInfo.h"
  17. #include "llvm/MC/MCContext.h"
  18. using namespace llvm;
  19. // Exception handling & setjmp-longjmp handling related options. These are
  20. // defined here to be shared between WebAssembly and its subdirectories.
  21. // Emscripten's asm.js-style exception handling
  22. cl::opt<bool> WebAssembly::WasmEnableEmEH(
  23. "enable-emscripten-cxx-exceptions",
  24. cl::desc("WebAssembly Emscripten-style exception handling"),
  25. cl::init(false));
  26. // Emscripten's asm.js-style setjmp/longjmp handling
  27. cl::opt<bool> WebAssembly::WasmEnableEmSjLj(
  28. "enable-emscripten-sjlj",
  29. cl::desc("WebAssembly Emscripten-style setjmp/longjmp handling"),
  30. cl::init(false));
  31. // Exception handling using wasm EH instructions
  32. cl::opt<bool>
  33. WebAssembly::WasmEnableEH("wasm-enable-eh",
  34. cl::desc("WebAssembly exception handling"),
  35. cl::init(false));
  36. // setjmp/longjmp handling using wasm EH instrutions
  37. cl::opt<bool>
  38. WebAssembly::WasmEnableSjLj("wasm-enable-sjlj",
  39. cl::desc("WebAssembly setjmp/longjmp handling"),
  40. cl::init(false));
  41. // Function names in libc++abi and libunwind
  42. const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch";
  43. const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow";
  44. const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev";
  45. const char *const WebAssembly::PersonalityWrapperFn =
  46. "_Unwind_Wasm_CallPersonality";
  47. /// Test whether MI is a child of some other node in an expression tree.
  48. bool WebAssembly::isChild(const MachineInstr &MI,
  49. const WebAssemblyFunctionInfo &MFI) {
  50. if (MI.getNumOperands() == 0)
  51. return false;
  52. const MachineOperand &MO = MI.getOperand(0);
  53. if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
  54. return false;
  55. Register Reg = MO.getReg();
  56. return Reg.isVirtual() && MFI.isVRegStackified(Reg);
  57. }
  58. bool WebAssembly::mayThrow(const MachineInstr &MI) {
  59. switch (MI.getOpcode()) {
  60. case WebAssembly::THROW:
  61. case WebAssembly::THROW_S:
  62. case WebAssembly::RETHROW:
  63. case WebAssembly::RETHROW_S:
  64. return true;
  65. }
  66. if (isCallIndirect(MI.getOpcode()))
  67. return true;
  68. if (!MI.isCall())
  69. return false;
  70. const MachineOperand &MO = getCalleeOp(MI);
  71. assert(MO.isGlobal() || MO.isSymbol());
  72. if (MO.isSymbol()) {
  73. // Some intrinsics are lowered to calls to external symbols, which are then
  74. // lowered to calls to library functions. Most of libcalls don't throw, but
  75. // we only list some of them here now.
  76. // TODO Consider adding 'nounwind' info in TargetLowering::CallLoweringInfo
  77. // instead for more accurate info.
  78. const char *Name = MO.getSymbolName();
  79. if (strcmp(Name, "memcpy") == 0 || strcmp(Name, "memmove") == 0 ||
  80. strcmp(Name, "memset") == 0)
  81. return false;
  82. return true;
  83. }
  84. const auto *F = dyn_cast<Function>(MO.getGlobal());
  85. if (!F)
  86. return true;
  87. if (F->doesNotThrow())
  88. return false;
  89. // These functions never throw
  90. if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn ||
  91. F->getName() == StdTerminateFn)
  92. return false;
  93. // TODO Can we exclude call instructions that are marked as 'nounwind' in the
  94. // original LLVm IR? (Even when the callee may throw)
  95. return true;
  96. }
  97. const MachineOperand &WebAssembly::getCalleeOp(const MachineInstr &MI) {
  98. switch (MI.getOpcode()) {
  99. case WebAssembly::CALL:
  100. case WebAssembly::CALL_S:
  101. case WebAssembly::RET_CALL:
  102. case WebAssembly::RET_CALL_S:
  103. return MI.getOperand(MI.getNumExplicitDefs());
  104. case WebAssembly::CALL_INDIRECT:
  105. case WebAssembly::CALL_INDIRECT_S:
  106. case WebAssembly::RET_CALL_INDIRECT:
  107. case WebAssembly::RET_CALL_INDIRECT_S:
  108. return MI.getOperand(MI.getNumExplicitOperands() - 1);
  109. default:
  110. llvm_unreachable("Not a call instruction");
  111. }
  112. }
  113. MCSymbolWasm *WebAssembly::getOrCreateFunctionTableSymbol(
  114. MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
  115. StringRef Name = "__indirect_function_table";
  116. MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
  117. if (Sym) {
  118. if (!Sym->isFunctionTable())
  119. Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
  120. } else {
  121. Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
  122. Sym->setFunctionTable();
  123. // The default function table is synthesized by the linker.
  124. Sym->setUndefined();
  125. }
  126. // MVP object files can't have symtab entries for tables.
  127. if (!(Subtarget && Subtarget->hasReferenceTypes()))
  128. Sym->setOmitFromLinkingSection();
  129. return Sym;
  130. }
  131. MCSymbolWasm *WebAssembly::getOrCreateFuncrefCallTableSymbol(
  132. MCContext &Ctx, const WebAssemblySubtarget *Subtarget) {
  133. StringRef Name = "__funcref_call_table";
  134. MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
  135. if (Sym) {
  136. if (!Sym->isFunctionTable())
  137. Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
  138. } else {
  139. Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
  140. // Setting Weak ensure only one table is left after linking when multiple
  141. // modules define the table.
  142. Sym->setWeak(true);
  143. wasm::WasmLimits Limits = {0, 1, 1};
  144. wasm::WasmTableType TableType = {wasm::WASM_TYPE_FUNCREF, Limits};
  145. Sym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);
  146. Sym->setTableType(TableType);
  147. }
  148. // MVP object files can't have symtab entries for tables.
  149. if (!(Subtarget && Subtarget->hasReferenceTypes()))
  150. Sym->setOmitFromLinkingSection();
  151. return Sym;
  152. }
  153. // Find a catch instruction from an EH pad.
  154. MachineInstr *WebAssembly::findCatch(MachineBasicBlock *EHPad) {
  155. assert(EHPad->isEHPad());
  156. auto Pos = EHPad->begin();
  157. // Skip any label or debug instructions. Also skip 'end' marker instructions
  158. // that may exist after marker placement in CFGStackify.
  159. while (Pos != EHPad->end() &&
  160. (Pos->isLabel() || Pos->isDebugInstr() || isMarker(Pos->getOpcode())))
  161. Pos++;
  162. if (Pos != EHPad->end() && WebAssembly::isCatch(Pos->getOpcode()))
  163. return &*Pos;
  164. return nullptr;
  165. }
  166. unsigned WebAssembly::getCopyOpcodeForRegClass(const TargetRegisterClass *RC) {
  167. assert(RC != nullptr);
  168. switch (RC->getID()) {
  169. case WebAssembly::I32RegClassID:
  170. return WebAssembly::COPY_I32;
  171. case WebAssembly::I64RegClassID:
  172. return WebAssembly::COPY_I64;
  173. case WebAssembly::F32RegClassID:
  174. return WebAssembly::COPY_F32;
  175. case WebAssembly::F64RegClassID:
  176. return WebAssembly::COPY_F64;
  177. case WebAssembly::V128RegClassID:
  178. return WebAssembly::COPY_V128;
  179. case WebAssembly::FUNCREFRegClassID:
  180. return WebAssembly::COPY_FUNCREF;
  181. case WebAssembly::EXTERNREFRegClassID:
  182. return WebAssembly::COPY_EXTERNREF;
  183. default:
  184. llvm_unreachable("Unexpected register class");
  185. }
  186. }