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/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"
28 
29 using namespace llvm;
30 
31 #define DEBUG_TYPE "M68k-expand-pseudos"
32 
33 namespace {
34 class M68kExpandPseudo : public MachineFunctionPass {
35 public:
36   static char ID;
37   M68kExpandPseudo() : MachineFunctionPass(ID) {}
38 
39   void getAnalysisUsage(AnalysisUsage &AU) const override {
40     AU.setPreservesCFG();
41     AU.addPreservedID(MachineLoopInfoID);
42     AU.addPreservedID(MachineDominatorsID);
43     MachineFunctionPass::getAnalysisUsage(AU);
44   }
45 
46   const M68kSubtarget *STI;
47   const M68kInstrInfo *TII;
48   const M68kRegisterInfo *TRI;
49   const M68kMachineFunctionInfo *MFI;
50   const M68kFrameLowering *FL;
51 
52   bool runOnMachineFunction(MachineFunction &Fn) override;
53 
54   MachineFunctionProperties getRequiredProperties() const override {
55     return MachineFunctionProperties().set(
56         MachineFunctionProperties::Property::NoVRegs);
57   }
58 
59   StringRef getPassName() const override {
60     return "M68k pseudo instruction expansion pass";
61   }
62 
63 private:
64   bool ExpandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI);
65   bool ExpandMBB(MachineBasicBlock &MBB);
66 };
67 char M68kExpandPseudo::ID = 0;
68 } // End anonymous namespace.
69 
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
80   switch (Opcode) {
81   default:
82     return false;
83 
84   case M68k::MOVXd16d8:
85     return TII->ExpandMOVX_RR(MIB, MVT::i16, MVT::i8);
86   case M68k::MOVXd32d8:
87     return TII->ExpandMOVX_RR(MIB, MVT::i32, MVT::i8);
88   case M68k::MOVXd32d16:
89     return TII->ExpandMOVX_RR(MIB, MVT::i32, MVT::i16);
90 
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);
97 
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);
104 
105   case M68k::MOVSXd16j8:
106     return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dj), MVT::i16,
107                                 MVT::i8);
108   case M68k::MOVSXd32j8:
109     return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dj), MVT::i32,
110                                 MVT::i8);
111   case M68k::MOVSXd32j16:
112     return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16rj), MVT::i32,
113                                 MVT::i16);
114 
115   case M68k::MOVZXd16j8:
116     return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dj), MVT::i16,
117                                 MVT::i8);
118   case M68k::MOVZXd32j8:
119     return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dj), MVT::i32,
120                                 MVT::i8);
121   case M68k::MOVZXd32j16:
122     return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16rj), MVT::i32,
123                                 MVT::i16);
124 
125   case M68k::MOVSXd16p8:
126     return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dp), MVT::i16,
127                                 MVT::i8);
128   case M68k::MOVSXd32p8:
129     return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8dp), MVT::i32,
130                                 MVT::i8);
131   case M68k::MOVSXd32p16:
132     return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16rp), MVT::i32,
133                                 MVT::i16);
134 
135   case M68k::MOVZXd16p8:
136     return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dp), MVT::i16,
137                                 MVT::i8);
138   case M68k::MOVZXd32p8:
139     return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8dp), MVT::i32,
140                                 MVT::i8);
141   case M68k::MOVZXd32p16:
142     return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16rp), MVT::i32,
143                                 MVT::i16);
144 
145   case M68k::MOVSXd16f8:
146     return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8df), MVT::i16,
147                                 MVT::i8);
148   case M68k::MOVSXd32f8:
149     return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV8df), MVT::i32,
150                                 MVT::i8);
151   case M68k::MOVSXd32f16:
152     return TII->ExpandMOVSZX_RM(MIB, true, TII->get(M68k::MOV16rf), MVT::i32,
153                                 MVT::i16);
154 
155   case M68k::MOVZXd16f8:
156     return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8df), MVT::i16,
157                                 MVT::i8);
158   case M68k::MOVZXd32f8:
159     return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV8df), MVT::i32,
160                                 MVT::i8);
161   case M68k::MOVZXd32f16:
162     return TII->ExpandMOVSZX_RM(MIB, false, TII->get(M68k::MOV16rf), MVT::i32,
163                                 MVT::i16);
164 
165   case M68k::MOV8cd:
166     return TII->ExpandCCR(MIB, /*IsToCCR=*/true);
167   case M68k::MOV8dc:
168     return TII->ExpandCCR(MIB, /*IsToCCR=*/false);
169 
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);
176 
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);
183 
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);
190 
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);
197 
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.");
203 
204     // Adjust stack pointer.
205     int StackAdj = StackAdjust.getImm();
206     int MaxTCDelta = MFI->getTCReturnAddrDelta();
207     int Offset = 0;
208     assert(MaxTCDelta <= 0 && "MaxTCDelta should never be positive");
209 
210     // Incoporate the retaddr area.
211     Offset = StackAdj - MaxTCDelta;
212     assert(Offset >= 0 && "Offset should never be negative");
213 
214     if (Offset) {
215       // Check for possible merge with preceding ADD instruction.
216       Offset += FL->mergeSPUpdates(MBB, MBBI, true);
217       FL->emitSPUpdate(MBB, MBBI, Offset, /*InEpilogue=*/true);
218     }
219 
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());
227       } else {
228         assert(JumpTarget.isSymbol());
229         MIB.addExternalSymbol(JumpTarget.getSymbolName(),
230                               JumpTarget.getTargetFlags());
231       }
232     } else {
233       BuildMI(MBB, MBBI, DL, TII->get(M68k::TAILJMPj))
234           .addReg(JumpTarget.getReg(), RegState::Kill);
235     }
236 
237     MachineInstr &NewMI = *std::prev(MBBI);
238     NewMI.copyImplicitOps(*MBBI->getParent()->getParent(), *MBBI);
239 
240     // Delete the pseudo instruction TCRETURN.
241     MBB.erase(MBBI);
242 
243     return true;
244   }
245   case M68k::RET: {
246     // Adjust stack to erase error code
247     int64_t StackAdj = MBBI->getOperand(0).getImm();
248     MachineInstrBuilder MIB;
249 
250     if (StackAdj == 0) {
251       MIB = BuildMI(MBB, MBBI, DL, TII->get(M68k::RTS));
252     } else if (isUInt<16>(StackAdj)) {
253 
254       if (STI->atLeastM68020()) {
255         llvm_unreachable("RTD is not implemented");
256       } else {
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)
260             .addReg(M68k::SP);
261 
262         // Adjust SP
263         FL->emitSPUpdate(MBB, MBBI, StackAdj, /*InEpilogue=*/true);
264 
265         // Put the return address on stack
266         BuildMI(MBB, MBBI, DL, TII->get(M68k::MOV32ja))
267             .addReg(M68k::SP)
268             .addReg(M68k::A1);
269 
270         // RTS
271         BuildMI(MBB, MBBI, DL, TII->get(M68k::RTS));
272       }
273     } else {
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");
278     }
279 
280     // FIXME: Can rest of the operands be ignored, if there is any?
281     MBB.erase(MBBI);
282     return true;
283   }
284   }
285   llvm_unreachable("Previous switch has a fallthrough?");
286 }
287 
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;
292 
293   // MBBI may be invalidated by the expansion.
294   MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
295   while (MBBI != E) {
296     MachineBasicBlock::iterator NMBBI = std::next(MBBI);
297     Modified |= ExpandMI(MBB, MBBI);
298     MBBI = NMBBI;
299   }
300 
301   return Modified;
302 }
303 
304 bool M68kExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
305   STI = &MF.getSubtarget<M68kSubtarget>();
306   TII = STI->getInstrInfo();
307   TRI = STI->getRegisterInfo();
308   MFI = MF.getInfo<M68kMachineFunctionInfo>();
309   FL = STI->getFrameLowering();
310 
311   bool Modified = false;
312   for (MachineBasicBlock &MBB : MF)
313     Modified |= ExpandMBB(MBB);
314   return Modified;
315 }
316 
317 /// Returns an instance of the pseudo instruction expansion pass.
318 FunctionPass *llvm::createM68kExpandPseudoPass() {
319   return new M68kExpandPseudo();
320 }
321