Path: blob/main/contrib/llvm-project/llvm/lib/Target/M68k/M68kCollapseMOVEMPass.cpp
35266 views
//===-- M68kCollapseMOVEMPass.cpp - Expand MOVEM pass -----------*- C++ -*-===//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/// `MOVEM` is an instruction that moves multiple registers a time according to10/// the given mask. Thus sometimes it's pretty expensive.11/// This file contains a pass that collapses sequential MOVEM instructions into12/// a single one.13///14//===----------------------------------------------------------------------===//1516#include "M68k.h"17#include "M68kFrameLowering.h"18#include "M68kInstrInfo.h"19#include "M68kMachineFunction.h"20#include "M68kSubtarget.h"2122#include "llvm/CodeGen/MachineFunctionPass.h"23#include "llvm/CodeGen/MachineInstrBuilder.h"24#include "llvm/CodeGen/MachineRegisterInfo.h"25#include "llvm/IR/EHPersonalities.h"26#include "llvm/IR/GlobalValue.h"27#include "llvm/Support/MathExtras.h"2829using namespace llvm;3031#define DEBUG_TYPE "m68k-collapse-movem"32#define PASS_NAME "M68k MOVEM collapser pass"3334namespace {3536enum UpdateType { Ascending, Descending, Intermixed };3738/// An abtraction of the MOVEM chain currently processing39class MOVEMState {40MachineBasicBlock::iterator Begin;41MachineBasicBlock::iterator End;4243unsigned Base;4445int Start;46int Stop;4748unsigned Mask;4950enum class AccessTy { None, Load, Store };51AccessTy Access;5253public:54MOVEMState()55: Begin(nullptr), End(nullptr), Base(0), Start(INT_MIN), Stop(INT_MAX),56Mask(0), Access(AccessTy::None) {}5758void setBegin(MachineBasicBlock::iterator &MI) {59assert(Begin == nullptr);60Begin = MI;61}6263void setEnd(MachineBasicBlock::iterator &MI) {64assert(End == nullptr);65End = MI;66}6768bool hasBase() const { return Base != 0; }6970unsigned getBase() const {71assert(Base);72return Base;73}7475MachineBasicBlock::iterator begin() {76assert(Begin != nullptr);77return Begin;78}7980MachineBasicBlock::iterator end() {81assert(End != nullptr);82return End;83}8485unsigned getMask() const { return Mask; }8687void setBase(int Value) {88assert(!hasBase());89Base = Value;90}9192// You need to call this before Mask update93UpdateType classifyUpdateByMask(unsigned NewMask) const {94assert(NewMask && "Mask needs to select at least one register");9596if (NewMask > Mask) {97return Ascending;98} else if (NewMask < Mask) {99return Descending;100}101102return Intermixed;103}104105bool update(int O, int M) {106UpdateType Type = classifyUpdateByMask(M);107if (Type == Intermixed)108return false;109if (Start == INT_MIN) {110Start = Stop = O;111updateMask(M);112return true;113} else if (Type == Descending && O == Start - 4) {114Start -= 4;115updateMask(M);116return true;117} else if (Type == Ascending && O == Stop + 4) {118Stop += 4;119updateMask(M);120return true;121}122123return false;124}125126int getFinalOffset() const {127assert(128Start != INT_MIN &&129"MOVEM in control mode should increment the address in each iteration");130return Start;131}132133bool updateMask(unsigned Value) {134assert(isUInt<16>(Value) && "Mask must fit 16 bit");135assert(!(Value & Mask) &&136"This is weird, there should be no intersections");137Mask |= Value;138return true;139}140141void setLoad() { Access = AccessTy::Load; }142void setStore() { Access = AccessTy::Store; }143144bool isLoad() const { return Access == AccessTy::Load; }145bool isStore() const { return Access == AccessTy::Store; }146};147148/// This Pass first walks through all the MOVEM instructions149/// that are chained together and record each of the150/// instruction's properties like register mask and data151/// access type into a `MOVEState` instance.152/// Then we perform reduction / collapsing on this `MOVEMState`153/// representation before creating a new `MOVEM` instruction154/// based on the collapsed result, as well as removing155/// redundant `MOVEM` instructions.156class M68kCollapseMOVEM : public MachineFunctionPass {157public:158static char ID;159160const M68kSubtarget *STI;161const M68kInstrInfo *TII;162const M68kRegisterInfo *TRI;163const M68kMachineFunctionInfo *MFI;164const M68kFrameLowering *FL;165166M68kCollapseMOVEM() : MachineFunctionPass(ID) {}167168void Finish(MachineBasicBlock &MBB, MOVEMState &State) {169auto MI = State.begin();170auto End = State.end();171DebugLoc DL = MI->getDebugLoc();172173// No need to delete then add a single instruction174if (std::next(MI) == End) {175State = MOVEMState();176return;177}178179// Delete all the MOVEM instruction till the end180while (MI != End) {181auto Next = std::next(MI);182MBB.erase(MI);183MI = Next;184}185186// Add a unified one187if (State.isLoad()) {188BuildMI(MBB, End, DL, TII->get(M68k::MOVM32mp))189.addImm(State.getMask())190.addImm(State.getFinalOffset())191.addReg(State.getBase());192} else {193BuildMI(MBB, End, DL, TII->get(M68k::MOVM32pm))194.addImm(State.getFinalOffset())195.addReg(State.getBase())196.addImm(State.getMask());197}198199State = MOVEMState();200}201202bool ProcessMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,203MOVEMState &State, unsigned Mask, int Offset, unsigned Reg,204bool IsStore = false) {205if (State.hasBase()) {206// If current Type, Reg, Offset and Mask is in proper order then207// merge in the state208MOVEMState Temp = State;209if (State.isStore() == IsStore && State.getBase() == Reg &&210State.update(Offset, Mask)) {211return true;212// Otherwise we Finish processing of the current MOVEM sequance and213// start a new one214} else {215State = Temp;216State.setEnd(MI);217Finish(MBB, State);218return ProcessMI(MBB, MI, State, Mask, Offset, Reg, IsStore);219}220// If this is the first instruction is sequance then initialize the State221} else if (Reg == TRI->getStackRegister() ||222Reg == TRI->getBaseRegister() ||223Reg == TRI->getFrameRegister(*MBB.getParent())) {224State.setBegin(MI);225State.setBase(Reg);226State.update(Offset, Mask);227IsStore ? State.setStore() : State.setLoad();228return true;229}230return false;231}232233bool runOnMachineFunction(MachineFunction &MF) override {234STI = &MF.getSubtarget<M68kSubtarget>();235TII = STI->getInstrInfo();236TRI = STI->getRegisterInfo();237MFI = MF.getInfo<M68kMachineFunctionInfo>();238FL = STI->getFrameLowering();239240bool Modified = false;241242MOVEMState State;243244unsigned Mask = 0;245unsigned Reg = 0;246int Offset = 0;247248for (auto &MBB : MF) {249auto MI = MBB.begin(), E = MBB.end();250while (MI != E) {251// Processing might change current instruction, save next first252auto NMI = std::next(MI);253switch (MI->getOpcode()) {254default:255if (State.hasBase()) {256State.setEnd(MI);257Finish(MBB, State);258Modified = true;259}260break;261case M68k::MOVM32jm:262Mask = MI->getOperand(1).getImm();263Reg = MI->getOperand(0).getReg();264Offset = 0;265Modified |= ProcessMI(MBB, MI, State, Mask, Offset, Reg, true);266break;267case M68k::MOVM32pm:268Mask = MI->getOperand(2).getImm();269Reg = MI->getOperand(1).getReg();270Offset = MI->getOperand(0).getImm();271Modified |= ProcessMI(MBB, MI, State, Mask, Offset, Reg, true);272break;273case M68k::MOVM32mj:274Mask = MI->getOperand(0).getImm();275Reg = MI->getOperand(1).getReg();276Offset = 0;277Modified |= ProcessMI(MBB, MI, State, Mask, Offset, Reg, false);278break;279case M68k::MOVM32mp:280Mask = MI->getOperand(0).getImm();281Reg = MI->getOperand(2).getReg();282Offset = MI->getOperand(1).getImm();283Modified |= ProcessMI(MBB, MI, State, Mask, Offset, Reg, false);284break;285}286MI = NMI;287}288289if (State.hasBase()) {290State.setEnd(MI);291Finish(MBB, State);292}293}294295return Modified;296}297};298299char M68kCollapseMOVEM::ID = 0;300} // anonymous namespace.301302INITIALIZE_PASS(M68kCollapseMOVEM, DEBUG_TYPE, PASS_NAME, false, false)303304/// Returns an instance of the pseudo instruction expansion pass.305FunctionPass *llvm::createM68kCollapseMOVEMPass() {306return new M68kCollapseMOVEM();307}308309310