1 //===-- AVRRelaxMemOperations.cpp - Relax out of range loads/stores -------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file contains a pass which relaxes out of range memory operations into
10 // equivalent operations which handle bigger addresses.
12 //===----------------------------------------------------------------------===//
15 #include "AVRInstrInfo.h"
16 #include "AVRTargetMachine.h"
17 #include "MCTargetDesc/AVRMCTargetDesc.h"
19 #include "llvm/CodeGen/MachineFunctionPass.h"
20 #include "llvm/CodeGen/MachineInstrBuilder.h"
21 #include "llvm/CodeGen/MachineRegisterInfo.h"
22 #include "llvm/CodeGen/TargetRegisterInfo.h"
26 #define AVR_RELAX_MEM_OPS_NAME "AVR memory operation relaxation pass"
30 class AVRRelaxMem
: public MachineFunctionPass
{
34 AVRRelaxMem() : MachineFunctionPass(ID
) {
35 initializeAVRRelaxMemPass(*PassRegistry::getPassRegistry());
38 bool runOnMachineFunction(MachineFunction
&MF
) override
;
40 StringRef
getPassName() const override
{ return AVR_RELAX_MEM_OPS_NAME
; }
43 typedef MachineBasicBlock Block
;
44 typedef Block::iterator BlockIt
;
46 const TargetInstrInfo
*TII
;
48 template <unsigned OP
> bool relax(Block
&MBB
, BlockIt MBBI
);
50 bool runOnBasicBlock(Block
&MBB
);
51 bool runOnInstruction(Block
&MBB
, BlockIt MBBI
);
53 MachineInstrBuilder
buildMI(Block
&MBB
, BlockIt MBBI
, unsigned Opcode
) {
54 return BuildMI(MBB
, MBBI
, MBBI
->getDebugLoc(), TII
->get(Opcode
));
58 char AVRRelaxMem::ID
= 0;
60 bool AVRRelaxMem::runOnMachineFunction(MachineFunction
&MF
) {
61 bool Modified
= false;
63 const AVRSubtarget
&STI
= MF
.getSubtarget
<AVRSubtarget
>();
64 TII
= STI
.getInstrInfo();
66 for (Block
&MBB
: MF
) {
67 bool BlockModified
= runOnBasicBlock(MBB
);
68 Modified
|= BlockModified
;
74 bool AVRRelaxMem::runOnBasicBlock(Block
&MBB
) {
75 bool Modified
= false;
77 BlockIt MBBI
= MBB
.begin(), E
= MBB
.end();
79 BlockIt NMBBI
= std::next(MBBI
);
80 Modified
|= runOnInstruction(MBB
, MBBI
);
88 bool AVRRelaxMem::relax
<AVR::STDWPtrQRr
>(Block
&MBB
, BlockIt MBBI
) {
89 MachineInstr
&MI
= *MBBI
;
91 MachineOperand
&Ptr
= MI
.getOperand(0);
92 MachineOperand
&Src
= MI
.getOperand(2);
93 int64_t Imm
= MI
.getOperand(1).getImm();
95 // We can definitely optimise this better.
97 // Push the previous state of the pointer register.
98 // This instruction must preserve the value.
99 buildMI(MBB
, MBBI
, AVR::PUSHWRr
)
100 .addReg(Ptr
.getReg());
102 // Add the immediate to the pointer register.
103 buildMI(MBB
, MBBI
, AVR::SBCIWRdK
)
104 .addReg(Ptr
.getReg(), RegState::Define
)
105 .addReg(Ptr
.getReg())
108 // Store the value in the source register to the address
109 // pointed to by the pointer register.
110 buildMI(MBB
, MBBI
, AVR::STWPtrRr
)
111 .addReg(Ptr
.getReg())
112 .addReg(Src
.getReg(), getKillRegState(Src
.isKill()));
114 // Pop the original state of the pointer register.
115 buildMI(MBB
, MBBI
, AVR::POPWRd
)
116 .addReg(Ptr
.getReg(), getKillRegState(Ptr
.isKill()));
118 MI
.removeFromParent();
124 bool AVRRelaxMem::runOnInstruction(Block
&MBB
, BlockIt MBBI
) {
125 MachineInstr
&MI
= *MBBI
;
126 int Opcode
= MBBI
->getOpcode();
130 return relax<Op>(MBB, MI)
133 RELAX(AVR::STDWPtrQRr
);
139 } // end of anonymous namespace
141 INITIALIZE_PASS(AVRRelaxMem
, "avr-relax-mem",
142 AVR_RELAX_MEM_OPS_NAME
, false, false)
146 FunctionPass
*createAVRRelaxMemPass() { return new AVRRelaxMem(); }
148 } // end of namespace llvm