From d8d27f4a4b9461aee581217691d896d4eba985fa Mon Sep 17 00:00:00 2001 From: Sanjiv Gupta Date: Wed, 6 May 2009 08:02:01 +0000 Subject: [PATCH] Emit banksel and movlp instructions. Split large global data (both initialized and un-initialized) into multiple sections of <= 80 bytes. Provide routines to manage PIC16 ABI naming conventions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@71073 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/PIC16/PIC16.h | 93 +++++++++++ lib/Target/PIC16/PIC16AsmPrinter.cpp | 168 ++++++-------------- lib/Target/PIC16/PIC16AsmPrinter.h | 5 +- lib/Target/PIC16/PIC16ISelLowering.cpp | 16 +- lib/Target/PIC16/PIC16InstrInfo.cpp | 8 +- lib/Target/PIC16/PIC16InstrInfo.h | 17 ++ lib/Target/PIC16/PIC16InstrInfo.td | 13 +- lib/Target/PIC16/PIC16MemSelOpt.cpp | 163 +++++++++++++++++++ lib/Target/PIC16/PIC16TargetAsmInfo.cpp | 203 ++++++++++++++++++++++++ lib/Target/PIC16/PIC16TargetAsmInfo.h | 35 +++- lib/Target/PIC16/PIC16TargetMachine.cpp | 6 + lib/Target/PIC16/PIC16TargetMachine.h | 1 + 12 files changed, 586 insertions(+), 142 deletions(-) create mode 100644 lib/Target/PIC16/PIC16MemSelOpt.cpp diff --git a/lib/Target/PIC16/PIC16.h b/lib/Target/PIC16/PIC16.h index 42bd7bc8e14..330bed85ff3 100644 --- a/lib/Target/PIC16/PIC16.h +++ b/lib/Target/PIC16/PIC16.h @@ -18,6 +18,7 @@ #include "llvm/Target/TargetMachine.h" #include #include +#include namespace llvm { class PIC16TargetMachine; @@ -39,6 +40,94 @@ namespace PIC16CC { UGE }; } + // A Central object to manage all ABI naming conventions. + class PIC16ABINames { + public: + // Map the name of the symbol to its section name. + // Current ABI: + // ------------------------------------------------------ + // Global variables do not have any '.' in their names. + // they are prefixed with @ + // These are maily function names and global variable names. + // ------------------------------------------------------- + // Functions and auto variables. + // Names are mangled as .. + // Where prefix is a special char '@' and id is any one of + // the following + // .auto. - an automatic var of a function. + // .temp. - temproray data of a function. + // .ret. - return value label for a function. + // .frame. - Frame label for a function where retval, args + // and temps are stored. + // .args. - Label used to pass arguments to a direct call. + // Example - Function name: @foo + // Its frame: @foo.frame. + // Its retval: @foo.ret. + // Its local vars: @foo.auto.a + // Its temp data: @foo.temp. + // Its arg passing: @foo.args. + //---------------------------------------------- + // Libcall - compiler generated libcall names must have a .lib. + // This id will be used to emit extern decls for libcalls. + // Example - libcall name: @sra_i8.lib. + // To pass args: @sra_i8.args. + // To return val: @sra_i8.ret. + //---------------------------------------------- + + enum IDs { + PREFIX_SYMBOL, + + FUNC_AUTOS, + FUNC_FRAME, + FUNC_RET, + FUNC_ARGS, + FUNC_TEMPS, + + LIBCALL, + + FRAME_SECTION, + AUTOS_SECTION + }; + + }; + + inline static const char *getIDName(PIC16ABINames::IDs id) { + switch (id) { + default: assert(0 && "Unknown id"); + case PIC16ABINames::PREFIX_SYMBOL: return "@"; + case PIC16ABINames::FUNC_AUTOS: return ".auto."; + case PIC16ABINames::FUNC_FRAME: return ".frame."; + case PIC16ABINames::FUNC_TEMPS: return ".temp."; + case PIC16ABINames::FUNC_ARGS: return ".args."; + case PIC16ABINames::FUNC_RET: return ".ret."; + case PIC16ABINames::FRAME_SECTION: return "fpdata"; + case PIC16ABINames::AUTOS_SECTION: return "fadata"; + } + } + + inline static PIC16ABINames::IDs getID(const std::string &Sym) { + if (Sym.find(getIDName(PIC16ABINames::FUNC_TEMPS))) + return PIC16ABINames::FUNC_TEMPS; + + if (Sym.find(getIDName(PIC16ABINames::FUNC_FRAME))) + return PIC16ABINames::FUNC_FRAME; + + if (Sym.find(getIDName(PIC16ABINames::FUNC_RET))) + return PIC16ABINames::FUNC_RET; + + if (Sym.find(getIDName(PIC16ABINames::FUNC_ARGS))) + return PIC16ABINames::FUNC_ARGS; + + if (Sym.find(getIDName(PIC16ABINames::FUNC_AUTOS))) + return PIC16ABINames::FUNC_AUTOS; + + if (Sym.find(getIDName(PIC16ABINames::LIBCALL))) + return PIC16ABINames::LIBCALL; + + // It does not have any ID. So its a global. + assert (0 && "Could not determine ID symbol type"); + } + inline static const char *PIC16CondCodeToString(PIC16CC::CondCodes CC) { switch (CC) { @@ -73,11 +162,15 @@ namespace PIC16CC { } + FunctionPass *createPIC16ISelDag(PIC16TargetMachine &TM); FunctionPass *createPIC16CodePrinterPass(raw_ostream &OS, PIC16TargetMachine &TM, CodeGenOpt::Level OptLevel, bool Verbose); + // Banksel optimzer pass. + FunctionPass *createPIC16MemSelOptimizerPass(); + std::string getSectionNameForSym(const std::string &Sym); } // end namespace llvm; // Defines symbolic names for PIC16 registers. This defines a mapping from diff --git a/lib/Target/PIC16/PIC16AsmPrinter.cpp b/lib/Target/PIC16/PIC16AsmPrinter.cpp index 510e105ebd2..87ecb2004bc 100644 --- a/lib/Target/PIC16/PIC16AsmPrinter.cpp +++ b/lib/Target/PIC16/PIC16AsmPrinter.cpp @@ -45,51 +45,6 @@ inline static bool isLocalName (std::string &Name) { } bool PIC16AsmPrinter::printMachineInstruction(const MachineInstr *MI) { - std::string NewBank = ""; - unsigned Operands = MI->getNumOperands(); - if (Operands > 1) { - // If we have a Global address or external symbol then we need to print - // banksel for it. - unsigned BankSelVar = 0; - MachineOperand Op = MI->getOperand(BankSelVar); - while (BankSelVar < Operands-1) { - Op = MI->getOperand(BankSelVar); - if ((Op.getType() == MachineOperand::MO_GlobalAddress) || - (Op.getType() == MachineOperand::MO_ExternalSymbol)) - break; - BankSelVar++; - } - if (BankSelVar < Operands-1) { - unsigned OpType = Op.getType(); - if (OpType == MachineOperand::MO_GlobalAddress ) - NewBank = Op.getGlobal()->getSection(); - else { - // External Symbol is generated for temp data and arguments. They are - // in fpdata..# section. - std::string ESName = Op.getSymbolName(); - int index = ESName.find_first_of("."); - std::string FnName = ESName.substr(0,index); - NewBank = "fpdata." + FnName +".#"; - } - // Operand after global address or external symbol should be banksel. - // Value 1 for this operand means we need to generate banksel else do not - // generate banksel. - const MachineOperand &BS = MI->getOperand(BankSelVar+1); - // If Section names are same then the variables are in same section. - // This is not true for external variables as section names for global - // variables in all files are same at this time. For eg. initialized - // data in put in idata.# section in all files. - if ((BS.getType() == MachineOperand::MO_Immediate - && (int)BS.getImm() == 1) - && ((Op.isGlobal() && Op.getGlobal()->hasExternalLinkage()) || - (NewBank.compare(CurBank) != 0))) { - O << "\tbanksel "; - printOperand(MI, BankSelVar); - O << "\n"; - CurBank = NewBank; - } - } - } printInstruction(MI); return true; } @@ -118,8 +73,8 @@ bool PIC16AsmPrinter::runOnMachineFunction(MachineFunction &MF) { SwitchToSection (fCodeSection); // Emit the frame address of the function at the beginning of code. - O << " retlw low(" << FunctionLabelBegin<< CurrentFnName << ".frame)\n"; - O << " retlw high(" << FunctionLabelBegin<< CurrentFnName << ".frame)\n"; + O << " retlw low(" << FunctionLabelBegin<< CurrentFnName << ".frame.)\n"; + O << " retlw high(" << FunctionLabelBegin<< CurrentFnName << ".frame.)\n"; O << CurrentFnName << ":\n"; @@ -131,7 +86,6 @@ bool PIC16AsmPrinter::runOnMachineFunction(MachineFunction &MF) { printBasicBlockLabel(I, true); O << '\n'; } - CurBank = ""; // For emitting line directives, we need to keep track of the current // source line. When it changes then only emit the line directive. @@ -225,8 +179,7 @@ bool PIC16AsmPrinter::doInitialization (Module &M) { DW->BeginModule(&M, MMI, O, this, TAI); EmitExternsAndGlobals (M); - EmitInitData (M); - EmitUnInitData(M); + EmitGlobalData(M); EmitRomData(M); return Result; } @@ -245,13 +198,13 @@ void PIC16AsmPrinter::EmitExternsAndGlobals (Module &M) { if (I->isDeclaration()) { O << "\textern " <hasExternalLinkage()) { O << "\tglobal " << Name << "\n"; - O << "\tglobal " << FunctionLabelBegin << Name << ".retval\n"; - O << "\tglobal " << FunctionLabelBegin<< Name << ".args\n"; + O << "\tglobal " << FunctionLabelBegin << Name << ".ret.\n"; + O << "\tglobal " << FunctionLabelBegin<< Name << ".args.\n"; } } @@ -274,35 +227,6 @@ void PIC16AsmPrinter::EmitExternsAndGlobals (Module &M) { } } -void PIC16AsmPrinter::EmitInitData (Module &M) { - SwitchToSection(TAI->getDataSection()); - for (Module::global_iterator I = M.global_begin(), E = M.global_end(); - I != E; ++I) { - if (!I->hasInitializer()) // External global require no code. - continue; - - Constant *C = I->getInitializer(); - const PointerType *PtrTy = I->getType(); - int AddrSpace = PtrTy->getAddressSpace(); - - if ((!C->isNullValue()) && (AddrSpace == PIC16ISD::RAM_SPACE)) { - - if (EmitSpecialLLVMGlobal(I)) - continue; - - // Any variables reaching here with "." in its name is a local scope - // variable and should not be printed in global data section. - std::string Name = Mang->getValueName(I); - if (isLocalName(Name)) - continue; - - I->setSection(TAI->getDataSection()->getName()); - O << Name; - EmitGlobalConstant(C, AddrSpace); - } - } -} - void PIC16AsmPrinter::EmitRomData (Module &M) { SwitchToSection(TAI->getReadOnlySection()); @@ -335,39 +259,6 @@ void PIC16AsmPrinter::EmitRomData (Module &M) IsRomData = false; } -void PIC16AsmPrinter::EmitUnInitData (Module &M) -{ - SwitchToSection(TAI->getBSSSection_()); - const TargetData *TD = TM.getTargetData(); - - for (Module::global_iterator I = M.global_begin(), E = M.global_end(); - I != E; ++I) { - if (!I->hasInitializer()) // External global require no code. - continue; - - Constant *C = I->getInitializer(); - if (C->isNullValue()) { - - if (EmitSpecialLLVMGlobal(I)) - continue; - - // Any variables reaching here with "." in its name is a local scope - // variable and should not be printed in global data section. - std::string name = Mang->getValueName(I); - if (name.find(".") != std::string::npos) - continue; - - I->setSection(TAI->getBSSSection_()->getName()); - - const Type *Ty = C->getType(); - unsigned Size = TD->getTypePaddedSize(Ty); - - O << name << " " <<"RES"<< " " << Size ; - O << "\n"; - } - } -} - bool PIC16AsmPrinter::doFinalization(Module &M) { O << "\t" << "END\n"; bool Result = AsmPrinter::doFinalization(M); @@ -390,7 +281,7 @@ void PIC16AsmPrinter::emitFunctionData(MachineFunction &MF) { // Emit function frame label - O << FunctionLabelBegin << CurrentFnName << ".frame:\n"; + O << FunctionLabelBegin << CurrentFnName << ".frame.:\n"; const Type *RetType = F->getReturnType(); unsigned RetSize = 0; @@ -399,10 +290,10 @@ void PIC16AsmPrinter::emitFunctionData(MachineFunction &MF) { //Emit function return value space if(RetSize > 0) - O << FunctionLabelBegin << CurrentFnName << ".retval RES " << RetSize + O << FunctionLabelBegin << CurrentFnName << ".ret. RES " << RetSize << "\n"; else - O << FunctionLabelBegin << CurrentFnName << ".retval:\n"; + O << FunctionLabelBegin << CurrentFnName << ".ret.:\n"; // Emit variable to hold the space for function arguments unsigned ArgSize = 0; @@ -411,13 +302,13 @@ void PIC16AsmPrinter::emitFunctionData(MachineFunction &MF) { const Type *Ty = argi->getType(); ArgSize += TD->getTypePaddedSize(Ty); } - O << FunctionLabelBegin << CurrentFnName << ".args RES " << ArgSize + O << FunctionLabelBegin << CurrentFnName << ".args. RES " << ArgSize << "\n"; // Emit temporary space int TempSize = PTLI->GetTmpSize(); if (TempSize > 0 ) - O << FunctionLabelBegin << CurrentFnName << ".tmp RES " << TempSize + O << FunctionLabelBegin << CurrentFnName << ".temp. RES " << TempSize <<"\n"; // Emit the section name for local variables. @@ -454,5 +345,40 @@ void PIC16AsmPrinter::emitFunctionData(MachineFunction &MF) { // Emit memory reserve directive. O << FunctionLabelBegin << VarName << " RES " << Size << "\n"; } +} + +void PIC16AsmPrinter::EmitGlobalData (Module &M) +{ + const PIC16TargetAsmInfo *PTAI = static_cast(TAI); + const_cast(PTAI)->SetSectionForGVs(M); + const TargetData *TD = TM.getTargetData(); + std::vector IDATASections = PTAI->getIDATASections(); + for (unsigned i = 0; i < IDATASections.size(); i++) { + SwitchToSection(IDATASections[i]->S_); + std::vector Items = IDATASections[i]->Items; + for (unsigned j = 0; j < Items.size(); j++) { + std::string Name = Mang->getValueName(Items[j]); + Constant *C = Items[j]->getInitializer(); + int AddrSpace = Items[j]->getType()->getAddressSpace(); + O << Name; + EmitGlobalConstant(C, AddrSpace); + } + } + + std::vector BSSSections = PTAI->getBSSSections(); + for (unsigned i = 0; i < BSSSections.size(); i++) { + SwitchToSection(BSSSections[i]->S_); + std::vector Items = BSSSections[i]->Items; + for (unsigned j = 0; j < Items.size(); j++) { + std::string Name = Mang->getValueName(Items[j]); + Constant *C = Items[j]->getInitializer(); + const Type *Ty = C->getType(); + unsigned Size = TD->getTypePaddedSize(Ty); + + O << Name << " " <<"RES"<< " " << Size ; + O << "\n"; + } + } } + diff --git a/lib/Target/PIC16/PIC16AsmPrinter.h b/lib/Target/PIC16/PIC16AsmPrinter.h index 227de7074b1..13a269b5fa3 100644 --- a/lib/Target/PIC16/PIC16AsmPrinter.h +++ b/lib/Target/PIC16/PIC16AsmPrinter.h @@ -28,7 +28,6 @@ namespace llvm { const TargetAsmInfo *T, CodeGenOpt::Level OL, bool V) : AsmPrinter(O, TM, T, OL, V) { - CurBank = ""; FunctionLabelBegin = '@'; IsRomData = false; PTLI = TM.getTargetLowering(); @@ -44,8 +43,7 @@ namespace llvm { bool printInstruction(const MachineInstr *MI); // definition autogenerated. bool printMachineInstruction(const MachineInstr *MI); void EmitExternsAndGlobals (Module &M); - void EmitInitData (Module &M); - void EmitUnInitData (Module &M); + void EmitGlobalData (Module &M); void EmitRomData (Module &M); void emitFunctionData(MachineFunction &MF); @@ -55,7 +53,6 @@ namespace llvm { private: PIC16TargetLowering *PTLI; - std::string CurBank; bool IsRomData; char FunctionLabelBegin; }; diff --git a/lib/Target/PIC16/PIC16ISelLowering.cpp b/lib/Target/PIC16/PIC16ISelLowering.cpp index b817d05c05f..2e5730af6cd 100644 --- a/lib/Target/PIC16/PIC16ISelLowering.cpp +++ b/lib/Target/PIC16/PIC16ISelLowering.cpp @@ -531,7 +531,7 @@ PIC16TargetLowering::LegalizeFrameIndex(SDValue Op, SelectionDAG &DAG, unsigned FIndex = FR->getIndex(); char *tmpName = new char [strlen(Name.c_str()) + 8]; if (FIndex < ReservedFrameCount) { - sprintf(tmpName, "%s.frame", Name.c_str()); + sprintf(tmpName, "%s.frame.", Name.c_str()); ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8); Offset = 0; for (unsigned i=0; igetObjectSize(FIndex)); } @@ -850,7 +850,7 @@ SDValue PIC16TargetLowering::ConvertToMemOperand(SDValue Op, // Put the value on stack. // Get a stack slot index and convert to es. int FI = MF.getFrameInfo()->CreateStackObject(1, 1); - sprintf(tmpName, "%s.tmp", FuncName.c_str()); + sprintf(tmpName, "%s.temp.", FuncName.c_str()); SDValue ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8); // Store the value to ES. @@ -1065,7 +1065,7 @@ SDValue PIC16TargetLowering::LowerRET(SDValue Op, SelectionDAG &DAG) { std::string FuncName = F->getName(); char *tmpName = new char [strlen(FuncName.c_str()) + 8]; - sprintf(tmpName, "%s.frame", FuncName.c_str()); + sprintf(tmpName, "%s.frame.", FuncName.c_str()); SDVTList VTs = DAG.getVTList (MVT::i8, MVT::Other); SDValue ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8); SDValue BS = DAG.getConstant(1, MVT::i8); @@ -1250,12 +1250,12 @@ SDValue PIC16TargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) { // Label for argument passing char *argFrame = new char [strlen(Name.c_str()) + 8]; - sprintf(argFrame, "%s.args", Name.c_str()); + sprintf(argFrame, "%s.args.", Name.c_str()); ArgLabel = DAG.getTargetExternalSymbol(argFrame, MVT::i8); // Label for reading return value char *retName = new char [strlen(Name.c_str()) + 8]; - sprintf(retName, "%s.retval", Name.c_str()); + sprintf(retName, "%s.ret.", Name.c_str()); RetLabel = DAG.getTargetExternalSymbol(retName, MVT::i8); } else { // if indirect call @@ -1451,8 +1451,8 @@ SDValue PIC16TargetLowering::LowerFORMAL_ARGUMENTS(SDValue Op, InitReservedFrameCount(F); // Create the .args external symbol. - char *tmpName = new char [strlen(FuncName.c_str()) + 6]; - sprintf(tmpName, "%s.args", FuncName.c_str()); + char *tmpName = new char [strlen(FuncName.c_str()) + 8]; + sprintf(tmpName, "%s.args.", FuncName.c_str()); SDValue ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8); // Load arg values from the label + offset. diff --git a/lib/Target/PIC16/PIC16InstrInfo.cpp b/lib/Target/PIC16/PIC16InstrInfo.cpp index 8d8a0199540..9185437edb4 100644 --- a/lib/Target/PIC16/PIC16InstrInfo.cpp +++ b/lib/Target/PIC16/PIC16InstrInfo.cpp @@ -76,8 +76,8 @@ void PIC16InstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, const Function *Func = MBB.getParent()->getFunction(); const std::string FuncName = Func->getName(); - char *tmpName = new char [strlen(FuncName.c_str()) + 6]; - sprintf(tmpName, "%s.tmp", FuncName.c_str()); + char *tmpName = new char [strlen(FuncName.c_str()) + 10]; + sprintf(tmpName, "%s.temp.", FuncName.c_str()); // On the order of operands here: think "movwf SrcReg, tmp_slot, offset". if (RC == PIC16::GPRRegisterClass) { @@ -119,8 +119,8 @@ void PIC16InstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, const Function *Func = MBB.getParent()->getFunction(); const std::string FuncName = Func->getName(); - char *tmpName = new char [strlen(FuncName.c_str()) + 6]; - sprintf(tmpName, "%s.tmp", FuncName.c_str()); + char *tmpName = new char [strlen(FuncName.c_str()) + 10]; + sprintf(tmpName, "%s.temp.", FuncName.c_str()); // On the order of operands here: think "movf FrameIndex, W". if (RC == PIC16::GPRRegisterClass) { diff --git a/lib/Target/PIC16/PIC16InstrInfo.h b/lib/Target/PIC16/PIC16InstrInfo.h index 04927b7f344..60b02ab6b47 100644 --- a/lib/Target/PIC16/PIC16InstrInfo.h +++ b/lib/Target/PIC16/PIC16InstrInfo.h @@ -64,6 +64,23 @@ public: unsigned &SrcReg, unsigned &DstReg, unsigned &SrcSubIdx, unsigned &DstSubIdx) const; + static inline bool hasNoMemOperand (const MachineInstr &MI) { + + if (MI.getNumOperands() == 0) return true; + + switch (MI.getOpcode()) { + default: return false; // Beware + case PIC16::movlw_lo_1: + case PIC16::movlw_hi_1: + case PIC16::movlw_lo_2: + case PIC16::movlw_hi_2: + return true; + } + } + + + + }; } // namespace llvm diff --git a/lib/Target/PIC16/PIC16InstrInfo.td b/lib/Target/PIC16/PIC16InstrInfo.td index 09872b3c41b..6c11bd5355d 100644 --- a/lib/Target/PIC16/PIC16InstrInfo.td +++ b/lib/Target/PIC16/PIC16InstrInfo.td @@ -470,13 +470,18 @@ let usesCustomDAGSchedInserter = 1 in { // Expanded by the scheduler. // Banksel. -let isReMaterializable = 1 in { def banksel : - Pseudo<(outs BSR:$dst), + Pseudo<(outs), (ins i8mem:$ptr), "banksel $ptr", - [(set BSR:$dst, (Banksel tglobaladdr:$ptr))]>; -} + []>; + +def pagesel : + Pseudo<(outs), + (ins i8mem:$ptr), + "movlp $ptr", + []>; + // Return insn. def Return : diff --git a/lib/Target/PIC16/PIC16MemSelOpt.cpp b/lib/Target/PIC16/PIC16MemSelOpt.cpp new file mode 100644 index 00000000000..0458c5a4174 --- /dev/null +++ b/lib/Target/PIC16/PIC16MemSelOpt.cpp @@ -0,0 +1,163 @@ +//===-- 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 "PIC16InstrInfo.h" +#include "PIC16TargetAsmInfo.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" +#include "llvm/Support/Compiler.h" + +using namespace llvm; + +namespace { + struct VISIBILITY_HIDDEN 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; + + }; + 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=""; + + for (MachineBasicBlock::iterator I = BB.begin(); I != BB.end(); ++I) { + Changed |= processInstruction(I); + } + return Changed; +} + +bool MemSelOpt::processInstruction(MachineInstr *MI) { + bool Changed = false; + + unsigned NumOperands = MI->getNumOperands(); + // If this insn has only one operand, probably it is not going to + // access any data memory. + if (PIC16InstrInfo::hasNoMemOperand(*MI)) return Changed; + + // Scan for the memory address operand. + // FIXME: Should we use standard interfaces like memoperands_iterator, + // hasMemOperand() etc ? + int MemOpPos = -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 should be BS. + MemOpPos = i; + break; + } + } + + // If we did not find an insn accessing memory. Continue. + if (MemOpPos == -1) return Changed; + + // Get the MemOp. + MachineOperand &Op = MI->getOperand(MemOpPos); + + // If this is a pagesel material, handle it first. + if (MI->getOpcode() == PIC16::CALL) { + DebugLoc dl = MI->getDebugLoc(); + BuildMI(*MBB, MI, dl, TII->get(PIC16::pagesel)). + addOperand(Op); + return true; + } + + // Get the section name(NewBank) for MemOp. + std::string NewBank = CurBank; + if (Op.getType() == MachineOperand::MO_GlobalAddress && + Op.getGlobal()->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) { + NewBank = Op.getGlobal()->getSection(); + } else if (Op.getType() == MachineOperand::MO_ExternalSymbol) { + // External Symbol is generated for temp data and arguments. They are + // in fpdata..# section. + std::string Sym = Op.getSymbolName(); + NewBank = getSectionNameForSym(Sym); + } + + // If the previous and new section names are same, we don't need to + // emit banksel. + if (NewBank.compare(CurBank) != 0 ) { + DebugLoc dl = MI->getDebugLoc(); + BuildMI(*MBB, MI, dl, TII->get(PIC16::banksel)). + addOperand(Op); + Changed = true; + CurBank = NewBank; + } + + return Changed; +} + diff --git a/lib/Target/PIC16/PIC16TargetAsmInfo.cpp b/lib/Target/PIC16/PIC16TargetAsmInfo.cpp index 6b0a0d029a8..ac4039baf76 100644 --- a/lib/Target/PIC16/PIC16TargetAsmInfo.cpp +++ b/lib/Target/PIC16/PIC16TargetAsmInfo.cpp @@ -14,6 +14,8 @@ #include "PIC16TargetAsmInfo.h" #include "PIC16TargetMachine.h" #include "llvm/GlobalValue.h" +#include "llvm/GlobalVariable.h" +#include "llvm/DerivedTypes.h" using namespace llvm; @@ -61,3 +63,204 @@ const char *PIC16TargetAsmInfo::getASDirective(unsigned size, return NULL; } +const Section * +PIC16TargetAsmInfo::getBSSSectionForGlobal(const GlobalVariable *GV) const { + assert (GV->hasInitializer() && "This global doesn't need space"); + Constant *C = GV->getInitializer(); + assert (C->isNullValue() && "Unitialized globals has non-zero initializer"); + + // Find how much space this global needs. + const TargetData *TD = TM.getTargetData(); + const Type *Ty = C->getType(); + unsigned ValSize = TD->getTypePaddedSize(Ty); + + // Go through all BSS Sections and assign this variable + // to the first available section having enough space. + PIC16Section *FoundBSS = NULL; + for (unsigned i = 0; i < BSSSections.size(); i++) { + if (DataBankSize - BSSSections[i]->Size >= ValSize) { + FoundBSS = BSSSections[i]; + break; + } + } + + // No BSS section spacious enough was found. Crate a new one. + if (! FoundBSS) { + char *name = new char[32]; + sprintf (name, "udata.%d.# UDATA", BSSSections.size()); + const Section *NewSection = getNamedSection (name); + + FoundBSS = new PIC16Section(NewSection); + + // Add this newly created BSS section to the list of BSSSections. + BSSSections.push_back(FoundBSS); + } + + // Insert the GV into this BSS. + FoundBSS->Items.push_back(GV); + FoundBSS->Size += ValSize; + + // We can't do this here because GV is const . + // const std::string SName = FoundBSS->S_->getName(); + // GV->setSection(SName); + + return FoundBSS->S_; +} + +const Section * +PIC16TargetAsmInfo::getIDATASectionForGlobal(const GlobalVariable *GV) const { + assert (GV->hasInitializer() && "This global doesn't need space"); + Constant *C = GV->getInitializer(); + assert (!C->isNullValue() && "initialized globals has zero initializer"); + assert (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE && + "can split initialized RAM data only"); + + // Find how much space this global needs. + const TargetData *TD = TM.getTargetData(); + const Type *Ty = C->getType(); + unsigned ValSize = TD->getTypePaddedSize(Ty); + + // Go through all IDATA Sections and assign this variable + // to the first available section having enough space. + PIC16Section *FoundIDATA = NULL; + for (unsigned i = 0; i < IDATASections.size(); i++) { + if ( DataBankSize - IDATASections[i]->Size >= ValSize) { + FoundIDATA = IDATASections[i]; + break; + } + } + + // No IDATA section spacious enough was found. Crate a new one. + if (! FoundIDATA) { + char *name = new char[32]; + sprintf (name, "idata.%d.# IDATA", IDATASections.size()); + const Section *NewSection = getNamedSection (name); + + FoundIDATA = new PIC16Section(NewSection); + + // Add this newly created IDATA section to the list of IDATASections. + IDATASections.push_back(FoundIDATA); + } + + // Insert the GV into this IDATA. + FoundIDATA->Items.push_back(GV); + FoundIDATA->Size += ValSize; + + // We can't do this here because GV is const . + // GV->setSection(FoundIDATA->S->getName()); + + return FoundIDATA->S_; +} + +// Override default implementation to put the true globals into +// multiple data sections if required. +const Section* +PIC16TargetAsmInfo::SelectSectionForGlobal(const GlobalValue *GV1) const { + // We select the section based on the initializer here, so it really + // has to be a GlobalVariable. + if (!isa(GV1)) + return TargetAsmInfo::SelectSectionForGlobal(GV1); + + const GlobalVariable *GV = dyn_cast(GV1); + // We are only dealing with true globals here. So names with a "." + // are local globals. Also declarations are not entertained. + std::string name = GV->getName(); + if (name.find(".auto.") != std::string::npos + || name.find(".arg.") != std::string::npos || !GV->hasInitializer()) + return TargetAsmInfo::SelectSectionForGlobal(GV); + + const Constant *C = GV->getInitializer(); + // See if this is an uninitialized global. + if (C->isNullValue()) + return getBSSSectionForGlobal(GV); + + // This is initialized data. We only deal with initialized data in RAM. + if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) + return getIDATASectionForGlobal(GV); + + // Else let the default implementation take care of it. + return TargetAsmInfo::SelectSectionForGlobal(GV); +} + +void PIC16TargetAsmInfo::SetSectionForGVs(Module &M) { + for (Module::global_iterator I = M.global_begin(), E = M.global_end(); + I != E; ++I) { + if (!I->hasInitializer()) // External global require no code. + continue; + + // Any variables reaching here with "." in its name is a local scope + // variable and should not be printed in global data section. + std::string name = I->getName(); + if (name.find(".auto.") != std::string::npos + || name.find(".arg.") != std::string::npos) + continue; + int AddrSpace = I->getType()->getAddressSpace(); + + if (AddrSpace == PIC16ISD::RAM_SPACE) + I->setSection(SectionForGlobal(I)->getName()); + } +} + + +// Helper routine. +// Func name starts after prefix and followed by a . +static std::string getFuncNameForSym(const std::string &Sym, + PIC16ABINames::IDs PrefixType) { + + const char *prefix = getIDName (PIC16ABINames::PREFIX_SYMBOL); + + // This name may or may not start with prefix; + // Func names start after prfix in that case. + size_t func_name_start = 0; + if (Sym.find(prefix, 0, strlen(prefix)) != std::string::npos) + func_name_start = strlen(prefix); + + // Position of the . after func name. + size_t func_name_end = Sym.find ('.', func_name_start); + + return Sym.substr (func_name_start, func_name_end); +} + +// Helper routine to create a section name given the section prefix +// and func name. +static std::string +getSectionNameForFunc (const std::string &Fname, + const PIC16ABINames::IDs sec_id) { + std::string sec_id_string = getIDName (sec_id); + return sec_id_string + "." + Fname + ".#"; +} + + +// Get the section for the given external symbol names. +// This function is meant for only mangled external symbol names. +std::string +llvm::getSectionNameForSym(const std::string &Sym) { + std::string SectionName; + + PIC16ABINames::IDs id = getID (Sym); + std::string Fname = getFuncNameForSym (Sym, id); + + switch (id) { + default : assert (0 && "Could not determine external symbol type"); + case PIC16ABINames::FUNC_FRAME: + case PIC16ABINames::FUNC_RET: + case PIC16ABINames::FUNC_TEMPS: + case PIC16ABINames::FUNC_ARGS: { + return getSectionNameForFunc (Fname, PIC16ABINames::FRAME_SECTION); + } + case PIC16ABINames::FUNC_AUTOS: { + return getSectionNameForFunc (Fname, PIC16ABINames::AUTOS_SECTION); + } + } +} + +PIC16TargetAsmInfo::~PIC16TargetAsmInfo() { + + for (unsigned i = 0; i < BSSSections.size(); i++) { + delete BSSSections[i]; + } + + for (unsigned i = 0; i < IDATASections.size(); i++) { + delete IDATASections[i]; + } +} diff --git a/lib/Target/PIC16/PIC16TargetAsmInfo.h b/lib/Target/PIC16/PIC16TargetAsmInfo.h index 305e74d5a30..4675bc9e9b9 100644 --- a/lib/Target/PIC16/PIC16TargetAsmInfo.h +++ b/lib/Target/PIC16/PIC16TargetAsmInfo.h @@ -14,21 +14,54 @@ #ifndef PIC16TARGETASMINFO_H #define PIC16TARGETASMINFO_H +#include "PIC16.h" #include "llvm/Target/TargetAsmInfo.h" - +#include +#include "llvm/Module.h" +#define DataBankSize 80 namespace llvm { // Forward declaration. class PIC16TargetMachine; + class GlobalVariable; + // PIC16 Splits the global data into mulitple udata and idata sections. + // Each udata and idata section needs to contain a list of globals that + // they contain, in order to avoid scanning over all the global values + // again and printing only those that match the current section. + // Keeping values inside the sections make printing a section much easier. + struct PIC16Section { + const Section *S_; // Connection to actual Section. + unsigned Size; // Total size of the objects contained. + std::vector Items; + + PIC16Section (const Section *s) { S_ = s; Size = 0; } + }; + struct PIC16TargetAsmInfo : public TargetAsmInfo { + std::string getSectionNameForSym(const std::string &Sym) const; PIC16TargetAsmInfo(const PIC16TargetMachine &TM); + virtual ~PIC16TargetAsmInfo(); private: + mutable std::vector BSSSections; + mutable std::vector IDATASections; + const char *RomData8bitsDirective; const char *RomData16bitsDirective; const char *RomData32bitsDirective; const char *getRomDirective(unsigned size) const; virtual const char *getASDirective(unsigned size, unsigned AS) const; + const Section *getBSSSectionForGlobal(const GlobalVariable *GV) const; + const Section *getIDATASectionForGlobal(const GlobalVariable *GV) const; + virtual const Section *SelectSectionForGlobal(const GlobalValue *GV) const; + public: + void SetSectionForGVs(Module &M); + std::vector getBSSSections() const { + return BSSSections; + } + std::vector getIDATASections() const { + return IDATASections; + } }; } // namespace llvm diff --git a/lib/Target/PIC16/PIC16TargetMachine.cpp b/lib/Target/PIC16/PIC16TargetMachine.cpp index 9c52ee54f20..bda632608ea 100644 --- a/lib/Target/PIC16/PIC16TargetMachine.cpp +++ b/lib/Target/PIC16/PIC16TargetMachine.cpp @@ -70,4 +70,10 @@ addAssemblyEmitter(PassManagerBase &PM, CodeGenOpt::Level OptLevel, return false; } +bool PIC16TargetMachine::addPostRegAlloc(PassManagerBase &PM, + CodeGenOpt::Level OptLevel) { + PM.add(createPIC16MemSelOptimizerPass()); + return true; // -print-machineinstr should print after this. +} + diff --git a/lib/Target/PIC16/PIC16TargetMachine.h b/lib/Target/PIC16/PIC16TargetMachine.h index d9604592658..7f62d5c13d6 100644 --- a/lib/Target/PIC16/PIC16TargetMachine.h +++ b/lib/Target/PIC16/PIC16TargetMachine.h @@ -62,6 +62,7 @@ public: virtual bool addAssemblyEmitter(PassManagerBase &PM, CodeGenOpt::Level OptLevel, bool Verbose, raw_ostream &Out); + virtual bool addPostRegAlloc(PassManagerBase &PM, CodeGenOpt::Level OptLevel); }; // PIC16TargetMachine. /// CooperTargetMachine -- 2.34.1