diff options
Diffstat (limited to 'contrib/llvm/lib/Target/PIC16/PIC16MemSelOpt.cpp')
-rw-r--r-- | contrib/llvm/lib/Target/PIC16/PIC16MemSelOpt.cpp | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/PIC16/PIC16MemSelOpt.cpp b/contrib/llvm/lib/Target/PIC16/PIC16MemSelOpt.cpp new file mode 100644 index 0000000..ab81ed1 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16MemSelOpt.cpp @@ -0,0 +1,254 @@ +//===-- PIC16MemSelOpt.cpp - PIC16 banksel optimizer --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the pass which optimizes the emitting of banksel +// instructions before accessing data memory. This currently works within +// a basic block only and keep tracks of the last accessed memory bank. +// If memory access continues to be in the same bank it just makes banksel +// immediate, which is a part of the insn accessing the data memory, from 1 +// to zero. The asm printer emits a banksel only if that immediate is 1. +// +// FIXME: this is not implemented yet. The banksel pass only works on local +// basic blocks. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "pic16-codegen" +#include "PIC16.h" +#include "PIC16ABINames.h" +#include "PIC16InstrInfo.h" +#include "PIC16MCAsmInfo.h" +#include "PIC16TargetMachine.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/GlobalValue.h" +#include "llvm/DerivedTypes.h" + +using namespace llvm; + +namespace { + struct MemSelOpt : public MachineFunctionPass { + static char ID; + MemSelOpt() : MachineFunctionPass(&ID) {} + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addPreservedID(MachineLoopInfoID); + AU.addPreservedID(MachineDominatorsID); + MachineFunctionPass::getAnalysisUsage(AU); + } + + virtual bool runOnMachineFunction(MachineFunction &MF); + + virtual const char *getPassName() const { + return "PIC16 Memsel Optimizer"; + } + + bool processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB); + bool processInstruction(MachineInstr *MI); + + private: + const TargetInstrInfo *TII; // Machine instruction info. + MachineBasicBlock *MBB; // Current basic block + std::string CurBank; + int PageChanged; + + }; + char MemSelOpt::ID = 0; +} + +FunctionPass *llvm::createPIC16MemSelOptimizerPass() { + return new MemSelOpt(); +} + + +/// runOnMachineFunction - Loop over all of the basic blocks, transforming FP +/// register references into FP stack references. +/// +bool MemSelOpt::runOnMachineFunction(MachineFunction &MF) { + TII = MF.getTarget().getInstrInfo(); + bool Changed = false; + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + Changed |= processBasicBlock(MF, *I); + } + + return Changed; +} + +/// processBasicBlock - Loop over all of the instructions in the basic block, +/// transforming FP instructions into their stack form. +/// +bool MemSelOpt::processBasicBlock(MachineFunction &MF, MachineBasicBlock &BB) { + bool Changed = false; + MBB = &BB; + + // Let us assume that when entering a basic block now bank is selected. + // Ideally we should look at the predecessors for this information. + CurBank=""; + PageChanged=0; + + MachineBasicBlock::iterator I; + for (I = BB.begin(); I != BB.end(); ++I) { + Changed |= processInstruction(I); + + // if the page has changed insert a page sel before + // any instruction that needs one + if (PageChanged == 1) + { + // Restore the page if it was changed, before leaving the basic block, + // because it may be required by the goto terminator or the fall thru + // basic blcok. + // If the terminator is return, we don't need to restore since there + // is no goto or fall thru basic block. + if ((I->getOpcode() == PIC16::sublw_3) || //macro has goto + (I->getOpcode() == PIC16::sublw_6) || //macro has goto + (I->getOpcode() == PIC16::addlwc) || //macro has goto + (TII->get(I->getOpcode()).isBranch())) + { + DebugLoc dl = I->getDebugLoc(); + BuildMI(*MBB, I, dl, TII->get(PIC16::pagesel)).addExternalSymbol("$"); + Changed = true; + PageChanged = 0; + } + } + } + + // The basic block is over, but if we did not find any goto yet, + // we haven't restored the page. + // Restore the page if it was changed, before leaving the basic block, + // because it may be required by fall thru basic blcok. + // If the terminator is return, we don't need to restore since there + // is fall thru basic block. + if (PageChanged == 1) { + // save the end pointer before we move back to last insn. + MachineBasicBlock::iterator J = I; + I--; + const TargetInstrDesc &TID = TII->get(I->getOpcode()); + if (! TID.isReturn()) + { + DebugLoc dl = I->getDebugLoc(); + BuildMI(*MBB, J, dl, + TII->get(PIC16::pagesel)).addExternalSymbol("$"); + Changed = true; + PageChanged = 0; + } + } + + + return Changed; +} + +bool MemSelOpt::processInstruction(MachineInstr *MI) { + bool Changed = false; + + unsigned NumOperands = MI->getNumOperands(); + if (NumOperands == 0) return false; + + + // If this insn is not going to access any memory, return. + const TargetInstrDesc &TID = TII->get(MI->getOpcode()); + if (!(TID.isBranch() || TID.isCall() || TID.mayLoad() || TID.mayStore())) + return false; + + // The first thing we should do is that record if banksel/pagesel are + // changed in an unknown way. This can happend via any type of call. + // We do it here first before scanning of MemOp / BBOp as the indirect + // call insns do not have any operands, but they still may change bank/page. + if (TID.isCall()) { + // Record that we have changed the page, so that we can restore it + // before basic block ends. + // We require to signal that a page anc bank change happened even for + // indirect calls. + PageChanged = 1; + + // When a call is made, there may be banksel for variables in callee. + // Hence the banksel in caller needs to be reset. + CurBank = ""; + } + + // Scan for the memory address operand. + // FIXME: Should we use standard interfaces like memoperands_iterator, + // hasMemOperand() etc ? + int MemOpPos = -1; + int BBOpPos = -1; + for (unsigned i = 0; i < NumOperands; i++) { + MachineOperand Op = MI->getOperand(i); + if (Op.getType() == MachineOperand::MO_GlobalAddress || + Op.getType() == MachineOperand::MO_ExternalSymbol) { + // We found one mem operand. Next one may be BS. + MemOpPos = i; + } + if (Op.getType() == MachineOperand::MO_MachineBasicBlock) { + // We found one BB operand. Next one may be pagesel. + BBOpPos = i; + } + } + + // If we did not find an insn accessing memory. Continue. + if ((MemOpPos == -1) && + (BBOpPos == -1)) + return false; + assert ((BBOpPos != MemOpPos) && "operand can only be of one type"); + + + // If this is a pagesel material, handle it first. + // CALL and br_ucond insns use MemOp (GA or ES) and not BBOp. + // Pagesel is required only for a direct call. + if ((MI->getOpcode() == PIC16::CALL)) { + // Get the BBOp. + MachineOperand &MemOp = MI->getOperand(MemOpPos); + DebugLoc dl = MI->getDebugLoc(); + BuildMI(*MBB, MI, dl, TII->get(PIC16::pagesel)).addOperand(MemOp); + + // CALL and br_ucond needs only pagesel. so we are done. + return true; + } + + // Pagesel is handled. Now, add a Banksel if needed. + if (MemOpPos == -1) return Changed; + // Get the MemOp. + MachineOperand &Op = MI->getOperand(MemOpPos); + + // Get the section name(NewBank) for MemOp. + // This assumes that the section names for globals are already set by + // AsmPrinter->doInitialization. + std::string NewBank = CurBank; + bool hasExternalLinkage = false; + if (Op.getType() == MachineOperand::MO_GlobalAddress && + Op.getGlobal()->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) { + if (Op.getGlobal()->hasExternalLinkage()) + hasExternalLinkage= true; + NewBank = Op.getGlobal()->getSection(); + } else if (Op.getType() == MachineOperand::MO_ExternalSymbol) { + // External Symbol is generated for temp data and arguments. They are + // in fpdata.<functionname>.# section. + std::string Sym = Op.getSymbolName(); + NewBank = PAN::getSectionNameForSym(Sym); + } + + // If the section is shared section, do not emit banksel. + if (NewBank == PAN::getSharedUDataSectionName()) + return Changed; + + // If the previous and new section names are same, we don't need to + // emit banksel. + if (NewBank.compare(CurBank) != 0 || hasExternalLinkage) { + DebugLoc dl = MI->getDebugLoc(); + BuildMI(*MBB, MI, dl, TII->get(PIC16::banksel)). + addOperand(Op); + Changed = true; + CurBank = NewBank; + } + + return Changed; +} + |