1285163Sdim//===-- WebAssemblyInstrInfo.cpp - WebAssembly Instruction Information ----===// 2285163Sdim// 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 6285163Sdim// 7285163Sdim//===----------------------------------------------------------------------===// 8285163Sdim/// 9285163Sdim/// \file 10341825Sdim/// This file contains the WebAssembly implementation of the 11285163Sdim/// TargetInstrInfo class. 12285163Sdim/// 13285163Sdim//===----------------------------------------------------------------------===// 14285163Sdim 15285163Sdim#include "WebAssemblyInstrInfo.h" 16285163Sdim#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 17360784Sdim#include "WebAssembly.h" 18309124Sdim#include "WebAssemblyMachineFunctionInfo.h" 19285163Sdim#include "WebAssemblySubtarget.h" 20285163Sdim#include "llvm/CodeGen/MachineFrameInfo.h" 21285163Sdim#include "llvm/CodeGen/MachineInstrBuilder.h" 22285163Sdim#include "llvm/CodeGen/MachineMemOperand.h" 23285163Sdim#include "llvm/CodeGen/MachineRegisterInfo.h" 24285163Sdimusing namespace llvm; 25285163Sdim 26285163Sdim#define DEBUG_TYPE "wasm-instr-info" 27285163Sdim 28296417Sdim#define GET_INSTRINFO_CTOR_DTOR 29296417Sdim#include "WebAssemblyGenInstrInfo.inc" 30296417Sdim 31353358Sdim// defines WebAssembly::getNamedOperandIdx 32353358Sdim#define GET_INSTRINFO_NAMED_OPS 33353358Sdim#include "WebAssemblyGenInstrInfo.inc" 34353358Sdim 35285163SdimWebAssemblyInstrInfo::WebAssemblyInstrInfo(const WebAssemblySubtarget &STI) 36296417Sdim : WebAssemblyGenInstrInfo(WebAssembly::ADJCALLSTACKDOWN, 37341825Sdim WebAssembly::ADJCALLSTACKUP, 38341825Sdim WebAssembly::CATCHRET), 39296417Sdim RI(STI.getTargetTriple()) {} 40296417Sdim 41309124Sdimbool WebAssemblyInstrInfo::isReallyTriviallyReMaterializable( 42360784Sdim const MachineInstr &MI, AAResults *AA) const { 43309124Sdim switch (MI.getOpcode()) { 44309124Sdim case WebAssembly::CONST_I32: 45309124Sdim case WebAssembly::CONST_I64: 46309124Sdim case WebAssembly::CONST_F32: 47309124Sdim case WebAssembly::CONST_F64: 48309124Sdim // isReallyTriviallyReMaterializableGeneric misses these because of the 49309124Sdim // ARGUMENTS implicit def, so we manualy override it here. 50309124Sdim return true; 51309124Sdim default: 52309124Sdim return false; 53309124Sdim } 54309124Sdim} 55309124Sdim 56296417Sdimvoid WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 57296417Sdim MachineBasicBlock::iterator I, 58360784Sdim const DebugLoc &DL, MCRegister DestReg, 59360784Sdim MCRegister SrcReg, bool KillSrc) const { 60296417Sdim // This method is called by post-RA expansion, which expects only pregs to 61296417Sdim // exist. However we need to handle both here. 62296417Sdim auto &MRI = MBB.getParent()->getRegInfo(); 63309124Sdim const TargetRegisterClass *RC = 64360784Sdim Register::isVirtualRegister(DestReg) 65309124Sdim ? MRI.getRegClass(DestReg) 66309124Sdim : MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(DestReg); 67296417Sdim 68314564Sdim unsigned CopyOpcode; 69296417Sdim if (RC == &WebAssembly::I32RegClass) 70314564Sdim CopyOpcode = WebAssembly::COPY_I32; 71296417Sdim else if (RC == &WebAssembly::I64RegClass) 72314564Sdim CopyOpcode = WebAssembly::COPY_I64; 73296417Sdim else if (RC == &WebAssembly::F32RegClass) 74314564Sdim CopyOpcode = WebAssembly::COPY_F32; 75296417Sdim else if (RC == &WebAssembly::F64RegClass) 76314564Sdim CopyOpcode = WebAssembly::COPY_F64; 77344779Sdim else if (RC == &WebAssembly::V128RegClass) 78344779Sdim CopyOpcode = WebAssembly::COPY_V128; 79353358Sdim else if (RC == &WebAssembly::EXNREFRegClass) 80353358Sdim CopyOpcode = WebAssembly::COPY_EXNREF; 81296417Sdim else 82296417Sdim llvm_unreachable("Unexpected register class"); 83296417Sdim 84314564Sdim BuildMI(MBB, I, DL, get(CopyOpcode), DestReg) 85296417Sdim .addReg(SrcReg, KillSrc ? RegState::Kill : 0); 86296417Sdim} 87296417Sdim 88344779SdimMachineInstr *WebAssemblyInstrInfo::commuteInstructionImpl( 89344779Sdim MachineInstr &MI, bool NewMI, unsigned OpIdx1, unsigned OpIdx2) const { 90309124Sdim // If the operands are stackified, we can't reorder them. 91309124Sdim WebAssemblyFunctionInfo &MFI = 92309124Sdim *MI.getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>(); 93309124Sdim if (MFI.isVRegStackified(MI.getOperand(OpIdx1).getReg()) || 94309124Sdim MFI.isVRegStackified(MI.getOperand(OpIdx2).getReg())) 95309124Sdim return nullptr; 96309124Sdim 97309124Sdim // Otherwise use the default implementation. 98309124Sdim return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2); 99309124Sdim} 100309124Sdim 101296417Sdim// Branch analysis. 102309124Sdimbool WebAssemblyInstrInfo::analyzeBranch(MachineBasicBlock &MBB, 103296417Sdim MachineBasicBlock *&TBB, 104296417Sdim MachineBasicBlock *&FBB, 105296417Sdim SmallVectorImpl<MachineOperand> &Cond, 106296417Sdim bool /*AllowModify*/) const { 107353358Sdim const auto &MFI = *MBB.getParent()->getInfo<WebAssemblyFunctionInfo>(); 108353358Sdim // WebAssembly has control flow that doesn't have explicit branches or direct 109353358Sdim // fallthrough (e.g. try/catch), which can't be modeled by analyzeBranch. It 110353358Sdim // is created after CFGStackify. 111353358Sdim if (MFI.isCFGStackified()) 112353358Sdim return true; 113353358Sdim 114296417Sdim bool HaveCond = false; 115296417Sdim for (MachineInstr &MI : MBB.terminators()) { 116296417Sdim switch (MI.getOpcode()) { 117296417Sdim default: 118296417Sdim // Unhandled instruction; bail out. 119296417Sdim return true; 120296417Sdim case WebAssembly::BR_IF: 121296417Sdim if (HaveCond) 122296417Sdim return true; 123296417Sdim Cond.push_back(MachineOperand::CreateImm(true)); 124309124Sdim Cond.push_back(MI.getOperand(1)); 125309124Sdim TBB = MI.getOperand(0).getMBB(); 126296417Sdim HaveCond = true; 127296417Sdim break; 128296417Sdim case WebAssembly::BR_UNLESS: 129296417Sdim if (HaveCond) 130296417Sdim return true; 131296417Sdim Cond.push_back(MachineOperand::CreateImm(false)); 132309124Sdim Cond.push_back(MI.getOperand(1)); 133309124Sdim TBB = MI.getOperand(0).getMBB(); 134296417Sdim HaveCond = true; 135296417Sdim break; 136296417Sdim case WebAssembly::BR: 137296417Sdim if (!HaveCond) 138296417Sdim TBB = MI.getOperand(0).getMBB(); 139296417Sdim else 140296417Sdim FBB = MI.getOperand(0).getMBB(); 141296417Sdim break; 142353358Sdim case WebAssembly::BR_ON_EXN: 143353358Sdim if (HaveCond) 144353358Sdim return true; 145353358Sdim Cond.push_back(MachineOperand::CreateImm(true)); 146353358Sdim Cond.push_back(MI.getOperand(2)); 147353358Sdim TBB = MI.getOperand(0).getMBB(); 148353358Sdim HaveCond = true; 149353358Sdim break; 150296417Sdim } 151296417Sdim if (MI.isBarrier()) 152296417Sdim break; 153296417Sdim } 154296417Sdim 155296417Sdim return false; 156296417Sdim} 157296417Sdim 158314564Sdimunsigned WebAssemblyInstrInfo::removeBranch(MachineBasicBlock &MBB, 159314564Sdim int *BytesRemoved) const { 160314564Sdim assert(!BytesRemoved && "code size not handled"); 161314564Sdim 162296417Sdim MachineBasicBlock::instr_iterator I = MBB.instr_end(); 163296417Sdim unsigned Count = 0; 164296417Sdim 165296417Sdim while (I != MBB.instr_begin()) { 166296417Sdim --I; 167341825Sdim if (I->isDebugInstr()) 168296417Sdim continue; 169296417Sdim if (!I->isTerminator()) 170296417Sdim break; 171296417Sdim // Remove the branch. 172296417Sdim I->eraseFromParent(); 173296417Sdim I = MBB.instr_end(); 174296417Sdim ++Count; 175296417Sdim } 176296417Sdim 177296417Sdim return Count; 178296417Sdim} 179296417Sdim 180344779Sdimunsigned WebAssemblyInstrInfo::insertBranch( 181344779Sdim MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, 182344779Sdim ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const { 183314564Sdim assert(!BytesAdded && "code size not handled"); 184314564Sdim 185296417Sdim if (Cond.empty()) { 186296417Sdim if (!TBB) 187296417Sdim return 0; 188296417Sdim 189296417Sdim BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(TBB); 190296417Sdim return 1; 191296417Sdim } 192296417Sdim 193296417Sdim assert(Cond.size() == 2 && "Expected a flag and a successor block"); 194296417Sdim 195353358Sdim MachineFunction &MF = *MBB.getParent(); 196353358Sdim auto &MRI = MF.getRegInfo(); 197353358Sdim bool IsBrOnExn = Cond[1].isReg() && MRI.getRegClass(Cond[1].getReg()) == 198353358Sdim &WebAssembly::EXNREFRegClass; 199353358Sdim 200296417Sdim if (Cond[0].getImm()) { 201353358Sdim if (IsBrOnExn) { 202353358Sdim const char *CPPExnSymbol = MF.createExternalSymbolName("__cpp_exception"); 203353358Sdim BuildMI(&MBB, DL, get(WebAssembly::BR_ON_EXN)) 204353358Sdim .addMBB(TBB) 205353358Sdim .addExternalSymbol(CPPExnSymbol) 206353358Sdim .add(Cond[1]); 207353358Sdim } else 208353358Sdim BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]); 209296417Sdim } else { 210353358Sdim assert(!IsBrOnExn && "br_on_exn does not have a reversed condition"); 211321369Sdim BuildMI(&MBB, DL, get(WebAssembly::BR_UNLESS)).addMBB(TBB).add(Cond[1]); 212296417Sdim } 213296417Sdim if (!FBB) 214296417Sdim return 1; 215296417Sdim 216296417Sdim BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(FBB); 217296417Sdim return 2; 218296417Sdim} 219296417Sdim 220314564Sdimbool WebAssemblyInstrInfo::reverseBranchCondition( 221296417Sdim SmallVectorImpl<MachineOperand> &Cond) const { 222353358Sdim assert(Cond.size() == 2 && "Expected a flag and a condition expression"); 223353358Sdim 224353358Sdim // br_on_exn's condition cannot be reversed 225353358Sdim MachineFunction &MF = *Cond[1].getParent()->getParent()->getParent(); 226353358Sdim auto &MRI = MF.getRegInfo(); 227353358Sdim if (Cond[1].isReg() && 228353358Sdim MRI.getRegClass(Cond[1].getReg()) == &WebAssembly::EXNREFRegClass) 229353358Sdim return true; 230353358Sdim 231296417Sdim Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm()); 232296417Sdim return false; 233296417Sdim} 234360784Sdim 235360784SdimArrayRef<std::pair<int, const char *>> 236360784SdimWebAssemblyInstrInfo::getSerializableTargetIndices() const { 237360784Sdim static const std::pair<int, const char *> TargetIndices[] = { 238360784Sdim {WebAssembly::TI_LOCAL_START, "wasm-local-start"}, 239360784Sdim {WebAssembly::TI_GLOBAL_START, "wasm-global-start"}, 240360784Sdim {WebAssembly::TI_OPERAND_STACK_START, "wasm-operator-stack-start"}}; 241360784Sdim return makeArrayRef(TargetIndices); 242360784Sdim} 243