Path: blob/main/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp
35266 views
//===-- WebAssemblyInstrInfo.cpp - WebAssembly Instruction Information ----===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// This file contains the WebAssembly implementation of the10/// TargetInstrInfo class.11///12//===----------------------------------------------------------------------===//1314#include "WebAssemblyInstrInfo.h"15#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"16#include "WebAssembly.h"17#include "WebAssemblyMachineFunctionInfo.h"18#include "WebAssemblySubtarget.h"19#include "WebAssemblyUtilities.h"20#include "llvm/CodeGen/MachineFrameInfo.h"21#include "llvm/CodeGen/MachineInstrBuilder.h"22#include "llvm/CodeGen/MachineMemOperand.h"23#include "llvm/CodeGen/MachineRegisterInfo.h"24using namespace llvm;2526#define DEBUG_TYPE "wasm-instr-info"2728#define GET_INSTRINFO_CTOR_DTOR29#include "WebAssemblyGenInstrInfo.inc"3031// defines WebAssembly::getNamedOperandIdx32#define GET_INSTRINFO_NAMED_OPS33#include "WebAssemblyGenInstrInfo.inc"3435WebAssemblyInstrInfo::WebAssemblyInstrInfo(const WebAssemblySubtarget &STI)36: WebAssemblyGenInstrInfo(WebAssembly::ADJCALLSTACKDOWN,37WebAssembly::ADJCALLSTACKUP,38WebAssembly::CATCHRET),39RI(STI.getTargetTriple()) {}4041bool WebAssemblyInstrInfo::isReallyTriviallyReMaterializable(42const MachineInstr &MI) const {43switch (MI.getOpcode()) {44case WebAssembly::CONST_I32:45case WebAssembly::CONST_I64:46case WebAssembly::CONST_F32:47case WebAssembly::CONST_F64:48// TargetInstrInfo::isReallyTriviallyReMaterializable misses these49// because of the ARGUMENTS implicit def, so we manualy override it here.50return true;51default:52return TargetInstrInfo::isReallyTriviallyReMaterializable(MI);53}54}5556void WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock &MBB,57MachineBasicBlock::iterator I,58const DebugLoc &DL, MCRegister DestReg,59MCRegister SrcReg, bool KillSrc) const {60// This method is called by post-RA expansion, which expects only pregs to61// exist. However we need to handle both here.62auto &MRI = MBB.getParent()->getRegInfo();63const TargetRegisterClass *RC =64Register::isVirtualRegister(DestReg)65? MRI.getRegClass(DestReg)66: MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(DestReg);6768unsigned CopyOpcode = WebAssembly::getCopyOpcodeForRegClass(RC);6970BuildMI(MBB, I, DL, get(CopyOpcode), DestReg)71.addReg(SrcReg, KillSrc ? RegState::Kill : 0);72}7374MachineInstr *WebAssemblyInstrInfo::commuteInstructionImpl(75MachineInstr &MI, bool NewMI, unsigned OpIdx1, unsigned OpIdx2) const {76// If the operands are stackified, we can't reorder them.77WebAssemblyFunctionInfo &MFI =78*MI.getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();79if (MFI.isVRegStackified(MI.getOperand(OpIdx1).getReg()) ||80MFI.isVRegStackified(MI.getOperand(OpIdx2).getReg()))81return nullptr;8283// Otherwise use the default implementation.84return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2);85}8687// Branch analysis.88bool WebAssemblyInstrInfo::analyzeBranch(MachineBasicBlock &MBB,89MachineBasicBlock *&TBB,90MachineBasicBlock *&FBB,91SmallVectorImpl<MachineOperand> &Cond,92bool /*AllowModify*/) const {93const auto &MFI = *MBB.getParent()->getInfo<WebAssemblyFunctionInfo>();94// WebAssembly has control flow that doesn't have explicit branches or direct95// fallthrough (e.g. try/catch), which can't be modeled by analyzeBranch. It96// is created after CFGStackify.97if (MFI.isCFGStackified())98return true;99100bool HaveCond = false;101for (MachineInstr &MI : MBB.terminators()) {102switch (MI.getOpcode()) {103default:104// Unhandled instruction; bail out.105return true;106case WebAssembly::BR_IF:107if (HaveCond)108return true;109Cond.push_back(MachineOperand::CreateImm(true));110Cond.push_back(MI.getOperand(1));111TBB = MI.getOperand(0).getMBB();112HaveCond = true;113break;114case WebAssembly::BR_UNLESS:115if (HaveCond)116return true;117Cond.push_back(MachineOperand::CreateImm(false));118Cond.push_back(MI.getOperand(1));119TBB = MI.getOperand(0).getMBB();120HaveCond = true;121break;122case WebAssembly::BR:123if (!HaveCond)124TBB = MI.getOperand(0).getMBB();125else126FBB = MI.getOperand(0).getMBB();127break;128}129if (MI.isBarrier())130break;131}132133return false;134}135136unsigned WebAssemblyInstrInfo::removeBranch(MachineBasicBlock &MBB,137int *BytesRemoved) const {138assert(!BytesRemoved && "code size not handled");139140MachineBasicBlock::instr_iterator I = MBB.instr_end();141unsigned Count = 0;142143while (I != MBB.instr_begin()) {144--I;145if (I->isDebugInstr())146continue;147if (!I->isTerminator())148break;149// Remove the branch.150I->eraseFromParent();151I = MBB.instr_end();152++Count;153}154155return Count;156}157158unsigned WebAssemblyInstrInfo::insertBranch(159MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,160ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {161assert(!BytesAdded && "code size not handled");162163if (Cond.empty()) {164if (!TBB)165return 0;166167BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(TBB);168return 1;169}170171assert(Cond.size() == 2 && "Expected a flag and a successor block");172173if (Cond[0].getImm())174BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]);175else176BuildMI(&MBB, DL, get(WebAssembly::BR_UNLESS)).addMBB(TBB).add(Cond[1]);177if (!FBB)178return 1;179180BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(FBB);181return 2;182}183184bool WebAssemblyInstrInfo::reverseBranchCondition(185SmallVectorImpl<MachineOperand> &Cond) const {186assert(Cond.size() == 2 && "Expected a flag and a condition expression");187Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm());188return false;189}190191ArrayRef<std::pair<int, const char *>>192WebAssemblyInstrInfo::getSerializableTargetIndices() const {193static const std::pair<int, const char *> TargetIndices[] = {194{WebAssembly::TI_LOCAL, "wasm-local"},195{WebAssembly::TI_GLOBAL_FIXED, "wasm-global-fixed"},196{WebAssembly::TI_OPERAND_STACK, "wasm-operand-stack"},197{WebAssembly::TI_GLOBAL_RELOC, "wasm-global-reloc"},198{WebAssembly::TI_LOCAL_INDIRECT, "wasm-local-indirect"}};199return ArrayRef(TargetIndices);200}201202const MachineOperand &203WebAssemblyInstrInfo::getCalleeOperand(const MachineInstr &MI) const {204return WebAssembly::getCalleeOp(MI);205}206207// This returns true when the instruction defines a value of a TargetIndex208// operand that can be tracked by offsets. For Wasm, this returns true for only209// local.set/local.tees. This is currently used by LiveDebugValues analysis.210//211// These are not included:212// - In theory we need to add global.set here too, but we don't have global213// indices at this point because they are relocatable and we address them by214// names until linking, so we don't have 'offsets' (which are used to store215// local/global indices) to deal with in LiveDebugValues. And we don't216// associate debug info in values in globals anyway.217// - All other value-producing instructions, i.e. instructions with defs, can218// define values in the Wasm stack, which is represented by TI_OPERAND_STACK219// TargetIndex. But they don't have offset info within the instruction itself,220// and debug info analysis for them is handled separately in221// WebAssemblyDebugFixup pass, so we don't worry about them here.222bool WebAssemblyInstrInfo::isExplicitTargetIndexDef(const MachineInstr &MI,223int &Index,224int64_t &Offset) const {225unsigned Opc = MI.getOpcode();226if (WebAssembly::isLocalSet(Opc) || WebAssembly::isLocalTee(Opc)) {227Index = WebAssembly::TI_LOCAL;228Offset = MI.explicit_uses().begin()->getImm();229return true;230}231return false;232}233234235