WebAssemblyLowerBrUnless.cpp revision 341825
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" 26using namespace llvm; 27 28#define DEBUG_TYPE "wasm-lower-br_unless" 29 30namespace { 31class 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 43public: 44 static char ID; // Pass identification, replacement for typeid 45 WebAssemblyLowerBrUnless() : MachineFunctionPass(ID) {} 46}; 47} // end anonymous namespace 48 49char WebAssemblyLowerBrUnless::ID = 0; 50INITIALIZE_PASS(WebAssemblyLowerBrUnless, DEBUG_TYPE, 51 "Lowers br_unless into inverted br_if", false, false) 52 53FunctionPass *llvm::createWebAssemblyLowerBrUnless() { 54 return new WebAssemblyLowerBrUnless(); 55} 56 57bool 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: Def->setDesc(TII.get(NE_I32)); Inverted = true; break; 82 case NE_I32: Def->setDesc(TII.get(EQ_I32)); Inverted = true; break; 83 case GT_S_I32: Def->setDesc(TII.get(LE_S_I32)); Inverted = true; break; 84 case GE_S_I32: Def->setDesc(TII.get(LT_S_I32)); Inverted = true; break; 85 case LT_S_I32: Def->setDesc(TII.get(GE_S_I32)); Inverted = true; break; 86 case LE_S_I32: Def->setDesc(TII.get(GT_S_I32)); Inverted = true; break; 87 case GT_U_I32: Def->setDesc(TII.get(LE_U_I32)); Inverted = true; break; 88 case GE_U_I32: Def->setDesc(TII.get(LT_U_I32)); Inverted = true; break; 89 case LT_U_I32: Def->setDesc(TII.get(GE_U_I32)); Inverted = true; break; 90 case LE_U_I32: Def->setDesc(TII.get(GT_U_I32)); Inverted = true; break; 91 case EQ_I64: Def->setDesc(TII.get(NE_I64)); Inverted = true; break; 92 case NE_I64: Def->setDesc(TII.get(EQ_I64)); Inverted = true; break; 93 case GT_S_I64: Def->setDesc(TII.get(LE_S_I64)); Inverted = true; break; 94 case GE_S_I64: Def->setDesc(TII.get(LT_S_I64)); Inverted = true; break; 95 case LT_S_I64: Def->setDesc(TII.get(GE_S_I64)); Inverted = true; break; 96 case LE_S_I64: Def->setDesc(TII.get(GT_S_I64)); Inverted = true; break; 97 case GT_U_I64: Def->setDesc(TII.get(LE_U_I64)); Inverted = true; break; 98 case GE_U_I64: Def->setDesc(TII.get(LT_U_I64)); Inverted = true; break; 99 case LT_U_I64: Def->setDesc(TII.get(GE_U_I64)); Inverted = true; break; 100 case LE_U_I64: Def->setDesc(TII.get(GT_U_I64)); Inverted = true; break; 101 case EQ_F32: Def->setDesc(TII.get(NE_F32)); Inverted = true; break; 102 case NE_F32: Def->setDesc(TII.get(EQ_F32)); Inverted = true; break; 103 case EQ_F64: Def->setDesc(TII.get(NE_F64)); Inverted = true; break; 104 case NE_F64: Def->setDesc(TII.get(EQ_F64)); Inverted = true; break; 105 case EQZ_I32: { 106 // Invert an eqz by replacing it with its operand. 107 Cond = Def->getOperand(1).getReg(); 108 Def->eraseFromParent(); 109 Inverted = true; 110 break; 111 } 112 default: break; 113 } 114 } 115 116 // If we weren't able to invert the condition in place. Insert an 117 // instruction to invert it. 118 if (!Inverted) { 119 unsigned Tmp = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 120 BuildMI(MBB, MI, MI->getDebugLoc(), TII.get(WebAssembly::EQZ_I32), Tmp) 121 .addReg(Cond); 122 MFI.stackifyVReg(Tmp); 123 Cond = Tmp; 124 Inverted = true; 125 } 126 127 // The br_unless condition has now been inverted. Insert a br_if and 128 // delete the br_unless. 129 assert(Inverted); 130 BuildMI(MBB, MI, MI->getDebugLoc(), TII.get(WebAssembly::BR_IF)) 131 .add(MI->getOperand(0)) 132 .addReg(Cond); 133 MBB.erase(MI); 134 } 135 } 136 137 return true; 138} 139