17d523365SDimitry Andric //===-- WebAssemblyLowerBrUnless.cpp - Lower br_unless --------------------===//
27d523365SDimitry Andric //
37d523365SDimitry Andric //                     The LLVM Compiler Infrastructure
47d523365SDimitry Andric //
57d523365SDimitry Andric // This file is distributed under the University of Illinois Open Source
67d523365SDimitry Andric // License. See LICENSE.TXT for details.
77d523365SDimitry Andric //
87d523365SDimitry Andric //===----------------------------------------------------------------------===//
97d523365SDimitry Andric ///
107d523365SDimitry Andric /// \file
114ba319b5SDimitry Andric /// This file lowers br_unless into br_if with an inverted condition.
127d523365SDimitry Andric ///
137d523365SDimitry Andric /// br_unless is not currently in the spec, but it's very convenient for LLVM
147d523365SDimitry Andric /// to use. This pass allows LLVM to use it, for now.
157d523365SDimitry Andric ///
167d523365SDimitry Andric //===----------------------------------------------------------------------===//
177d523365SDimitry Andric 
183ca95b02SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
19db17bf38SDimitry Andric #include "WebAssembly.h"
207d523365SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
217d523365SDimitry Andric #include "WebAssemblySubtarget.h"
227d523365SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
237d523365SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
247d523365SDimitry Andric #include "llvm/Support/Debug.h"
257d523365SDimitry Andric #include "llvm/Support/raw_ostream.h"
267d523365SDimitry Andric using namespace llvm;
277d523365SDimitry Andric 
287d523365SDimitry Andric #define DEBUG_TYPE "wasm-lower-br_unless"
297d523365SDimitry Andric 
307d523365SDimitry Andric namespace {
317d523365SDimitry Andric class WebAssemblyLowerBrUnless final : public MachineFunctionPass {
getPassName() const32d88c1a5aSDimitry Andric   StringRef getPassName() const override {
337d523365SDimitry Andric     return "WebAssembly Lower br_unless";
347d523365SDimitry Andric   }
357d523365SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const367d523365SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
377d523365SDimitry Andric     AU.setPreservesCFG();
387d523365SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
397d523365SDimitry Andric   }
407d523365SDimitry Andric 
417d523365SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
427d523365SDimitry Andric 
437d523365SDimitry Andric public:
447d523365SDimitry Andric   static char ID; // Pass identification, replacement for typeid
WebAssemblyLowerBrUnless()457d523365SDimitry Andric   WebAssemblyLowerBrUnless() : MachineFunctionPass(ID) {}
467d523365SDimitry Andric };
477d523365SDimitry Andric } // end anonymous namespace
487d523365SDimitry Andric 
497d523365SDimitry Andric char WebAssemblyLowerBrUnless::ID = 0;
504ba319b5SDimitry Andric INITIALIZE_PASS(WebAssemblyLowerBrUnless, DEBUG_TYPE,
514ba319b5SDimitry Andric                 "Lowers br_unless into inverted br_if", false, false)
524ba319b5SDimitry Andric 
createWebAssemblyLowerBrUnless()537d523365SDimitry Andric FunctionPass *llvm::createWebAssemblyLowerBrUnless() {
547d523365SDimitry Andric   return new WebAssemblyLowerBrUnless();
557d523365SDimitry Andric }
567d523365SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)577d523365SDimitry Andric bool WebAssemblyLowerBrUnless::runOnMachineFunction(MachineFunction &MF) {
584ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "********** Lowering br_unless **********\n"
597d523365SDimitry Andric                        "********** Function: "
607d523365SDimitry Andric                     << MF.getName() << '\n');
617d523365SDimitry Andric 
627d523365SDimitry Andric   auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
637d523365SDimitry Andric   const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
647d523365SDimitry Andric   auto &MRI = MF.getRegInfo();
657d523365SDimitry Andric 
667d523365SDimitry Andric   for (auto &MBB : MF) {
677d523365SDimitry Andric     for (auto MII = MBB.begin(); MII != MBB.end();) {
687d523365SDimitry Andric       MachineInstr *MI = &*MII++;
697d523365SDimitry Andric       if (MI->getOpcode() != WebAssembly::BR_UNLESS)
707d523365SDimitry Andric         continue;
717d523365SDimitry Andric 
723ca95b02SDimitry Andric       unsigned Cond = MI->getOperand(1).getReg();
737d523365SDimitry Andric       bool Inverted = false;
747d523365SDimitry Andric 
757d523365SDimitry Andric       // Attempt to invert the condition in place.
767d523365SDimitry Andric       if (MFI.isVRegStackified(Cond)) {
777d523365SDimitry Andric         assert(MRI.hasOneDef(Cond));
787d523365SDimitry Andric         MachineInstr *Def = MRI.getVRegDef(Cond);
797d523365SDimitry Andric         switch (Def->getOpcode()) {
807d523365SDimitry Andric           using namespace WebAssembly;
81*b5893f02SDimitry Andric         case EQ_I32:
82*b5893f02SDimitry Andric           Def->setDesc(TII.get(NE_I32));
83*b5893f02SDimitry Andric           Inverted = true;
84*b5893f02SDimitry Andric           break;
85*b5893f02SDimitry Andric         case NE_I32:
86*b5893f02SDimitry Andric           Def->setDesc(TII.get(EQ_I32));
87*b5893f02SDimitry Andric           Inverted = true;
88*b5893f02SDimitry Andric           break;
89*b5893f02SDimitry Andric         case GT_S_I32:
90*b5893f02SDimitry Andric           Def->setDesc(TII.get(LE_S_I32));
91*b5893f02SDimitry Andric           Inverted = true;
92*b5893f02SDimitry Andric           break;
93*b5893f02SDimitry Andric         case GE_S_I32:
94*b5893f02SDimitry Andric           Def->setDesc(TII.get(LT_S_I32));
95*b5893f02SDimitry Andric           Inverted = true;
96*b5893f02SDimitry Andric           break;
97*b5893f02SDimitry Andric         case LT_S_I32:
98*b5893f02SDimitry Andric           Def->setDesc(TII.get(GE_S_I32));
99*b5893f02SDimitry Andric           Inverted = true;
100*b5893f02SDimitry Andric           break;
101*b5893f02SDimitry Andric         case LE_S_I32:
102*b5893f02SDimitry Andric           Def->setDesc(TII.get(GT_S_I32));
103*b5893f02SDimitry Andric           Inverted = true;
104*b5893f02SDimitry Andric           break;
105*b5893f02SDimitry Andric         case GT_U_I32:
106*b5893f02SDimitry Andric           Def->setDesc(TII.get(LE_U_I32));
107*b5893f02SDimitry Andric           Inverted = true;
108*b5893f02SDimitry Andric           break;
109*b5893f02SDimitry Andric         case GE_U_I32:
110*b5893f02SDimitry Andric           Def->setDesc(TII.get(LT_U_I32));
111*b5893f02SDimitry Andric           Inverted = true;
112*b5893f02SDimitry Andric           break;
113*b5893f02SDimitry Andric         case LT_U_I32:
114*b5893f02SDimitry Andric           Def->setDesc(TII.get(GE_U_I32));
115*b5893f02SDimitry Andric           Inverted = true;
116*b5893f02SDimitry Andric           break;
117*b5893f02SDimitry Andric         case LE_U_I32:
118*b5893f02SDimitry Andric           Def->setDesc(TII.get(GT_U_I32));
119*b5893f02SDimitry Andric           Inverted = true;
120*b5893f02SDimitry Andric           break;
121*b5893f02SDimitry Andric         case EQ_I64:
122*b5893f02SDimitry Andric           Def->setDesc(TII.get(NE_I64));
123*b5893f02SDimitry Andric           Inverted = true;
124*b5893f02SDimitry Andric           break;
125*b5893f02SDimitry Andric         case NE_I64:
126*b5893f02SDimitry Andric           Def->setDesc(TII.get(EQ_I64));
127*b5893f02SDimitry Andric           Inverted = true;
128*b5893f02SDimitry Andric           break;
129*b5893f02SDimitry Andric         case GT_S_I64:
130*b5893f02SDimitry Andric           Def->setDesc(TII.get(LE_S_I64));
131*b5893f02SDimitry Andric           Inverted = true;
132*b5893f02SDimitry Andric           break;
133*b5893f02SDimitry Andric         case GE_S_I64:
134*b5893f02SDimitry Andric           Def->setDesc(TII.get(LT_S_I64));
135*b5893f02SDimitry Andric           Inverted = true;
136*b5893f02SDimitry Andric           break;
137*b5893f02SDimitry Andric         case LT_S_I64:
138*b5893f02SDimitry Andric           Def->setDesc(TII.get(GE_S_I64));
139*b5893f02SDimitry Andric           Inverted = true;
140*b5893f02SDimitry Andric           break;
141*b5893f02SDimitry Andric         case LE_S_I64:
142*b5893f02SDimitry Andric           Def->setDesc(TII.get(GT_S_I64));
143*b5893f02SDimitry Andric           Inverted = true;
144*b5893f02SDimitry Andric           break;
145*b5893f02SDimitry Andric         case GT_U_I64:
146*b5893f02SDimitry Andric           Def->setDesc(TII.get(LE_U_I64));
147*b5893f02SDimitry Andric           Inverted = true;
148*b5893f02SDimitry Andric           break;
149*b5893f02SDimitry Andric         case GE_U_I64:
150*b5893f02SDimitry Andric           Def->setDesc(TII.get(LT_U_I64));
151*b5893f02SDimitry Andric           Inverted = true;
152*b5893f02SDimitry Andric           break;
153*b5893f02SDimitry Andric         case LT_U_I64:
154*b5893f02SDimitry Andric           Def->setDesc(TII.get(GE_U_I64));
155*b5893f02SDimitry Andric           Inverted = true;
156*b5893f02SDimitry Andric           break;
157*b5893f02SDimitry Andric         case LE_U_I64:
158*b5893f02SDimitry Andric           Def->setDesc(TII.get(GT_U_I64));
159*b5893f02SDimitry Andric           Inverted = true;
160*b5893f02SDimitry Andric           break;
161*b5893f02SDimitry Andric         case EQ_F32:
162*b5893f02SDimitry Andric           Def->setDesc(TII.get(NE_F32));
163*b5893f02SDimitry Andric           Inverted = true;
164*b5893f02SDimitry Andric           break;
165*b5893f02SDimitry Andric         case NE_F32:
166*b5893f02SDimitry Andric           Def->setDesc(TII.get(EQ_F32));
167*b5893f02SDimitry Andric           Inverted = true;
168*b5893f02SDimitry Andric           break;
169*b5893f02SDimitry Andric         case EQ_F64:
170*b5893f02SDimitry Andric           Def->setDesc(TII.get(NE_F64));
171*b5893f02SDimitry Andric           Inverted = true;
172*b5893f02SDimitry Andric           break;
173*b5893f02SDimitry Andric         case NE_F64:
174*b5893f02SDimitry Andric           Def->setDesc(TII.get(EQ_F64));
175*b5893f02SDimitry Andric           Inverted = true;
176*b5893f02SDimitry Andric           break;
1772cab237bSDimitry Andric         case EQZ_I32: {
1782cab237bSDimitry Andric           // Invert an eqz by replacing it with its operand.
1792cab237bSDimitry Andric           Cond = Def->getOperand(1).getReg();
1802cab237bSDimitry Andric           Def->eraseFromParent();
1812cab237bSDimitry Andric           Inverted = true;
1822cab237bSDimitry Andric           break;
1832cab237bSDimitry Andric         }
184*b5893f02SDimitry Andric         default:
185*b5893f02SDimitry Andric           break;
1867d523365SDimitry Andric         }
1877d523365SDimitry Andric       }
1887d523365SDimitry Andric 
1897d523365SDimitry Andric       // If we weren't able to invert the condition in place. Insert an
190d88c1a5aSDimitry Andric       // instruction to invert it.
1917d523365SDimitry Andric       if (!Inverted) {
1927d523365SDimitry Andric         unsigned Tmp = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
1933ca95b02SDimitry Andric         BuildMI(MBB, MI, MI->getDebugLoc(), TII.get(WebAssembly::EQZ_I32), Tmp)
1943ca95b02SDimitry Andric             .addReg(Cond);
195d88c1a5aSDimitry Andric         MFI.stackifyVReg(Tmp);
1967d523365SDimitry Andric         Cond = Tmp;
1977d523365SDimitry Andric         Inverted = true;
1987d523365SDimitry Andric       }
1997d523365SDimitry Andric 
2007d523365SDimitry Andric       // The br_unless condition has now been inverted. Insert a br_if and
2017d523365SDimitry Andric       // delete the br_unless.
2027d523365SDimitry Andric       assert(Inverted);
2037d523365SDimitry Andric       BuildMI(MBB, MI, MI->getDebugLoc(), TII.get(WebAssembly::BR_IF))
2047a7e6055SDimitry Andric           .add(MI->getOperand(0))
2053ca95b02SDimitry Andric           .addReg(Cond);
2067d523365SDimitry Andric       MBB.erase(MI);
2077d523365SDimitry Andric     }
2087d523365SDimitry Andric   }
2097d523365SDimitry Andric 
2107d523365SDimitry Andric   return true;
2117d523365SDimitry Andric }
212