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 (MachineInstr &MI : llvm::make_early_inc_range(MBB)) { 67 if (MI.getOpcode() != WebAssembly::BR_UNLESS) 68 continue; 69 70 Register Cond = MI.getOperand(1).getReg(); 71 bool Inverted = false; 72 73 // Attempt to invert the condition in place. 74 if (MFI.isVRegStackified(Cond)) { 75 assert(MRI.hasOneDef(Cond)); 76 MachineInstr *Def = MRI.getVRegDef(Cond); 77 switch (Def->getOpcode()) { 78 using namespace WebAssembly; 79 case EQ_I32: 80 Def->setDesc(TII.get(NE_I32)); 81 Inverted = true; 82 break; 83 case NE_I32: 84 Def->setDesc(TII.get(EQ_I32)); 85 Inverted = true; 86 break; 87 case GT_S_I32: 88 Def->setDesc(TII.get(LE_S_I32)); 89 Inverted = true; 90 break; 91 case GE_S_I32: 92 Def->setDesc(TII.get(LT_S_I32)); 93 Inverted = true; 94 break; 95 case LT_S_I32: 96 Def->setDesc(TII.get(GE_S_I32)); 97 Inverted = true; 98 break; 99 case LE_S_I32: 100 Def->setDesc(TII.get(GT_S_I32)); 101 Inverted = true; 102 break; 103 case GT_U_I32: 104 Def->setDesc(TII.get(LE_U_I32)); 105 Inverted = true; 106 break; 107 case GE_U_I32: 108 Def->setDesc(TII.get(LT_U_I32)); 109 Inverted = true; 110 break; 111 case LT_U_I32: 112 Def->setDesc(TII.get(GE_U_I32)); 113 Inverted = true; 114 break; 115 case LE_U_I32: 116 Def->setDesc(TII.get(GT_U_I32)); 117 Inverted = true; 118 break; 119 case EQ_I64: 120 Def->setDesc(TII.get(NE_I64)); 121 Inverted = true; 122 break; 123 case NE_I64: 124 Def->setDesc(TII.get(EQ_I64)); 125 Inverted = true; 126 break; 127 case GT_S_I64: 128 Def->setDesc(TII.get(LE_S_I64)); 129 Inverted = true; 130 break; 131 case GE_S_I64: 132 Def->setDesc(TII.get(LT_S_I64)); 133 Inverted = true; 134 break; 135 case LT_S_I64: 136 Def->setDesc(TII.get(GE_S_I64)); 137 Inverted = true; 138 break; 139 case LE_S_I64: 140 Def->setDesc(TII.get(GT_S_I64)); 141 Inverted = true; 142 break; 143 case GT_U_I64: 144 Def->setDesc(TII.get(LE_U_I64)); 145 Inverted = true; 146 break; 147 case GE_U_I64: 148 Def->setDesc(TII.get(LT_U_I64)); 149 Inverted = true; 150 break; 151 case LT_U_I64: 152 Def->setDesc(TII.get(GE_U_I64)); 153 Inverted = true; 154 break; 155 case LE_U_I64: 156 Def->setDesc(TII.get(GT_U_I64)); 157 Inverted = true; 158 break; 159 case EQ_F32: 160 Def->setDesc(TII.get(NE_F32)); 161 Inverted = true; 162 break; 163 case NE_F32: 164 Def->setDesc(TII.get(EQ_F32)); 165 Inverted = true; 166 break; 167 case EQ_F64: 168 Def->setDesc(TII.get(NE_F64)); 169 Inverted = true; 170 break; 171 case NE_F64: 172 Def->setDesc(TII.get(EQ_F64)); 173 Inverted = true; 174 break; 175 case EQZ_I32: { 176 // Invert an eqz by replacing it with its operand. 177 Cond = Def->getOperand(1).getReg(); 178 Def->eraseFromParent(); 179 Inverted = true; 180 break; 181 } 182 default: 183 break; 184 } 185 } 186 187 // If we weren't able to invert the condition in place. Insert an 188 // instruction to invert it. 189 if (!Inverted) { 190 Register Tmp = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 191 BuildMI(MBB, &MI, MI.getDebugLoc(), TII.get(WebAssembly::EQZ_I32), Tmp) 192 .addReg(Cond); 193 MFI.stackifyVReg(MRI, Tmp); 194 Cond = Tmp; 195 Inverted = true; 196 } 197 198 // The br_unless condition has now been inverted. Insert a br_if and 199 // delete the br_unless. 200 assert(Inverted); 201 BuildMI(MBB, &MI, MI.getDebugLoc(), TII.get(WebAssembly::BR_IF)) 202 .add(MI.getOperand(0)) 203 .addReg(Cond); 204 MBB.erase(&MI); 205 } 206 } 207 208 return true; 209 } 210