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; |
38 | M68kExpandPseudo() : MachineFunctionPass(ID) {} |
39 | |
40 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
41 | AU.setPreservesCFG(); |
42 | AU.addPreservedID(ID&: MachineLoopInfoID); |
43 | AU.addPreservedID(ID&: 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 | |
55 | 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 | |
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::MOVXd16d8: |
84 | return TII->ExpandMOVX_RR(MIB, MVT::MVTDst: i16, MVT::MVTSrc: i8); |
85 | case M68k::MOVXd32d8: |
86 | return TII->ExpandMOVX_RR(MIB, MVT::MVTDst: i32, MVT::MVTSrc: i8); |
87 | case M68k::MOVXd32d16: |
88 | return TII->ExpandMOVX_RR(MIB, MVT::MVTDst: i32, MVT::MVTSrc: i16); |
89 | |
90 | case M68k::MOVSXd16d8: |
91 | return TII->ExpandMOVSZX_RR(MIB, IsSigned: true, MVT::MVTDst: i16, MVT::MVTSrc: i8); |
92 | case M68k::MOVSXd32d8: |
93 | return TII->ExpandMOVSZX_RR(MIB, IsSigned: true, MVT::MVTDst: i32, MVT::MVTSrc: i8); |
94 | case M68k::MOVSXd32d16: |
95 | return TII->ExpandMOVSZX_RR(MIB, IsSigned: true, MVT::MVTDst: i32, MVT::MVTSrc: i16); |
96 | |
97 | case M68k::MOVZXd16d8: |
98 | return TII->ExpandMOVSZX_RR(MIB, IsSigned: false, MVT::MVTDst: i16, MVT::MVTSrc: i8); |
99 | case M68k::MOVZXd32d8: |
100 | return TII->ExpandMOVSZX_RR(MIB, IsSigned: false, MVT::MVTDst: i32, MVT::MVTSrc: i8); |
101 | case M68k::MOVZXd32d16: |
102 | return TII->ExpandMOVSZX_RR(MIB, IsSigned: false, MVT::MVTDst: i32, MVT::MVTSrc: i16); |
103 | |
104 | case M68k::MOVSXd16j8: |
105 | return TII->ExpandMOVSZX_RM(MIB, IsSigned: true, Desc: TII->get(M68k::MOV8dj), MVT::MVTDst: i16, |
106 | MVT::MVTSrc: i8); |
107 | case M68k::MOVSXd32j8: |
108 | return TII->ExpandMOVSZX_RM(MIB, IsSigned: true, Desc: TII->get(M68k::MOV8dj), MVT::MVTDst: i32, |
109 | MVT::MVTSrc: i8); |
110 | case M68k::MOVSXd32j16: |
111 | return TII->ExpandMOVSZX_RM(MIB, IsSigned: true, Desc: TII->get(M68k::MOV16rj), MVT::MVTDst: i32, |
112 | MVT::MVTSrc: i16); |
113 | |
114 | case M68k::MOVZXd16j8: |
115 | return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dj), MVT::i16, |
116 | MVT::i8); |
117 | case M68k::MOVZXd32j8: |
118 | return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dj), MVT::i32, |
119 | MVT::i8); |
120 | case M68k::MOVZXd32j16: |
121 | return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16rj), MVT::i32, |
122 | MVT::i16); |
123 | |
124 | case M68k::MOVSXd16p8: |
125 | return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dp), MVT::i16, |
126 | MVT::i8); |
127 | case M68k::MOVSXd32p8: |
128 | return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dp), MVT::i32, |
129 | MVT::i8); |
130 | case M68k::MOVSXd32p16: |
131 | return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16rp), MVT::i32, |
132 | MVT::i16); |
133 | |
134 | case M68k::MOVZXd16p8: |
135 | return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dp), MVT::i16, |
136 | MVT::i8); |
137 | case M68k::MOVZXd32p8: |
138 | return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dp), MVT::i32, |
139 | MVT::i8); |
140 | case M68k::MOVZXd32p16: |
141 | return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16rp), MVT::i32, |
142 | MVT::i16); |
143 | |
144 | case M68k::MOVSXd16f8: |
145 | return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8df), MVT::i16, |
146 | MVT::i8); |
147 | case M68k::MOVSXd32f8: |
148 | return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8df), MVT::i32, |
149 | MVT::i8); |
150 | case M68k::MOVSXd32f16: |
151 | return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16rf), MVT::i32, |
152 | MVT::i16); |
153 | |
154 | case M68k::MOVZXd16f8: |
155 | return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8df), MVT::i16, |
156 | MVT::i8); |
157 | case M68k::MOVZXd32f8: |
158 | return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8df), MVT::i32, |
159 | MVT::i8); |
160 | case M68k::MOVZXd32f16: |
161 | return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16rf), MVT::i32, |
162 | MVT::i16); |
163 | |
164 | case M68k::MOVSXd16q8: |
165 | return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dq), MVT::i16, |
166 | MVT::i8); |
167 | case M68k::MOVSXd32q8: |
168 | return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dq), MVT::i32, |
169 | MVT::i8); |
170 | case M68k::MOVSXd32q16: |
171 | return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16dq), MVT::i32, |
172 | MVT::i16); |
173 | |
174 | case M68k::MOVZXd16q8: |
175 | return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dq), MVT::i16, |
176 | MVT::i8); |
177 | case M68k::MOVZXd32q8: |
178 | return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dq), MVT::i32, |
179 | MVT::i8); |
180 | case M68k::MOVZXd32q16: |
181 | return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16dq), MVT::i32, |
182 | MVT::i16); |
183 | |
184 | case M68k::MOV8cd: |
185 | return TII->ExpandCCR(MIB, /*IsToCCR=*/true); |
186 | case M68k::MOV8dc: |
187 | return TII->ExpandCCR(MIB, /*IsToCCR=*/false); |
188 | |
189 | case M68k::MOVM8jm_P: |
190 | return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false); |
191 | case M68k::MOVM16jm_P: |
192 | return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false); |
193 | case M68k::MOVM32jm_P: |
194 | return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32jm), /*IsRM=*/false); |
195 | |
196 | case M68k::MOVM8pm_P: |
197 | return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false); |
198 | case M68k::MOVM16pm_P: |
199 | return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false); |
200 | case M68k::MOVM32pm_P: |
201 | return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32pm), /*IsRM=*/false); |
202 | |
203 | case M68k::MOVM8mj_P: |
204 | return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true); |
205 | case M68k::MOVM16mj_P: |
206 | return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true); |
207 | case M68k::MOVM32mj_P: |
208 | return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mj), /*IsRM=*/true); |
209 | |
210 | case M68k::MOVM8mp_P: |
211 | return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true); |
212 | case M68k::MOVM16mp_P: |
213 | return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true); |
214 | case M68k::MOVM32mp_P: |
215 | return TII->ExpandMOVEM(MIB, TII->get(M68k::MOVM32mp), /*IsRM=*/true); |
216 | |
217 | case M68k::TCRETURNq: |
218 | case M68k::TCRETURNj: { |
219 | MachineOperand &JumpTarget = MI.getOperand(i: 0); |
220 | MachineOperand &StackAdjust = MI.getOperand(i: 1); |
221 | assert(StackAdjust.isImm() && "Expecting immediate value." ); |
222 | |
223 | // Adjust stack pointer. |
224 | int StackAdj = StackAdjust.getImm(); |
225 | int MaxTCDelta = MFI->getTCReturnAddrDelta(); |
226 | int Offset = 0; |
227 | assert(MaxTCDelta <= 0 && "MaxTCDelta should never be positive" ); |
228 | |
229 | // Incoporate the retaddr area. |
230 | Offset = StackAdj - MaxTCDelta; |
231 | assert(Offset >= 0 && "Offset should never be negative" ); |
232 | |
233 | if (Offset) { |
234 | // Check for possible merge with preceding ADD instruction. |
235 | Offset += FL->mergeSPUpdates(MBB, MBBI, doMergeWithPrevious: true); |
236 | FL->emitSPUpdate(MBB, MBBI, NumBytes: Offset, /*InEpilogue=*/true); |
237 | } |
238 | |
239 | // Jump to label or value in register. |
240 | if (Opcode == M68k::TCRETURNq) { |
241 | MachineInstrBuilder MIB = |
242 | BuildMI(MBB, MBBI, DL, TII->get(M68k::TAILJMPq)); |
243 | if (JumpTarget.isGlobal()) { |
244 | MIB.addGlobalAddress(GV: JumpTarget.getGlobal(), Offset: JumpTarget.getOffset(), |
245 | TargetFlags: JumpTarget.getTargetFlags()); |
246 | } else { |
247 | assert(JumpTarget.isSymbol()); |
248 | MIB.addExternalSymbol(FnName: JumpTarget.getSymbolName(), |
249 | TargetFlags: JumpTarget.getTargetFlags()); |
250 | } |
251 | } else { |
252 | BuildMI(MBB, MBBI, DL, TII->get(M68k::TAILJMPj)) |
253 | .addReg(JumpTarget.getReg(), RegState::Kill); |
254 | } |
255 | |
256 | MachineInstr &NewMI = *std::prev(x: MBBI); |
257 | NewMI.copyImplicitOps(MF&: *MBBI->getParent()->getParent(), MI: *MBBI); |
258 | |
259 | // Delete the pseudo instruction TCRETURN. |
260 | MBB.erase(I: MBBI); |
261 | |
262 | return true; |
263 | } |
264 | case M68k::RET: { |
265 | if (MBB.getParent()->getFunction().getCallingConv() == |
266 | CallingConv::M68k_INTR) { |
267 | BuildMI(MBB, MBBI, DL, TII->get(M68k::RTE)); |
268 | } else if (int64_t StackAdj = MBBI->getOperand(i: 0).getImm(); StackAdj == 0) { |
269 | BuildMI(MBB, MBBI, DL, TII->get(M68k::RTS)); |
270 | } else { |
271 | // Copy return address from stack to a free address(A0 or A1) register |
272 | // TODO check if pseudo expand uses free address register |
273 | BuildMI(MBB, MBBI, DL, TII->get(M68k::MOV32aj), M68k::A1) |
274 | .addReg(M68k::SP); |
275 | |
276 | // Adjust SP |
277 | FL->emitSPUpdate(MBB, MBBI, NumBytes: StackAdj, /*InEpilogue=*/true); |
278 | |
279 | // Put the return address on stack |
280 | BuildMI(MBB, MBBI, DL, TII->get(M68k::MOV32ja)) |
281 | .addReg(M68k::SP) |
282 | .addReg(M68k::A1); |
283 | |
284 | // RTS |
285 | BuildMI(MBB, MBBI, DL, TII->get(M68k::RTS)); |
286 | } |
287 | |
288 | // FIXME: Can rest of the operands be ignored, if there is any? |
289 | MBB.erase(I: MBBI); |
290 | return true; |
291 | } |
292 | } |
293 | llvm_unreachable("Previous switch has a fallthrough?" ); |
294 | } |
295 | |
296 | /// Expand all pseudo instructions contained in \p MBB. |
297 | /// \returns true if any expansion occurred for \p MBB. |
298 | bool M68kExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) { |
299 | bool Modified = false; |
300 | |
301 | // MBBI may be invalidated by the expansion. |
302 | MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); |
303 | while (MBBI != E) { |
304 | MachineBasicBlock::iterator NMBBI = std::next(x: MBBI); |
305 | Modified |= ExpandMI(MBB, MBBI); |
306 | MBBI = NMBBI; |
307 | } |
308 | |
309 | return Modified; |
310 | } |
311 | |
312 | bool M68kExpandPseudo::runOnMachineFunction(MachineFunction &MF) { |
313 | STI = &MF.getSubtarget<M68kSubtarget>(); |
314 | TII = STI->getInstrInfo(); |
315 | TRI = STI->getRegisterInfo(); |
316 | MFI = MF.getInfo<M68kMachineFunctionInfo>(); |
317 | FL = STI->getFrameLowering(); |
318 | |
319 | bool Modified = false; |
320 | for (MachineBasicBlock &MBB : MF) |
321 | Modified |= ExpandMBB(MBB); |
322 | return Modified; |
323 | } |
324 | |
325 | /// Returns an instance of the pseudo instruction expansion pass. |
326 | FunctionPass *llvm::createM68kExpandPseudoPass() { |
327 | return new M68kExpandPseudo(); |
328 | } |
329 | |