WebAssemblyPeephole.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. //===-- WebAssemblyPeephole.cpp - WebAssembly Peephole Optimiztions -------===//
  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. /// Late peephole optimizations for WebAssembly.
  11. ///
  12. //===----------------------------------------------------------------------===//
  13. #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
  14. #include "Utils/WebAssemblyUtilities.h"
  15. #include "WebAssembly.h"
  16. #include "WebAssemblyMachineFunctionInfo.h"
  17. #include "WebAssemblySubtarget.h"
  18. #include "llvm/Analysis/TargetLibraryInfo.h"
  19. #include "llvm/CodeGen/MachineFunctionPass.h"
  20. #include "llvm/CodeGen/MachineInstrBuilder.h"
  21. #include "llvm/CodeGen/MachineRegisterInfo.h"
  22. using namespace llvm;
  23. #define DEBUG_TYPE "wasm-peephole"
  24. static cl::opt<bool> DisableWebAssemblyFallthroughReturnOpt(
  25. "disable-wasm-fallthrough-return-opt", cl::Hidden,
  26. cl::desc("WebAssembly: Disable fallthrough-return optimizations."),
  27. cl::init(false));
  28. namespace {
  29. class WebAssemblyPeephole final : public MachineFunctionPass {
  30. StringRef getPassName() const override {
  31. return "WebAssembly late peephole optimizer";
  32. }
  33. void getAnalysisUsage(AnalysisUsage &AU) const override {
  34. AU.setPreservesCFG();
  35. AU.addRequired<TargetLibraryInfoWrapperPass>();
  36. MachineFunctionPass::getAnalysisUsage(AU);
  37. }
  38. bool runOnMachineFunction(MachineFunction &MF) override;
  39. public:
  40. static char ID;
  41. WebAssemblyPeephole() : MachineFunctionPass(ID) {}
  42. };
  43. } // end anonymous namespace
  44. char WebAssemblyPeephole::ID = 0;
  45. INITIALIZE_PASS(WebAssemblyPeephole, DEBUG_TYPE,
  46. "WebAssembly peephole optimizations", false, false)
  47. FunctionPass *llvm::createWebAssemblyPeephole() {
  48. return new WebAssemblyPeephole();
  49. }
  50. /// If desirable, rewrite NewReg to a drop register.
  51. static bool maybeRewriteToDrop(unsigned OldReg, unsigned NewReg,
  52. MachineOperand &MO, WebAssemblyFunctionInfo &MFI,
  53. MachineRegisterInfo &MRI) {
  54. bool Changed = false;
  55. if (OldReg == NewReg) {
  56. Changed = true;
  57. Register NewReg = MRI.createVirtualRegister(MRI.getRegClass(OldReg));
  58. MO.setReg(NewReg);
  59. MO.setIsDead();
  60. MFI.stackifyVReg(MRI, NewReg);
  61. }
  62. return Changed;
  63. }
  64. static bool maybeRewriteToFallthrough(MachineInstr &MI, MachineBasicBlock &MBB,
  65. const MachineFunction &MF,
  66. WebAssemblyFunctionInfo &MFI,
  67. MachineRegisterInfo &MRI,
  68. const WebAssemblyInstrInfo &TII) {
  69. if (DisableWebAssemblyFallthroughReturnOpt)
  70. return false;
  71. if (&MBB != &MF.back())
  72. return false;
  73. MachineBasicBlock::iterator End = MBB.end();
  74. --End;
  75. assert(End->getOpcode() == WebAssembly::END_FUNCTION);
  76. --End;
  77. if (&MI != &*End)
  78. return false;
  79. for (auto &MO : MI.explicit_operands()) {
  80. // If the operand isn't stackified, insert a COPY to read the operands and
  81. // stackify them.
  82. Register Reg = MO.getReg();
  83. if (!MFI.isVRegStackified(Reg)) {
  84. unsigned CopyLocalOpc;
  85. const TargetRegisterClass *RegClass = MRI.getRegClass(Reg);
  86. CopyLocalOpc = WebAssembly::getCopyOpcodeForRegClass(RegClass);
  87. Register NewReg = MRI.createVirtualRegister(RegClass);
  88. BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(CopyLocalOpc), NewReg)
  89. .addReg(Reg);
  90. MO.setReg(NewReg);
  91. MFI.stackifyVReg(MRI, NewReg);
  92. }
  93. }
  94. MI.setDesc(TII.get(WebAssembly::FALLTHROUGH_RETURN));
  95. return true;
  96. }
  97. bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) {
  98. LLVM_DEBUG({
  99. dbgs() << "********** Peephole **********\n"
  100. << "********** Function: " << MF.getName() << '\n';
  101. });
  102. MachineRegisterInfo &MRI = MF.getRegInfo();
  103. WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
  104. const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
  105. const WebAssemblyTargetLowering &TLI =
  106. *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering();
  107. auto &LibInfo =
  108. getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(MF.getFunction());
  109. bool Changed = false;
  110. for (auto &MBB : MF)
  111. for (auto &MI : MBB)
  112. switch (MI.getOpcode()) {
  113. default:
  114. break;
  115. case WebAssembly::CALL: {
  116. MachineOperand &Op1 = MI.getOperand(1);
  117. if (Op1.isSymbol()) {
  118. StringRef Name(Op1.getSymbolName());
  119. if (Name == TLI.getLibcallName(RTLIB::MEMCPY) ||
  120. Name == TLI.getLibcallName(RTLIB::MEMMOVE) ||
  121. Name == TLI.getLibcallName(RTLIB::MEMSET)) {
  122. LibFunc Func;
  123. if (LibInfo.getLibFunc(Name, Func)) {
  124. const auto &Op2 = MI.getOperand(2);
  125. if (!Op2.isReg())
  126. report_fatal_error("Peephole: call to builtin function with "
  127. "wrong signature, not consuming reg");
  128. MachineOperand &MO = MI.getOperand(0);
  129. Register OldReg = MO.getReg();
  130. Register NewReg = Op2.getReg();
  131. if (MRI.getRegClass(NewReg) != MRI.getRegClass(OldReg))
  132. report_fatal_error("Peephole: call to builtin function with "
  133. "wrong signature, from/to mismatch");
  134. Changed |= maybeRewriteToDrop(OldReg, NewReg, MO, MFI, MRI);
  135. }
  136. }
  137. }
  138. break;
  139. }
  140. // Optimize away an explicit void return at the end of the function.
  141. case WebAssembly::RETURN:
  142. Changed |= maybeRewriteToFallthrough(MI, MBB, MF, MFI, MRI, TII);
  143. break;
  144. }
  145. return Changed;
  146. }