xref: /aosp_15_r20/external/llvm/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker //===-- WebAssemblyLowerBrUnless.cpp - Lower br_unless --------------------===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker //                     The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker ///
10*9880d681SAndroid Build Coastguard Worker /// \file
11*9880d681SAndroid Build Coastguard Worker /// \brief This file lowers br_unless into br_if with an inverted condition.
12*9880d681SAndroid Build Coastguard Worker ///
13*9880d681SAndroid Build Coastguard Worker /// br_unless is not currently in the spec, but it's very convenient for LLVM
14*9880d681SAndroid Build Coastguard Worker /// to use. This pass allows LLVM to use it, for now.
15*9880d681SAndroid Build Coastguard Worker ///
16*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
17*9880d681SAndroid Build Coastguard Worker 
18*9880d681SAndroid Build Coastguard Worker #include "WebAssembly.h"
19*9880d681SAndroid Build Coastguard Worker #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
20*9880d681SAndroid Build Coastguard Worker #include "WebAssemblyMachineFunctionInfo.h"
21*9880d681SAndroid Build Coastguard Worker #include "WebAssemblySubtarget.h"
22*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/MachineFunctionPass.h"
23*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/MachineInstrBuilder.h"
24*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/Debug.h"
25*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/raw_ostream.h"
26*9880d681SAndroid Build Coastguard Worker using namespace llvm;
27*9880d681SAndroid Build Coastguard Worker 
28*9880d681SAndroid Build Coastguard Worker #define DEBUG_TYPE "wasm-lower-br_unless"
29*9880d681SAndroid Build Coastguard Worker 
30*9880d681SAndroid Build Coastguard Worker namespace {
31*9880d681SAndroid Build Coastguard Worker class WebAssemblyLowerBrUnless final : public MachineFunctionPass {
getPassName() const32*9880d681SAndroid Build Coastguard Worker   const char *getPassName() const override {
33*9880d681SAndroid Build Coastguard Worker     return "WebAssembly Lower br_unless";
34*9880d681SAndroid Build Coastguard Worker   }
35*9880d681SAndroid Build Coastguard Worker 
getAnalysisUsage(AnalysisUsage & AU) const36*9880d681SAndroid Build Coastguard Worker   void getAnalysisUsage(AnalysisUsage &AU) const override {
37*9880d681SAndroid Build Coastguard Worker     AU.setPreservesCFG();
38*9880d681SAndroid Build Coastguard Worker     MachineFunctionPass::getAnalysisUsage(AU);
39*9880d681SAndroid Build Coastguard Worker   }
40*9880d681SAndroid Build Coastguard Worker 
41*9880d681SAndroid Build Coastguard Worker   bool runOnMachineFunction(MachineFunction &MF) override;
42*9880d681SAndroid Build Coastguard Worker 
43*9880d681SAndroid Build Coastguard Worker public:
44*9880d681SAndroid Build Coastguard Worker   static char ID; // Pass identification, replacement for typeid
WebAssemblyLowerBrUnless()45*9880d681SAndroid Build Coastguard Worker   WebAssemblyLowerBrUnless() : MachineFunctionPass(ID) {}
46*9880d681SAndroid Build Coastguard Worker };
47*9880d681SAndroid Build Coastguard Worker } // end anonymous namespace
48*9880d681SAndroid Build Coastguard Worker 
49*9880d681SAndroid Build Coastguard Worker char WebAssemblyLowerBrUnless::ID = 0;
createWebAssemblyLowerBrUnless()50*9880d681SAndroid Build Coastguard Worker FunctionPass *llvm::createWebAssemblyLowerBrUnless() {
51*9880d681SAndroid Build Coastguard Worker   return new WebAssemblyLowerBrUnless();
52*9880d681SAndroid Build Coastguard Worker }
53*9880d681SAndroid Build Coastguard Worker 
runOnMachineFunction(MachineFunction & MF)54*9880d681SAndroid Build Coastguard Worker bool WebAssemblyLowerBrUnless::runOnMachineFunction(MachineFunction &MF) {
55*9880d681SAndroid Build Coastguard Worker   DEBUG(dbgs() << "********** Lowering br_unless **********\n"
56*9880d681SAndroid Build Coastguard Worker                   "********** Function: "
57*9880d681SAndroid Build Coastguard Worker                << MF.getName() << '\n');
58*9880d681SAndroid Build Coastguard Worker 
59*9880d681SAndroid Build Coastguard Worker   auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
60*9880d681SAndroid Build Coastguard Worker   const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
61*9880d681SAndroid Build Coastguard Worker   auto &MRI = MF.getRegInfo();
62*9880d681SAndroid Build Coastguard Worker 
63*9880d681SAndroid Build Coastguard Worker   for (auto &MBB : MF) {
64*9880d681SAndroid Build Coastguard Worker     for (auto MII = MBB.begin(); MII != MBB.end();) {
65*9880d681SAndroid Build Coastguard Worker       MachineInstr *MI = &*MII++;
66*9880d681SAndroid Build Coastguard Worker       if (MI->getOpcode() != WebAssembly::BR_UNLESS)
67*9880d681SAndroid Build Coastguard Worker         continue;
68*9880d681SAndroid Build Coastguard Worker 
69*9880d681SAndroid Build Coastguard Worker       unsigned Cond = MI->getOperand(1).getReg();
70*9880d681SAndroid Build Coastguard Worker       bool Inverted = false;
71*9880d681SAndroid Build Coastguard Worker 
72*9880d681SAndroid Build Coastguard Worker       // Attempt to invert the condition in place.
73*9880d681SAndroid Build Coastguard Worker       if (MFI.isVRegStackified(Cond)) {
74*9880d681SAndroid Build Coastguard Worker         assert(MRI.hasOneDef(Cond));
75*9880d681SAndroid Build Coastguard Worker         MachineInstr *Def = MRI.getVRegDef(Cond);
76*9880d681SAndroid Build Coastguard Worker         switch (Def->getOpcode()) {
77*9880d681SAndroid Build Coastguard Worker           using namespace WebAssembly;
78*9880d681SAndroid Build Coastguard Worker         case EQ_I32: Def->setDesc(TII.get(NE_I32)); Inverted = true; break;
79*9880d681SAndroid Build Coastguard Worker         case NE_I32: Def->setDesc(TII.get(EQ_I32)); Inverted = true; break;
80*9880d681SAndroid Build Coastguard Worker         case GT_S_I32: Def->setDesc(TII.get(LE_S_I32)); Inverted = true; break;
81*9880d681SAndroid Build Coastguard Worker         case GE_S_I32: Def->setDesc(TII.get(LT_S_I32)); Inverted = true; break;
82*9880d681SAndroid Build Coastguard Worker         case LT_S_I32: Def->setDesc(TII.get(GE_S_I32)); Inverted = true; break;
83*9880d681SAndroid Build Coastguard Worker         case LE_S_I32: Def->setDesc(TII.get(GT_S_I32)); Inverted = true; break;
84*9880d681SAndroid Build Coastguard Worker         case GT_U_I32: Def->setDesc(TII.get(LE_U_I32)); Inverted = true; break;
85*9880d681SAndroid Build Coastguard Worker         case GE_U_I32: Def->setDesc(TII.get(LT_U_I32)); Inverted = true; break;
86*9880d681SAndroid Build Coastguard Worker         case LT_U_I32: Def->setDesc(TII.get(GE_U_I32)); Inverted = true; break;
87*9880d681SAndroid Build Coastguard Worker         case LE_U_I32: Def->setDesc(TII.get(GT_U_I32)); Inverted = true; break;
88*9880d681SAndroid Build Coastguard Worker         case EQ_I64: Def->setDesc(TII.get(NE_I64)); Inverted = true; break;
89*9880d681SAndroid Build Coastguard Worker         case NE_I64: Def->setDesc(TII.get(EQ_I64)); Inverted = true; break;
90*9880d681SAndroid Build Coastguard Worker         case GT_S_I64: Def->setDesc(TII.get(LE_S_I64)); Inverted = true; break;
91*9880d681SAndroid Build Coastguard Worker         case GE_S_I64: Def->setDesc(TII.get(LT_S_I64)); Inverted = true; break;
92*9880d681SAndroid Build Coastguard Worker         case LT_S_I64: Def->setDesc(TII.get(GE_S_I64)); Inverted = true; break;
93*9880d681SAndroid Build Coastguard Worker         case LE_S_I64: Def->setDesc(TII.get(GT_S_I64)); Inverted = true; break;
94*9880d681SAndroid Build Coastguard Worker         case GT_U_I64: Def->setDesc(TII.get(LE_U_I64)); Inverted = true; break;
95*9880d681SAndroid Build Coastguard Worker         case GE_U_I64: Def->setDesc(TII.get(LT_U_I64)); Inverted = true; break;
96*9880d681SAndroid Build Coastguard Worker         case LT_U_I64: Def->setDesc(TII.get(GE_U_I64)); Inverted = true; break;
97*9880d681SAndroid Build Coastguard Worker         case LE_U_I64: Def->setDesc(TII.get(GT_U_I64)); Inverted = true; break;
98*9880d681SAndroid Build Coastguard Worker         case EQ_F32: Def->setDesc(TII.get(NE_F32)); Inverted = true; break;
99*9880d681SAndroid Build Coastguard Worker         case NE_F32: Def->setDesc(TII.get(EQ_F32)); Inverted = true; break;
100*9880d681SAndroid Build Coastguard Worker         case EQ_F64: Def->setDesc(TII.get(NE_F64)); Inverted = true; break;
101*9880d681SAndroid Build Coastguard Worker         case NE_F64: Def->setDesc(TII.get(EQ_F64)); Inverted = true; break;
102*9880d681SAndroid Build Coastguard Worker         default: break;
103*9880d681SAndroid Build Coastguard Worker         }
104*9880d681SAndroid Build Coastguard Worker       }
105*9880d681SAndroid Build Coastguard Worker 
106*9880d681SAndroid Build Coastguard Worker       // If we weren't able to invert the condition in place. Insert an
107*9880d681SAndroid Build Coastguard Worker       // expression to invert it.
108*9880d681SAndroid Build Coastguard Worker       if (!Inverted) {
109*9880d681SAndroid Build Coastguard Worker         unsigned Tmp = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
110*9880d681SAndroid Build Coastguard Worker         MFI.stackifyVReg(Tmp);
111*9880d681SAndroid Build Coastguard Worker         BuildMI(MBB, MI, MI->getDebugLoc(), TII.get(WebAssembly::EQZ_I32), Tmp)
112*9880d681SAndroid Build Coastguard Worker             .addReg(Cond);
113*9880d681SAndroid Build Coastguard Worker         Cond = Tmp;
114*9880d681SAndroid Build Coastguard Worker         Inverted = true;
115*9880d681SAndroid Build Coastguard Worker       }
116*9880d681SAndroid Build Coastguard Worker 
117*9880d681SAndroid Build Coastguard Worker       // The br_unless condition has now been inverted. Insert a br_if and
118*9880d681SAndroid Build Coastguard Worker       // delete the br_unless.
119*9880d681SAndroid Build Coastguard Worker       assert(Inverted);
120*9880d681SAndroid Build Coastguard Worker       BuildMI(MBB, MI, MI->getDebugLoc(), TII.get(WebAssembly::BR_IF))
121*9880d681SAndroid Build Coastguard Worker           .addOperand(MI->getOperand(0))
122*9880d681SAndroid Build Coastguard Worker           .addReg(Cond);
123*9880d681SAndroid Build Coastguard Worker       MBB.erase(MI);
124*9880d681SAndroid Build Coastguard Worker     }
125*9880d681SAndroid Build Coastguard Worker   }
126*9880d681SAndroid Build Coastguard Worker 
127*9880d681SAndroid Build Coastguard Worker   return true;
128*9880d681SAndroid Build Coastguard Worker }
129