LLVM 19.0.0git
M68kCollapseMOVEMPass.cpp
Go to the documentation of this file.
1//===-- M68kCollapseMOVEMPass.cpp - Expand MOVEM pass -----------*- C++ -*-===//
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-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// `MOVEM` is an instruction that moves multiple registers a time according to
11/// the given mask. Thus sometimes it's pretty expensive.
12/// This file contains a pass that collapses sequential MOVEM instructions into
13/// a single one.
14///
15//===----------------------------------------------------------------------===//
16
17#include "M68k.h"
18#include "M68kFrameLowering.h"
19#include "M68kInstrInfo.h"
20#include "M68kMachineFunction.h"
21#include "M68kSubtarget.h"
22
27#include "llvm/IR/GlobalValue.h"
29
30using namespace llvm;
31
32#define DEBUG_TYPE "m68k-collapse-movem"
33#define PASS_NAME "M68k MOVEM collapser pass"
34
35namespace {
36
37enum UpdateType { Ascending, Descending, Intermixed };
38
39/// An abtraction of the MOVEM chain currently processing
40class MOVEMState {
43
44 unsigned Base;
45
46 int Start;
47 int Stop;
48
49 unsigned Mask;
50
51 enum class AccessTy { None, Load, Store };
52 AccessTy Access;
53
54public:
55 MOVEMState()
56 : Begin(nullptr), End(nullptr), Base(0), Start(INT_MIN), Stop(INT_MAX),
57 Mask(0), Access(AccessTy::None) {}
58
59 void setBegin(MachineBasicBlock::iterator &MI) {
60 assert(Begin == nullptr);
61 Begin = MI;
62 }
63
64 void setEnd(MachineBasicBlock::iterator &MI) {
65 assert(End == nullptr);
66 End = MI;
67 }
68
69 bool hasBase() const { return Base != 0; }
70
71 unsigned getBase() const {
72 assert(Base);
73 return Base;
74 }
75
77 assert(Begin != nullptr);
78 return Begin;
79 }
80
82 assert(End != nullptr);
83 return End;
84 }
85
86 unsigned getMask() const { return Mask; }
87
88 void setBase(int Value) {
89 assert(!hasBase());
90 Base = Value;
91 }
92
93 // You need to call this before Mask update
94 UpdateType classifyUpdateByMask(unsigned NewMask) const {
95 assert(NewMask && "Mask needs to select at least one register");
96
97 if (NewMask > Mask) {
98 return Ascending;
99 } else if (NewMask < Mask) {
100 return Descending;
101 }
102
103 return Intermixed;
104 }
105
106 bool update(int O, int M) {
107 UpdateType Type = classifyUpdateByMask(M);
108 if (Type == Intermixed)
109 return false;
110 if (Start == INT_MIN) {
111 Start = Stop = O;
112 updateMask(M);
113 return true;
114 } else if (Type == Descending && O == Start - 4) {
115 Start -= 4;
116 updateMask(M);
117 return true;
118 } else if (Type == Ascending && O == Stop + 4) {
119 Stop += 4;
120 updateMask(M);
121 return true;
122 }
123
124 return false;
125 }
126
127 int getFinalOffset() const {
128 assert(
129 Start != INT_MIN &&
130 "MOVEM in control mode should increment the address in each iteration");
131 return Start;
132 }
133
134 bool updateMask(unsigned Value) {
135 assert(isUInt<16>(Value) && "Mask must fit 16 bit");
136 assert(!(Value & Mask) &&
137 "This is weird, there should be no intersections");
138 Mask |= Value;
139 return true;
140 }
141
142 void setLoad() { Access = AccessTy::Load; }
143 void setStore() { Access = AccessTy::Store; }
144
145 bool isLoad() const { return Access == AccessTy::Load; }
146 bool isStore() const { return Access == AccessTy::Store; }
147};
148
149/// This Pass first walks through all the MOVEM instructions
150/// that are chained together and record each of the
151/// instruction's properties like register mask and data
152/// access type into a `MOVEState` instance.
153/// Then we perform reduction / collapsing on this `MOVEMState`
154/// representation before creating a new `MOVEM` instruction
155/// based on the collapsed result, as well as removing
156/// redundant `MOVEM` instructions.
157class M68kCollapseMOVEM : public MachineFunctionPass {
158public:
159 static char ID;
160
161 const M68kSubtarget *STI;
162 const M68kInstrInfo *TII;
163 const M68kRegisterInfo *TRI;
164 const M68kMachineFunctionInfo *MFI;
165 const M68kFrameLowering *FL;
166
167 M68kCollapseMOVEM() : MachineFunctionPass(ID) {}
168
169 void Finish(MachineBasicBlock &MBB, MOVEMState &State) {
170 auto MI = State.begin();
171 auto End = State.end();
172 DebugLoc DL = MI->getDebugLoc();
173
174 // No need to delete then add a single instruction
175 if (std::next(MI) == End) {
176 State = MOVEMState();
177 return;
178 }
179
180 // Delete all the MOVEM instruction till the end
181 while (MI != End) {
182 auto Next = std::next(MI);
183 MBB.erase(MI);
184 MI = Next;
185 }
186
187 // Add a unified one
188 if (State.isLoad()) {
189 BuildMI(MBB, End, DL, TII->get(M68k::MOVM32mp))
190 .addImm(State.getMask())
191 .addImm(State.getFinalOffset())
192 .addReg(State.getBase());
193 } else {
194 BuildMI(MBB, End, DL, TII->get(M68k::MOVM32pm))
195 .addImm(State.getFinalOffset())
196 .addReg(State.getBase())
197 .addImm(State.getMask());
198 }
199
200 State = MOVEMState();
201 }
202
204 MOVEMState &State, unsigned Mask, int Offset, unsigned Reg,
205 bool IsStore = false) {
206 if (State.hasBase()) {
207 // If current Type, Reg, Offset and Mask is in proper order then
208 // merge in the state
209 MOVEMState Temp = State;
210 if (State.isStore() == IsStore && State.getBase() == Reg &&
211 State.update(Offset, Mask)) {
212 return true;
213 // Otherwise we Finish processing of the current MOVEM sequance and
214 // start a new one
215 } else {
216 State = Temp;
217 State.setEnd(MI);
218 Finish(MBB, State);
219 return ProcessMI(MBB, MI, State, Mask, Offset, Reg, IsStore);
220 }
221 // If this is the first instruction is sequance then initialize the State
222 } else if (Reg == TRI->getStackRegister() ||
223 Reg == TRI->getBaseRegister() ||
224 Reg == TRI->getFrameRegister(*MBB.getParent())) {
225 State.setBegin(MI);
226 State.setBase(Reg);
227 State.update(Offset, Mask);
228 IsStore ? State.setStore() : State.setLoad();
229 return true;
230 }
231 return false;
232 }
233
234 bool runOnMachineFunction(MachineFunction &MF) override {
235 STI = &MF.getSubtarget<M68kSubtarget>();
236 TII = STI->getInstrInfo();
237 TRI = STI->getRegisterInfo();
239 FL = STI->getFrameLowering();
240
241 bool Modified = false;
242
243 MOVEMState State;
244
245 unsigned Mask = 0;
246 unsigned Reg = 0;
247 int Offset = 0;
248
249 for (auto &MBB : MF) {
250 auto MI = MBB.begin(), E = MBB.end();
251 while (MI != E) {
252 // Processing might change current instruction, save next first
253 auto NMI = std::next(MI);
254 switch (MI->getOpcode()) {
255 default:
256 if (State.hasBase()) {
257 State.setEnd(MI);
258 Finish(MBB, State);
259 Modified = true;
260 }
261 break;
262 case M68k::MOVM32jm:
263 Mask = MI->getOperand(1).getImm();
264 Reg = MI->getOperand(0).getReg();
265 Offset = 0;
266 Modified |= ProcessMI(MBB, MI, State, Mask, Offset, Reg, true);
267 break;
268 case M68k::MOVM32pm:
269 Mask = MI->getOperand(2).getImm();
270 Reg = MI->getOperand(1).getReg();
271 Offset = MI->getOperand(0).getImm();
272 Modified |= ProcessMI(MBB, MI, State, Mask, Offset, Reg, true);
273 break;
274 case M68k::MOVM32mj:
275 Mask = MI->getOperand(0).getImm();
276 Reg = MI->getOperand(1).getReg();
277 Offset = 0;
278 Modified |= ProcessMI(MBB, MI, State, Mask, Offset, Reg, false);
279 break;
280 case M68k::MOVM32mp:
281 Mask = MI->getOperand(0).getImm();
282 Reg = MI->getOperand(2).getReg();
283 Offset = MI->getOperand(1).getImm();
284 Modified |= ProcessMI(MBB, MI, State, Mask, Offset, Reg, false);
285 break;
286 }
287 MI = NMI;
288 }
289
290 if (State.hasBase()) {
291 State.setEnd(MI);
292 Finish(MBB, State);
293 }
294 }
295
296 return Modified;
297 }
298};
299
300char M68kCollapseMOVEM::ID = 0;
301} // anonymous namespace.
302
303INITIALIZE_PASS(M68kCollapseMOVEM, DEBUG_TYPE, PASS_NAME, false, false)
304
305/// Returns an instance of the pseudo instruction expansion pass.
307 return new M68kCollapseMOVEM();
308}
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static bool isLoad(int Opcode)
static bool isStore(int Opcode)
bool End
Definition: ELF_riscv.cpp:480
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define PASS_NAME
#define DEBUG_TYPE
This file contains the M68k declaration of TargetFrameLowering class.
This file contains the M68k implementation of the TargetInstrInfo class.
This file declares the M68k specific subclass of MachineFunctionInfo.
This file declares the M68k specific subclass of TargetSubtargetInfo.
This file contains the entry points for global functions defined in the M68k target library,...
unsigned const TargetRegisterInfo * TRI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
@ None
A debug info location.
Definition: DebugLoc.h:33
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:311
const M68kInstrInfo * getInstrInfo() const override
const M68kRegisterInfo * getRegisterInfo() const override
const M68kFrameLowering * getFrameLowering() const override
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
LLVM Value Representation.
Definition: Value.h:74
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:456
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
FunctionPass * createM68kCollapseMOVEMPass()
Finds sequential MOVEM instruction and collapse them into a single one.