10b57cec5SDimitry Andric //===-- WebAssemblyInstrInfo.cpp - WebAssembly Instruction Information ----===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// This file contains the WebAssembly implementation of the 110b57cec5SDimitry Andric /// TargetInstrInfo class. 120b57cec5SDimitry Andric /// 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "WebAssemblyInstrInfo.h" 160b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 17480093f4SDimitry Andric #include "WebAssembly.h" 180b57cec5SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h" 190b57cec5SDimitry Andric #include "WebAssemblySubtarget.h" 20*5f757f3fSDimitry Andric #include "WebAssemblyUtilities.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h" 240b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 250b57cec5SDimitry Andric using namespace llvm; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-instr-info" 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric #define GET_INSTRINFO_CTOR_DTOR 300b57cec5SDimitry Andric #include "WebAssemblyGenInstrInfo.inc" 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric // defines WebAssembly::getNamedOperandIdx 330b57cec5SDimitry Andric #define GET_INSTRINFO_NAMED_OPS 340b57cec5SDimitry Andric #include "WebAssemblyGenInstrInfo.inc" 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric WebAssemblyInstrInfo::WebAssemblyInstrInfo(const WebAssemblySubtarget &STI) 370b57cec5SDimitry Andric : WebAssemblyGenInstrInfo(WebAssembly::ADJCALLSTACKDOWN, 380b57cec5SDimitry Andric WebAssembly::ADJCALLSTACKUP, 390b57cec5SDimitry Andric WebAssembly::CATCHRET), 400b57cec5SDimitry Andric RI(STI.getTargetTriple()) {} 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric bool WebAssemblyInstrInfo::isReallyTriviallyReMaterializable( 43fcaf7f86SDimitry Andric const MachineInstr &MI) const { 440b57cec5SDimitry Andric switch (MI.getOpcode()) { 450b57cec5SDimitry Andric case WebAssembly::CONST_I32: 460b57cec5SDimitry Andric case WebAssembly::CONST_I64: 470b57cec5SDimitry Andric case WebAssembly::CONST_F32: 480b57cec5SDimitry Andric case WebAssembly::CONST_F64: 49*5f757f3fSDimitry Andric // TargetInstrInfo::isReallyTriviallyReMaterializable misses these 50*5f757f3fSDimitry Andric // because of the ARGUMENTS implicit def, so we manualy override it here. 510b57cec5SDimitry Andric return true; 520b57cec5SDimitry Andric default: 53*5f757f3fSDimitry Andric return TargetInstrInfo::isReallyTriviallyReMaterializable(MI); 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric } 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric void WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 580b57cec5SDimitry Andric MachineBasicBlock::iterator I, 59480093f4SDimitry Andric const DebugLoc &DL, MCRegister DestReg, 60480093f4SDimitry Andric MCRegister SrcReg, bool KillSrc) const { 610b57cec5SDimitry Andric // This method is called by post-RA expansion, which expects only pregs to 620b57cec5SDimitry Andric // exist. However we need to handle both here. 630b57cec5SDimitry Andric auto &MRI = MBB.getParent()->getRegInfo(); 640b57cec5SDimitry Andric const TargetRegisterClass *RC = 658bcb0991SDimitry Andric Register::isVirtualRegister(DestReg) 660b57cec5SDimitry Andric ? MRI.getRegClass(DestReg) 670b57cec5SDimitry Andric : MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(DestReg); 680b57cec5SDimitry Andric 69753f127fSDimitry Andric unsigned CopyOpcode = WebAssembly::getCopyOpcodeForRegClass(RC); 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric BuildMI(MBB, I, DL, get(CopyOpcode), DestReg) 720b57cec5SDimitry Andric .addReg(SrcReg, KillSrc ? RegState::Kill : 0); 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric MachineInstr *WebAssemblyInstrInfo::commuteInstructionImpl( 760b57cec5SDimitry Andric MachineInstr &MI, bool NewMI, unsigned OpIdx1, unsigned OpIdx2) const { 770b57cec5SDimitry Andric // If the operands are stackified, we can't reorder them. 780b57cec5SDimitry Andric WebAssemblyFunctionInfo &MFI = 790b57cec5SDimitry Andric *MI.getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>(); 800b57cec5SDimitry Andric if (MFI.isVRegStackified(MI.getOperand(OpIdx1).getReg()) || 810b57cec5SDimitry Andric MFI.isVRegStackified(MI.getOperand(OpIdx2).getReg())) 820b57cec5SDimitry Andric return nullptr; 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric // Otherwise use the default implementation. 850b57cec5SDimitry Andric return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2); 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric // Branch analysis. 890b57cec5SDimitry Andric bool WebAssemblyInstrInfo::analyzeBranch(MachineBasicBlock &MBB, 900b57cec5SDimitry Andric MachineBasicBlock *&TBB, 910b57cec5SDimitry Andric MachineBasicBlock *&FBB, 920b57cec5SDimitry Andric SmallVectorImpl<MachineOperand> &Cond, 930b57cec5SDimitry Andric bool /*AllowModify*/) const { 940b57cec5SDimitry Andric const auto &MFI = *MBB.getParent()->getInfo<WebAssemblyFunctionInfo>(); 950b57cec5SDimitry Andric // WebAssembly has control flow that doesn't have explicit branches or direct 960b57cec5SDimitry Andric // fallthrough (e.g. try/catch), which can't be modeled by analyzeBranch. It 970b57cec5SDimitry Andric // is created after CFGStackify. 980b57cec5SDimitry Andric if (MFI.isCFGStackified()) 990b57cec5SDimitry Andric return true; 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric bool HaveCond = false; 1020b57cec5SDimitry Andric for (MachineInstr &MI : MBB.terminators()) { 1030b57cec5SDimitry Andric switch (MI.getOpcode()) { 1040b57cec5SDimitry Andric default: 1050b57cec5SDimitry Andric // Unhandled instruction; bail out. 1060b57cec5SDimitry Andric return true; 1070b57cec5SDimitry Andric case WebAssembly::BR_IF: 1080b57cec5SDimitry Andric if (HaveCond) 1090b57cec5SDimitry Andric return true; 1100b57cec5SDimitry Andric Cond.push_back(MachineOperand::CreateImm(true)); 1110b57cec5SDimitry Andric Cond.push_back(MI.getOperand(1)); 1120b57cec5SDimitry Andric TBB = MI.getOperand(0).getMBB(); 1130b57cec5SDimitry Andric HaveCond = true; 1140b57cec5SDimitry Andric break; 1150b57cec5SDimitry Andric case WebAssembly::BR_UNLESS: 1160b57cec5SDimitry Andric if (HaveCond) 1170b57cec5SDimitry Andric return true; 1180b57cec5SDimitry Andric Cond.push_back(MachineOperand::CreateImm(false)); 1190b57cec5SDimitry Andric Cond.push_back(MI.getOperand(1)); 1200b57cec5SDimitry Andric TBB = MI.getOperand(0).getMBB(); 1210b57cec5SDimitry Andric HaveCond = true; 1220b57cec5SDimitry Andric break; 1230b57cec5SDimitry Andric case WebAssembly::BR: 1240b57cec5SDimitry Andric if (!HaveCond) 1250b57cec5SDimitry Andric TBB = MI.getOperand(0).getMBB(); 1260b57cec5SDimitry Andric else 1270b57cec5SDimitry Andric FBB = MI.getOperand(0).getMBB(); 1280b57cec5SDimitry Andric break; 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric if (MI.isBarrier()) 1310b57cec5SDimitry Andric break; 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric return false; 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric unsigned WebAssemblyInstrInfo::removeBranch(MachineBasicBlock &MBB, 1380b57cec5SDimitry Andric int *BytesRemoved) const { 1390b57cec5SDimitry Andric assert(!BytesRemoved && "code size not handled"); 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric MachineBasicBlock::instr_iterator I = MBB.instr_end(); 1420b57cec5SDimitry Andric unsigned Count = 0; 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric while (I != MBB.instr_begin()) { 1450b57cec5SDimitry Andric --I; 1460b57cec5SDimitry Andric if (I->isDebugInstr()) 1470b57cec5SDimitry Andric continue; 1480b57cec5SDimitry Andric if (!I->isTerminator()) 1490b57cec5SDimitry Andric break; 1500b57cec5SDimitry Andric // Remove the branch. 1510b57cec5SDimitry Andric I->eraseFromParent(); 1520b57cec5SDimitry Andric I = MBB.instr_end(); 1530b57cec5SDimitry Andric ++Count; 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric return Count; 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric unsigned WebAssemblyInstrInfo::insertBranch( 1600b57cec5SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, 1610b57cec5SDimitry Andric ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const { 1620b57cec5SDimitry Andric assert(!BytesAdded && "code size not handled"); 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric if (Cond.empty()) { 1650b57cec5SDimitry Andric if (!TBB) 1660b57cec5SDimitry Andric return 0; 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(TBB); 1690b57cec5SDimitry Andric return 1; 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric assert(Cond.size() == 2 && "Expected a flag and a successor block"); 1730b57cec5SDimitry Andric 174e8d8bef9SDimitry Andric if (Cond[0].getImm()) 1750b57cec5SDimitry Andric BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]); 176e8d8bef9SDimitry Andric else 1770b57cec5SDimitry Andric BuildMI(&MBB, DL, get(WebAssembly::BR_UNLESS)).addMBB(TBB).add(Cond[1]); 1780b57cec5SDimitry Andric if (!FBB) 1790b57cec5SDimitry Andric return 1; 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(FBB); 1820b57cec5SDimitry Andric return 2; 1830b57cec5SDimitry Andric } 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric bool WebAssemblyInstrInfo::reverseBranchCondition( 1860b57cec5SDimitry Andric SmallVectorImpl<MachineOperand> &Cond) const { 1870b57cec5SDimitry Andric assert(Cond.size() == 2 && "Expected a flag and a condition expression"); 1880b57cec5SDimitry Andric Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm()); 1890b57cec5SDimitry Andric return false; 1900b57cec5SDimitry Andric } 191480093f4SDimitry Andric 192480093f4SDimitry Andric ArrayRef<std::pair<int, const char *>> 193480093f4SDimitry Andric WebAssemblyInstrInfo::getSerializableTargetIndices() const { 194480093f4SDimitry Andric static const std::pair<int, const char *> TargetIndices[] = { 1955ffd83dbSDimitry Andric {WebAssembly::TI_LOCAL, "wasm-local"}, 1965ffd83dbSDimitry Andric {WebAssembly::TI_GLOBAL_FIXED, "wasm-global-fixed"}, 1975ffd83dbSDimitry Andric {WebAssembly::TI_OPERAND_STACK, "wasm-operand-stack"}, 198fe6060f1SDimitry Andric {WebAssembly::TI_GLOBAL_RELOC, "wasm-global-reloc"}, 199fe6060f1SDimitry Andric {WebAssembly::TI_LOCAL_INDIRECT, "wasm-local-indirect"}}; 200bdd1243dSDimitry Andric return ArrayRef(TargetIndices); 201480093f4SDimitry Andric } 202fe6060f1SDimitry Andric 203fe6060f1SDimitry Andric const MachineOperand & 204fe6060f1SDimitry Andric WebAssemblyInstrInfo::getCalleeOperand(const MachineInstr &MI) const { 205fe6060f1SDimitry Andric return WebAssembly::getCalleeOp(MI); 206fe6060f1SDimitry Andric } 207bdd1243dSDimitry Andric 208bdd1243dSDimitry Andric // This returns true when the instruction defines a value of a TargetIndex 209bdd1243dSDimitry Andric // operand that can be tracked by offsets. For Wasm, this returns true for only 210bdd1243dSDimitry Andric // local.set/local.tees. This is currently used by LiveDebugValues analysis. 211bdd1243dSDimitry Andric // 212bdd1243dSDimitry Andric // These are not included: 213bdd1243dSDimitry Andric // - In theory we need to add global.set here too, but we don't have global 214bdd1243dSDimitry Andric // indices at this point because they are relocatable and we address them by 215bdd1243dSDimitry Andric // names until linking, so we don't have 'offsets' (which are used to store 216bdd1243dSDimitry Andric // local/global indices) to deal with in LiveDebugValues. And we don't 217bdd1243dSDimitry Andric // associate debug info in values in globals anyway. 218bdd1243dSDimitry Andric // - All other value-producing instructions, i.e. instructions with defs, can 219bdd1243dSDimitry Andric // define values in the Wasm stack, which is represented by TI_OPERAND_STACK 220bdd1243dSDimitry Andric // TargetIndex. But they don't have offset info within the instruction itself, 221bdd1243dSDimitry Andric // and debug info analysis for them is handled separately in 222bdd1243dSDimitry Andric // WebAssemblyDebugFixup pass, so we don't worry about them here. 223bdd1243dSDimitry Andric bool WebAssemblyInstrInfo::isExplicitTargetIndexDef(const MachineInstr &MI, 224bdd1243dSDimitry Andric int &Index, 225bdd1243dSDimitry Andric int64_t &Offset) const { 226bdd1243dSDimitry Andric unsigned Opc = MI.getOpcode(); 227bdd1243dSDimitry Andric if (WebAssembly::isLocalSet(Opc) || WebAssembly::isLocalTee(Opc)) { 228bdd1243dSDimitry Andric Index = WebAssembly::TI_LOCAL; 229bdd1243dSDimitry Andric Offset = MI.explicit_uses().begin()->getImm(); 230bdd1243dSDimitry Andric return true; 231bdd1243dSDimitry Andric } 232bdd1243dSDimitry Andric return false; 233bdd1243dSDimitry Andric } 234