1 //===--M68kExpandPseudo.cpp - Expand pseudo instructions ------*- 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 /// This file contains a pass that expands pseudo instructions into target
11 /// instructions to allow proper scheduling, if-conversion, other late
12 /// optimizations, or simply the encoding of the instructions.
14 //===----------------------------------------------------------------------===//
17 #include "M68kFrameLowering.h"
18 #include "M68kInstrInfo.h"
19 #include "M68kMachineFunction.h"
20 #include "M68kSubtarget.h"
22 #include "llvm/Analysis/EHPersonalities.h"
23 #include "llvm/CodeGen/MachineFunctionPass.h"
24 #include "llvm/CodeGen/MachineInstrBuilder.h"
25 #include "llvm/CodeGen/MachineRegisterInfo.h"
26 #include "llvm/CodeGen/Passes.h" // For IDs of passes that are preserved.
27 #include "llvm/IR/GlobalValue.h"
31 #define DEBUG_TYPE "M68k-expand-pseudos"
34 class M68kExpandPseudo
: public MachineFunctionPass
{
37 M68kExpandPseudo() : MachineFunctionPass(ID
) {}
39 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
41 AU
.addPreservedID(MachineLoopInfoID
);
42 AU
.addPreservedID(MachineDominatorsID
);
43 MachineFunctionPass::getAnalysisUsage(AU
);
46 const M68kSubtarget
*STI
;
47 const M68kInstrInfo
*TII
;
48 const M68kRegisterInfo
*TRI
;
49 const M68kMachineFunctionInfo
*MFI
;
50 const M68kFrameLowering
*FL
;
52 bool runOnMachineFunction(MachineFunction
&Fn
) override
;
54 MachineFunctionProperties
getRequiredProperties() const override
{
55 return MachineFunctionProperties().set(
56 MachineFunctionProperties::Property::NoVRegs
);
59 StringRef
getPassName() const override
{
60 return "M68k pseudo instruction expansion pass";
64 bool ExpandMI(MachineBasicBlock
&MBB
, MachineBasicBlock::iterator MBBI
);
65 bool ExpandMBB(MachineBasicBlock
&MBB
);
67 char M68kExpandPseudo::ID
= 0;
68 } // End anonymous namespace.
70 /// If \p MBBI is a pseudo instruction, this method expands
71 /// it to the corresponding (sequence of) actual instruction(s).
72 /// \returns true if \p MBBI has been expanded.
73 bool M68kExpandPseudo::ExpandMI(MachineBasicBlock
&MBB
,
74 MachineBasicBlock::iterator MBBI
) {
75 MachineInstr
&MI
= *MBBI
;
76 MachineInstrBuilder
MIB(*MI
.getParent()->getParent(), MI
);
77 unsigned Opcode
= MI
.getOpcode();
78 DebugLoc DL
= MBBI
->getDebugLoc();
79 /// TODO infer argument size to create less switch cases
85 return TII
->ExpandMOVX_RR(MIB
, MVT::i16
, MVT::i8
);
87 return TII
->ExpandMOVX_RR(MIB
, MVT::i32
, MVT::i8
);
88 case M68k::MOVXd32d16
:
89 return TII
->ExpandMOVX_RR(MIB
, MVT::i32
, MVT::i16
);
91 case M68k::MOVSXd16d8
:
92 return TII
->ExpandMOVSZX_RR(MIB
, true, MVT::i16
, MVT::i8
);
93 case M68k::MOVSXd32d8
:
94 return TII
->ExpandMOVSZX_RR(MIB
, true, MVT::i32
, MVT::i8
);
95 case M68k::MOVSXd32d16
:
96 return TII
->ExpandMOVSZX_RR(MIB
, true, MVT::i32
, MVT::i16
);
98 case M68k::MOVZXd16d8
:
99 return TII
->ExpandMOVSZX_RR(MIB
, false, MVT::i16
, MVT::i8
);
100 case M68k::MOVZXd32d8
:
101 return TII
->ExpandMOVSZX_RR(MIB
, false, MVT::i32
, MVT::i8
);
102 case M68k::MOVZXd32d16
:
103 return TII
->ExpandMOVSZX_RR(MIB
, false, MVT::i32
, MVT::i16
);
105 case M68k::MOVSXd16j8
:
106 return TII
->ExpandMOVSZX_RM(MIB
, true, TII
->get(M68k::MOV8dj
), MVT::i16
,
108 case M68k::MOVSXd32j8
:
109 return TII
->ExpandMOVSZX_RM(MIB
, true, TII
->get(M68k::MOV8dj
), MVT::i32
,
111 case M68k::MOVSXd32j16
:
112 return TII
->ExpandMOVSZX_RM(MIB
, true, TII
->get(M68k::MOV16rj
), MVT::i32
,
115 case M68k::MOVZXd16j8
:
116 return TII
->ExpandMOVSZX_RM(MIB
, false, TII
->get(M68k::MOV8dj
), MVT::i16
,
118 case M68k::MOVZXd32j8
:
119 return TII
->ExpandMOVSZX_RM(MIB
, false, TII
->get(M68k::MOV8dj
), MVT::i32
,
121 case M68k::MOVZXd32j16
:
122 return TII
->ExpandMOVSZX_RM(MIB
, false, TII
->get(M68k::MOV16rj
), MVT::i32
,
125 case M68k::MOVSXd16p8
:
126 return TII
->ExpandMOVSZX_RM(MIB
, true, TII
->get(M68k::MOV8dp
), MVT::i16
,
128 case M68k::MOVSXd32p8
:
129 return TII
->ExpandMOVSZX_RM(MIB
, true, TII
->get(M68k::MOV8dp
), MVT::i32
,
131 case M68k::MOVSXd32p16
:
132 return TII
->ExpandMOVSZX_RM(MIB
, true, TII
->get(M68k::MOV16rp
), MVT::i32
,
135 case M68k::MOVZXd16p8
:
136 return TII
->ExpandMOVSZX_RM(MIB
, false, TII
->get(M68k::MOV8dp
), MVT::i16
,
138 case M68k::MOVZXd32p8
:
139 return TII
->ExpandMOVSZX_RM(MIB
, false, TII
->get(M68k::MOV8dp
), MVT::i32
,
141 case M68k::MOVZXd32p16
:
142 return TII
->ExpandMOVSZX_RM(MIB
, false, TII
->get(M68k::MOV16rp
), MVT::i32
,
145 case M68k::MOVSXd16f8
:
146 return TII
->ExpandMOVSZX_RM(MIB
, true, TII
->get(M68k::MOV8df
), MVT::i16
,
148 case M68k::MOVSXd32f8
:
149 return TII
->ExpandMOVSZX_RM(MIB
, true, TII
->get(M68k::MOV8df
), MVT::i32
,
151 case M68k::MOVSXd32f16
:
152 return TII
->ExpandMOVSZX_RM(MIB
, true, TII
->get(M68k::MOV16rf
), MVT::i32
,
155 case M68k::MOVZXd16f8
:
156 return TII
->ExpandMOVSZX_RM(MIB
, false, TII
->get(M68k::MOV8df
), MVT::i16
,
158 case M68k::MOVZXd32f8
:
159 return TII
->ExpandMOVSZX_RM(MIB
, false, TII
->get(M68k::MOV8df
), MVT::i32
,
161 case M68k::MOVZXd32f16
:
162 return TII
->ExpandMOVSZX_RM(MIB
, false, TII
->get(M68k::MOV16rf
), MVT::i32
,
166 return TII
->ExpandCCR(MIB
, /*IsToCCR=*/true);
168 return TII
->ExpandCCR(MIB
, /*IsToCCR=*/false);
170 case M68k::MOVM8jm_P
:
171 return TII
->ExpandMOVEM(MIB
, TII
->get(M68k::MOVM32jm
), /*IsRM=*/false);
172 case M68k::MOVM16jm_P
:
173 return TII
->ExpandMOVEM(MIB
, TII
->get(M68k::MOVM32jm
), /*IsRM=*/false);
174 case M68k::MOVM32jm_P
:
175 return TII
->ExpandMOVEM(MIB
, TII
->get(M68k::MOVM32jm
), /*IsRM=*/false);
177 case M68k::MOVM8pm_P
:
178 return TII
->ExpandMOVEM(MIB
, TII
->get(M68k::MOVM32pm
), /*IsRM=*/false);
179 case M68k::MOVM16pm_P
:
180 return TII
->ExpandMOVEM(MIB
, TII
->get(M68k::MOVM32pm
), /*IsRM=*/false);
181 case M68k::MOVM32pm_P
:
182 return TII
->ExpandMOVEM(MIB
, TII
->get(M68k::MOVM32pm
), /*IsRM=*/false);
184 case M68k::MOVM8mj_P
:
185 return TII
->ExpandMOVEM(MIB
, TII
->get(M68k::MOVM32mj
), /*IsRM=*/true);
186 case M68k::MOVM16mj_P
:
187 return TII
->ExpandMOVEM(MIB
, TII
->get(M68k::MOVM32mj
), /*IsRM=*/true);
188 case M68k::MOVM32mj_P
:
189 return TII
->ExpandMOVEM(MIB
, TII
->get(M68k::MOVM32mj
), /*IsRM=*/true);
191 case M68k::MOVM8mp_P
:
192 return TII
->ExpandMOVEM(MIB
, TII
->get(M68k::MOVM32mp
), /*IsRM=*/true);
193 case M68k::MOVM16mp_P
:
194 return TII
->ExpandMOVEM(MIB
, TII
->get(M68k::MOVM32mp
), /*IsRM=*/true);
195 case M68k::MOVM32mp_P
:
196 return TII
->ExpandMOVEM(MIB
, TII
->get(M68k::MOVM32mp
), /*IsRM=*/true);
198 case M68k::TCRETURNq
:
199 case M68k::TCRETURNj
: {
200 MachineOperand
&JumpTarget
= MI
.getOperand(0);
201 MachineOperand
&StackAdjust
= MI
.getOperand(1);
202 assert(StackAdjust
.isImm() && "Expecting immediate value.");
204 // Adjust stack pointer.
205 int StackAdj
= StackAdjust
.getImm();
206 int MaxTCDelta
= MFI
->getTCReturnAddrDelta();
208 assert(MaxTCDelta
<= 0 && "MaxTCDelta should never be positive");
210 // Incoporate the retaddr area.
211 Offset
= StackAdj
- MaxTCDelta
;
212 assert(Offset
>= 0 && "Offset should never be negative");
215 // Check for possible merge with preceding ADD instruction.
216 Offset
+= FL
->mergeSPUpdates(MBB
, MBBI
, true);
217 FL
->emitSPUpdate(MBB
, MBBI
, Offset
, /*InEpilogue=*/true);
220 // Jump to label or value in register.
221 if (Opcode
== M68k::TCRETURNq
) {
222 MachineInstrBuilder MIB
=
223 BuildMI(MBB
, MBBI
, DL
, TII
->get(M68k::TAILJMPq
));
224 if (JumpTarget
.isGlobal()) {
225 MIB
.addGlobalAddress(JumpTarget
.getGlobal(), JumpTarget
.getOffset(),
226 JumpTarget
.getTargetFlags());
228 assert(JumpTarget
.isSymbol());
229 MIB
.addExternalSymbol(JumpTarget
.getSymbolName(),
230 JumpTarget
.getTargetFlags());
233 BuildMI(MBB
, MBBI
, DL
, TII
->get(M68k::TAILJMPj
))
234 .addReg(JumpTarget
.getReg(), RegState::Kill
);
237 MachineInstr
&NewMI
= *std::prev(MBBI
);
238 NewMI
.copyImplicitOps(*MBBI
->getParent()->getParent(), *MBBI
);
240 // Delete the pseudo instruction TCRETURN.
246 // Adjust stack to erase error code
247 int64_t StackAdj
= MBBI
->getOperand(0).getImm();
248 MachineInstrBuilder MIB
;
251 MIB
= BuildMI(MBB
, MBBI
, DL
, TII
->get(M68k::RTS
));
252 } else if (isUInt
<16>(StackAdj
)) {
254 if (STI
->atLeastM68020()) {
255 llvm_unreachable("RTD is not implemented");
257 // Copy PC from stack to a free address(A0 or A1) register
258 // TODO check if pseudo expand uses free address register
259 BuildMI(MBB
, MBBI
, DL
, TII
->get(M68k::MOV32aj
), M68k::A1
)
263 FL
->emitSPUpdate(MBB
, MBBI
, StackAdj
, /*InEpilogue=*/true);
265 // Put the return address on stack
266 BuildMI(MBB
, MBBI
, DL
, TII
->get(M68k::MOV32ja
))
271 BuildMI(MBB
, MBBI
, DL
, TII
->get(M68k::RTS
));
274 // TODO: RTD can only handle immediates as big as 2**16-1.
275 // If we need to pop off bytes before the return address, we
276 // must do it manually.
277 llvm_unreachable("Stack adjustment size not supported");
280 // FIXME: Can rest of the operands be ignored, if there is any?
285 llvm_unreachable("Previous switch has a fallthrough?");
288 /// Expand all pseudo instructions contained in \p MBB.
289 /// \returns true if any expansion occurred for \p MBB.
290 bool M68kExpandPseudo::ExpandMBB(MachineBasicBlock
&MBB
) {
291 bool Modified
= false;
293 // MBBI may be invalidated by the expansion.
294 MachineBasicBlock::iterator MBBI
= MBB
.begin(), E
= MBB
.end();
296 MachineBasicBlock::iterator NMBBI
= std::next(MBBI
);
297 Modified
|= ExpandMI(MBB
, MBBI
);
304 bool M68kExpandPseudo::runOnMachineFunction(MachineFunction
&MF
) {
305 STI
= &static_cast<const M68kSubtarget
&>(MF
.getSubtarget());
306 TII
= STI
->getInstrInfo();
307 TRI
= STI
->getRegisterInfo();
308 MFI
= MF
.getInfo
<M68kMachineFunctionInfo
>();
309 FL
= STI
->getFrameLowering();
311 bool Modified
= false;
312 for (MachineBasicBlock
&MBB
: MF
)
313 Modified
|= ExpandMBB(MBB
);
317 /// Returns an instance of the pseudo instruction expansion pass.
318 FunctionPass
*llvm::createM68kExpandPseudoPass() {
319 return new M68kExpandPseudo();