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