WebAssemblyInstrInfo.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. //===-- WebAssemblyInstrInfo.cpp - WebAssembly Instruction Information ----===//
  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 contains the WebAssembly implementation of the
  11. /// TargetInstrInfo class.
  12. ///
  13. //===----------------------------------------------------------------------===//
  14. #include "WebAssemblyInstrInfo.h"
  15. #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
  16. #include "Utils/WebAssemblyUtilities.h"
  17. #include "WebAssembly.h"
  18. #include "WebAssemblyMachineFunctionInfo.h"
  19. #include "WebAssemblySubtarget.h"
  20. #include "llvm/CodeGen/MachineFrameInfo.h"
  21. #include "llvm/CodeGen/MachineInstrBuilder.h"
  22. #include "llvm/CodeGen/MachineMemOperand.h"
  23. #include "llvm/CodeGen/MachineRegisterInfo.h"
  24. using namespace llvm;
  25. #define DEBUG_TYPE "wasm-instr-info"
  26. #define GET_INSTRINFO_CTOR_DTOR
  27. #include "WebAssemblyGenInstrInfo.inc"
  28. // defines WebAssembly::getNamedOperandIdx
  29. #define GET_INSTRINFO_NAMED_OPS
  30. #include "WebAssemblyGenInstrInfo.inc"
  31. WebAssemblyInstrInfo::WebAssemblyInstrInfo(const WebAssemblySubtarget &STI)
  32. : WebAssemblyGenInstrInfo(WebAssembly::ADJCALLSTACKDOWN,
  33. WebAssembly::ADJCALLSTACKUP,
  34. WebAssembly::CATCHRET),
  35. RI(STI.getTargetTriple()) {}
  36. bool WebAssemblyInstrInfo::isReallyTriviallyReMaterializable(
  37. const MachineInstr &MI) const {
  38. switch (MI.getOpcode()) {
  39. case WebAssembly::CONST_I32:
  40. case WebAssembly::CONST_I64:
  41. case WebAssembly::CONST_F32:
  42. case WebAssembly::CONST_F64:
  43. // isReallyTriviallyReMaterializableGeneric misses these because of the
  44. // ARGUMENTS implicit def, so we manualy override it here.
  45. return true;
  46. default:
  47. return false;
  48. }
  49. }
  50. void WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
  51. MachineBasicBlock::iterator I,
  52. const DebugLoc &DL, MCRegister DestReg,
  53. MCRegister SrcReg, bool KillSrc) const {
  54. // This method is called by post-RA expansion, which expects only pregs to
  55. // exist. However we need to handle both here.
  56. auto &MRI = MBB.getParent()->getRegInfo();
  57. const TargetRegisterClass *RC =
  58. Register::isVirtualRegister(DestReg)
  59. ? MRI.getRegClass(DestReg)
  60. : MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(DestReg);
  61. unsigned CopyOpcode = WebAssembly::getCopyOpcodeForRegClass(RC);
  62. BuildMI(MBB, I, DL, get(CopyOpcode), DestReg)
  63. .addReg(SrcReg, KillSrc ? RegState::Kill : 0);
  64. }
  65. MachineInstr *WebAssemblyInstrInfo::commuteInstructionImpl(
  66. MachineInstr &MI, bool NewMI, unsigned OpIdx1, unsigned OpIdx2) const {
  67. // If the operands are stackified, we can't reorder them.
  68. WebAssemblyFunctionInfo &MFI =
  69. *MI.getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();
  70. if (MFI.isVRegStackified(MI.getOperand(OpIdx1).getReg()) ||
  71. MFI.isVRegStackified(MI.getOperand(OpIdx2).getReg()))
  72. return nullptr;
  73. // Otherwise use the default implementation.
  74. return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2);
  75. }
  76. // Branch analysis.
  77. bool WebAssemblyInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
  78. MachineBasicBlock *&TBB,
  79. MachineBasicBlock *&FBB,
  80. SmallVectorImpl<MachineOperand> &Cond,
  81. bool /*AllowModify*/) const {
  82. const auto &MFI = *MBB.getParent()->getInfo<WebAssemblyFunctionInfo>();
  83. // WebAssembly has control flow that doesn't have explicit branches or direct
  84. // fallthrough (e.g. try/catch), which can't be modeled by analyzeBranch. It
  85. // is created after CFGStackify.
  86. if (MFI.isCFGStackified())
  87. return true;
  88. bool HaveCond = false;
  89. for (MachineInstr &MI : MBB.terminators()) {
  90. switch (MI.getOpcode()) {
  91. default:
  92. // Unhandled instruction; bail out.
  93. return true;
  94. case WebAssembly::BR_IF:
  95. if (HaveCond)
  96. return true;
  97. Cond.push_back(MachineOperand::CreateImm(true));
  98. Cond.push_back(MI.getOperand(1));
  99. TBB = MI.getOperand(0).getMBB();
  100. HaveCond = true;
  101. break;
  102. case WebAssembly::BR_UNLESS:
  103. if (HaveCond)
  104. return true;
  105. Cond.push_back(MachineOperand::CreateImm(false));
  106. Cond.push_back(MI.getOperand(1));
  107. TBB = MI.getOperand(0).getMBB();
  108. HaveCond = true;
  109. break;
  110. case WebAssembly::BR:
  111. if (!HaveCond)
  112. TBB = MI.getOperand(0).getMBB();
  113. else
  114. FBB = MI.getOperand(0).getMBB();
  115. break;
  116. }
  117. if (MI.isBarrier())
  118. break;
  119. }
  120. return false;
  121. }
  122. unsigned WebAssemblyInstrInfo::removeBranch(MachineBasicBlock &MBB,
  123. int *BytesRemoved) const {
  124. assert(!BytesRemoved && "code size not handled");
  125. MachineBasicBlock::instr_iterator I = MBB.instr_end();
  126. unsigned Count = 0;
  127. while (I != MBB.instr_begin()) {
  128. --I;
  129. if (I->isDebugInstr())
  130. continue;
  131. if (!I->isTerminator())
  132. break;
  133. // Remove the branch.
  134. I->eraseFromParent();
  135. I = MBB.instr_end();
  136. ++Count;
  137. }
  138. return Count;
  139. }
  140. unsigned WebAssemblyInstrInfo::insertBranch(
  141. MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
  142. ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {
  143. assert(!BytesAdded && "code size not handled");
  144. if (Cond.empty()) {
  145. if (!TBB)
  146. return 0;
  147. BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(TBB);
  148. return 1;
  149. }
  150. assert(Cond.size() == 2 && "Expected a flag and a successor block");
  151. if (Cond[0].getImm())
  152. BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]);
  153. else
  154. BuildMI(&MBB, DL, get(WebAssembly::BR_UNLESS)).addMBB(TBB).add(Cond[1]);
  155. if (!FBB)
  156. return 1;
  157. BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(FBB);
  158. return 2;
  159. }
  160. bool WebAssemblyInstrInfo::reverseBranchCondition(
  161. SmallVectorImpl<MachineOperand> &Cond) const {
  162. assert(Cond.size() == 2 && "Expected a flag and a condition expression");
  163. Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm());
  164. return false;
  165. }
  166. ArrayRef<std::pair<int, const char *>>
  167. WebAssemblyInstrInfo::getSerializableTargetIndices() const {
  168. static const std::pair<int, const char *> TargetIndices[] = {
  169. {WebAssembly::TI_LOCAL, "wasm-local"},
  170. {WebAssembly::TI_GLOBAL_FIXED, "wasm-global-fixed"},
  171. {WebAssembly::TI_OPERAND_STACK, "wasm-operand-stack"},
  172. {WebAssembly::TI_GLOBAL_RELOC, "wasm-global-reloc"},
  173. {WebAssembly::TI_LOCAL_INDIRECT, "wasm-local-indirect"}};
  174. return ArrayRef(TargetIndices);
  175. }
  176. const MachineOperand &
  177. WebAssemblyInstrInfo::getCalleeOperand(const MachineInstr &MI) const {
  178. return WebAssembly::getCalleeOp(MI);
  179. }
  180. // This returns true when the instruction defines a value of a TargetIndex
  181. // operand that can be tracked by offsets. For Wasm, this returns true for only
  182. // local.set/local.tees. This is currently used by LiveDebugValues analysis.
  183. //
  184. // These are not included:
  185. // - In theory we need to add global.set here too, but we don't have global
  186. // indices at this point because they are relocatable and we address them by
  187. // names until linking, so we don't have 'offsets' (which are used to store
  188. // local/global indices) to deal with in LiveDebugValues. And we don't
  189. // associate debug info in values in globals anyway.
  190. // - All other value-producing instructions, i.e. instructions with defs, can
  191. // define values in the Wasm stack, which is represented by TI_OPERAND_STACK
  192. // TargetIndex. But they don't have offset info within the instruction itself,
  193. // and debug info analysis for them is handled separately in
  194. // WebAssemblyDebugFixup pass, so we don't worry about them here.
  195. bool WebAssemblyInstrInfo::isExplicitTargetIndexDef(const MachineInstr &MI,
  196. int &Index,
  197. int64_t &Offset) const {
  198. unsigned Opc = MI.getOpcode();
  199. if (WebAssembly::isLocalSet(Opc) || WebAssembly::isLocalTee(Opc)) {
  200. Index = WebAssembly::TI_LOCAL;
  201. Offset = MI.explicit_uses().begin()->getImm();
  202. return true;
  203. }
  204. return false;
  205. }