WebAssemblyLowerBrUnless.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. //===-- WebAssemblyLowerBrUnless.cpp - Lower br_unless --------------------===//
  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 lowers br_unless into br_if with an inverted condition.
  11. ///
  12. /// br_unless is not currently in the spec, but it's very convenient for LLVM
  13. /// to use. This pass allows LLVM to use it, for now.
  14. ///
  15. //===----------------------------------------------------------------------===//
  16. #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
  17. #include "WebAssembly.h"
  18. #include "WebAssemblyMachineFunctionInfo.h"
  19. #include "WebAssemblySubtarget.h"
  20. #include "llvm/CodeGen/MachineFunctionPass.h"
  21. #include "llvm/CodeGen/MachineInstrBuilder.h"
  22. #include "llvm/Support/Debug.h"
  23. #include "llvm/Support/raw_ostream.h"
  24. using namespace llvm;
  25. #define DEBUG_TYPE "wasm-lower-br_unless"
  26. namespace {
  27. class WebAssemblyLowerBrUnless final : public MachineFunctionPass {
  28. StringRef getPassName() const override {
  29. return "WebAssembly Lower br_unless";
  30. }
  31. void getAnalysisUsage(AnalysisUsage &AU) const override {
  32. AU.setPreservesCFG();
  33. MachineFunctionPass::getAnalysisUsage(AU);
  34. }
  35. bool runOnMachineFunction(MachineFunction &MF) override;
  36. public:
  37. static char ID; // Pass identification, replacement for typeid
  38. WebAssemblyLowerBrUnless() : MachineFunctionPass(ID) {}
  39. };
  40. } // end anonymous namespace
  41. char WebAssemblyLowerBrUnless::ID = 0;
  42. INITIALIZE_PASS(WebAssemblyLowerBrUnless, DEBUG_TYPE,
  43. "Lowers br_unless into inverted br_if", false, false)
  44. FunctionPass *llvm::createWebAssemblyLowerBrUnless() {
  45. return new WebAssemblyLowerBrUnless();
  46. }
  47. bool WebAssemblyLowerBrUnless::runOnMachineFunction(MachineFunction &MF) {
  48. LLVM_DEBUG(dbgs() << "********** Lowering br_unless **********\n"
  49. "********** Function: "
  50. << MF.getName() << '\n');
  51. auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
  52. const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
  53. auto &MRI = MF.getRegInfo();
  54. for (auto &MBB : MF) {
  55. for (MachineInstr &MI : llvm::make_early_inc_range(MBB)) {
  56. if (MI.getOpcode() != WebAssembly::BR_UNLESS)
  57. continue;
  58. Register Cond = MI.getOperand(1).getReg();
  59. bool Inverted = false;
  60. // Attempt to invert the condition in place.
  61. if (MFI.isVRegStackified(Cond)) {
  62. assert(MRI.hasOneDef(Cond));
  63. MachineInstr *Def = MRI.getVRegDef(Cond);
  64. switch (Def->getOpcode()) {
  65. using namespace WebAssembly;
  66. case EQ_I32:
  67. Def->setDesc(TII.get(NE_I32));
  68. Inverted = true;
  69. break;
  70. case NE_I32:
  71. Def->setDesc(TII.get(EQ_I32));
  72. Inverted = true;
  73. break;
  74. case GT_S_I32:
  75. Def->setDesc(TII.get(LE_S_I32));
  76. Inverted = true;
  77. break;
  78. case GE_S_I32:
  79. Def->setDesc(TII.get(LT_S_I32));
  80. Inverted = true;
  81. break;
  82. case LT_S_I32:
  83. Def->setDesc(TII.get(GE_S_I32));
  84. Inverted = true;
  85. break;
  86. case LE_S_I32:
  87. Def->setDesc(TII.get(GT_S_I32));
  88. Inverted = true;
  89. break;
  90. case GT_U_I32:
  91. Def->setDesc(TII.get(LE_U_I32));
  92. Inverted = true;
  93. break;
  94. case GE_U_I32:
  95. Def->setDesc(TII.get(LT_U_I32));
  96. Inverted = true;
  97. break;
  98. case LT_U_I32:
  99. Def->setDesc(TII.get(GE_U_I32));
  100. Inverted = true;
  101. break;
  102. case LE_U_I32:
  103. Def->setDesc(TII.get(GT_U_I32));
  104. Inverted = true;
  105. break;
  106. case EQ_I64:
  107. Def->setDesc(TII.get(NE_I64));
  108. Inverted = true;
  109. break;
  110. case NE_I64:
  111. Def->setDesc(TII.get(EQ_I64));
  112. Inverted = true;
  113. break;
  114. case GT_S_I64:
  115. Def->setDesc(TII.get(LE_S_I64));
  116. Inverted = true;
  117. break;
  118. case GE_S_I64:
  119. Def->setDesc(TII.get(LT_S_I64));
  120. Inverted = true;
  121. break;
  122. case LT_S_I64:
  123. Def->setDesc(TII.get(GE_S_I64));
  124. Inverted = true;
  125. break;
  126. case LE_S_I64:
  127. Def->setDesc(TII.get(GT_S_I64));
  128. Inverted = true;
  129. break;
  130. case GT_U_I64:
  131. Def->setDesc(TII.get(LE_U_I64));
  132. Inverted = true;
  133. break;
  134. case GE_U_I64:
  135. Def->setDesc(TII.get(LT_U_I64));
  136. Inverted = true;
  137. break;
  138. case LT_U_I64:
  139. Def->setDesc(TII.get(GE_U_I64));
  140. Inverted = true;
  141. break;
  142. case LE_U_I64:
  143. Def->setDesc(TII.get(GT_U_I64));
  144. Inverted = true;
  145. break;
  146. case EQ_F32:
  147. Def->setDesc(TII.get(NE_F32));
  148. Inverted = true;
  149. break;
  150. case NE_F32:
  151. Def->setDesc(TII.get(EQ_F32));
  152. Inverted = true;
  153. break;
  154. case EQ_F64:
  155. Def->setDesc(TII.get(NE_F64));
  156. Inverted = true;
  157. break;
  158. case NE_F64:
  159. Def->setDesc(TII.get(EQ_F64));
  160. Inverted = true;
  161. break;
  162. case EQZ_I32: {
  163. // Invert an eqz by replacing it with its operand.
  164. Cond = Def->getOperand(1).getReg();
  165. Def->eraseFromParent();
  166. Inverted = true;
  167. break;
  168. }
  169. default:
  170. break;
  171. }
  172. }
  173. // If we weren't able to invert the condition in place. Insert an
  174. // instruction to invert it.
  175. if (!Inverted) {
  176. Register Tmp = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
  177. BuildMI(MBB, &MI, MI.getDebugLoc(), TII.get(WebAssembly::EQZ_I32), Tmp)
  178. .addReg(Cond);
  179. MFI.stackifyVReg(MRI, Tmp);
  180. Cond = Tmp;
  181. Inverted = true;
  182. }
  183. // The br_unless condition has now been inverted. Insert a br_if and
  184. // delete the br_unless.
  185. assert(Inverted);
  186. BuildMI(MBB, &MI, MI.getDebugLoc(), TII.get(WebAssembly::BR_IF))
  187. .add(MI.getOperand(0))
  188. .addReg(Cond);
  189. MBB.erase(&MI);
  190. }
  191. }
  192. return true;
  193. }