236 lines · cpp
1//===-- WebAssemblyInstrInfo.cpp - WebAssembly Instruction Information ----===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file contains the WebAssembly implementation of the11/// TargetInstrInfo class.12///13//===----------------------------------------------------------------------===//14 15#include "WebAssemblyInstrInfo.h"16#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"17#include "WebAssembly.h"18#include "WebAssemblyMachineFunctionInfo.h"19#include "WebAssemblySubtarget.h"20#include "WebAssemblyUtilities.h"21#include "llvm/CodeGen/MachineFrameInfo.h"22#include "llvm/CodeGen/MachineInstrBuilder.h"23#include "llvm/CodeGen/MachineMemOperand.h"24#include "llvm/CodeGen/MachineRegisterInfo.h"25using namespace llvm;26 27#define DEBUG_TYPE "wasm-instr-info"28 29#define GET_INSTRINFO_CTOR_DTOR30#include "WebAssemblyGenInstrInfo.inc"31 32// defines WebAssembly::getNamedOperandIdx33#define GET_INSTRINFO_NAMED_OPS34#include "WebAssemblyGenInstrInfo.inc"35 36WebAssemblyInstrInfo::WebAssemblyInstrInfo(const WebAssemblySubtarget &STI)37 : WebAssemblyGenInstrInfo(STI, RI, WebAssembly::ADJCALLSTACKDOWN,38 WebAssembly::ADJCALLSTACKUP,39 WebAssembly::CATCHRET),40 RI(STI.getTargetTriple()) {}41 42bool WebAssemblyInstrInfo::isReMaterializableImpl(43 const MachineInstr &MI) const {44 switch (MI.getOpcode()) {45 case WebAssembly::CONST_I32:46 case WebAssembly::CONST_I64:47 case WebAssembly::CONST_F32:48 case WebAssembly::CONST_F64:49 // TargetInstrInfo::isReMaterializableImpl misses these50 // because of the ARGUMENTS implicit def, so we manualy override it here.51 return true;52 default:53 return TargetInstrInfo::isReMaterializableImpl(MI);54 }55}56 57void WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock &MBB,58 MachineBasicBlock::iterator I,59 const DebugLoc &DL, Register DestReg,60 Register SrcReg, bool KillSrc,61 bool RenamableDest,62 bool RenamableSrc) const {63 // This method is called by post-RA expansion, which expects only pregs to64 // exist. However we need to handle both here.65 auto &MRI = MBB.getParent()->getRegInfo();66 const TargetRegisterClass *RC =67 DestReg.isVirtual()68 ? MRI.getRegClass(DestReg)69 : MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(DestReg);70 71 unsigned CopyOpcode = WebAssembly::getCopyOpcodeForRegClass(RC);72 73 BuildMI(MBB, I, DL, get(CopyOpcode), DestReg)74 .addReg(SrcReg, KillSrc ? RegState::Kill : 0);75}76 77MachineInstr *WebAssemblyInstrInfo::commuteInstructionImpl(78 MachineInstr &MI, bool NewMI, unsigned OpIdx1, unsigned OpIdx2) const {79 // If the operands are stackified, we can't reorder them.80 WebAssemblyFunctionInfo &MFI =81 *MI.getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>();82 if (MFI.isVRegStackified(MI.getOperand(OpIdx1).getReg()) ||83 MFI.isVRegStackified(MI.getOperand(OpIdx2).getReg()))84 return nullptr;85 86 // Otherwise use the default implementation.87 return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2);88}89 90// Branch analysis.91bool WebAssemblyInstrInfo::analyzeBranch(MachineBasicBlock &MBB,92 MachineBasicBlock *&TBB,93 MachineBasicBlock *&FBB,94 SmallVectorImpl<MachineOperand> &Cond,95 bool /*AllowModify*/) const {96 const auto &MFI = *MBB.getParent()->getInfo<WebAssemblyFunctionInfo>();97 // WebAssembly has control flow that doesn't have explicit branches or direct98 // fallthrough (e.g. try/catch), which can't be modeled by analyzeBranch. It99 // is created after CFGStackify.100 if (MFI.isCFGStackified())101 return true;102 103 bool HaveCond = false;104 for (MachineInstr &MI : MBB.terminators()) {105 switch (MI.getOpcode()) {106 default:107 // Unhandled instruction; bail out.108 return true;109 case WebAssembly::BR_IF:110 if (HaveCond)111 return true;112 Cond.push_back(MachineOperand::CreateImm(true));113 Cond.push_back(MI.getOperand(1));114 TBB = MI.getOperand(0).getMBB();115 HaveCond = true;116 break;117 case WebAssembly::BR_UNLESS:118 if (HaveCond)119 return true;120 Cond.push_back(MachineOperand::CreateImm(false));121 Cond.push_back(MI.getOperand(1));122 TBB = MI.getOperand(0).getMBB();123 HaveCond = true;124 break;125 case WebAssembly::BR:126 if (!HaveCond)127 TBB = MI.getOperand(0).getMBB();128 else129 FBB = MI.getOperand(0).getMBB();130 break;131 }132 if (MI.isBarrier())133 break;134 }135 136 return false;137}138 139unsigned WebAssemblyInstrInfo::removeBranch(MachineBasicBlock &MBB,140 int *BytesRemoved) const {141 assert(!BytesRemoved && "code size not handled");142 143 MachineBasicBlock::instr_iterator I = MBB.instr_end();144 unsigned Count = 0;145 146 while (I != MBB.instr_begin()) {147 --I;148 if (I->isDebugInstr())149 continue;150 if (!I->isTerminator())151 break;152 // Remove the branch.153 I->eraseFromParent();154 I = MBB.instr_end();155 ++Count;156 }157 158 return Count;159}160 161unsigned WebAssemblyInstrInfo::insertBranch(162 MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,163 ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {164 assert(!BytesAdded && "code size not handled");165 166 if (Cond.empty()) {167 if (!TBB)168 return 0;169 170 BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(TBB);171 return 1;172 }173 174 assert(Cond.size() == 2 && "Expected a flag and a successor block");175 176 if (Cond[0].getImm())177 BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]);178 else179 BuildMI(&MBB, DL, get(WebAssembly::BR_UNLESS)).addMBB(TBB).add(Cond[1]);180 if (!FBB)181 return 1;182 183 BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(FBB);184 return 2;185}186 187bool WebAssemblyInstrInfo::reverseBranchCondition(188 SmallVectorImpl<MachineOperand> &Cond) const {189 assert(Cond.size() == 2 && "Expected a flag and a condition expression");190 Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm());191 return false;192}193 194ArrayRef<std::pair<int, const char *>>195WebAssemblyInstrInfo::getSerializableTargetIndices() const {196 static const std::pair<int, const char *> TargetIndices[] = {197 {WebAssembly::TI_LOCAL, "wasm-local"},198 {WebAssembly::TI_GLOBAL_FIXED, "wasm-global-fixed"},199 {WebAssembly::TI_OPERAND_STACK, "wasm-operand-stack"},200 {WebAssembly::TI_GLOBAL_RELOC, "wasm-global-reloc"},201 {WebAssembly::TI_LOCAL_INDIRECT, "wasm-local-indirect"}};202 return ArrayRef(TargetIndices);203}204 205const MachineOperand &206WebAssemblyInstrInfo::getCalleeOperand(const MachineInstr &MI) const {207 return WebAssembly::getCalleeOp(MI);208}209 210// This returns true when the instruction defines a value of a TargetIndex211// operand that can be tracked by offsets. For Wasm, this returns true for only212// local.set/local.tees. This is currently used by LiveDebugValues analysis.213//214// These are not included:215// - In theory we need to add global.set here too, but we don't have global216// indices at this point because they are relocatable and we address them by217// names until linking, so we don't have 'offsets' (which are used to store218// local/global indices) to deal with in LiveDebugValues. And we don't219// associate debug info in values in globals anyway.220// - All other value-producing instructions, i.e. instructions with defs, can221// define values in the Wasm stack, which is represented by TI_OPERAND_STACK222// TargetIndex. But they don't have offset info within the instruction itself,223// and debug info analysis for them is handled separately in224// WebAssemblyDebugFixup pass, so we don't worry about them here.225bool WebAssemblyInstrInfo::isExplicitTargetIndexDef(const MachineInstr &MI,226 int &Index,227 int64_t &Offset) const {228 unsigned Opc = MI.getOpcode();229 if (WebAssembly::isLocalSet(Opc) || WebAssembly::isLocalTee(Opc)) {230 Index = WebAssembly::TI_LOCAL;231 Offset = MI.explicit_uses().begin()->getImm();232 return true;233 }234 return false;235}236