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" 26using namespace llvm; 27 28#define DEBUG_TYPE "wasm-lower-br_unless" 29 30namespace { 31class 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 43public: 44 static char ID; // Pass identification, replacement for typeid 45 WebAssemblyLowerBrUnless() : MachineFunctionPass(ID) {} 46}; 47} // end anonymous namespace 48 49char WebAssemblyLowerBrUnless::ID = 0; 50FunctionPass *llvm::createWebAssemblyLowerBrUnless() { 51 return new WebAssemblyLowerBrUnless(); 52} 53 54bool 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