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 /// \brief 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 "WebAssembly.h" 19 #include "WebAssemblyMachineFunctionInfo.h" 20 #include "WebAssemblySubtarget.h" 21 #include "MCTargetDesc/WebAssemblyMCTargetDesc.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 const char *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 FunctionPass *llvm::createWebAssemblyLowerBrUnless() { 51 return new WebAssemblyLowerBrUnless(); 52 } 53 54 bool WebAssemblyLowerBrUnless::runOnMachineFunction(MachineFunction &MF) { 55 DEBUG(dbgs() << "********** Lowering br_unless **********\n" 56 "********** Function: " 57 << MF.getName() << '\n'); 58 59 auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 60 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 61 auto &MRI = MF.getRegInfo(); 62 63 for (auto &MBB : MF) { 64 for (auto MII = MBB.begin(); MII != MBB.end(); ) { 65 MachineInstr *MI = &*MII++; 66 if (MI->getOpcode() != WebAssembly::BR_UNLESS) 67 continue; 68 69 unsigned Cond = MI->getOperand(0).getReg(); 70 bool Inverted = false; 71 72 // Attempt to invert the condition in place. 73 if (MFI.isVRegStackified(Cond)) { 74 assert(MRI.hasOneDef(Cond)); 75 MachineInstr *Def = MRI.getVRegDef(Cond); 76 switch (Def->getOpcode()) { 77 using namespace WebAssembly; 78 case EQ_I32: Def->setDesc(TII.get(NE_I32)); Inverted = true; break; 79 case NE_I32: Def->setDesc(TII.get(EQ_I32)); Inverted = true; break; 80 case GT_S_I32: Def->setDesc(TII.get(LE_S_I32)); Inverted = true; break; 81 case GE_S_I32: Def->setDesc(TII.get(LT_S_I32)); Inverted = true; break; 82 case LT_S_I32: Def->setDesc(TII.get(GE_S_I32)); Inverted = true; break; 83 case LE_S_I32: Def->setDesc(TII.get(GT_S_I32)); Inverted = true; break; 84 case GT_U_I32: Def->setDesc(TII.get(LE_U_I32)); Inverted = true; break; 85 case GE_U_I32: Def->setDesc(TII.get(LT_U_I32)); Inverted = true; break; 86 case LT_U_I32: Def->setDesc(TII.get(GE_U_I32)); Inverted = true; break; 87 case LE_U_I32: Def->setDesc(TII.get(GT_U_I32)); Inverted = true; break; 88 case EQ_I64: Def->setDesc(TII.get(NE_I64)); Inverted = true; break; 89 case NE_I64: Def->setDesc(TII.get(EQ_I64)); Inverted = true; break; 90 case GT_S_I64: Def->setDesc(TII.get(LE_S_I64)); Inverted = true; break; 91 case GE_S_I64: Def->setDesc(TII.get(LT_S_I64)); Inverted = true; break; 92 case LT_S_I64: Def->setDesc(TII.get(GE_S_I64)); Inverted = true; break; 93 case LE_S_I64: Def->setDesc(TII.get(GT_S_I64)); Inverted = true; break; 94 case GT_U_I64: Def->setDesc(TII.get(LE_U_I64)); Inverted = true; break; 95 case GE_U_I64: Def->setDesc(TII.get(LT_U_I64)); Inverted = true; break; 96 case LT_U_I64: Def->setDesc(TII.get(GE_U_I64)); Inverted = true; break; 97 case LE_U_I64: Def->setDesc(TII.get(GT_U_I64)); Inverted = true; break; 98 case EQ_F32: Def->setDesc(TII.get(NE_F32)); Inverted = true; break; 99 case NE_F32: Def->setDesc(TII.get(EQ_F32)); Inverted = true; break; 100 case EQ_F64: Def->setDesc(TII.get(NE_F64)); Inverted = true; break; 101 case NE_F64: Def->setDesc(TII.get(EQ_F64)); Inverted = true; break; 102 default: break; 103 } 104 } 105 106 // If we weren't able to invert the condition in place. Insert an 107 // expression to invert it. 108 if (!Inverted) { 109 unsigned ZeroReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 110 MFI.stackifyVReg(ZeroReg); 111 BuildMI(MBB, MI, MI->getDebugLoc(), TII.get(WebAssembly::CONST_I32), ZeroReg) 112 .addImm(0); 113 unsigned Tmp = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 114 MFI.stackifyVReg(Tmp); 115 BuildMI(MBB, MI, MI->getDebugLoc(), TII.get(WebAssembly::EQ_I32), Tmp) 116 .addReg(Cond) 117 .addReg(ZeroReg); 118 Cond = Tmp; 119 Inverted = true; 120 } 121 122 // The br_unless condition has now been inverted. Insert a br_if and 123 // delete the br_unless. 124 assert(Inverted); 125 BuildMI(MBB, MI, MI->getDebugLoc(), TII.get(WebAssembly::BR_IF)) 126 .addReg(Cond) 127 .addMBB(MI->getOperand(1).getMBB()); 128 MBB.erase(MI); 129 } 130 } 131 132 return true; 133 } 134