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
This commit is contained in:
Sanjiv Gupta 2009-05-06 08:02:01 +00:00
parent 7af1c78b98
commit d8d27f4a4b
12 changed files with 587 additions and 143 deletions

View File

@ -18,6 +18,7 @@
#include "llvm/Target/TargetMachine.h"
#include <iosfwd>
#include <cassert>
#include <string>
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 <prefix><funcname>.<id>.<varname>
// 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

View File

@ -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.<functionname>.# 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 " <<Name << "\n";
O << "\textern " << FunctionLabelBegin << Name << ".retval\n";
O << "\textern " << FunctionLabelBegin << Name << ".args\n";
O << "\textern " << FunctionLabelBegin << Name << ".ret.\n";
O << "\textern " << FunctionLabelBegin << Name << ".args.\n";
}
else if (I->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<const PIC16TargetAsmInfo *>(TAI);
const_cast<PIC16TargetAsmInfo *>(PTAI)->SetSectionForGVs(M);
const TargetData *TD = TM.getTargetData();
std::vector <PIC16Section *>IDATASections = PTAI->getIDATASections();
for (unsigned i = 0; i < IDATASections.size(); i++) {
SwitchToSection(IDATASections[i]->S_);
std::vector<const GlobalVariable*> 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 <PIC16Section *>BSSSections = PTAI->getBSSSections();
for (unsigned i = 0; i < BSSSections.size(); i++) {
SwitchToSection(BSSSections[i]->S_);
std::vector<const GlobalVariable*> 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";
}
}
}

View File

@ -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;
};

View File

@ -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; i<FIndex ; ++i) {
@ -539,7 +539,7 @@ PIC16TargetLowering::LegalizeFrameIndex(SDValue Op, SelectionDAG &DAG,
}
} else {
// FrameIndex has been made for some temporary storage
sprintf(tmpName, "%s.tmp", Name.c_str());
sprintf(tmpName, "%s.temp.", Name.c_str());
ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8);
Offset = GetTmpOffsetForFI(FIndex, MFI->getObjectSize(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 <fname>.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.

View File

@ -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) {

View File

@ -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

View File

@ -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 :

View File

@ -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.<functionname>.# 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;
}

View File

@ -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<GlobalVariable>(GV1))
return TargetAsmInfo::SelectSectionForGlobal(GV1);
const GlobalVariable *GV = dyn_cast<GlobalVariable>(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];
}
}

View File

@ -14,21 +14,54 @@
#ifndef PIC16TARGETASMINFO_H
#define PIC16TARGETASMINFO_H
#include "PIC16.h"
#include "llvm/Target/TargetAsmInfo.h"
#include <vector>
#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<const GlobalVariable*> 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<PIC16Section *> BSSSections;
mutable std::vector<PIC16Section *> 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<PIC16Section *> getBSSSections() const {
return BSSSections;
}
std::vector<PIC16Section *> getIDATASections() const {
return IDATASections;
}
};
} // namespace llvm

View File

@ -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.
}

View File

@ -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