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