LLVM 23.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 if (Mask & M)
108 // We've already seen this register and are planning on collapsing it
109 // into a MOVEM. This cannot be done twice for the same register in the
110 // same MOVEM, so bail out now.
111 return false;
112 UpdateType Type = classifyUpdateByMask(M);
113 if (Type == Intermixed)
114 return false;
115 if (Start == INT_MIN) {
116 Start = Stop = O;
117 updateMask(M);
118 return true;
119 } else if (Type == Descending && O == Start - 4) {
120 Start -= 4;
121 updateMask(M);
122 return true;
123 } else if (Type == Ascending && O == Stop + 4) {
124 Stop += 4;
125 updateMask(M);
126 return true;
127 }
128
129 return false;
130 }
131
132 int getFinalOffset() const {
133 assert(
134 Start != INT_MIN &&
135 "MOVEM in control mode should increment the address in each iteration");
136 return Start;
137 }
138
139 bool updateMask(unsigned Value) {
140 assert(isUInt<16>(Value) && "Mask must fit 16 bit");
141 assert(!(Value & Mask) &&
142 "This is weird, there should be no intersections");
143 Mask |= Value;
144 return true;
145 }
146
147 void setLoad() { Access = AccessTy::Load; }
148 void setStore() { Access = AccessTy::Store; }
149
150 bool isLoad() const { return Access == AccessTy::Load; }
151 bool isStore() const { return Access == AccessTy::Store; }
152};
153
154/// This Pass first walks through all the MOVEM instructions
155/// that are chained together and record each of the
156/// instruction's properties like register mask and data
157/// access type into a `MOVEState` instance.
158/// Then we perform reduction / collapsing on this `MOVEMState`
159/// representation before creating a new `MOVEM` instruction
160/// based on the collapsed result, as well as removing
161/// redundant `MOVEM` instructions.
162class M68kCollapseMOVEM : public MachineFunctionPass {
163public:
164 static char ID;
165
166 const M68kSubtarget *STI;
167 const M68kInstrInfo *TII;
168 const M68kRegisterInfo *TRI;
169 const M68kMachineFunctionInfo *MFI;
170 const M68kFrameLowering *FL;
171
172 M68kCollapseMOVEM() : MachineFunctionPass(ID) {}
173
174 void Finish(MachineBasicBlock &MBB, MOVEMState &State) {
175 auto MI = State.begin();
176 auto End = State.end();
177 DebugLoc DL = MI->getDebugLoc();
178
179 // No need to delete then add a single instruction
180 if (std::next(MI) == End) {
181 State = MOVEMState();
182 return;
183 }
184
185 // Delete all the MOVEM instruction till the end
186 while (MI != End) {
187 auto Next = std::next(MI);
188 MBB.erase(MI);
189 MI = Next;
190 }
191
192 // Add a unified one
193 if (State.isLoad()) {
194 BuildMI(MBB, End, DL, TII->get(M68k::MOVM32mp))
195 .addImm(State.getMask())
196 .addImm(State.getFinalOffset())
197 .addReg(State.getBase());
198 } else {
199 BuildMI(MBB, End, DL, TII->get(M68k::MOVM32pm))
200 .addImm(State.getFinalOffset())
201 .addReg(State.getBase())
202 .addImm(State.getMask());
203 }
204
205 State = MOVEMState();
206 }
207
209 MOVEMState &State, unsigned Mask, int Offset, unsigned Reg,
210 bool IsStore = false) {
211 if (State.hasBase()) {
212 // If current Type, Reg, Offset and Mask is in proper order then
213 // merge in the state
214 MOVEMState Temp = State;
215 if (State.isStore() == IsStore && State.getBase() == Reg &&
216 State.update(Offset, Mask)) {
217 return true;
218 // Otherwise we Finish processing of the current MOVEM sequance and
219 // start a new one
220 } else {
221 State = Temp;
222 State.setEnd(MI);
223 Finish(MBB, State);
224 return ProcessMI(MBB, MI, State, Mask, Offset, Reg, IsStore);
225 }
226 // If this is the first instruction is sequance then initialize the State
227 } else if (Reg == TRI->getStackRegister() ||
228 Reg == TRI->getBaseRegister() ||
229 Reg == TRI->getFrameRegister(*MBB.getParent())) {
230 State.setBegin(MI);
231 State.setBase(Reg);
232 State.update(Offset, Mask);
233 IsStore ? State.setStore() : State.setLoad();
234 return true;
235 }
236 return false;
237 }
238
239 bool runOnMachineFunction(MachineFunction &MF) override {
240 STI = &MF.getSubtarget<M68kSubtarget>();
241 TII = STI->getInstrInfo();
242 TRI = STI->getRegisterInfo();
244 FL = STI->getFrameLowering();
245
246 bool Modified = false;
247
248 MOVEMState State;
249
250 unsigned Mask = 0;
251 unsigned Reg = 0;
252 int Offset = 0;
253
254 for (auto &MBB : MF) {
255 auto MI = MBB.begin(), E = MBB.end();
256 while (MI != E) {
257 // Processing might change current instruction, save next first
258 auto NMI = std::next(MI);
259 switch (MI->getOpcode()) {
260 default:
261 if (State.hasBase()) {
262 State.setEnd(MI);
263 Finish(MBB, State);
264 Modified = true;
265 }
266 break;
267 case M68k::MOVM32jm:
268 Mask = MI->getOperand(1).getImm();
269 Reg = MI->getOperand(0).getReg();
270 Offset = 0;
271 Modified |= ProcessMI(MBB, MI, State, Mask, Offset, Reg, true);
272 break;
273 case M68k::MOVM32pm:
274 Mask = MI->getOperand(2).getImm();
275 Reg = MI->getOperand(1).getReg();
276 Offset = MI->getOperand(0).getImm();
277 Modified |= ProcessMI(MBB, MI, State, Mask, Offset, Reg, true);
278 break;
279 case M68k::MOVM32mj:
280 Mask = MI->getOperand(0).getImm();
281 Reg = MI->getOperand(1).getReg();
282 Offset = 0;
283 Modified |= ProcessMI(MBB, MI, State, Mask, Offset, Reg, false);
284 break;
285 case M68k::MOVM32mp:
286 Mask = MI->getOperand(0).getImm();
287 Reg = MI->getOperand(2).getReg();
288 Offset = MI->getOperand(1).getImm();
289 Modified |= ProcessMI(MBB, MI, State, Mask, Offset, Reg, false);
290 break;
291 }
292 MI = NMI;
293 }
294
295 if (State.hasBase()) {
296 State.setEnd(MI);
297 Finish(MBB, State);
298 }
299 }
300
301 return Modified;
302 }
303};
304
305char M68kCollapseMOVEM::ID = 0;
306} // anonymous namespace.
307
308INITIALIZE_PASS(M68kCollapseMOVEM, DEBUG_TYPE, PASS_NAME, false, false)
309
310/// Returns an instance of the pseudo instruction expansion pass.
312 return new M68kCollapseMOVEM();
313}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static bool isLoad(int Opcode)
static bool isStore(int Opcode)
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
DXIL Resource Access
#define DEBUG_TYPE
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
static std::pair< Value *, APInt > getMask(Value *WideMask, unsigned Factor, ElementCount LeafValueEC)
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,...
Register Reg
Register const TargetRegisterInfo * TRI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
#define PASS_NAME
A debug info location.
Definition DebugLoc.h:123
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
const M68kInstrInfo * getInstrInfo() const override
const M68kRegisterInfo * getRegisterInfo() const override
const M68kFrameLowering * getFrameLowering() const override
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
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:75
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 Types.h:26
@ Offset
Definition DWP.cpp:532
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.
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:189
FunctionAddr VTableAddr Next
Definition InstrProf.h:141