1d88c1a5aSDimitry Andric //===-- AVRRelaxMemOperations.cpp - Relax out of range loads/stores -------===//
2d88c1a5aSDimitry Andric //
3d88c1a5aSDimitry Andric //                     The LLVM Compiler Infrastructure
4d88c1a5aSDimitry Andric //
5d88c1a5aSDimitry Andric // This file is distributed under the University of Illinois Open Source
6d88c1a5aSDimitry Andric // License. See LICENSE.TXT for details.
7d88c1a5aSDimitry Andric //
8d88c1a5aSDimitry Andric //===----------------------------------------------------------------------===//
9d88c1a5aSDimitry Andric //
10d88c1a5aSDimitry Andric // This file contains a pass which relaxes out of range memory operations into
11d88c1a5aSDimitry Andric // equivalent operations which handle bigger addresses.
12d88c1a5aSDimitry Andric //
13d88c1a5aSDimitry Andric //===----------------------------------------------------------------------===//
14d88c1a5aSDimitry Andric 
15d88c1a5aSDimitry Andric #include "AVR.h"
16d88c1a5aSDimitry Andric #include "AVRInstrInfo.h"
17d88c1a5aSDimitry Andric #include "AVRTargetMachine.h"
18d88c1a5aSDimitry Andric #include "MCTargetDesc/AVRMCTargetDesc.h"
19d88c1a5aSDimitry Andric 
20d88c1a5aSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
21d88c1a5aSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
22d88c1a5aSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
23*2cab237bSDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
24d88c1a5aSDimitry Andric 
25d88c1a5aSDimitry Andric using namespace llvm;
26d88c1a5aSDimitry Andric 
27d88c1a5aSDimitry Andric #define AVR_RELAX_MEM_OPS_NAME "AVR memory operation relaxation pass"
28d88c1a5aSDimitry Andric 
29d88c1a5aSDimitry Andric namespace {
30d88c1a5aSDimitry Andric 
31d88c1a5aSDimitry Andric class AVRRelaxMem : public MachineFunctionPass {
32d88c1a5aSDimitry Andric public:
33d88c1a5aSDimitry Andric   static char ID;
34d88c1a5aSDimitry Andric 
AVRRelaxMem()35d88c1a5aSDimitry Andric   AVRRelaxMem() : MachineFunctionPass(ID) {
36d88c1a5aSDimitry Andric     initializeAVRRelaxMemPass(*PassRegistry::getPassRegistry());
37d88c1a5aSDimitry Andric   }
38d88c1a5aSDimitry Andric 
39d88c1a5aSDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
40d88c1a5aSDimitry Andric 
getPassName() const41d88c1a5aSDimitry Andric   StringRef getPassName() const override { return AVR_RELAX_MEM_OPS_NAME; }
42d88c1a5aSDimitry Andric 
43d88c1a5aSDimitry Andric private:
44d88c1a5aSDimitry Andric   typedef MachineBasicBlock Block;
45d88c1a5aSDimitry Andric   typedef Block::iterator BlockIt;
46d88c1a5aSDimitry Andric 
47d88c1a5aSDimitry Andric   const TargetInstrInfo *TII;
48d88c1a5aSDimitry Andric 
49d88c1a5aSDimitry Andric   template <unsigned OP> bool relax(Block &MBB, BlockIt MBBI);
50d88c1a5aSDimitry Andric 
51d88c1a5aSDimitry Andric   bool runOnBasicBlock(Block &MBB);
52d88c1a5aSDimitry Andric   bool runOnInstruction(Block &MBB, BlockIt MBBI);
53d88c1a5aSDimitry Andric 
buildMI(Block & MBB,BlockIt MBBI,unsigned Opcode)54d88c1a5aSDimitry Andric   MachineInstrBuilder buildMI(Block &MBB, BlockIt MBBI, unsigned Opcode) {
55d88c1a5aSDimitry Andric     return BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Opcode));
56d88c1a5aSDimitry Andric   }
57d88c1a5aSDimitry Andric };
58d88c1a5aSDimitry Andric 
59d88c1a5aSDimitry Andric char AVRRelaxMem::ID = 0;
60d88c1a5aSDimitry Andric 
runOnMachineFunction(MachineFunction & MF)61d88c1a5aSDimitry Andric bool AVRRelaxMem::runOnMachineFunction(MachineFunction &MF) {
62d88c1a5aSDimitry Andric   bool Modified = false;
63d88c1a5aSDimitry Andric 
64d88c1a5aSDimitry Andric   const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
65d88c1a5aSDimitry Andric   TII = STI.getInstrInfo();
66d88c1a5aSDimitry Andric 
67d88c1a5aSDimitry Andric   for (Block &MBB : MF) {
68d88c1a5aSDimitry Andric     bool BlockModified = runOnBasicBlock(MBB);
69d88c1a5aSDimitry Andric     Modified |= BlockModified;
70d88c1a5aSDimitry Andric   }
71d88c1a5aSDimitry Andric 
72d88c1a5aSDimitry Andric   return Modified;
73d88c1a5aSDimitry Andric }
74d88c1a5aSDimitry Andric 
runOnBasicBlock(Block & MBB)75d88c1a5aSDimitry Andric bool AVRRelaxMem::runOnBasicBlock(Block &MBB) {
76d88c1a5aSDimitry Andric   bool Modified = false;
77d88c1a5aSDimitry Andric 
78d88c1a5aSDimitry Andric   BlockIt MBBI = MBB.begin(), E = MBB.end();
79d88c1a5aSDimitry Andric   while (MBBI != E) {
80d88c1a5aSDimitry Andric     BlockIt NMBBI = std::next(MBBI);
81d88c1a5aSDimitry Andric     Modified |= runOnInstruction(MBB, MBBI);
82d88c1a5aSDimitry Andric     MBBI = NMBBI;
83d88c1a5aSDimitry Andric   }
84d88c1a5aSDimitry Andric 
85d88c1a5aSDimitry Andric   return Modified;
86d88c1a5aSDimitry Andric }
87d88c1a5aSDimitry Andric 
88d88c1a5aSDimitry Andric template <>
relax(Block & MBB,BlockIt MBBI)89d88c1a5aSDimitry Andric bool AVRRelaxMem::relax<AVR::STDWPtrQRr>(Block &MBB, BlockIt MBBI) {
90d88c1a5aSDimitry Andric   MachineInstr &MI = *MBBI;
91d88c1a5aSDimitry Andric 
92d88c1a5aSDimitry Andric   MachineOperand &Ptr = MI.getOperand(0);
93d88c1a5aSDimitry Andric   MachineOperand &Src = MI.getOperand(2);
94d88c1a5aSDimitry Andric   int64_t Imm = MI.getOperand(1).getImm();
95d88c1a5aSDimitry Andric 
96d88c1a5aSDimitry Andric   // We can definitely optimise this better.
97d88c1a5aSDimitry Andric   if (Imm > 63) {
98d88c1a5aSDimitry Andric     // Push the previous state of the pointer register.
99d88c1a5aSDimitry Andric     // This instruction must preserve the value.
100d88c1a5aSDimitry Andric     buildMI(MBB, MBBI, AVR::PUSHWRr)
101d88c1a5aSDimitry Andric       .addReg(Ptr.getReg());
102d88c1a5aSDimitry Andric 
103d88c1a5aSDimitry Andric     // Add the immediate to the pointer register.
104d88c1a5aSDimitry Andric     buildMI(MBB, MBBI, AVR::SBCIWRdK)
105d88c1a5aSDimitry Andric       .addReg(Ptr.getReg(), RegState::Define)
106d88c1a5aSDimitry Andric       .addReg(Ptr.getReg())
107d88c1a5aSDimitry Andric       .addImm(-Imm);
108d88c1a5aSDimitry Andric 
109d88c1a5aSDimitry Andric     // Store the value in the source register to the address
110d88c1a5aSDimitry Andric     // pointed to by the pointer register.
111d88c1a5aSDimitry Andric     buildMI(MBB, MBBI, AVR::STWPtrRr)
112d88c1a5aSDimitry Andric       .addReg(Ptr.getReg())
113d88c1a5aSDimitry Andric       .addReg(Src.getReg(), getKillRegState(Src.isKill()));
114d88c1a5aSDimitry Andric 
115d88c1a5aSDimitry Andric     // Pop the original state of the pointer register.
116d88c1a5aSDimitry Andric     buildMI(MBB, MBBI, AVR::POPWRd)
117d88c1a5aSDimitry Andric       .addReg(Ptr.getReg(), getKillRegState(Ptr.isKill()));
118d88c1a5aSDimitry Andric 
119d88c1a5aSDimitry Andric     MI.removeFromParent();
120d88c1a5aSDimitry Andric   }
121d88c1a5aSDimitry Andric 
122d88c1a5aSDimitry Andric   return false;
123d88c1a5aSDimitry Andric }
124d88c1a5aSDimitry Andric 
runOnInstruction(Block & MBB,BlockIt MBBI)125d88c1a5aSDimitry Andric bool AVRRelaxMem::runOnInstruction(Block &MBB, BlockIt MBBI) {
126d88c1a5aSDimitry Andric   MachineInstr &MI = *MBBI;
127d88c1a5aSDimitry Andric   int Opcode = MBBI->getOpcode();
128d88c1a5aSDimitry Andric 
129d88c1a5aSDimitry Andric #define RELAX(Op)                \
130d88c1a5aSDimitry Andric   case Op:                       \
131d88c1a5aSDimitry Andric     return relax<Op>(MBB, MI)
132d88c1a5aSDimitry Andric 
133d88c1a5aSDimitry Andric   switch (Opcode) {
134d88c1a5aSDimitry Andric     RELAX(AVR::STDWPtrQRr);
135d88c1a5aSDimitry Andric   }
136d88c1a5aSDimitry Andric #undef RELAX
137d88c1a5aSDimitry Andric   return false;
138d88c1a5aSDimitry Andric }
139d88c1a5aSDimitry Andric 
140d88c1a5aSDimitry Andric } // end of anonymous namespace
141d88c1a5aSDimitry Andric 
142d88c1a5aSDimitry Andric INITIALIZE_PASS(AVRRelaxMem, "avr-relax-mem",
143d88c1a5aSDimitry Andric                 AVR_RELAX_MEM_OPS_NAME, false, false)
144d88c1a5aSDimitry Andric 
145d88c1a5aSDimitry Andric namespace llvm {
146d88c1a5aSDimitry Andric 
createAVRRelaxMemPass()147d88c1a5aSDimitry Andric FunctionPass *createAVRRelaxMemPass() { return new AVRRelaxMem(); }
148d88c1a5aSDimitry Andric 
149d88c1a5aSDimitry Andric } // end of namespace llvm
150