xref: /freebsd/contrib/llvm-project/llvm/lib/Target/M68k/M68kExpandPseudo.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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