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/Analysis/EHPersonalities.h"
24 #include "llvm/CodeGen/MachineFunctionPass.h"
25 #include "llvm/CodeGen/MachineInstrBuilder.h"
26 #include "llvm/CodeGen/MachineRegisterInfo.h"
27 #include "llvm/IR/GlobalValue.h"
28 #include "llvm/Support/MathExtras.h"
32 #define DEBUG_TYPE "M68k-collapse-movem"
36 enum UpdateType
{ Ascending
, Descending
, Intermixed
};
38 /// An abtraction of the MOVEM chain currently processing
40 MachineBasicBlock::iterator Begin
;
41 MachineBasicBlock::iterator End
;
50 enum class AccessTy
{ None
, Load
, Store
};
55 : Begin(nullptr), End(nullptr), Base(0), Start(INT_MIN
), Stop(INT_MAX
),
56 Mask(0), Access(AccessTy::None
) {}
58 void setBegin(MachineBasicBlock::iterator
&MI
) {
59 assert(Begin
== nullptr);
63 void setEnd(MachineBasicBlock::iterator
&MI
) {
64 assert(End
== nullptr);
68 bool hasBase() const { return Base
!= 0; }
70 unsigned getBase() const {
75 MachineBasicBlock::iterator
begin() {
76 assert(Begin
!= nullptr);
80 MachineBasicBlock::iterator
end() {
81 assert(End
!= nullptr);
85 unsigned getMask() const { return Mask
; }
87 void setBase(int Value
) {
92 // You need to call this before Mask update
93 UpdateType
classifyUpdateByMask(unsigned NewMask
) const {
94 assert(NewMask
&& "Mask needs to select at least one register");
98 } else if (NewMask
< Mask
) {
105 bool update(int O
, int M
) {
106 UpdateType Type
= classifyUpdateByMask(M
);
107 if (Type
== Intermixed
)
109 if (Start
== INT_MIN
) {
113 } else if (Type
== Descending
&& O
== Start
- 4) {
117 } else if (Type
== Ascending
&& O
== Stop
+ 4) {
126 int getFinalOffset() const {
129 "MOVEM in control mode should increment the address in each iteration");
133 bool updateMask(unsigned Value
) {
134 assert(isUInt
<16>(Value
) && "Mask must fit 16 bit");
135 assert(!(Value
& Mask
) &&
136 "This is weird, there should be no intersections");
141 void setLoad() { Access
= AccessTy::Load
; }
142 void setStore() { Access
= AccessTy::Store
; }
144 bool isLoad() const { return Access
== AccessTy::Load
; }
145 bool isStore() const { return Access
== AccessTy::Store
; }
148 /// This Pass first walks through all the MOVEM instructions
149 /// that are chained together and record each of the
150 /// instruction's properties like register mask and data
151 /// access type into a `MOVEState` instance.
152 /// Then we perform reduction / collapsing on this `MOVEMState`
153 /// representation before creating a new `MOVEM` instruction
154 /// based on the collapsed result, as well as removing
155 /// redundant `MOVEM` instructions.
156 class M68kCollapseMOVEM
: public MachineFunctionPass
{
160 const M68kSubtarget
*STI
;
161 const M68kInstrInfo
*TII
;
162 const M68kRegisterInfo
*TRI
;
163 const M68kMachineFunctionInfo
*MFI
;
164 const M68kFrameLowering
*FL
;
166 M68kCollapseMOVEM() : MachineFunctionPass(ID
) {}
168 void Finish(MachineBasicBlock
&MBB
, MOVEMState
&State
) {
169 auto MI
= State
.begin();
170 auto End
= State
.end();
171 DebugLoc DL
= MI
->getDebugLoc();
173 // No need to delete then add a single instruction
174 if (std::next(MI
) == End
) {
175 State
= MOVEMState();
179 // Delete all the MOVEM instruction till the end
181 auto Next
= std::next(MI
);
187 if (State
.isLoad()) {
188 BuildMI(MBB
, End
, DL
, TII
->get(M68k::MOVM32mp
))
189 .addImm(State
.getMask())
190 .addImm(State
.getFinalOffset())
191 .addReg(State
.getBase());
193 BuildMI(MBB
, End
, DL
, TII
->get(M68k::MOVM32pm
))
194 .addImm(State
.getFinalOffset())
195 .addReg(State
.getBase())
196 .addImm(State
.getMask());
199 State
= MOVEMState();
202 bool ProcessMI(MachineBasicBlock
&MBB
, MachineBasicBlock::iterator MI
,
203 MOVEMState
&State
, unsigned Mask
, int Offset
, unsigned Reg
,
204 bool IsStore
= false) {
205 if (State
.hasBase()) {
206 // If current Type, Reg, Offset and Mask is in proper order then
207 // merge in the state
208 MOVEMState Temp
= State
;
209 if (State
.isStore() == IsStore
&& State
.getBase() == Reg
&&
210 State
.update(Offset
, Mask
)) {
212 // Otherwise we Finish processing of the current MOVEM sequance and
218 return ProcessMI(MBB
, MI
, State
, Mask
, Offset
, Reg
, IsStore
);
220 // If this is the first instruction is sequance then initialize the State
221 } else if (Reg
== TRI
->getStackRegister() ||
222 Reg
== TRI
->getBaseRegister() ||
223 Reg
== TRI
->getFrameRegister(*MBB
.getParent())) {
226 State
.update(Offset
, Mask
);
227 IsStore
? State
.setStore() : State
.setLoad();
233 bool runOnMachineFunction(MachineFunction
&MF
) override
{
234 STI
= &static_cast<const M68kSubtarget
&>(MF
.getSubtarget());
235 TII
= STI
->getInstrInfo();
236 TRI
= STI
->getRegisterInfo();
237 MFI
= MF
.getInfo
<M68kMachineFunctionInfo
>();
238 FL
= STI
->getFrameLowering();
240 bool Modified
= false;
248 for (auto &MBB
: MF
) {
249 auto MI
= MBB
.begin(), E
= MBB
.end();
251 // Processing might change current instruction, save next first
252 auto NMI
= std::next(MI
);
253 switch (MI
->getOpcode()) {
255 if (State
.hasBase()) {
262 Mask
= MI
->getOperand(1).getImm();
263 Reg
= MI
->getOperand(0).getReg();
265 Modified
|= ProcessMI(MBB
, MI
, State
, Mask
, Offset
, Reg
, true);
268 Mask
= MI
->getOperand(2).getImm();
269 Reg
= MI
->getOperand(1).getReg();
270 Offset
= MI
->getOperand(0).getImm();
271 Modified
|= ProcessMI(MBB
, MI
, State
, Mask
, Offset
, Reg
, true);
274 Mask
= MI
->getOperand(0).getImm();
275 Reg
= MI
->getOperand(1).getReg();
277 Modified
|= ProcessMI(MBB
, MI
, State
, Mask
, Offset
, Reg
, false);
280 Mask
= MI
->getOperand(0).getImm();
281 Reg
= MI
->getOperand(2).getReg();
282 Offset
= MI
->getOperand(1).getImm();
283 Modified
|= ProcessMI(MBB
, MI
, State
, Mask
, Offset
, Reg
, false);
289 if (State
.hasBase()) {
298 StringRef
getPassName() const override
{ return "M68k MOVEM collapser pass"; }
301 char M68kCollapseMOVEM::ID
= 0;
302 } // anonymous namespace.
304 /// Returns an instance of the pseudo instruction expansion pass.
305 FunctionPass
*llvm::createM68kCollapseMOVEMPass() {
306 return new M68kCollapseMOVEM();