LLVM 24.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 // Add a unified MOVEM
186 MachineInstrBuilder NewMIB;
187 if (State.isLoad()) {
188 NewMIB = BuildMI(MBB, End, DL, TII->get(M68k::MOVM32mp))
189 .addImm(State.getMask())
190 .addImm(State.getFinalOffset())
191 .addReg(State.getBase());
192 } else {
193 NewMIB = BuildMI(MBB, End, DL, TII->get(M68k::MOVM32pm))
194 .addImm(State.getFinalOffset())
195 .addReg(State.getBase())
196 .addImm(State.getMask());
197 }
198
199 // Delete all the old MOVEM instructions, and copy their implicit defs/uses
200 // over to the new instruction.
201 MachineFunction *MF = MBB.getParent();
202 MachineInstr *NewMI = NewMIB.getInstr();
203 while (MI != NewMI) {
204 auto Next = std::next(MI);
205 NewMI->copyImplicitOps(*MF, *MI);
206 MBB.erase(MI);
207 MI = Next;
208 }
209
210 State = MOVEMState();
211 }
212
214 MOVEMState &State, unsigned Mask, int Offset, unsigned Reg,
215 bool IsStore = false) {
216 if (State.hasBase()) {
217 // If current Type, Reg, Offset and Mask is in proper order then
218 // merge in the state
219 MOVEMState Temp = State;
220 if (State.isStore() == IsStore && State.getBase() == Reg &&
221 State.update(Offset, Mask)) {
222 return true;
223 // Otherwise we Finish processing of the current MOVEM sequance and
224 // start a new one
225 } else {
226 State = Temp;
227 State.setEnd(MI);
228 Finish(MBB, State);
229 return ProcessMI(MBB, MI, State, Mask, Offset, Reg, IsStore);
230 }
231 // If this is the first instruction is sequance then initialize the State
232 } else if (Reg == TRI->getStackRegister() ||
233 Reg == TRI->getBaseRegister() ||
234 Reg == TRI->getFrameRegister(*MBB.getParent())) {
235 State.setBegin(MI);
236 State.setBase(Reg);
237 State.update(Offset, Mask);
238 IsStore ? State.setStore() : State.setLoad();
239 return true;
240 }
241 return false;
242 }
243
244 bool runOnMachineFunction(MachineFunction &MF) override {
245 STI = &MF.getSubtarget<M68kSubtarget>();
246 TII = STI->getInstrInfo();
247 TRI = STI->getRegisterInfo();
249 FL = STI->getFrameLowering();
250
251 bool Modified = false;
252
253 MOVEMState State;
254
255 unsigned Mask = 0;
256 unsigned Reg = 0;
257 int Offset = 0;
258
259 for (auto &MBB : MF) {
260 auto MI = MBB.begin(), E = MBB.end();
261 while (MI != E) {
262 // Processing might change current instruction, save next first
263 auto NMI = std::next(MI);
264 switch (MI->getOpcode()) {
265 default:
266 if (State.hasBase()) {
267 State.setEnd(MI);
268 Finish(MBB, State);
269 Modified = true;
270 }
271 break;
272 case M68k::MOVM32jm:
273 Mask = MI->getOperand(1).getImm();
274 Reg = MI->getOperand(0).getReg();
275 Offset = 0;
276 Modified |= ProcessMI(MBB, MI, State, Mask, Offset, Reg, true);
277 break;
278 case M68k::MOVM32pm:
279 Mask = MI->getOperand(2).getImm();
280 Reg = MI->getOperand(1).getReg();
281 Offset = MI->getOperand(0).getImm();
282 Modified |= ProcessMI(MBB, MI, State, Mask, Offset, Reg, true);
283 break;
284 case M68k::MOVM32mj:
285 Mask = MI->getOperand(0).getImm();
286 Reg = MI->getOperand(1).getReg();
287 Offset = 0;
288 Modified |= ProcessMI(MBB, MI, State, Mask, Offset, Reg, false);
289 break;
290 case M68k::MOVM32mp:
291 Mask = MI->getOperand(0).getImm();
292 Reg = MI->getOperand(2).getReg();
293 Offset = MI->getOperand(1).getImm();
294 Modified |= ProcessMI(MBB, MI, State, Mask, Offset, Reg, false);
295 break;
296 }
297 MI = NMI;
298 }
299
300 if (State.hasBase()) {
301 State.setEnd(MI);
302 Finish(MBB, State);
303 }
304 }
305
306 return Modified;
307 }
308};
309
310char M68kCollapseMOVEM::ID = 0;
311} // anonymous namespace.
312
313INITIALIZE_PASS(M68kCollapseMOVEM, DEBUG_TYPE, PASS_NAME, false, false)
314
315/// Returns an instance of the pseudo instruction expansion pass.
317 return new M68kCollapseMOVEM();
318}
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:126
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 & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
Representation of each machine instruction.
LLVM_ABI void copyImplicitOps(MachineFunction &MF, const MachineInstr &MI)
Copy implicit register operands from specified instruction to this instruction.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM Value Representation.
Definition Value.h:75
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
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:190
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147