Index: llvm/trunk/lib/Target/AVR/AVR.h =================================================================== --- llvm/trunk/lib/Target/AVR/AVR.h +++ llvm/trunk/lib/Target/AVR/AVR.h @@ -27,10 +27,12 @@ CodeGenOpt::Level OptLevel); FunctionPass *createAVRExpandPseudoPass(); FunctionPass *createAVRFrameAnalyzerPass(); +FunctionPass *createAVRRelaxMemPass(); FunctionPass *createAVRDynAllocaSRPass(); FunctionPass *createAVRBranchSelectionPass(); void initializeAVRExpandPseudoPass(PassRegistry&); +void initializeAVRRelaxMemPass(PassRegistry&); /// Contains the AVR backend. namespace AVR { Index: llvm/trunk/lib/Target/AVR/AVRFrameLowering.cpp =================================================================== --- llvm/trunk/lib/Target/AVR/AVRFrameLowering.cpp +++ llvm/trunk/lib/Target/AVR/AVRFrameLowering.cpp @@ -338,7 +338,6 @@ // pointer since it is guaranteed to contain a copy of SP. unsigned STOpc = (Opcode == AVR::STDWSPQRr) ? AVR::STDWPtrQRr : AVR::STDPtrQRr; - assert(isUInt<6>(MI.getOperand(1).getImm()) && "Offset is out of range"); MI.setDesc(TII.get(STOpc)); MI.getOperand(0).setReg(AVR::R29R28); Index: llvm/trunk/lib/Target/AVR/AVRRelaxMemOperations.cpp =================================================================== --- llvm/trunk/lib/Target/AVR/AVRRelaxMemOperations.cpp +++ llvm/trunk/lib/Target/AVR/AVRRelaxMemOperations.cpp @@ -0,0 +1,149 @@ +//===-- AVRRelaxMemOperations.cpp - Relax out of range loads/stores -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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/Target/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 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(); + 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(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(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 Index: llvm/trunk/lib/Target/AVR/AVRTargetMachine.cpp =================================================================== --- llvm/trunk/lib/Target/AVR/AVRTargetMachine.cpp +++ llvm/trunk/lib/Target/AVR/AVRTargetMachine.cpp @@ -80,6 +80,7 @@ auto &PR = *PassRegistry::getPassRegistry(); initializeAVRExpandPseudoPass(PR); + initializeAVRRelaxMemPass(PR); } const AVRSubtarget *AVRTargetMachine::getSubtargetImpl() const { @@ -108,6 +109,9 @@ addPass(createAVRDynAllocaSRPass()); } -void AVRPassConfig::addPreSched2() { addPass(createAVRExpandPseudoPass()); } +void AVRPassConfig::addPreSched2() { + addPass(createAVRRelaxMemPass()); + addPass(createAVRExpandPseudoPass()); +} } // end of namespace llvm Index: llvm/trunk/lib/Target/AVR/CMakeLists.txt =================================================================== --- llvm/trunk/lib/Target/AVR/CMakeLists.txt +++ llvm/trunk/lib/Target/AVR/CMakeLists.txt @@ -24,6 +24,7 @@ AVRISelDAGToDAG.cpp AVRISelLowering.cpp AVRMCInstLower.cpp + AVRRelaxMemOperations.cpp AVRRegisterInfo.cpp AVRSubtarget.cpp AVRTargetMachine.cpp Index: llvm/trunk/test/CodeGen/AVR/relax-mem/STDWPtrQRr.mir =================================================================== --- llvm/trunk/test/CodeGen/AVR/relax-mem/STDWPtrQRr.mir +++ llvm/trunk/test/CodeGen/AVR/relax-mem/STDWPtrQRr.mir @@ -0,0 +1,31 @@ +# RUN: llc -O0 -run-pass=avr-relax-mem %s -o - 2>&1 | FileCheck %s + +--- | + target triple = "avr--" + define void @test() { + entry: + ret void + } +... + +--- +name: test +body: | + bb.0.entry: + + ; CHECK-LABEL: test + + ; We shouldn't expand things which already have 6-bit imms. + ; CHECK: STDWPtrQRr %r29r28, 63, %r1r0 + STDWPtrQRr %r29r28, 63, %r1r0 + + ; We shouldn't expand things which already have 6-bit imms. + ; CHECK-NEXT: STDWPtrQRr %r29r28, 0, %r1r0 + STDWPtrQRr %r29r28, 0, %r1r0 + + ; CHECK-NEXT: PUSHWRr %r29r28, implicit-def %sp, implicit %sp + ; CHECK-NEXT: %r29r28 = SBCIWRdK %r29r28, -64, implicit-def %sreg, implicit %sreg + ; CHECK-NEXT: STWPtrRr %r29r28, %r1r0 + ; CHECK-NEXT: POPWRd %r29r28, implicit-def %sp, implicit %sp + STDWPtrQRr %r29r28, 64, %r1r0 +...