1292915Sdim//===-- WebAssemblyLowerBrUnless.cpp - Lower br_unless --------------------===// 2292915Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6292915Sdim// 7292915Sdim//===----------------------------------------------------------------------===// 8292915Sdim/// 9292915Sdim/// \file 10341825Sdim/// This file lowers br_unless into br_if with an inverted condition. 11292915Sdim/// 12292915Sdim/// br_unless is not currently in the spec, but it's very convenient for LLVM 13292915Sdim/// to use. This pass allows LLVM to use it, for now. 14292915Sdim/// 15292915Sdim//===----------------------------------------------------------------------===// 16292915Sdim 17321369Sdim#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 18292915Sdim#include "WebAssembly.h" 19292915Sdim#include "WebAssemblyMachineFunctionInfo.h" 20292915Sdim#include "WebAssemblySubtarget.h" 21292915Sdim#include "llvm/CodeGen/MachineFunctionPass.h" 22292915Sdim#include "llvm/CodeGen/MachineInstrBuilder.h" 23292915Sdim#include "llvm/Support/Debug.h" 24292915Sdim#include "llvm/Support/raw_ostream.h" 25292915Sdimusing namespace llvm; 26292915Sdim 27292915Sdim#define DEBUG_TYPE "wasm-lower-br_unless" 28292915Sdim 29292915Sdimnamespace { 30292915Sdimclass WebAssemblyLowerBrUnless final : public MachineFunctionPass { 31314564Sdim StringRef getPassName() const override { 32292915Sdim return "WebAssembly Lower br_unless"; 33292915Sdim } 34292915Sdim 35292915Sdim void getAnalysisUsage(AnalysisUsage &AU) const override { 36292915Sdim AU.setPreservesCFG(); 37292915Sdim MachineFunctionPass::getAnalysisUsage(AU); 38292915Sdim } 39292915Sdim 40292915Sdim bool runOnMachineFunction(MachineFunction &MF) override; 41292915Sdim 42292915Sdimpublic: 43292915Sdim static char ID; // Pass identification, replacement for typeid 44292915Sdim WebAssemblyLowerBrUnless() : MachineFunctionPass(ID) {} 45292915Sdim}; 46292915Sdim} // end anonymous namespace 47292915Sdim 48292915Sdimchar WebAssemblyLowerBrUnless::ID = 0; 49341825SdimINITIALIZE_PASS(WebAssemblyLowerBrUnless, DEBUG_TYPE, 50341825Sdim "Lowers br_unless into inverted br_if", false, false) 51341825Sdim 52292915SdimFunctionPass *llvm::createWebAssemblyLowerBrUnless() { 53292915Sdim return new WebAssemblyLowerBrUnless(); 54292915Sdim} 55292915Sdim 56292915Sdimbool WebAssemblyLowerBrUnless::runOnMachineFunction(MachineFunction &MF) { 57341825Sdim LLVM_DEBUG(dbgs() << "********** Lowering br_unless **********\n" 58341825Sdim "********** Function: " 59341825Sdim << MF.getName() << '\n'); 60292915Sdim 61292915Sdim auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 62292915Sdim const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 63292915Sdim auto &MRI = MF.getRegInfo(); 64292915Sdim 65292915Sdim for (auto &MBB : MF) { 66309124Sdim for (auto MII = MBB.begin(); MII != MBB.end();) { 67292915Sdim MachineInstr *MI = &*MII++; 68292915Sdim if (MI->getOpcode() != WebAssembly::BR_UNLESS) 69292915Sdim continue; 70292915Sdim 71360784Sdim Register Cond = MI->getOperand(1).getReg(); 72292915Sdim bool Inverted = false; 73292915Sdim 74292915Sdim // Attempt to invert the condition in place. 75292915Sdim if (MFI.isVRegStackified(Cond)) { 76292915Sdim assert(MRI.hasOneDef(Cond)); 77292915Sdim MachineInstr *Def = MRI.getVRegDef(Cond); 78292915Sdim switch (Def->getOpcode()) { 79309124Sdim using namespace WebAssembly; 80344779Sdim case EQ_I32: 81344779Sdim Def->setDesc(TII.get(NE_I32)); 82344779Sdim Inverted = true; 83344779Sdim break; 84344779Sdim case NE_I32: 85344779Sdim Def->setDesc(TII.get(EQ_I32)); 86344779Sdim Inverted = true; 87344779Sdim break; 88344779Sdim case GT_S_I32: 89344779Sdim Def->setDesc(TII.get(LE_S_I32)); 90344779Sdim Inverted = true; 91344779Sdim break; 92344779Sdim case GE_S_I32: 93344779Sdim Def->setDesc(TII.get(LT_S_I32)); 94344779Sdim Inverted = true; 95344779Sdim break; 96344779Sdim case LT_S_I32: 97344779Sdim Def->setDesc(TII.get(GE_S_I32)); 98344779Sdim Inverted = true; 99344779Sdim break; 100344779Sdim case LE_S_I32: 101344779Sdim Def->setDesc(TII.get(GT_S_I32)); 102344779Sdim Inverted = true; 103344779Sdim break; 104344779Sdim case GT_U_I32: 105344779Sdim Def->setDesc(TII.get(LE_U_I32)); 106344779Sdim Inverted = true; 107344779Sdim break; 108344779Sdim case GE_U_I32: 109344779Sdim Def->setDesc(TII.get(LT_U_I32)); 110344779Sdim Inverted = true; 111344779Sdim break; 112344779Sdim case LT_U_I32: 113344779Sdim Def->setDesc(TII.get(GE_U_I32)); 114344779Sdim Inverted = true; 115344779Sdim break; 116344779Sdim case LE_U_I32: 117344779Sdim Def->setDesc(TII.get(GT_U_I32)); 118344779Sdim Inverted = true; 119344779Sdim break; 120344779Sdim case EQ_I64: 121344779Sdim Def->setDesc(TII.get(NE_I64)); 122344779Sdim Inverted = true; 123344779Sdim break; 124344779Sdim case NE_I64: 125344779Sdim Def->setDesc(TII.get(EQ_I64)); 126344779Sdim Inverted = true; 127344779Sdim break; 128344779Sdim case GT_S_I64: 129344779Sdim Def->setDesc(TII.get(LE_S_I64)); 130344779Sdim Inverted = true; 131344779Sdim break; 132344779Sdim case GE_S_I64: 133344779Sdim Def->setDesc(TII.get(LT_S_I64)); 134344779Sdim Inverted = true; 135344779Sdim break; 136344779Sdim case LT_S_I64: 137344779Sdim Def->setDesc(TII.get(GE_S_I64)); 138344779Sdim Inverted = true; 139344779Sdim break; 140344779Sdim case LE_S_I64: 141344779Sdim Def->setDesc(TII.get(GT_S_I64)); 142344779Sdim Inverted = true; 143344779Sdim break; 144344779Sdim case GT_U_I64: 145344779Sdim Def->setDesc(TII.get(LE_U_I64)); 146344779Sdim Inverted = true; 147344779Sdim break; 148344779Sdim case GE_U_I64: 149344779Sdim Def->setDesc(TII.get(LT_U_I64)); 150344779Sdim Inverted = true; 151344779Sdim break; 152344779Sdim case LT_U_I64: 153344779Sdim Def->setDesc(TII.get(GE_U_I64)); 154344779Sdim Inverted = true; 155344779Sdim break; 156344779Sdim case LE_U_I64: 157344779Sdim Def->setDesc(TII.get(GT_U_I64)); 158344779Sdim Inverted = true; 159344779Sdim break; 160344779Sdim case EQ_F32: 161344779Sdim Def->setDesc(TII.get(NE_F32)); 162344779Sdim Inverted = true; 163344779Sdim break; 164344779Sdim case NE_F32: 165344779Sdim Def->setDesc(TII.get(EQ_F32)); 166344779Sdim Inverted = true; 167344779Sdim break; 168344779Sdim case EQ_F64: 169344779Sdim Def->setDesc(TII.get(NE_F64)); 170344779Sdim Inverted = true; 171344779Sdim break; 172344779Sdim case NE_F64: 173344779Sdim Def->setDesc(TII.get(EQ_F64)); 174344779Sdim Inverted = true; 175344779Sdim break; 176327952Sdim case EQZ_I32: { 177327952Sdim // Invert an eqz by replacing it with its operand. 178327952Sdim Cond = Def->getOperand(1).getReg(); 179327952Sdim Def->eraseFromParent(); 180327952Sdim Inverted = true; 181327952Sdim break; 182327952Sdim } 183344779Sdim default: 184344779Sdim break; 185292915Sdim } 186292915Sdim } 187292915Sdim 188292915Sdim // If we weren't able to invert the condition in place. Insert an 189314564Sdim // instruction to invert it. 190292915Sdim if (!Inverted) { 191360784Sdim Register Tmp = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 192309124Sdim BuildMI(MBB, MI, MI->getDebugLoc(), TII.get(WebAssembly::EQZ_I32), Tmp) 193309124Sdim .addReg(Cond); 194314564Sdim MFI.stackifyVReg(Tmp); 195292915Sdim Cond = Tmp; 196292915Sdim Inverted = true; 197292915Sdim } 198292915Sdim 199292915Sdim // The br_unless condition has now been inverted. Insert a br_if and 200292915Sdim // delete the br_unless. 201292915Sdim assert(Inverted); 202292915Sdim BuildMI(MBB, MI, MI->getDebugLoc(), TII.get(WebAssembly::BR_IF)) 203321369Sdim .add(MI->getOperand(0)) 204309124Sdim .addReg(Cond); 205292915Sdim MBB.erase(MI); 206292915Sdim } 207292915Sdim } 208292915Sdim 209292915Sdim return true; 210292915Sdim} 211