|  | //===-- AVRRelaxMemOperations.cpp - Relax out of range loads/stores -------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file contains a pass which relaxes out of range memory operations into | 
|  | // equivalent operations which handle bigger addresses. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "AVR.h" | 
|  | #include "AVRInstrInfo.h" | 
|  | #include "AVRTargetMachine.h" | 
|  | #include "MCTargetDesc/AVRMCTargetDesc.h" | 
|  |  | 
|  | #include "llvm/CodeGen/MachineFunctionPass.h" | 
|  | #include "llvm/CodeGen/MachineInstrBuilder.h" | 
|  | #include "llvm/CodeGen/MachineRegisterInfo.h" | 
|  | #include "llvm/CodeGen/TargetRegisterInfo.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | #define AVR_RELAX_MEM_OPS_NAME "AVR memory operation relaxation pass" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class AVRRelaxMem : public MachineFunctionPass { | 
|  | public: | 
|  | static char ID; | 
|  |  | 
|  | AVRRelaxMem() : MachineFunctionPass(ID) { | 
|  | initializeAVRRelaxMemPass(*PassRegistry::getPassRegistry()); | 
|  | } | 
|  |  | 
|  | bool runOnMachineFunction(MachineFunction &MF) override; | 
|  |  | 
|  | StringRef getPassName() const override { return AVR_RELAX_MEM_OPS_NAME; } | 
|  |  | 
|  | private: | 
|  | typedef MachineBasicBlock Block; | 
|  | typedef Block::iterator BlockIt; | 
|  |  | 
|  | const TargetInstrInfo *TII; | 
|  |  | 
|  | template <unsigned OP> bool relax(Block &MBB, BlockIt MBBI); | 
|  |  | 
|  | bool runOnBasicBlock(Block &MBB); | 
|  | bool runOnInstruction(Block &MBB, BlockIt MBBI); | 
|  |  | 
|  | MachineInstrBuilder buildMI(Block &MBB, BlockIt MBBI, unsigned Opcode) { | 
|  | return BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Opcode)); | 
|  | } | 
|  | }; | 
|  |  | 
|  | char AVRRelaxMem::ID = 0; | 
|  |  | 
|  | bool AVRRelaxMem::runOnMachineFunction(MachineFunction &MF) { | 
|  | bool Modified = false; | 
|  |  | 
|  | const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>(); | 
|  | TII = STI.getInstrInfo(); | 
|  |  | 
|  | for (Block &MBB : MF) { | 
|  | bool BlockModified = runOnBasicBlock(MBB); | 
|  | Modified |= BlockModified; | 
|  | } | 
|  |  | 
|  | return Modified; | 
|  | } | 
|  |  | 
|  | bool AVRRelaxMem::runOnBasicBlock(Block &MBB) { | 
|  | bool Modified = false; | 
|  |  | 
|  | BlockIt MBBI = MBB.begin(), E = MBB.end(); | 
|  | while (MBBI != E) { | 
|  | BlockIt NMBBI = std::next(MBBI); | 
|  | Modified |= runOnInstruction(MBB, MBBI); | 
|  | MBBI = NMBBI; | 
|  | } | 
|  |  | 
|  | return Modified; | 
|  | } | 
|  |  | 
|  | template <> | 
|  | bool AVRRelaxMem::relax<AVR::STDWPtrQRr>(Block &MBB, BlockIt MBBI) { | 
|  | MachineInstr &MI = *MBBI; | 
|  |  | 
|  | MachineOperand &Ptr = MI.getOperand(0); | 
|  | MachineOperand &Src = MI.getOperand(2); | 
|  | int64_t Imm = MI.getOperand(1).getImm(); | 
|  |  | 
|  | // We can definitely optimise this better. | 
|  | if (Imm > 63) { | 
|  | // Push the previous state of the pointer register. | 
|  | // This instruction must preserve the value. | 
|  | buildMI(MBB, MBBI, AVR::PUSHWRr) | 
|  | .addReg(Ptr.getReg()); | 
|  |  | 
|  | // Add the immediate to the pointer register. | 
|  | buildMI(MBB, MBBI, AVR::SBCIWRdK) | 
|  | .addReg(Ptr.getReg(), RegState::Define) | 
|  | .addReg(Ptr.getReg()) | 
|  | .addImm(-Imm); | 
|  |  | 
|  | // Store the value in the source register to the address | 
|  | // pointed to by the pointer register. | 
|  | buildMI(MBB, MBBI, AVR::STWPtrRr) | 
|  | .addReg(Ptr.getReg()) | 
|  | .addReg(Src.getReg(), getKillRegState(Src.isKill())); | 
|  |  | 
|  | // Pop the original state of the pointer register. | 
|  | buildMI(MBB, MBBI, AVR::POPWRd) | 
|  | .addReg(Ptr.getReg(), getKillRegState(Ptr.isKill())); | 
|  |  | 
|  | MI.removeFromParent(); | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool AVRRelaxMem::runOnInstruction(Block &MBB, BlockIt MBBI) { | 
|  | MachineInstr &MI = *MBBI; | 
|  | int Opcode = MBBI->getOpcode(); | 
|  |  | 
|  | #define RELAX(Op)                \ | 
|  | case Op:                       \ | 
|  | return relax<Op>(MBB, MI) | 
|  |  | 
|  | switch (Opcode) { | 
|  | RELAX(AVR::STDWPtrQRr); | 
|  | } | 
|  | #undef RELAX | 
|  | return false; | 
|  | } | 
|  |  | 
|  | } // end of anonymous namespace | 
|  |  | 
|  | INITIALIZE_PASS(AVRRelaxMem, "avr-relax-mem", | 
|  | AVR_RELAX_MEM_OPS_NAME, false, false) | 
|  |  | 
|  | namespace llvm { | 
|  |  | 
|  | FunctionPass *createAVRRelaxMemPass() { return new AVRRelaxMem(); } | 
|  |  | 
|  | } // end of namespace llvm |