mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-11-01 15:11:24 +00:00
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:
parent
7af1c78b98
commit
d8d27f4a4b
@ -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
|
||||
|
@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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 :
|
||||
|
163
lib/Target/PIC16/PIC16MemSelOpt.cpp
Normal file
163
lib/Target/PIC16/PIC16MemSelOpt.cpp
Normal 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;
|
||||
}
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user