summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/Target/AVR/AVR.h2
-rw-r--r--llvm/lib/Target/AVR/AVRFrameLowering.cpp1
-rw-r--r--llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp149
-rw-r--r--llvm/lib/Target/AVR/AVRTargetMachine.cpp6
-rw-r--r--llvm/lib/Target/AVR/CMakeLists.txt1
5 files changed, 157 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
OpenPOWER on IntegriCloud