1 //===-- M68kExpandPseudo.cpp - Expand pseudo instructions -------*- 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 /// 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.
13 ///
14 //===----------------------------------------------------------------------===//
15
16 #include "M68k.h"
17 #include "M68kFrameLowering.h"
18 #include "M68kInstrInfo.h"
19 #include "M68kMachineFunction.h"
20 #include "M68kSubtarget.h"
21
22 #include "llvm/CodeGen/MachineFunctionPass.h"
23 #include "llvm/CodeGen/MachineInstrBuilder.h"
24 #include "llvm/CodeGen/MachineRegisterInfo.h"
25 #include "llvm/CodeGen/Passes.h" // For IDs of passes that are preserved.
26 #include "llvm/IR/EHPersonalities.h"
27 #include "llvm/IR/GlobalValue.h"
28
29 using namespace llvm;
30
31 #define DEBUG_TYPE "m68k-expand-pseudo"
32 #define PASS_NAME "M68k pseudo instruction expansion pass"
33
34 namespace {
35 class M68kExpandPseudo : public MachineFunctionPass {
36 public:
37 static char ID;
M68kExpandPseudo()38 M68kExpandPseudo() : MachineFunctionPass(ID) {}
39
getAnalysisUsage(AnalysisUsage & AU) const40 void getAnalysisUsage(AnalysisUsage &AU) const override {
41 AU.setPreservesCFG();
42 AU.addPreservedID(MachineLoopInfoID);
43 AU.addPreservedID(MachineDominatorsID);
44 MachineFunctionPass::getAnalysisUsage(AU);
45 }
46
47 const M68kSubtarget *STI;
48 const M68kInstrInfo *TII;
49 const M68kRegisterInfo *TRI;
50 const M68kMachineFunctionInfo *MFI;
51 const M68kFrameLowering *FL;
52
53 bool runOnMachineFunction(MachineFunction &Fn) override;
54
getRequiredProperties() const55 MachineFunctionProperties getRequiredProperties() const override {
56 return MachineFunctionProperties().set(
57 MachineFunctionProperties::Property::NoVRegs);
58 }
59
60 private:
61 bool ExpandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI);
62 bool ExpandMBB(MachineBasicBlock &MBB);
63 };
64 char M68kExpandPseudo::ID = 0;
65 } // End anonymous namespace.
66
INITIALIZE_PASS(M68kExpandPseudo,DEBUG_TYPE,PASS_NAME,false,false)67 INITIALIZE_PASS(M68kExpandPseudo, DEBUG_TYPE, PASS_NAME, false, false)
68
69 /// If \p MBBI is a pseudo instruction, this method expands
70 /// it to the corresponding (sequence of) actual instruction(s).
71 /// \returns true if \p MBBI has been expanded.
72 bool M68kExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
73 MachineBasicBlock::iterator MBBI) {
74 MachineInstr &MI = *MBBI;
75 MachineInstrBuilder MIB(*MI.getParent()->getParent(), MI);
76 unsigned Opcode = MI.getOpcode();
77 DebugLoc DL = MBBI->getDebugLoc();
78 /// TODO infer argument size to create less switch cases
79 switch (Opcode) {
80 default:
81 return false;
82
83 case M68k::MOVI8di:
84 return TII->ExpandMOVI(MIB, MVT::i8);
85 case M68k::MOVI16ri:
86 return TII->ExpandMOVI(MIB, MVT::i16);
87 case M68k::MOVI32ri:
88 return TII->ExpandMOVI(MIB, MVT::i32);
89
90 case M68k::MOVXd16d8:
91 return TII->ExpandMOVX_RR(MIB, MVT::i16, MVT::i8);
92 case M68k::MOVXd32d8:
93 return TII->ExpandMOVX_RR(MIB, MVT::i32, MVT::i8);
94 case M68k::MOVXd32d16:
95 return TII->ExpandMOVX_RR(MIB, MVT::i32, MVT::i16);
96
97 case M68k::MOVSXd16d8:
98 return TII->ExpandMOVSZX_RR(MIB, true, MVT::i16, MVT::i8);
99 case M68k::MOVSXd32d8:
100 return TII->ExpandMOVSZX_RR(MIB, true, MVT::i32, MVT::i8);
101 case M68k::MOVSXd32d16:
102 return TII->ExpandMOVSZX_RR(MIB, true, MVT::i32, MVT::i16);
103
104 case M68k::MOVZXd16d8:
105 return TII->ExpandMOVSZX_RR(MIB, false, MVT::i16, MVT::i8);
106 case M68k::MOVZXd32d8:
107 return TII->ExpandMOVSZX_RR(MIB, false, MVT::i32, MVT::i8);
108 case M68k::MOVZXd32d16:
109 return TII->ExpandMOVSZX_RR(MIB, false, MVT::i32, MVT::i16);
110
111 case M68k::MOVSXd16j8:
112 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dj), MVT::i16,
113 MVT::i8);
114 case M68k::MOVSXd32j8:
115 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dj), MVT::i32,
116 MVT::i8);
117 case M68k::MOVSXd32j16:
118 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16rj), MVT::i32,
119 MVT::i16);
120
121 case M68k::MOVZXd16j8:
122 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dj), MVT::i16,
123 MVT::i8);
124 case M68k::MOVZXd32j8:
125 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dj), MVT::i32,
126 MVT::i8);
127 case M68k::MOVZXd32j16:
128 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16rj), MVT::i32,
129 MVT::i16);
130
131 case M68k::MOVSXd16p8:
132 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dp), MVT::i16,
133 MVT::i8);
134 case M68k::MOVSXd32p8:
135 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dp), MVT::i32,
136 MVT::i8);
137 case M68k::MOVSXd32p16:
138 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16rp), MVT::i32,
139 MVT::i16);
140
141 case M68k::MOVZXd16p8:
142 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dp), MVT::i16,
143 MVT::i8);
144 case M68k::MOVZXd32p8:
145 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dp), MVT::i32,
146 MVT::i8);
147 case M68k::MOVZXd32p16:
148 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16rp), MVT::i32,
149 MVT::i16);
150
151 case M68k::MOVSXd16f8:
152 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8df), MVT::i16,
153 MVT::i8);
154 case M68k::MOVSXd32f8:
155 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8df), MVT::i32,
156 MVT::i8);
157 case M68k::MOVSXd32f16:
158 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16rf), MVT::i32,
159 MVT::i16);
160
161 case M68k::MOVZXd16f8:
162 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8df), MVT::i16,
163 MVT::i8);
164 case M68k::MOVZXd32f8:
165 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8df), MVT::i32,
166 MVT::i8);
167 case M68k::MOVZXd32f16:
168 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16rf), MVT::i32,
169 MVT::i16);
170
171 case M68k::MOVSXd16q8:
172 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dq), MVT::i16,
173 MVT::i8);
174 case M68k::MOVSXd32q8:
175 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dq), MVT::i32,
176 MVT::i8);
177 case M68k::MOVSXd32q16:
178 return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16dq), MVT::i32,
179 MVT::i16);
180
181 case M68k::MOVZXd16q8:
182 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dq), MVT::i16,
183 MVT::i8);
184 case M68k::MOVZXd32q8:
185 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dq), MVT::i32,
186 MVT::i8);
187 case M68k::MOVZXd32q16:
188 return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16dq), MVT::i32,
189 MVT::i16);
190
191 case M68k::MOV8cd:
192 return TII->ExpandCCR(MIB, /*IsToCCR=*/true);
193 case M68k::MOV8dc:
194 return TII->ExpandCCR(MIB, /*IsToCCR=*/false);
195
196 case M68k::MOVM8jm_P:
197 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false);
198 case M68k::MOVM16jm_P:
199 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false);
200 case M68k::MOVM32jm_P:
201 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false);
202
203 case M68k::MOVM8pm_P:
204 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false);
205 case M68k::MOVM16pm_P:
206 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false);
207 case M68k::MOVM32pm_P:
208 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false);
209
210 case M68k::MOVM8mj_P:
211 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true);
212 case M68k::MOVM16mj_P:
213 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true);
214 case M68k::MOVM32mj_P:
215 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true);
216
217 case M68k::MOVM8mp_P:
218 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true);
219 case M68k::MOVM16mp_P:
220 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true);
221 case M68k::MOVM32mp_P:
222 return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true);
223
224 case M68k::TCRETURNq:
225 case M68k::TCRETURNj: {
226 MachineOperand &JumpTarget = MI.getOperand(0);
227 MachineOperand &StackAdjust = MI.getOperand(1);
228 assert(StackAdjust.isImm() && "Expecting immediate value.");
229
230 // Adjust stack pointer.
231 int StackAdj = StackAdjust.getImm();
232 int MaxTCDelta = MFI->getTCReturnAddrDelta();
233 int Offset = 0;
234 assert(MaxTCDelta <= 0 && "MaxTCDelta should never be positive");
235
236 // Incoporate the retaddr area.
237 Offset = StackAdj - MaxTCDelta;
238 assert(Offset >= 0 && "Offset should never be negative");
239
240 if (Offset) {
241 // Check for possible merge with preceding ADD instruction.
242 Offset += FL->mergeSPUpdates(MBB, MBBI, true);
243 FL->emitSPUpdate(MBB, MBBI, Offset, /*InEpilogue=*/true);
244 }
245
246 // Jump to label or value in register.
247 if (Opcode == M68k::TCRETURNq) {
248 MachineInstrBuilder MIB =
249 BuildMI(MBB, MBBI, DL, TII->get(M68k::TAILJMPq));
250 if (JumpTarget.isGlobal()) {
251 MIB.addGlobalAddress(JumpTarget.getGlobal(), JumpTarget.getOffset(),
252 JumpTarget.getTargetFlags());
253 } else {
254 assert(JumpTarget.isSymbol());
255 MIB.addExternalSymbol(JumpTarget.getSymbolName(),
256 JumpTarget.getTargetFlags());
257 }
258 } else {
259 BuildMI(MBB, MBBI, DL, TII->get(M68k::TAILJMPj))
260 .addReg(JumpTarget.getReg(), RegState::Kill);
261 }
262
263 MachineInstr &NewMI = *std::prev(MBBI);
264 NewMI.copyImplicitOps(*MBBI->getParent()->getParent(), *MBBI);
265
266 // Delete the pseudo instruction TCRETURN.
267 MBB.erase(MBBI);
268
269 return true;
270 }
271 case M68k::RET: {
272 if (MBB.getParent()->getFunction().getCallingConv() ==
273 CallingConv::M68k_INTR) {
274 BuildMI(MBB, MBBI, DL, TII->get(M68k::RTE));
275 } else if (int64_t StackAdj = MBBI->getOperand(0).getImm(); StackAdj == 0) {
276 BuildMI(MBB, MBBI, DL, TII->get(M68k::RTS));
277 } else {
278 // Copy return address from stack to a free address(A0 or A1) register
279 // TODO check if pseudo expand uses free address register
280 BuildMI(MBB, MBBI, DL, TII->get(M68k::MOV32aj), M68k::A1)
281 .addReg(M68k::SP);
282
283 // Adjust SP
284 FL->emitSPUpdate(MBB, MBBI, StackAdj, /*InEpilogue=*/true);
285
286 // Put the return address on stack
287 BuildMI(MBB, MBBI, DL, TII->get(M68k::MOV32ja))
288 .addReg(M68k::SP)
289 .addReg(M68k::A1);
290
291 // RTS
292 BuildMI(MBB, MBBI, DL, TII->get(M68k::RTS));
293 }
294
295 // FIXME: Can rest of the operands be ignored, if there is any?
296 MBB.erase(MBBI);
297 return true;
298 }
299 }
300 llvm_unreachable("Previous switch has a fallthrough?");
301 }
302
303 /// Expand all pseudo instructions contained in \p MBB.
304 /// \returns true if any expansion occurred for \p MBB.
ExpandMBB(MachineBasicBlock & MBB)305 bool M68kExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) {
306 bool Modified = false;
307
308 // MBBI may be invalidated by the expansion.
309 MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
310 while (MBBI != E) {
311 MachineBasicBlock::iterator NMBBI = std::next(MBBI);
312 Modified |= ExpandMI(MBB, MBBI);
313 MBBI = NMBBI;
314 }
315
316 return Modified;
317 }
318
runOnMachineFunction(MachineFunction & MF)319 bool M68kExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
320 STI = &MF.getSubtarget<M68kSubtarget>();
321 TII = STI->getInstrInfo();
322 TRI = STI->getRegisterInfo();
323 MFI = MF.getInfo<M68kMachineFunctionInfo>();
324 FL = STI->getFrameLowering();
325
326 bool Modified = false;
327 for (MachineBasicBlock &MBB : MF)
328 Modified |= ExpandMBB(MBB);
329 return Modified;
330 }
331
332 /// Returns an instance of the pseudo instruction expansion pass.
createM68kExpandPseudoPass()333 FunctionPass *llvm::createM68kExpandPseudoPass() {
334 return new M68kExpandPseudo();
335 }
336