diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-12-20 19:53:05 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-12-20 19:53:05 +0000 |
commit | 0b57cec536236d46e3dba9bd041533462f33dbb7 (patch) | |
tree | 56229dbdbbf76d18580f72f789003db17246c8d9 /contrib/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp | |
parent | 718ef55ec7785aae63f98f8ca05dc07ed399c16d (diff) |
Notes
Diffstat (limited to 'contrib/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp')
-rw-r--r-- | contrib/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp | 399 |
1 files changed, 0 insertions, 399 deletions
diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp deleted file mode 100644 index dbd62179f055..000000000000 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp +++ /dev/null @@ -1,399 +0,0 @@ -//===-- WebAssemblyExplicitLocals.cpp - Make Locals Explicit --------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// This file converts any remaining registers into WebAssembly locals. -/// -/// After register stackification and register coloring, convert non-stackified -/// registers into locals, inserting explicit local.get and local.set -/// instructions. -/// -//===----------------------------------------------------------------------===// - -#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" -#include "WebAssembly.h" -#include "WebAssemblyMachineFunctionInfo.h" -#include "WebAssemblySubtarget.h" -#include "WebAssemblyUtilities.h" -#include "llvm/CodeGen/MachineBlockFrequencyInfo.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/MachineRegisterInfo.h" -#include "llvm/CodeGen/Passes.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" -using namespace llvm; - -#define DEBUG_TYPE "wasm-explicit-locals" - -// A command-line option to disable this pass, and keep implicit locals -// for the purpose of testing with lit/llc ONLY. -// This produces output which is not valid WebAssembly, and is not supported -// by assemblers/disassemblers and other MC based tools. -static cl::opt<bool> WasmDisableExplicitLocals( - "wasm-disable-explicit-locals", cl::Hidden, - cl::desc("WebAssembly: output implicit locals in" - " instruction output for test purposes only."), - cl::init(false)); - -namespace { -class WebAssemblyExplicitLocals final : public MachineFunctionPass { - StringRef getPassName() const override { - return "WebAssembly Explicit Locals"; - } - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesCFG(); - AU.addPreserved<MachineBlockFrequencyInfo>(); - MachineFunctionPass::getAnalysisUsage(AU); - } - - bool runOnMachineFunction(MachineFunction &MF) override; - -public: - static char ID; // Pass identification, replacement for typeid - WebAssemblyExplicitLocals() : MachineFunctionPass(ID) {} -}; -} // end anonymous namespace - -char WebAssemblyExplicitLocals::ID = 0; -INITIALIZE_PASS(WebAssemblyExplicitLocals, DEBUG_TYPE, - "Convert registers to WebAssembly locals", false, false) - -FunctionPass *llvm::createWebAssemblyExplicitLocals() { - return new WebAssemblyExplicitLocals(); -} - -/// Return a local id number for the given register, assigning it a new one -/// if it doesn't yet have one. -static unsigned getLocalId(DenseMap<unsigned, unsigned> &Reg2Local, - unsigned &CurLocal, unsigned Reg) { - auto P = Reg2Local.insert(std::make_pair(Reg, CurLocal)); - if (P.second) - ++CurLocal; - return P.first->second; -} - -/// Get the appropriate drop opcode for the given register class. -static unsigned getDropOpcode(const TargetRegisterClass *RC) { - if (RC == &WebAssembly::I32RegClass) - return WebAssembly::DROP_I32; - if (RC == &WebAssembly::I64RegClass) - return WebAssembly::DROP_I64; - if (RC == &WebAssembly::F32RegClass) - return WebAssembly::DROP_F32; - if (RC == &WebAssembly::F64RegClass) - return WebAssembly::DROP_F64; - if (RC == &WebAssembly::V128RegClass) - return WebAssembly::DROP_V128; - if (RC == &WebAssembly::EXNREFRegClass) - return WebAssembly::DROP_EXNREF; - llvm_unreachable("Unexpected register class"); -} - -/// Get the appropriate local.get opcode for the given register class. -static unsigned getLocalGetOpcode(const TargetRegisterClass *RC) { - if (RC == &WebAssembly::I32RegClass) - return WebAssembly::LOCAL_GET_I32; - if (RC == &WebAssembly::I64RegClass) - return WebAssembly::LOCAL_GET_I64; - if (RC == &WebAssembly::F32RegClass) - return WebAssembly::LOCAL_GET_F32; - if (RC == &WebAssembly::F64RegClass) - return WebAssembly::LOCAL_GET_F64; - if (RC == &WebAssembly::V128RegClass) - return WebAssembly::LOCAL_GET_V128; - if (RC == &WebAssembly::EXNREFRegClass) - return WebAssembly::LOCAL_GET_EXNREF; - llvm_unreachable("Unexpected register class"); -} - -/// Get the appropriate local.set opcode for the given register class. -static unsigned getLocalSetOpcode(const TargetRegisterClass *RC) { - if (RC == &WebAssembly::I32RegClass) - return WebAssembly::LOCAL_SET_I32; - if (RC == &WebAssembly::I64RegClass) - return WebAssembly::LOCAL_SET_I64; - if (RC == &WebAssembly::F32RegClass) - return WebAssembly::LOCAL_SET_F32; - if (RC == &WebAssembly::F64RegClass) - return WebAssembly::LOCAL_SET_F64; - if (RC == &WebAssembly::V128RegClass) - return WebAssembly::LOCAL_SET_V128; - if (RC == &WebAssembly::EXNREFRegClass) - return WebAssembly::LOCAL_SET_EXNREF; - llvm_unreachable("Unexpected register class"); -} - -/// Get the appropriate local.tee opcode for the given register class. -static unsigned getLocalTeeOpcode(const TargetRegisterClass *RC) { - if (RC == &WebAssembly::I32RegClass) - return WebAssembly::LOCAL_TEE_I32; - if (RC == &WebAssembly::I64RegClass) - return WebAssembly::LOCAL_TEE_I64; - if (RC == &WebAssembly::F32RegClass) - return WebAssembly::LOCAL_TEE_F32; - if (RC == &WebAssembly::F64RegClass) - return WebAssembly::LOCAL_TEE_F64; - if (RC == &WebAssembly::V128RegClass) - return WebAssembly::LOCAL_TEE_V128; - if (RC == &WebAssembly::EXNREFRegClass) - return WebAssembly::LOCAL_TEE_EXNREF; - llvm_unreachable("Unexpected register class"); -} - -/// Get the type associated with the given register class. -static MVT typeForRegClass(const TargetRegisterClass *RC) { - if (RC == &WebAssembly::I32RegClass) - return MVT::i32; - if (RC == &WebAssembly::I64RegClass) - return MVT::i64; - if (RC == &WebAssembly::F32RegClass) - return MVT::f32; - if (RC == &WebAssembly::F64RegClass) - return MVT::f64; - if (RC == &WebAssembly::V128RegClass) - return MVT::v16i8; - if (RC == &WebAssembly::EXNREFRegClass) - return MVT::exnref; - llvm_unreachable("unrecognized register class"); -} - -/// Given a MachineOperand of a stackified vreg, return the instruction at the -/// start of the expression tree. -static MachineInstr *findStartOfTree(MachineOperand &MO, - MachineRegisterInfo &MRI, - WebAssemblyFunctionInfo &MFI) { - unsigned Reg = MO.getReg(); - assert(MFI.isVRegStackified(Reg)); - MachineInstr *Def = MRI.getVRegDef(Reg); - - // Find the first stackified use and proceed from there. - for (MachineOperand &DefMO : Def->explicit_uses()) { - if (!DefMO.isReg()) - continue; - return findStartOfTree(DefMO, MRI, MFI); - } - - // If there were no stackified uses, we've reached the start. - return Def; -} - -bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) { - LLVM_DEBUG(dbgs() << "********** Make Locals Explicit **********\n" - "********** Function: " - << MF.getName() << '\n'); - - // Disable this pass if directed to do so. - if (WasmDisableExplicitLocals) - return false; - - bool Changed = false; - MachineRegisterInfo &MRI = MF.getRegInfo(); - WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); - const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); - - // Map non-stackified virtual registers to their local ids. - DenseMap<unsigned, unsigned> Reg2Local; - - // Handle ARGUMENTS first to ensure that they get the designated numbers. - for (MachineBasicBlock::iterator I = MF.begin()->begin(), - E = MF.begin()->end(); - I != E;) { - MachineInstr &MI = *I++; - if (!WebAssembly::isArgument(MI.getOpcode())) - break; - unsigned Reg = MI.getOperand(0).getReg(); - assert(!MFI.isVRegStackified(Reg)); - Reg2Local[Reg] = static_cast<unsigned>(MI.getOperand(1).getImm()); - MI.eraseFromParent(); - Changed = true; - } - - // Start assigning local numbers after the last parameter. - unsigned CurLocal = static_cast<unsigned>(MFI.getParams().size()); - - // Precompute the set of registers that are unused, so that we can insert - // drops to their defs. - BitVector UseEmpty(MRI.getNumVirtRegs()); - for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I) - UseEmpty[I] = MRI.use_empty(TargetRegisterInfo::index2VirtReg(I)); - - // Visit each instruction in the function. - for (MachineBasicBlock &MBB : MF) { - for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) { - MachineInstr &MI = *I++; - assert(!WebAssembly::isArgument(MI.getOpcode())); - - if (MI.isDebugInstr() || MI.isLabel()) - continue; - - // Replace tee instructions with local.tee. The difference is that tee - // instructions have two defs, while local.tee instructions have one def - // and an index of a local to write to. - if (WebAssembly::isTee(MI.getOpcode())) { - assert(MFI.isVRegStackified(MI.getOperand(0).getReg())); - assert(!MFI.isVRegStackified(MI.getOperand(1).getReg())); - unsigned OldReg = MI.getOperand(2).getReg(); - const TargetRegisterClass *RC = MRI.getRegClass(OldReg); - - // Stackify the input if it isn't stackified yet. - if (!MFI.isVRegStackified(OldReg)) { - unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg); - unsigned NewReg = MRI.createVirtualRegister(RC); - unsigned Opc = getLocalGetOpcode(RC); - BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc), NewReg) - .addImm(LocalId); - MI.getOperand(2).setReg(NewReg); - MFI.stackifyVReg(NewReg); - } - - // Replace the TEE with a LOCAL_TEE. - unsigned LocalId = - getLocalId(Reg2Local, CurLocal, MI.getOperand(1).getReg()); - unsigned Opc = getLocalTeeOpcode(RC); - BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc), - MI.getOperand(0).getReg()) - .addImm(LocalId) - .addReg(MI.getOperand(2).getReg()); - - MI.eraseFromParent(); - Changed = true; - continue; - } - - // Insert local.sets for any defs that aren't stackified yet. Currently - // we handle at most one def. - assert(MI.getDesc().getNumDefs() <= 1); - if (MI.getDesc().getNumDefs() == 1) { - unsigned OldReg = MI.getOperand(0).getReg(); - if (!MFI.isVRegStackified(OldReg)) { - const TargetRegisterClass *RC = MRI.getRegClass(OldReg); - unsigned NewReg = MRI.createVirtualRegister(RC); - auto InsertPt = std::next(MI.getIterator()); - if (MI.getOpcode() == WebAssembly::IMPLICIT_DEF) { - MI.eraseFromParent(); - Changed = true; - continue; - } - if (UseEmpty[TargetRegisterInfo::virtReg2Index(OldReg)]) { - unsigned Opc = getDropOpcode(RC); - MachineInstr *Drop = - BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc)) - .addReg(NewReg); - // After the drop instruction, this reg operand will not be used - Drop->getOperand(0).setIsKill(); - } else { - unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg); - unsigned Opc = getLocalSetOpcode(RC); - BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc)) - .addImm(LocalId) - .addReg(NewReg); - } - MI.getOperand(0).setReg(NewReg); - // This register operand of the original instruction is now being used - // by the inserted drop or local.set instruction, so make it not dead - // yet. - MI.getOperand(0).setIsDead(false); - MFI.stackifyVReg(NewReg); - Changed = true; - } - } - - // Insert local.gets for any uses that aren't stackified yet. - MachineInstr *InsertPt = &MI; - for (MachineOperand &MO : reverse(MI.explicit_uses())) { - if (!MO.isReg()) - continue; - - unsigned OldReg = MO.getReg(); - - // Inline asm may have a def in the middle of the operands. Our contract - // with inline asm register operands is to provide local indices as - // immediates. - if (MO.isDef()) { - assert(MI.isInlineAsm()); - unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg); - // If this register operand is tied to another operand, we can't - // change it to an immediate. Untie it first. - MI.untieRegOperand(MI.getOperandNo(&MO)); - MO.ChangeToImmediate(LocalId); - continue; - } - - // If we see a stackified register, prepare to insert subsequent - // local.gets before the start of its tree. - if (MFI.isVRegStackified(OldReg)) { - InsertPt = findStartOfTree(MO, MRI, MFI); - continue; - } - - // Our contract with inline asm register operands is to provide local - // indices as immediates. - if (MI.isInlineAsm()) { - unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg); - // Untie it first if this reg operand is tied to another operand. - MI.untieRegOperand(MI.getOperandNo(&MO)); - MO.ChangeToImmediate(LocalId); - continue; - } - - // Insert a local.get. - unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg); - const TargetRegisterClass *RC = MRI.getRegClass(OldReg); - unsigned NewReg = MRI.createVirtualRegister(RC); - unsigned Opc = getLocalGetOpcode(RC); - InsertPt = - BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc), NewReg) - .addImm(LocalId); - MO.setReg(NewReg); - MFI.stackifyVReg(NewReg); - Changed = true; - } - - // Coalesce and eliminate COPY instructions. - if (WebAssembly::isCopy(MI.getOpcode())) { - MRI.replaceRegWith(MI.getOperand(1).getReg(), - MI.getOperand(0).getReg()); - MI.eraseFromParent(); - Changed = true; - } - } - } - - // Define the locals. - // TODO: Sort the locals for better compression. - MFI.setNumLocals(CurLocal - MFI.getParams().size()); - for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I) { - unsigned Reg = TargetRegisterInfo::index2VirtReg(I); - auto RL = Reg2Local.find(Reg); - if (RL == Reg2Local.end() || RL->second < MFI.getParams().size()) - continue; - - MFI.setLocal(RL->second - MFI.getParams().size(), - typeForRegClass(MRI.getRegClass(Reg))); - Changed = true; - } - -#ifndef NDEBUG - // Assert that all registers have been stackified at this point. - for (const MachineBasicBlock &MBB : MF) { - for (const MachineInstr &MI : MBB) { - if (MI.isDebugInstr() || MI.isLabel()) - continue; - for (const MachineOperand &MO : MI.explicit_operands()) { - assert( - (!MO.isReg() || MRI.use_empty(MO.getReg()) || - MFI.isVRegStackified(MO.getReg())) && - "WebAssemblyExplicitLocals failed to stackify a register operand"); - } - } - } -#endif - - return Changed; -} |