1 //===-- M68kCollapseMOVEMPass.cpp - Expand MOVEM pass -----------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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
15 //===----------------------------------------------------------------------===//
18 #include "M68kFrameLowering.h"
19 #include "M68kInstrInfo.h"
20 #include "M68kMachineFunction.h"
21 #include "M68kSubtarget.h"
23 #include "llvm/CodeGen/MachineFunctionPass.h"
24 #include "llvm/CodeGen/MachineInstrBuilder.h"
25 #include "llvm/CodeGen/MachineRegisterInfo.h"
26 #include "llvm/IR/EHPersonalities.h"
27 #include "llvm/IR/GlobalValue.h"
28 #include "llvm/Support/MathExtras.h"
32 #define DEBUG_TYPE "m68k-collapse-movem"
33 #define PASS_NAME "M68k MOVEM collapser pass"
37 enum UpdateType
{ Ascending
, Descending
, Intermixed
};
39 /// An abtraction of the MOVEM chain currently processing
41 MachineBasicBlock::iterator Begin
;
42 MachineBasicBlock::iterator End
;
51 enum class AccessTy
{ None
, Load
, Store
};
56 : Begin(nullptr), End(nullptr), Base(0), Start(INT_MIN
), Stop(INT_MAX
),
57 Mask(0), Access(AccessTy::None
) {}
59 void setBegin(MachineBasicBlock::iterator
&MI
) {
60 assert(Begin
== nullptr);
64 void setEnd(MachineBasicBlock::iterator
&MI
) {
65 assert(End
== nullptr);
69 bool hasBase() const { return Base
!= 0; }
71 unsigned getBase() const {
76 MachineBasicBlock::iterator
begin() {
77 assert(Begin
!= nullptr);
81 MachineBasicBlock::iterator
end() {
82 assert(End
!= nullptr);
86 unsigned getMask() const { return Mask
; }
88 void setBase(int Value
) {
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");
99 } else if (NewMask
< Mask
) {
106 bool update(int O
, int M
) {
107 UpdateType Type
= classifyUpdateByMask(M
);
108 if (Type
== Intermixed
)
110 if (Start
== INT_MIN
) {
114 } else if (Type
== Descending
&& O
== Start
- 4) {
118 } else if (Type
== Ascending
&& O
== Stop
+ 4) {
127 int getFinalOffset() const {
130 "MOVEM in control mode should increment the address in each iteration");
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");
142 void setLoad() { Access
= AccessTy::Load
; }
143 void setStore() { Access
= AccessTy::Store
; }
145 bool isLoad() const { return Access
== AccessTy::Load
; }
146 bool isStore() const { return Access
== AccessTy::Store
; }
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.
157 class M68kCollapseMOVEM
: public MachineFunctionPass
{
161 const M68kSubtarget
*STI
;
162 const M68kInstrInfo
*TII
;
163 const M68kRegisterInfo
*TRI
;
164 const M68kMachineFunctionInfo
*MFI
;
165 const M68kFrameLowering
*FL
;
167 M68kCollapseMOVEM() : MachineFunctionPass(ID
) {}
169 void Finish(MachineBasicBlock
&MBB
, MOVEMState
&State
) {
170 auto MI
= State
.begin();
171 auto End
= State
.end();
172 DebugLoc DL
= MI
->getDebugLoc();
174 // No need to delete then add a single instruction
175 if (std::next(MI
) == End
) {
176 State
= MOVEMState();
180 // Delete all the MOVEM instruction till the end
182 auto Next
= std::next(MI
);
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());
194 BuildMI(MBB
, End
, DL
, TII
->get(M68k::MOVM32pm
))
195 .addImm(State
.getFinalOffset())
196 .addReg(State
.getBase())
197 .addImm(State
.getMask());
200 State
= MOVEMState();
203 bool ProcessMI(MachineBasicBlock
&MBB
, MachineBasicBlock::iterator MI
,
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
)) {
213 // Otherwise we Finish processing of the current MOVEM sequance and
219 return ProcessMI(MBB
, MI
, State
, Mask
, Offset
, Reg
, IsStore
);
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())) {
227 State
.update(Offset
, Mask
);
228 IsStore
? State
.setStore() : State
.setLoad();
234 bool runOnMachineFunction(MachineFunction
&MF
) override
{
235 STI
= &MF
.getSubtarget
<M68kSubtarget
>();
236 TII
= STI
->getInstrInfo();
237 TRI
= STI
->getRegisterInfo();
238 MFI
= MF
.getInfo
<M68kMachineFunctionInfo
>();
239 FL
= STI
->getFrameLowering();
241 bool Modified
= false;
249 for (auto &MBB
: MF
) {
250 auto MI
= MBB
.begin(), E
= MBB
.end();
252 // Processing might change current instruction, save next first
253 auto NMI
= std::next(MI
);
254 switch (MI
->getOpcode()) {
256 if (State
.hasBase()) {
263 Mask
= MI
->getOperand(1).getImm();
264 Reg
= MI
->getOperand(0).getReg();
266 Modified
|= ProcessMI(MBB
, MI
, State
, Mask
, Offset
, Reg
, true);
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);
275 Mask
= MI
->getOperand(0).getImm();
276 Reg
= MI
->getOperand(1).getReg();
278 Modified
|= ProcessMI(MBB
, MI
, State
, Mask
, Offset
, Reg
, false);
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);
290 if (State
.hasBase()) {
300 char M68kCollapseMOVEM::ID
= 0;
301 } // anonymous namespace.
303 INITIALIZE_PASS(M68kCollapseMOVEM
, DEBUG_TYPE
, PASS_NAME
, false, false)
305 /// Returns an instance of the pseudo instruction expansion pass.
306 FunctionPass
*llvm::createM68kCollapseMOVEMPass() {
307 return new M68kCollapseMOVEM();