diff options
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/lib/Target/AVR/AVR.h | 2 | ||||
-rw-r--r-- | llvm/lib/Target/AVR/AVRFrameLowering.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp | 149 | ||||
-rw-r--r-- | llvm/lib/Target/AVR/AVRTargetMachine.cpp | 6 | ||||
-rw-r--r-- | llvm/lib/Target/AVR/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/test/CodeGen/AVR/relax-mem/STDWPtrQRr.mir | 31 |
6 files changed, 188 insertions, 2 deletions
diff --git a/llvm/lib/Target/AVR/AVR.h b/llvm/lib/Target/AVR/AVR.h index 0b4ba45262f..45119adb553 100644 --- a/llvm/lib/Target/AVR/AVR.h +++ b/llvm/lib/Target/AVR/AVR.h @@ -27,10 +27,12 @@ FunctionPass *createAVRISelDag(AVRTargetMachine &TM, 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 { diff --git a/llvm/lib/Target/AVR/AVRFrameLowering.cpp b/llvm/lib/Target/AVR/AVRFrameLowering.cpp index ab95be8f3ab..b8cb2215ddb 100644 --- a/llvm/lib/Target/AVR/AVRFrameLowering.cpp +++ b/llvm/lib/Target/AVR/AVRFrameLowering.cpp @@ -338,7 +338,6 @@ static void fixStackStores(MachineBasicBlock &MBB, // 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); diff --git a/llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp b/llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp new file mode 100644 index 00000000000..26dbcf77b45 --- /dev/null +++ b/llvm/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 <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 diff --git a/llvm/lib/Target/AVR/AVRTargetMachine.cpp b/llvm/lib/Target/AVR/AVRTargetMachine.cpp index 4189a242e9d..9d10ef96e11 100644 --- a/llvm/lib/Target/AVR/AVRTargetMachine.cpp +++ b/llvm/lib/Target/AVR/AVRTargetMachine.cpp @@ -80,6 +80,7 @@ extern "C" void LLVMInitializeAVRTarget() { auto &PR = *PassRegistry::getPassRegistry(); initializeAVRExpandPseudoPass(PR); + initializeAVRRelaxMemPass(PR); } const AVRSubtarget *AVRTargetMachine::getSubtargetImpl() const { @@ -108,6 +109,9 @@ void AVRPassConfig::addPreRegAlloc() { addPass(createAVRDynAllocaSRPass()); } -void AVRPassConfig::addPreSched2() { addPass(createAVRExpandPseudoPass()); } +void AVRPassConfig::addPreSched2() { + addPass(createAVRRelaxMemPass()); + addPass(createAVRExpandPseudoPass()); +} } // end of namespace llvm diff --git a/llvm/lib/Target/AVR/CMakeLists.txt b/llvm/lib/Target/AVR/CMakeLists.txt index 83f55020e88..af89a2476c4 100644 --- a/llvm/lib/Target/AVR/CMakeLists.txt +++ b/llvm/lib/Target/AVR/CMakeLists.txt @@ -24,6 +24,7 @@ add_llvm_target(AVRCodeGen AVRISelDAGToDAG.cpp AVRISelLowering.cpp AVRMCInstLower.cpp + AVRRelaxMemOperations.cpp AVRRegisterInfo.cpp AVRSubtarget.cpp AVRTargetMachine.cpp diff --git a/llvm/test/CodeGen/AVR/relax-mem/STDWPtrQRr.mir b/llvm/test/CodeGen/AVR/relax-mem/STDWPtrQRr.mir new file mode 100644 index 00000000000..b43c7750832 --- /dev/null +++ b/llvm/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 +... |