WebAssemblyExplicitLocals.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. //===-- WebAssemblyExplicitLocals.cpp - Make Locals Explicit --------------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. ///
  10. /// \file
  11. /// \brief This file converts any remaining registers into WebAssembly locals.
  12. ///
  13. /// After register stackification and register coloring, convert non-stackified
  14. /// registers into locals, inserting explicit get_local and set_local
  15. /// instructions.
  16. ///
  17. //===----------------------------------------------------------------------===//
  18. #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
  19. #include "WebAssembly.h"
  20. #include "WebAssemblyMachineFunctionInfo.h"
  21. #include "WebAssemblySubtarget.h"
  22. #include "WebAssemblyUtilities.h"
  23. #include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
  24. #include "llvm/CodeGen/MachineInstrBuilder.h"
  25. #include "llvm/CodeGen/MachineRegisterInfo.h"
  26. #include "llvm/CodeGen/Passes.h"
  27. #include "llvm/Support/Debug.h"
  28. #include "llvm/Support/raw_ostream.h"
  29. using namespace llvm;
  30. #define DEBUG_TYPE "wasm-explicit-locals"
  31. // A command-line option to disable this pass. Note that this produces output
  32. // which is not valid WebAssembly, though it may be more convenient for writing
  33. // LLVM unit tests with.
  34. static cl::opt<bool> DisableWebAssemblyExplicitLocals(
  35. "disable-wasm-explicit-locals", cl::ReallyHidden,
  36. cl::desc("WebAssembly: Disable emission of get_local/set_local."),
  37. cl::init(false));
  38. namespace {
  39. class WebAssemblyExplicitLocals final : public MachineFunctionPass {
  40. StringRef getPassName() const override {
  41. return "WebAssembly Explicit Locals";
  42. }
  43. void getAnalysisUsage(AnalysisUsage &AU) const override {
  44. AU.setPreservesCFG();
  45. AU.addPreserved<MachineBlockFrequencyInfo>();
  46. MachineFunctionPass::getAnalysisUsage(AU);
  47. }
  48. bool runOnMachineFunction(MachineFunction &MF) override;
  49. public:
  50. static char ID; // Pass identification, replacement for typeid
  51. WebAssemblyExplicitLocals() : MachineFunctionPass(ID) {}
  52. };
  53. } // end anonymous namespace
  54. char WebAssemblyExplicitLocals::ID = 0;
  55. FunctionPass *llvm::createWebAssemblyExplicitLocals() {
  56. return new WebAssemblyExplicitLocals();
  57. }
  58. /// Return a local id number for the given register, assigning it a new one
  59. /// if it doesn't yet have one.
  60. static unsigned getLocalId(DenseMap<unsigned, unsigned> &Reg2Local,
  61. unsigned &CurLocal, unsigned Reg) {
  62. auto P = Reg2Local.insert(std::make_pair(Reg, CurLocal));
  63. if (P.second)
  64. ++CurLocal;
  65. return P.first->second;
  66. }
  67. /// Get the appropriate drop opcode for the given register class.
  68. static unsigned getDropOpcode(const TargetRegisterClass *RC) {
  69. if (RC == &WebAssembly::I32RegClass)
  70. return WebAssembly::DROP_I32;
  71. if (RC == &WebAssembly::I64RegClass)
  72. return WebAssembly::DROP_I64;
  73. if (RC == &WebAssembly::F32RegClass)
  74. return WebAssembly::DROP_F32;
  75. if (RC == &WebAssembly::F64RegClass)
  76. return WebAssembly::DROP_F64;
  77. if (RC == &WebAssembly::V128RegClass)
  78. return WebAssembly::DROP_V128;
  79. if (RC == &WebAssembly::EXCEPT_REFRegClass)
  80. return WebAssembly::DROP_EXCEPT_REF;
  81. llvm_unreachable("Unexpected register class");
  82. }
  83. /// Get the appropriate get_local opcode for the given register class.
  84. static unsigned getGetLocalOpcode(const TargetRegisterClass *RC) {
  85. if (RC == &WebAssembly::I32RegClass)
  86. return WebAssembly::GET_LOCAL_I32;
  87. if (RC == &WebAssembly::I64RegClass)
  88. return WebAssembly::GET_LOCAL_I64;
  89. if (RC == &WebAssembly::F32RegClass)
  90. return WebAssembly::GET_LOCAL_F32;
  91. if (RC == &WebAssembly::F64RegClass)
  92. return WebAssembly::GET_LOCAL_F64;
  93. if (RC == &WebAssembly::V128RegClass)
  94. return WebAssembly::GET_LOCAL_V128;
  95. if (RC == &WebAssembly::EXCEPT_REFRegClass)
  96. return WebAssembly::GET_LOCAL_EXCEPT_REF;
  97. llvm_unreachable("Unexpected register class");
  98. }
  99. /// Get the appropriate set_local opcode for the given register class.
  100. static unsigned getSetLocalOpcode(const TargetRegisterClass *RC) {
  101. if (RC == &WebAssembly::I32RegClass)
  102. return WebAssembly::SET_LOCAL_I32;
  103. if (RC == &WebAssembly::I64RegClass)
  104. return WebAssembly::SET_LOCAL_I64;
  105. if (RC == &WebAssembly::F32RegClass)
  106. return WebAssembly::SET_LOCAL_F32;
  107. if (RC == &WebAssembly::F64RegClass)
  108. return WebAssembly::SET_LOCAL_F64;
  109. if (RC == &WebAssembly::V128RegClass)
  110. return WebAssembly::SET_LOCAL_V128;
  111. if (RC == &WebAssembly::EXCEPT_REFRegClass)
  112. return WebAssembly::SET_LOCAL_EXCEPT_REF;
  113. llvm_unreachable("Unexpected register class");
  114. }
  115. /// Get the appropriate tee_local opcode for the given register class.
  116. static unsigned getTeeLocalOpcode(const TargetRegisterClass *RC) {
  117. if (RC == &WebAssembly::I32RegClass)
  118. return WebAssembly::TEE_LOCAL_I32;
  119. if (RC == &WebAssembly::I64RegClass)
  120. return WebAssembly::TEE_LOCAL_I64;
  121. if (RC == &WebAssembly::F32RegClass)
  122. return WebAssembly::TEE_LOCAL_F32;
  123. if (RC == &WebAssembly::F64RegClass)
  124. return WebAssembly::TEE_LOCAL_F64;
  125. if (RC == &WebAssembly::V128RegClass)
  126. return WebAssembly::TEE_LOCAL_V128;
  127. if (RC == &WebAssembly::EXCEPT_REFRegClass)
  128. return WebAssembly::TEE_LOCAL_EXCEPT_REF;
  129. llvm_unreachable("Unexpected register class");
  130. }
  131. /// Get the type associated with the given register class.
  132. static MVT typeForRegClass(const TargetRegisterClass *RC) {
  133. if (RC == &WebAssembly::I32RegClass)
  134. return MVT::i32;
  135. if (RC == &WebAssembly::I64RegClass)
  136. return MVT::i64;
  137. if (RC == &WebAssembly::F32RegClass)
  138. return MVT::f32;
  139. if (RC == &WebAssembly::F64RegClass)
  140. return MVT::f64;
  141. if (RC == &WebAssembly::EXCEPT_REFRegClass)
  142. return MVT::ExceptRef;
  143. llvm_unreachable("unrecognized register class");
  144. }
  145. /// Given a MachineOperand of a stackified vreg, return the instruction at the
  146. /// start of the expression tree.
  147. static MachineInstr *FindStartOfTree(MachineOperand &MO,
  148. MachineRegisterInfo &MRI,
  149. WebAssemblyFunctionInfo &MFI) {
  150. unsigned Reg = MO.getReg();
  151. assert(MFI.isVRegStackified(Reg));
  152. MachineInstr *Def = MRI.getVRegDef(Reg);
  153. // Find the first stackified use and proceed from there.
  154. for (MachineOperand &DefMO : Def->explicit_uses()) {
  155. if (!DefMO.isReg())
  156. continue;
  157. return FindStartOfTree(DefMO, MRI, MFI);
  158. }
  159. // If there were no stackified uses, we've reached the start.
  160. return Def;
  161. }
  162. bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
  163. DEBUG(dbgs() << "********** Make Locals Explicit **********\n"
  164. "********** Function: "
  165. << MF.getName() << '\n');
  166. // Disable this pass if directed to do so.
  167. if (DisableWebAssemblyExplicitLocals)
  168. return false;
  169. // Disable this pass if we aren't doing direct wasm object emission.
  170. if (MF.getSubtarget<WebAssemblySubtarget>()
  171. .getTargetTriple().isOSBinFormatELF())
  172. return false;
  173. bool Changed = false;
  174. MachineRegisterInfo &MRI = MF.getRegInfo();
  175. WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
  176. const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
  177. // Map non-stackified virtual registers to their local ids.
  178. DenseMap<unsigned, unsigned> Reg2Local;
  179. // Handle ARGUMENTS first to ensure that they get the designated numbers.
  180. for (MachineBasicBlock::iterator I = MF.begin()->begin(),
  181. E = MF.begin()->end();
  182. I != E;) {
  183. MachineInstr &MI = *I++;
  184. if (!WebAssembly::isArgument(MI))
  185. break;
  186. unsigned Reg = MI.getOperand(0).getReg();
  187. assert(!MFI.isVRegStackified(Reg));
  188. Reg2Local[Reg] = MI.getOperand(1).getImm();
  189. MI.eraseFromParent();
  190. Changed = true;
  191. }
  192. // Start assigning local numbers after the last parameter.
  193. unsigned CurLocal = MFI.getParams().size();
  194. // Precompute the set of registers that are unused, so that we can insert
  195. // drops to their defs.
  196. BitVector UseEmpty(MRI.getNumVirtRegs());
  197. for (unsigned i = 0, e = MRI.getNumVirtRegs(); i < e; ++i)
  198. UseEmpty[i] = MRI.use_empty(TargetRegisterInfo::index2VirtReg(i));
  199. // Visit each instruction in the function.
  200. for (MachineBasicBlock &MBB : MF) {
  201. for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) {
  202. MachineInstr &MI = *I++;
  203. assert(!WebAssembly::isArgument(MI));
  204. if (MI.isDebugValue() || MI.isLabel())
  205. continue;
  206. // Replace tee instructions with tee_local. The difference is that tee
  207. // instructins have two defs, while tee_local instructions have one def
  208. // and an index of a local to write to.
  209. if (WebAssembly::isTee(MI)) {
  210. assert(MFI.isVRegStackified(MI.getOperand(0).getReg()));
  211. assert(!MFI.isVRegStackified(MI.getOperand(1).getReg()));
  212. unsigned OldReg = MI.getOperand(2).getReg();
  213. const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
  214. // Stackify the input if it isn't stackified yet.
  215. if (!MFI.isVRegStackified(OldReg)) {
  216. unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
  217. unsigned NewReg = MRI.createVirtualRegister(RC);
  218. unsigned Opc = getGetLocalOpcode(RC);
  219. BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc), NewReg)
  220. .addImm(LocalId);
  221. MI.getOperand(2).setReg(NewReg);
  222. MFI.stackifyVReg(NewReg);
  223. }
  224. // Replace the TEE with a TEE_LOCAL.
  225. unsigned LocalId =
  226. getLocalId(Reg2Local, CurLocal, MI.getOperand(1).getReg());
  227. unsigned Opc = getTeeLocalOpcode(RC);
  228. BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc),
  229. MI.getOperand(0).getReg())
  230. .addImm(LocalId)
  231. .addReg(MI.getOperand(2).getReg());
  232. MI.eraseFromParent();
  233. Changed = true;
  234. continue;
  235. }
  236. // Insert set_locals for any defs that aren't stackified yet. Currently
  237. // we handle at most one def.
  238. assert(MI.getDesc().getNumDefs() <= 1);
  239. if (MI.getDesc().getNumDefs() == 1) {
  240. unsigned OldReg = MI.getOperand(0).getReg();
  241. if (!MFI.isVRegStackified(OldReg)) {
  242. const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
  243. unsigned NewReg = MRI.createVirtualRegister(RC);
  244. auto InsertPt = std::next(MachineBasicBlock::iterator(&MI));
  245. if (MI.getOpcode() == WebAssembly::IMPLICIT_DEF) {
  246. MI.eraseFromParent();
  247. Changed = true;
  248. continue;
  249. }
  250. if (UseEmpty[TargetRegisterInfo::virtReg2Index(OldReg)]) {
  251. unsigned Opc = getDropOpcode(RC);
  252. BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
  253. .addReg(NewReg);
  254. } else {
  255. unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
  256. unsigned Opc = getSetLocalOpcode(RC);
  257. BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
  258. .addImm(LocalId)
  259. .addReg(NewReg);
  260. }
  261. MI.getOperand(0).setReg(NewReg);
  262. MFI.stackifyVReg(NewReg);
  263. Changed = true;
  264. }
  265. }
  266. // Insert get_locals for any uses that aren't stackified yet.
  267. MachineInstr *InsertPt = &MI;
  268. for (MachineOperand &MO : reverse(MI.explicit_uses())) {
  269. if (!MO.isReg())
  270. continue;
  271. unsigned OldReg = MO.getReg();
  272. // Inline asm may have a def in the middle of the operands. Our contract
  273. // with inline asm register operands is to provide local indices as
  274. // immediates.
  275. if (MO.isDef()) {
  276. assert(MI.getOpcode() == TargetOpcode::INLINEASM);
  277. unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
  278. MRI.removeRegOperandFromUseList(&MO);
  279. MO = MachineOperand::CreateImm(LocalId);
  280. continue;
  281. }
  282. // If we see a stackified register, prepare to insert subsequent
  283. // get_locals before the start of its tree.
  284. if (MFI.isVRegStackified(OldReg)) {
  285. InsertPt = FindStartOfTree(MO, MRI, MFI);
  286. continue;
  287. }
  288. // Our contract with inline asm register operands is to provide local
  289. // indices as immediates.
  290. if (MI.getOpcode() == TargetOpcode::INLINEASM) {
  291. unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
  292. MRI.removeRegOperandFromUseList(&MO);
  293. MO = MachineOperand::CreateImm(LocalId);
  294. continue;
  295. }
  296. // Insert a get_local.
  297. unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
  298. const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
  299. unsigned NewReg = MRI.createVirtualRegister(RC);
  300. unsigned Opc = getGetLocalOpcode(RC);
  301. InsertPt =
  302. BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc), NewReg)
  303. .addImm(LocalId);
  304. MO.setReg(NewReg);
  305. MFI.stackifyVReg(NewReg);
  306. Changed = true;
  307. }
  308. // Coalesce and eliminate COPY instructions.
  309. if (WebAssembly::isCopy(MI)) {
  310. MRI.replaceRegWith(MI.getOperand(1).getReg(),
  311. MI.getOperand(0).getReg());
  312. MI.eraseFromParent();
  313. Changed = true;
  314. }
  315. }
  316. }
  317. // Define the locals.
  318. // TODO: Sort the locals for better compression.
  319. MFI.setNumLocals(CurLocal - MFI.getParams().size());
  320. for (size_t i = 0, e = MRI.getNumVirtRegs(); i < e; ++i) {
  321. unsigned Reg = TargetRegisterInfo::index2VirtReg(i);
  322. auto I = Reg2Local.find(Reg);
  323. if (I == Reg2Local.end() || I->second < MFI.getParams().size())
  324. continue;
  325. MFI.setLocal(I->second - MFI.getParams().size(),
  326. typeForRegClass(MRI.getRegClass(Reg)));
  327. Changed = true;
  328. }
  329. #ifndef NDEBUG
  330. // Assert that all registers have been stackified at this point.
  331. for (const MachineBasicBlock &MBB : MF) {
  332. for (const MachineInstr &MI : MBB) {
  333. if (MI.isDebugValue() || MI.isLabel())
  334. continue;
  335. for (const MachineOperand &MO : MI.explicit_operands()) {
  336. assert(
  337. (!MO.isReg() || MRI.use_empty(MO.getReg()) ||
  338. MFI.isVRegStackified(MO.getReg())) &&
  339. "WebAssemblyExplicitLocals failed to stackify a register operand");
  340. }
  341. }
  342. }
  343. #endif
  344. return Changed;
  345. }