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