WebAssemblyExplicitLocals.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. //===-- WebAssemblyExplicitLocals.cpp - Make Locals Explicit --------------===//
  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 converts any remaining registers into WebAssembly locals.
  11. ///
  12. /// After register stackification and register coloring, convert non-stackified
  13. /// registers into locals, inserting explicit local.get and local.set
  14. /// instructions.
  15. ///
  16. //===----------------------------------------------------------------------===//
  17. #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
  18. #include "Utils/WebAssemblyUtilities.h"
  19. #include "WebAssembly.h"
  20. #include "WebAssemblyDebugValueManager.h"
  21. #include "WebAssemblyMachineFunctionInfo.h"
  22. #include "WebAssemblySubtarget.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. namespace {
  32. class WebAssemblyExplicitLocals final : public MachineFunctionPass {
  33. StringRef getPassName() const override {
  34. return "WebAssembly Explicit Locals";
  35. }
  36. void getAnalysisUsage(AnalysisUsage &AU) const override {
  37. AU.setPreservesCFG();
  38. AU.addPreserved<MachineBlockFrequencyInfo>();
  39. MachineFunctionPass::getAnalysisUsage(AU);
  40. }
  41. bool runOnMachineFunction(MachineFunction &MF) override;
  42. public:
  43. static char ID; // Pass identification, replacement for typeid
  44. WebAssemblyExplicitLocals() : MachineFunctionPass(ID) {}
  45. };
  46. } // end anonymous namespace
  47. char WebAssemblyExplicitLocals::ID = 0;
  48. INITIALIZE_PASS(WebAssemblyExplicitLocals, DEBUG_TYPE,
  49. "Convert registers to WebAssembly locals", false, false)
  50. FunctionPass *llvm::createWebAssemblyExplicitLocals() {
  51. return new WebAssemblyExplicitLocals();
  52. }
  53. static void checkFrameBase(WebAssemblyFunctionInfo &MFI, unsigned Local,
  54. unsigned Reg) {
  55. // Mark a local for the frame base vreg.
  56. if (MFI.isFrameBaseVirtual() && Reg == MFI.getFrameBaseVreg()) {
  57. LLVM_DEBUG({
  58. dbgs() << "Allocating local " << Local << "for VReg "
  59. << Register::virtReg2Index(Reg) << '\n';
  60. });
  61. MFI.setFrameBaseLocal(Local);
  62. }
  63. }
  64. /// Return a local id number for the given register, assigning it a new one
  65. /// if it doesn't yet have one.
  66. static unsigned getLocalId(DenseMap<unsigned, unsigned> &Reg2Local,
  67. WebAssemblyFunctionInfo &MFI, unsigned &CurLocal,
  68. unsigned Reg) {
  69. auto P = Reg2Local.insert(std::make_pair(Reg, CurLocal));
  70. if (P.second) {
  71. checkFrameBase(MFI, CurLocal, Reg);
  72. ++CurLocal;
  73. }
  74. return P.first->second;
  75. }
  76. /// Get the appropriate drop opcode for the given register class.
  77. static unsigned getDropOpcode(const TargetRegisterClass *RC) {
  78. if (RC == &WebAssembly::I32RegClass)
  79. return WebAssembly::DROP_I32;
  80. if (RC == &WebAssembly::I64RegClass)
  81. return WebAssembly::DROP_I64;
  82. if (RC == &WebAssembly::F32RegClass)
  83. return WebAssembly::DROP_F32;
  84. if (RC == &WebAssembly::F64RegClass)
  85. return WebAssembly::DROP_F64;
  86. if (RC == &WebAssembly::V128RegClass)
  87. return WebAssembly::DROP_V128;
  88. if (RC == &WebAssembly::FUNCREFRegClass)
  89. return WebAssembly::DROP_FUNCREF;
  90. if (RC == &WebAssembly::EXTERNREFRegClass)
  91. return WebAssembly::DROP_EXTERNREF;
  92. llvm_unreachable("Unexpected register class");
  93. }
  94. /// Get the appropriate local.get opcode for the given register class.
  95. static unsigned getLocalGetOpcode(const TargetRegisterClass *RC) {
  96. if (RC == &WebAssembly::I32RegClass)
  97. return WebAssembly::LOCAL_GET_I32;
  98. if (RC == &WebAssembly::I64RegClass)
  99. return WebAssembly::LOCAL_GET_I64;
  100. if (RC == &WebAssembly::F32RegClass)
  101. return WebAssembly::LOCAL_GET_F32;
  102. if (RC == &WebAssembly::F64RegClass)
  103. return WebAssembly::LOCAL_GET_F64;
  104. if (RC == &WebAssembly::V128RegClass)
  105. return WebAssembly::LOCAL_GET_V128;
  106. if (RC == &WebAssembly::FUNCREFRegClass)
  107. return WebAssembly::LOCAL_GET_FUNCREF;
  108. if (RC == &WebAssembly::EXTERNREFRegClass)
  109. return WebAssembly::LOCAL_GET_EXTERNREF;
  110. llvm_unreachable("Unexpected register class");
  111. }
  112. /// Get the appropriate local.set opcode for the given register class.
  113. static unsigned getLocalSetOpcode(const TargetRegisterClass *RC) {
  114. if (RC == &WebAssembly::I32RegClass)
  115. return WebAssembly::LOCAL_SET_I32;
  116. if (RC == &WebAssembly::I64RegClass)
  117. return WebAssembly::LOCAL_SET_I64;
  118. if (RC == &WebAssembly::F32RegClass)
  119. return WebAssembly::LOCAL_SET_F32;
  120. if (RC == &WebAssembly::F64RegClass)
  121. return WebAssembly::LOCAL_SET_F64;
  122. if (RC == &WebAssembly::V128RegClass)
  123. return WebAssembly::LOCAL_SET_V128;
  124. if (RC == &WebAssembly::FUNCREFRegClass)
  125. return WebAssembly::LOCAL_SET_FUNCREF;
  126. if (RC == &WebAssembly::EXTERNREFRegClass)
  127. return WebAssembly::LOCAL_SET_EXTERNREF;
  128. llvm_unreachable("Unexpected register class");
  129. }
  130. /// Get the appropriate local.tee opcode for the given register class.
  131. static unsigned getLocalTeeOpcode(const TargetRegisterClass *RC) {
  132. if (RC == &WebAssembly::I32RegClass)
  133. return WebAssembly::LOCAL_TEE_I32;
  134. if (RC == &WebAssembly::I64RegClass)
  135. return WebAssembly::LOCAL_TEE_I64;
  136. if (RC == &WebAssembly::F32RegClass)
  137. return WebAssembly::LOCAL_TEE_F32;
  138. if (RC == &WebAssembly::F64RegClass)
  139. return WebAssembly::LOCAL_TEE_F64;
  140. if (RC == &WebAssembly::V128RegClass)
  141. return WebAssembly::LOCAL_TEE_V128;
  142. if (RC == &WebAssembly::FUNCREFRegClass)
  143. return WebAssembly::LOCAL_TEE_FUNCREF;
  144. if (RC == &WebAssembly::EXTERNREFRegClass)
  145. return WebAssembly::LOCAL_TEE_EXTERNREF;
  146. llvm_unreachable("Unexpected register class");
  147. }
  148. /// Get the type associated with the given register class.
  149. static MVT typeForRegClass(const TargetRegisterClass *RC) {
  150. if (RC == &WebAssembly::I32RegClass)
  151. return MVT::i32;
  152. if (RC == &WebAssembly::I64RegClass)
  153. return MVT::i64;
  154. if (RC == &WebAssembly::F32RegClass)
  155. return MVT::f32;
  156. if (RC == &WebAssembly::F64RegClass)
  157. return MVT::f64;
  158. if (RC == &WebAssembly::V128RegClass)
  159. return MVT::v16i8;
  160. if (RC == &WebAssembly::FUNCREFRegClass)
  161. return MVT::funcref;
  162. if (RC == &WebAssembly::EXTERNREFRegClass)
  163. return MVT::externref;
  164. llvm_unreachable("unrecognized register class");
  165. }
  166. /// Given a MachineOperand of a stackified vreg, return the instruction at the
  167. /// start of the expression tree.
  168. static MachineInstr *findStartOfTree(MachineOperand &MO,
  169. MachineRegisterInfo &MRI,
  170. const WebAssemblyFunctionInfo &MFI) {
  171. Register Reg = MO.getReg();
  172. assert(MFI.isVRegStackified(Reg));
  173. MachineInstr *Def = MRI.getVRegDef(Reg);
  174. // If this instruction has any non-stackified defs, it is the start
  175. for (auto DefReg : Def->defs()) {
  176. if (!MFI.isVRegStackified(DefReg.getReg())) {
  177. return Def;
  178. }
  179. }
  180. // Find the first stackified use and proceed from there.
  181. for (MachineOperand &DefMO : Def->explicit_uses()) {
  182. if (!DefMO.isReg())
  183. continue;
  184. return findStartOfTree(DefMO, MRI, MFI);
  185. }
  186. // If there were no stackified uses, we've reached the start.
  187. return Def;
  188. }
  189. bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
  190. LLVM_DEBUG(dbgs() << "********** Make Locals Explicit **********\n"
  191. "********** Function: "
  192. << MF.getName() << '\n');
  193. bool Changed = false;
  194. MachineRegisterInfo &MRI = MF.getRegInfo();
  195. WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
  196. const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
  197. // Map non-stackified virtual registers to their local ids.
  198. DenseMap<unsigned, unsigned> Reg2Local;
  199. // Handle ARGUMENTS first to ensure that they get the designated numbers.
  200. for (MachineBasicBlock::iterator I = MF.begin()->begin(),
  201. E = MF.begin()->end();
  202. I != E;) {
  203. MachineInstr &MI = *I++;
  204. if (!WebAssembly::isArgument(MI.getOpcode()))
  205. break;
  206. Register Reg = MI.getOperand(0).getReg();
  207. assert(!MFI.isVRegStackified(Reg));
  208. auto Local = static_cast<unsigned>(MI.getOperand(1).getImm());
  209. Reg2Local[Reg] = Local;
  210. checkFrameBase(MFI, Local, Reg);
  211. // Update debug value to point to the local before removing.
  212. WebAssemblyDebugValueManager(&MI).replaceWithLocal(Local);
  213. MI.eraseFromParent();
  214. Changed = true;
  215. }
  216. // Start assigning local numbers after the last parameter and after any
  217. // already-assigned locals.
  218. unsigned CurLocal = static_cast<unsigned>(MFI.getParams().size());
  219. CurLocal += static_cast<unsigned>(MFI.getLocals().size());
  220. // Precompute the set of registers that are unused, so that we can insert
  221. // drops to their defs.
  222. BitVector UseEmpty(MRI.getNumVirtRegs());
  223. for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I)
  224. UseEmpty[I] = MRI.use_empty(Register::index2VirtReg(I));
  225. // Visit each instruction in the function.
  226. for (MachineBasicBlock &MBB : MF) {
  227. for (MachineInstr &MI : llvm::make_early_inc_range(MBB)) {
  228. assert(!WebAssembly::isArgument(MI.getOpcode()));
  229. if (MI.isDebugInstr() || MI.isLabel())
  230. continue;
  231. if (MI.getOpcode() == WebAssembly::IMPLICIT_DEF) {
  232. MI.eraseFromParent();
  233. Changed = true;
  234. continue;
  235. }
  236. // Replace tee instructions with local.tee. The difference is that tee
  237. // instructions have two defs, while local.tee instructions have one def
  238. // and an index of a local to write to.
  239. if (WebAssembly::isTee(MI.getOpcode())) {
  240. assert(MFI.isVRegStackified(MI.getOperand(0).getReg()));
  241. assert(!MFI.isVRegStackified(MI.getOperand(1).getReg()));
  242. Register OldReg = MI.getOperand(2).getReg();
  243. const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
  244. // Stackify the input if it isn't stackified yet.
  245. if (!MFI.isVRegStackified(OldReg)) {
  246. unsigned LocalId = getLocalId(Reg2Local, MFI, CurLocal, OldReg);
  247. Register NewReg = MRI.createVirtualRegister(RC);
  248. unsigned Opc = getLocalGetOpcode(RC);
  249. BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc), NewReg)
  250. .addImm(LocalId);
  251. MI.getOperand(2).setReg(NewReg);
  252. MFI.stackifyVReg(MRI, NewReg);
  253. }
  254. // Replace the TEE with a LOCAL_TEE.
  255. unsigned LocalId =
  256. getLocalId(Reg2Local, MFI, CurLocal, MI.getOperand(1).getReg());
  257. unsigned Opc = getLocalTeeOpcode(RC);
  258. BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc),
  259. MI.getOperand(0).getReg())
  260. .addImm(LocalId)
  261. .addReg(MI.getOperand(2).getReg());
  262. WebAssemblyDebugValueManager(&MI).replaceWithLocal(LocalId);
  263. MI.eraseFromParent();
  264. Changed = true;
  265. continue;
  266. }
  267. // Insert local.sets for any defs that aren't stackified yet.
  268. for (auto &Def : MI.defs()) {
  269. Register OldReg = Def.getReg();
  270. if (!MFI.isVRegStackified(OldReg)) {
  271. const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
  272. Register NewReg = MRI.createVirtualRegister(RC);
  273. auto InsertPt = std::next(MI.getIterator());
  274. if (UseEmpty[Register::virtReg2Index(OldReg)]) {
  275. unsigned Opc = getDropOpcode(RC);
  276. MachineInstr *Drop =
  277. BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
  278. .addReg(NewReg);
  279. // After the drop instruction, this reg operand will not be used
  280. Drop->getOperand(0).setIsKill();
  281. if (MFI.isFrameBaseVirtual() && OldReg == MFI.getFrameBaseVreg())
  282. MFI.clearFrameBaseVreg();
  283. } else {
  284. unsigned LocalId = getLocalId(Reg2Local, MFI, CurLocal, OldReg);
  285. unsigned Opc = getLocalSetOpcode(RC);
  286. WebAssemblyDebugValueManager(&MI).replaceWithLocal(LocalId);
  287. BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
  288. .addImm(LocalId)
  289. .addReg(NewReg);
  290. }
  291. // This register operand of the original instruction is now being used
  292. // by the inserted drop or local.set instruction, so make it not dead
  293. // yet.
  294. Def.setReg(NewReg);
  295. Def.setIsDead(false);
  296. MFI.stackifyVReg(MRI, NewReg);
  297. Changed = true;
  298. }
  299. }
  300. // Insert local.gets for any uses that aren't stackified yet.
  301. MachineInstr *InsertPt = &MI;
  302. for (MachineOperand &MO : reverse(MI.explicit_uses())) {
  303. if (!MO.isReg())
  304. continue;
  305. Register OldReg = MO.getReg();
  306. // Inline asm may have a def in the middle of the operands. Our contract
  307. // with inline asm register operands is to provide local indices as
  308. // immediates.
  309. if (MO.isDef()) {
  310. assert(MI.isInlineAsm());
  311. unsigned LocalId = getLocalId(Reg2Local, MFI, CurLocal, OldReg);
  312. // If this register operand is tied to another operand, we can't
  313. // change it to an immediate. Untie it first.
  314. MI.untieRegOperand(MI.getOperandNo(&MO));
  315. MO.ChangeToImmediate(LocalId);
  316. continue;
  317. }
  318. // If we see a stackified register, prepare to insert subsequent
  319. // local.gets before the start of its tree.
  320. if (MFI.isVRegStackified(OldReg)) {
  321. InsertPt = findStartOfTree(MO, MRI, MFI);
  322. continue;
  323. }
  324. // Our contract with inline asm register operands is to provide local
  325. // indices as immediates.
  326. if (MI.isInlineAsm()) {
  327. unsigned LocalId = getLocalId(Reg2Local, MFI, CurLocal, OldReg);
  328. // Untie it first if this reg operand is tied to another operand.
  329. MI.untieRegOperand(MI.getOperandNo(&MO));
  330. MO.ChangeToImmediate(LocalId);
  331. continue;
  332. }
  333. // Insert a local.get.
  334. unsigned LocalId = getLocalId(Reg2Local, MFI, CurLocal, OldReg);
  335. const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
  336. Register NewReg = MRI.createVirtualRegister(RC);
  337. unsigned Opc = getLocalGetOpcode(RC);
  338. // Use a InsertPt as our DebugLoc, since MI may be discontinuous from
  339. // the where this local is being inserted, causing non-linear stepping
  340. // in the debugger or function entry points where variables aren't live
  341. // yet. Alternative is previous instruction, but that is strictly worse
  342. // since it can point at the previous statement.
  343. // See crbug.com/1251909, crbug.com/1249745
  344. InsertPt = BuildMI(MBB, InsertPt, InsertPt->getDebugLoc(),
  345. TII->get(Opc), NewReg).addImm(LocalId);
  346. MO.setReg(NewReg);
  347. MFI.stackifyVReg(MRI, NewReg);
  348. Changed = true;
  349. }
  350. // Coalesce and eliminate COPY instructions.
  351. if (WebAssembly::isCopy(MI.getOpcode())) {
  352. MRI.replaceRegWith(MI.getOperand(1).getReg(),
  353. MI.getOperand(0).getReg());
  354. MI.eraseFromParent();
  355. Changed = true;
  356. }
  357. }
  358. }
  359. // Define the locals.
  360. // TODO: Sort the locals for better compression.
  361. MFI.setNumLocals(CurLocal - MFI.getParams().size());
  362. for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I) {
  363. Register Reg = Register::index2VirtReg(I);
  364. auto RL = Reg2Local.find(Reg);
  365. if (RL == Reg2Local.end() || RL->second < MFI.getParams().size())
  366. continue;
  367. MFI.setLocal(RL->second - MFI.getParams().size(),
  368. typeForRegClass(MRI.getRegClass(Reg)));
  369. Changed = true;
  370. }
  371. #ifndef NDEBUG
  372. // Assert that all registers have been stackified at this point.
  373. for (const MachineBasicBlock &MBB : MF) {
  374. for (const MachineInstr &MI : MBB) {
  375. if (MI.isDebugInstr() || MI.isLabel())
  376. continue;
  377. for (const MachineOperand &MO : MI.explicit_operands()) {
  378. assert(
  379. (!MO.isReg() || MRI.use_empty(MO.getReg()) ||
  380. MFI.isVRegStackified(MO.getReg())) &&
  381. "WebAssemblyExplicitLocals failed to stackify a register operand");
  382. }
  383. }
  384. }
  385. #endif
  386. return Changed;
  387. }