diff options
Diffstat (limited to 'contrib/llvm/lib/Target/PIC16')
44 files changed, 7482 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/PIC16/AsmPrinter/CMakeLists.txt b/contrib/llvm/lib/Target/PIC16/AsmPrinter/CMakeLists.txt new file mode 100644 index 0000000..d36bb8e --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/AsmPrinter/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories( + ${CMAKE_CURRENT_BINARY_DIR}/.. + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ) + +add_llvm_library(LLVMPIC16AsmPrinter + PIC16AsmPrinter.cpp + ) +add_dependencies(LLVMPIC16AsmPrinter PIC16CodeGenTable_gen) diff --git a/contrib/llvm/lib/Target/PIC16/AsmPrinter/Makefile b/contrib/llvm/lib/Target/PIC16/AsmPrinter/Makefile new file mode 100644 index 0000000..e3c0684 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/AsmPrinter/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/PIC16/AsmPrinter/Makefile ----------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../../.. +LIBRARYNAME = LLVMPIC16AsmPrinter + +# Hack: we need to include 'main' pic16 target directory to grab private headers +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/contrib/llvm/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp b/contrib/llvm/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp new file mode 100644 index 0000000..b665817 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp @@ -0,0 +1,512 @@ +//===-- PIC16AsmPrinter.cpp - PIC16 LLVM assembly writer ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to PIC16 assembly language. +// +//===----------------------------------------------------------------------===// + +#include "PIC16ABINames.h" +#include "PIC16AsmPrinter.h" +#include "PIC16Section.h" +#include "PIC16MCAsmInfo.h" +#include "PIC16MachineFunctionInfo.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/Module.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/SmallString.h" +#include <cstring> +using namespace llvm; + +#include "PIC16GenAsmWriter.inc" + +PIC16AsmPrinter::PIC16AsmPrinter(TargetMachine &TM, MCStreamer &Streamer) +: AsmPrinter(TM, Streamer), DbgInfo(Streamer, TM.getMCAsmInfo()) { + PMAI = static_cast<const PIC16MCAsmInfo*>(TM.getMCAsmInfo()); + PTOF = &getObjFileLowering(); +} + +void PIC16AsmPrinter::EmitInstruction(const MachineInstr *MI) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + printInstruction(MI, OS); + + OutStreamer.EmitRawText(OS.str()); +} + +static int getFunctionColor(const Function *F) { + if (F->hasSection()) { + std::string Sectn = F->getSection(); + std::string StrToFind = "Overlay="; + std::string::size_type Pos = Sectn.find(StrToFind); + + // Retreive the color number if the key is found. + if (Pos != std::string::npos) { + Pos += StrToFind.length(); + std::string Color = ""; + char c = Sectn.at(Pos); + // A Color can only consist of digits. + while (c >= '0' && c<= '9') { + Color.append(1,c); + Pos++; + if (Pos >= Sectn.length()) + break; + c = Sectn.at(Pos); + } + return atoi(Color.c_str()); + } + } + + // Color was not set for function, so return -1. + return -1; +} + +// Color the Auto section of the given function. +void PIC16AsmPrinter::ColorAutoSection(const Function *F) { + std::string SectionName = PAN::getAutosSectionName(CurrentFnSym->getName()); + PIC16Section* Section = PTOF->findPIC16Section(SectionName); + if (Section != NULL) { + int Color = getFunctionColor(F); + if (Color >= 0) + Section->setColor(Color); + } +} + + +/// runOnMachineFunction - This emits the frame section, autos section and +/// assembly for each instruction. Also takes care of function begin debug +/// directive and file begin debug directive (if required) for the function. +/// +bool PIC16AsmPrinter::runOnMachineFunction(MachineFunction &MF) { + // This calls the base class function required to be called at beginning + // of runOnMachineFunction. + SetupMachineFunction(MF); + + // Put the color information from function to its auto section. + const Function *F = MF.getFunction(); + ColorAutoSection(F); + + // Emit the function frame (args and temps). + EmitFunctionFrame(MF); + + DbgInfo.BeginFunction(MF); + + // Now emit the instructions of function in its code section. + const MCSection *fCodeSection = + getObjFileLowering().SectionForCode(CurrentFnSym->getName(), + PAN::isISR(F->getSection())); + + // Start the Code Section. + OutStreamer.SwitchSection(fCodeSection); + + // Emit the frame address of the function at the beginning of code. + OutStreamer.EmitRawText("\tretlw low(" + + Twine(PAN::getFrameLabel(CurrentFnSym->getName())) + + ")"); + OutStreamer.EmitRawText("\tretlw high(" + + Twine(PAN::getFrameLabel(CurrentFnSym->getName())) + + ")"); + + // Emit function start label. + OutStreamer.EmitLabel(CurrentFnSym); + + DebugLoc CurDL; + // Print out code for the function. + for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + + // Print a label for the basic block. + if (I != MF.begin()) + EmitBasicBlockStart(I); + + // Print a basic block. + for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); + II != E; ++II) { + // Emit the line directive if source line changed. + DebugLoc DL = II->getDebugLoc(); + if (!DL.isUnknown() && DL != CurDL) { + DbgInfo.ChangeDebugLoc(MF, DL); + CurDL = DL; + } + + // Print the assembly for the instruction. + EmitInstruction(II); + } + } + + // Emit function end debug directives. + DbgInfo.EndFunction(MF); + + return false; // we didn't modify anything. +} + + +// printOperand - print operand of insn. +void PIC16AsmPrinter::printOperand(const MachineInstr *MI, int opNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(opNum); + const Function *F = MI->getParent()->getParent()->getFunction(); + + switch (MO.getType()) { + case MachineOperand::MO_Register: + { + // For indirect load/store insns, the fsr name is printed as INDF. + std::string RegName = getRegisterName(MO.getReg()); + if ((MI->getOpcode() == PIC16::load_indirect) || + (MI->getOpcode() == PIC16::store_indirect)) + RegName.replace (0, 3, "INDF"); + O << RegName; + } + return; + + case MachineOperand::MO_Immediate: + O << (int)MO.getImm(); + return; + + case MachineOperand::MO_GlobalAddress: { + MCSymbol *Sym = Mang->getSymbol(MO.getGlobal()); + // FIXME: currently we do not have a memcpy def coming in the module + // by any chance, as we do not link in those as .bc lib. So these calls + // are always external and it is safe to emit an extern. + if (PAN::isMemIntrinsic(Sym->getName())) + LibcallDecls.insert(Sym->getName()); + + O << *Sym; + break; + } + case MachineOperand::MO_ExternalSymbol: { + const char *Sname = MO.getSymbolName(); + std::string Printname = Sname; + + // Intrinsic stuff needs to be renamed if we are printing IL fn. + if (PAN::isIntrinsicStuff(Printname)) { + if (PAN::isISR(F->getSection())) { + Printname = PAN::Rename(Sname); + } + // Record these decls, we need to print them in asm as extern. + LibcallDecls.insert(Printname); + } + + O << Printname; + break; + } + case MachineOperand::MO_MachineBasicBlock: + O << *MO.getMBB()->getSymbol(); + return; + + default: + llvm_unreachable(" Operand type not supported."); + } +} + +/// printCCOperand - Print the cond code operand. +/// +void PIC16AsmPrinter::printCCOperand(const MachineInstr *MI, int opNum, + raw_ostream &O) { + int CC = (int)MI->getOperand(opNum).getImm(); + O << PIC16CondCodeToString((PIC16CC::CondCodes)CC); +} + +/// printLibcallDecls - print the extern declarations for compiler +/// intrinsics. +/// +void PIC16AsmPrinter::printLibcallDecls() { + // If no libcalls used, return. + if (LibcallDecls.empty()) return; + + OutStreamer.AddComment("External decls for libcalls - BEGIN"); + OutStreamer.AddBlankLine(); + + for (std::set<std::string>::const_iterator I = LibcallDecls.begin(), + E = LibcallDecls.end(); I != E; I++) + OutStreamer.EmitRawText(MAI->getExternDirective() + Twine(*I)); + + OutStreamer.AddComment("External decls for libcalls - END"); + OutStreamer.AddBlankLine(); +} + +/// doInitialization - Perform Module level initializations here. +/// One task that we do here is to sectionize all global variables. +/// The MemSelOptimizer pass depends on the sectionizing. +/// +bool PIC16AsmPrinter::doInitialization(Module &M) { + bool Result = AsmPrinter::doInitialization(M); + + // Every asmbly contains these std headers. + OutStreamer.EmitRawText(StringRef("\n#include p16f1xxx.inc")); + OutStreamer.EmitRawText(StringRef("#include stdmacros.inc")); + + // Set the section names for all globals. + for (Module::global_iterator I = M.global_begin(), E = M.global_end(); + I != E; ++I) { + + // Record External Var Decls. + if (I->isDeclaration()) { + ExternalVarDecls.push_back(I); + continue; + } + + // Record Exteranl Var Defs. + if (I->hasExternalLinkage() || I->hasCommonLinkage()) { + ExternalVarDefs.push_back(I); + } + + // Sectionify actual data. + if (!I->hasAvailableExternallyLinkage()) { + const MCSection *S = getObjFileLowering().SectionForGlobal(I, Mang, TM); + + I->setSection(((const PIC16Section *)S)->getName()); + } + } + + DbgInfo.BeginModule(M); + EmitFunctionDecls(M); + EmitUndefinedVars(M); + EmitDefinedVars(M); + EmitIData(M); + EmitUData(M); + EmitRomData(M); + EmitSharedUdata(M); + EmitUserSections(M); + return Result; +} + +/// Emit extern decls for functions imported from other modules, and emit +/// global declarations for function defined in this module and which are +/// available to other modules. +/// +void PIC16AsmPrinter::EmitFunctionDecls(Module &M) { + // Emit declarations for external functions. + OutStreamer.AddComment("Function Declarations - BEGIN"); + OutStreamer.AddBlankLine(); + for (Module::iterator I = M.begin(), E = M.end(); I != E; I++) { + if (I->isIntrinsic() || I->getName() == "@abort") + continue; + + if (!I->isDeclaration() && !I->hasExternalLinkage()) + continue; + + MCSymbol *Sym = Mang->getSymbol(I); + + // Do not emit memcpy, memset, and memmove here. + // Calls to these routines can be generated in two ways, + // 1. User calling the standard lib function + // 2. Codegen generating these calls for llvm intrinsics. + // In the first case a prototype is alread availale, while in + // second case the call is via and externalsym and the prototype is missing. + // So declarations for these are currently always getting printing by + // tracking both kind of references in printInstrunction. + if (I->isDeclaration() && PAN::isMemIntrinsic(Sym->getName())) continue; + + const char *directive = I->isDeclaration() ? MAI->getExternDirective() : + MAI->getGlobalDirective(); + + OutStreamer.EmitRawText(directive + Twine(Sym->getName())); + OutStreamer.EmitRawText(directive + + Twine(PAN::getRetvalLabel(Sym->getName()))); + OutStreamer.EmitRawText(directive + + Twine(PAN::getArgsLabel(Sym->getName()))); + } + + OutStreamer.AddComment("Function Declarations - END"); + OutStreamer.AddBlankLine(); + +} + +// Emit variables imported from other Modules. +void PIC16AsmPrinter::EmitUndefinedVars(Module &M) { + std::vector<const GlobalVariable*> Items = ExternalVarDecls; + if (!Items.size()) return; + + OutStreamer.AddComment("Imported Variables - BEGIN"); + OutStreamer.AddBlankLine(); + for (unsigned j = 0; j < Items.size(); j++) + OutStreamer.EmitRawText(MAI->getExternDirective() + + Twine(Mang->getSymbol(Items[j])->getName())); + + OutStreamer.AddComment("Imported Variables - END"); + OutStreamer.AddBlankLine(); +} + +// Emit variables defined in this module and are available to other modules. +void PIC16AsmPrinter::EmitDefinedVars(Module &M) { + std::vector<const GlobalVariable*> Items = ExternalVarDefs; + if (!Items.size()) return; + + OutStreamer.AddComment("Exported Variables - BEGIN"); + OutStreamer.AddBlankLine(); + + for (unsigned j = 0; j < Items.size(); j++) + OutStreamer.EmitRawText(MAI->getGlobalDirective() + + Twine(Mang->getSymbol(Items[j])->getName())); + OutStreamer.AddComment("Exported Variables - END"); + OutStreamer.AddBlankLine(); +} + +// Emit initialized data placed in ROM. +void PIC16AsmPrinter::EmitRomData(Module &M) { + EmitSingleSection(PTOF->ROMDATASection()); +} + +// Emit Shared section udata. +void PIC16AsmPrinter::EmitSharedUdata(Module &M) { + EmitSingleSection(PTOF->SHAREDUDATASection()); +} + +bool PIC16AsmPrinter::doFinalization(Module &M) { + EmitAllAutos(M); + printLibcallDecls(); + DbgInfo.EndModule(M); + OutStreamer.EmitRawText(StringRef("\tEND")); + return AsmPrinter::doFinalization(M); +} + +void PIC16AsmPrinter::EmitFunctionFrame(MachineFunction &MF) { + const Function *F = MF.getFunction(); + const TargetData *TD = TM.getTargetData(); + PIC16MachineFunctionInfo *FuncInfo = MF.getInfo<PIC16MachineFunctionInfo>(); + + // Emit the data section name. + + PIC16Section *fPDataSection = + const_cast<PIC16Section *>(getObjFileLowering(). + SectionForFrame(CurrentFnSym->getName())); + + fPDataSection->setColor(getFunctionColor(F)); + OutStreamer.SwitchSection(fPDataSection); + + // Emit function frame label + OutStreamer.EmitRawText(PAN::getFrameLabel(CurrentFnSym->getName()) + + Twine(":")); + + const Type *RetType = F->getReturnType(); + unsigned RetSize = 0; + if (RetType->getTypeID() != Type::VoidTyID) + RetSize = TD->getTypeAllocSize(RetType); + + //Emit function return value space + // FIXME: Do not emit RetvalLable when retsize is zero. To do this + // we will need to avoid printing a global directive for Retval label + // in emitExternandGloblas. + if(RetSize > 0) + OutStreamer.EmitRawText(PAN::getRetvalLabel(CurrentFnSym->getName()) + + Twine(" RES ") + Twine(RetSize)); + else + OutStreamer.EmitRawText(PAN::getRetvalLabel(CurrentFnSym->getName()) + + Twine(":")); + + // Emit variable to hold the space for function arguments + unsigned ArgSize = 0; + for (Function::const_arg_iterator argi = F->arg_begin(), + arge = F->arg_end(); argi != arge ; ++argi) { + const Type *Ty = argi->getType(); + ArgSize += TD->getTypeAllocSize(Ty); + } + + OutStreamer.EmitRawText(PAN::getArgsLabel(CurrentFnSym->getName()) + + Twine(" RES ") + Twine(ArgSize)); + + // Emit temporary space + int TempSize = FuncInfo->getTmpSize(); + if (TempSize > 0) + OutStreamer.EmitRawText(PAN::getTempdataLabel(CurrentFnSym->getName()) + + Twine(" RES ") + Twine(TempSize)); +} + + +void PIC16AsmPrinter::EmitInitializedDataSection(const PIC16Section *S) { + /// Emit Section header. + OutStreamer.SwitchSection(S); + + std::vector<const GlobalVariable*> Items = S->Items; + for (unsigned j = 0; j < Items.size(); j++) { + Constant *C = Items[j]->getInitializer(); + int AddrSpace = Items[j]->getType()->getAddressSpace(); + OutStreamer.EmitRawText(Mang->getSymbol(Items[j])->getName()); + EmitGlobalConstant(C, AddrSpace); + } +} + +// Print all IDATA sections. +void PIC16AsmPrinter::EmitIData(Module &M) { + EmitSectionList (M, PTOF->IDATASections()); +} + +void PIC16AsmPrinter:: +EmitUninitializedDataSection(const PIC16Section *S) { + const TargetData *TD = TM.getTargetData(); + OutStreamer.SwitchSection(S); + std::vector<const GlobalVariable*> Items = S->Items; + for (unsigned j = 0; j < Items.size(); j++) { + Constant *C = Items[j]->getInitializer(); + const Type *Ty = C->getType(); + unsigned Size = TD->getTypeAllocSize(Ty); + OutStreamer.EmitRawText(Mang->getSymbol(Items[j])->getName() + + Twine(" RES ") + Twine(Size)); + } +} + +// Print all UDATA sections. +void PIC16AsmPrinter::EmitUData(Module &M) { + EmitSectionList (M, PTOF->UDATASections()); +} + +// Print all USER sections. +void PIC16AsmPrinter::EmitUserSections(Module &M) { + EmitSectionList (M, PTOF->USERSections()); +} + +// Print all AUTO sections. +void PIC16AsmPrinter::EmitAllAutos(Module &M) { + EmitSectionList (M, PTOF->AUTOSections()); +} + +extern "C" void LLVMInitializePIC16AsmPrinter() { + RegisterAsmPrinter<PIC16AsmPrinter> X(ThePIC16Target); +} + +// Emit one data section using correct section emitter based on section type. +void PIC16AsmPrinter::EmitSingleSection(const PIC16Section *S) { + if (S == NULL) return; + + switch (S->getType()) { + default: llvm_unreachable ("unknow user section type"); + case UDATA: + case UDATA_SHR: + case UDATA_OVR: + EmitUninitializedDataSection(S); + break; + case IDATA: + case ROMDATA: + EmitInitializedDataSection(S); + break; + } +} + +// Emit a list of sections. +void PIC16AsmPrinter:: +EmitSectionList(Module &M, const std::vector<PIC16Section *> &SList) { + for (unsigned i = 0; i < SList.size(); i++) { + // Exclude llvm specific metadata sections. + if (SList[i]->getName().find("llvm.") != std::string::npos) + continue; + OutStreamer.AddBlankLine(); + EmitSingleSection(SList[i]); + } +} + diff --git a/contrib/llvm/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h b/contrib/llvm/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h new file mode 100644 index 0000000..aa2e1f4 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h @@ -0,0 +1,88 @@ +//===-- PIC16AsmPrinter.h - PIC16 LLVM assembly writer ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to PIC16 assembly language. +// +//===----------------------------------------------------------------------===// + +#ifndef PIC16ASMPRINTER_H +#define PIC16ASMPRINTER_H + +#include "PIC16.h" +#include "PIC16TargetMachine.h" +#include "PIC16DebugInfo.h" +#include "PIC16MCAsmInfo.h" +#include "PIC16TargetObjectFile.h" +#include "llvm/Analysis/DebugInfo.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetMachine.h" +#include <list> +#include <set> +#include <string> + +namespace llvm { + class LLVM_LIBRARY_VISIBILITY PIC16AsmPrinter : public AsmPrinter { + public: + explicit PIC16AsmPrinter(TargetMachine &TM, MCStreamer &Streamer); + private: + virtual const char *getPassName() const { + return "PIC16 Assembly Printer"; + } + + const PIC16TargetObjectFile &getObjFileLowering() const { + return (const PIC16TargetObjectFile &)AsmPrinter::getObjFileLowering(); + } + + bool runOnMachineFunction(MachineFunction &F); + void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O); + void printCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O); + void printInstruction(const MachineInstr *MI, raw_ostream &O); + static const char *getRegisterName(unsigned RegNo); + + void EmitInstruction(const MachineInstr *MI); + void EmitFunctionDecls (Module &M); + void EmitUndefinedVars (Module &M); + void EmitDefinedVars (Module &M); + void EmitIData (Module &M); + void EmitUData (Module &M); + void EmitAllAutos (Module &M); + void EmitRomData (Module &M); + void EmitSharedUdata(Module &M); + void EmitUserSections (Module &M); + void EmitFunctionFrame(MachineFunction &MF); + void printLibcallDecls(); + void EmitUninitializedDataSection(const PIC16Section *S); + void EmitInitializedDataSection(const PIC16Section *S); + void EmitSingleSection(const PIC16Section *S); + void EmitSectionList(Module &M, + const std::vector< PIC16Section *> &SList); + void ColorAutoSection(const Function *F); + protected: + bool doInitialization(Module &M); + bool doFinalization(Module &M); + + /// EmitGlobalVariable - Emit the specified global variable and its + /// initializer to the output stream. + virtual void EmitGlobalVariable(const GlobalVariable *GV) { + // PIC16 doesn't use normal hooks for this. + } + + private: + const PIC16TargetObjectFile *PTOF; + PIC16DbgInfo DbgInfo; + const PIC16MCAsmInfo *PMAI; + std::set<std::string> LibcallDecls; // Sorted & uniqued set of extern decls. + std::vector<const GlobalVariable *> ExternalVarDecls; + std::vector<const GlobalVariable *> ExternalVarDefs; + }; +} // end of namespace + +#endif diff --git a/contrib/llvm/lib/Target/PIC16/CMakeLists.txt b/contrib/llvm/lib/Target/PIC16/CMakeLists.txt new file mode 100644 index 0000000..2b6cb9e --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/CMakeLists.txt @@ -0,0 +1,26 @@ +set(LLVM_TARGET_DEFINITIONS PIC16.td) + +tablegen(PIC16GenRegisterInfo.h.inc -gen-register-desc-header) +tablegen(PIC16GenRegisterNames.inc -gen-register-enums) +tablegen(PIC16GenRegisterInfo.inc -gen-register-desc) +tablegen(PIC16GenInstrNames.inc -gen-instr-enums) +tablegen(PIC16GenInstrInfo.inc -gen-instr-desc) +tablegen(PIC16GenAsmWriter.inc -gen-asm-writer) +tablegen(PIC16GenDAGISel.inc -gen-dag-isel) +tablegen(PIC16GenCallingConv.inc -gen-callingconv) +tablegen(PIC16GenSubtarget.inc -gen-subtarget) + +add_llvm_target(PIC16CodeGen + PIC16DebugInfo.cpp + PIC16InstrInfo.cpp + PIC16ISelDAGToDAG.cpp + PIC16ISelLowering.cpp + PIC16MemSelOpt.cpp + PIC16MCAsmInfo.cpp + PIC16RegisterInfo.cpp + PIC16Section.cpp + PIC16Subtarget.cpp + PIC16TargetMachine.cpp + PIC16TargetObjectFile.cpp + PIC16SelectionDAGInfo.cpp + ) diff --git a/contrib/llvm/lib/Target/PIC16/Makefile b/contrib/llvm/lib/Target/PIC16/Makefile new file mode 100644 index 0000000..9e784d1 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/Makefile @@ -0,0 +1,24 @@ +##===- lib/Target/PIC16/Makefile ---------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +LIBRARYNAME = LLVMPIC16CodeGen +TARGET = PIC16 + +# Make sure that tblgen is run, first thing. +BUILT_SOURCES = PIC16GenRegisterInfo.h.inc PIC16GenRegisterNames.inc \ + PIC16GenRegisterInfo.inc PIC16GenInstrNames.inc \ + PIC16GenInstrInfo.inc PIC16GenAsmWriter.inc \ + PIC16GenDAGISel.inc PIC16GenCallingConv.inc \ + PIC16GenSubtarget.inc + +DIRS = AsmPrinter TargetInfo PIC16Passes + +include $(LEVEL)/Makefile.common + diff --git a/contrib/llvm/lib/Target/PIC16/PIC16.h b/contrib/llvm/lib/Target/PIC16/PIC16.h new file mode 100644 index 0000000..08bb3e6 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16.h @@ -0,0 +1,134 @@ +//===-- PIC16.h - Top-level interface for PIC16 representation --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the entry points for global functions defined in +// the LLVM PIC16 back-end. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_PIC16_H +#define LLVM_TARGET_PIC16_H + +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetMachine.h" +#include <cassert> +#include <sstream> +#include <cstring> +#include <string> +#include <vector> + +namespace llvm { + class PIC16TargetMachine; + class FunctionPass; + class MachineCodeEmitter; + class formatted_raw_ostream; + +namespace PIC16CC { + enum CondCodes { + EQ, + NE, + LT, + LE, + GT, + GE, + ULT, + UGT, + ULE, + UGE + }; +} + + enum PIC16SectionType { + CODE, + UDATA, + IDATA, + ROMDATA, + UDATA_OVR, + UDATA_SHR + }; + + class ESNames { + std::vector<char*> stk; + ESNames() {} + public: + ~ESNames() { + while (!stk.empty()) + { + char* p = stk.back(); + delete [] p; + stk.pop_back(); + } + } + + // External symbol names require memory to live till the program end. + // So we have to allocate it and keep. Push all such allocations into a + // vector so that they get freed up on termination. + inline static const char *createESName (const std::string &name) { + static ESNames esn; + char *tmpName = new char[name.size() + 1]; + memcpy(tmpName, name.c_str(), name.size() + 1); + esn.stk.push_back(tmpName); + return tmpName; + } + + }; + + inline static const char *PIC16CondCodeToString(PIC16CC::CondCodes CC) { + switch (CC) { + default: llvm_unreachable("Unknown condition code"); + case PIC16CC::NE: return "ne"; + case PIC16CC::EQ: return "eq"; + case PIC16CC::LT: return "lt"; + case PIC16CC::ULT: return "lt"; + case PIC16CC::LE: return "le"; + case PIC16CC::ULE: return "le"; + case PIC16CC::GT: return "gt"; + case PIC16CC::UGT: return "gt"; + case PIC16CC::GE: return "ge"; + case PIC16CC::UGE: return "ge"; + } + } + + inline static bool isSignedComparison(PIC16CC::CondCodes CC) { + switch (CC) { + default: llvm_unreachable("Unknown condition code"); + case PIC16CC::NE: + case PIC16CC::EQ: + case PIC16CC::LT: + case PIC16CC::LE: + case PIC16CC::GE: + case PIC16CC::GT: + return true; + case PIC16CC::ULT: + case PIC16CC::UGT: + case PIC16CC::ULE: + case PIC16CC::UGE: + return false; // condition codes for unsigned comparison. + } + } + + + + FunctionPass *createPIC16ISelDag(PIC16TargetMachine &TM); + // Banksel optimizer pass. + FunctionPass *createPIC16MemSelOptimizerPass(); + + extern Target ThePIC16Target; + extern Target TheCooperTarget; + +} // end namespace llvm; + +// Defines symbolic names for PIC16 registers. This defines a mapping from +// register name to register number. +#include "PIC16GenRegisterNames.inc" + +// Defines symbolic names for the PIC16 instructions. +#include "PIC16GenInstrNames.inc" + +#endif diff --git a/contrib/llvm/lib/Target/PIC16/PIC16.td b/contrib/llvm/lib/Target/PIC16/PIC16.td new file mode 100644 index 0000000..b2b9b1c --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16.td @@ -0,0 +1,40 @@ +//===- PIC16.td - Describe the PIC16 Target Machine -----------*- tblgen -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This is the top level entry point for the PIC16 target. +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Target-independent interfaces +//===----------------------------------------------------------------------===// + +include "llvm/Target/Target.td" + +include "PIC16RegisterInfo.td" +include "PIC16InstrInfo.td" + +//===----------------------------------------------------------------------===// +// Subtarget Features. +//===----------------------------------------------------------------------===// +def FeatureCooper : SubtargetFeature<"cooper", "IsCooper", "true", + "PIC16 Cooper ISA Support">; + +//===----------------------------------------------------------------------===// +// PIC16 supported processors. +//===----------------------------------------------------------------------===// + +def : Processor<"generic", NoItineraries, []>; +def : Processor<"cooper", NoItineraries, [FeatureCooper]>; + + +def PIC16InstrInfo : InstrInfo {} + +def PIC16 : Target { + let InstructionSet = PIC16InstrInfo; +} + diff --git a/contrib/llvm/lib/Target/PIC16/PIC16ABINames.h b/contrib/llvm/lib/Target/PIC16/PIC16ABINames.h new file mode 100644 index 0000000..4c1a8da --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16ABINames.h @@ -0,0 +1,399 @@ +//===-- PIC16ABINames.h - PIC16 Naming conventios for ABI----- --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the functions to manage ABI Naming conventions for PIC16. +// +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_PIC16ABINAMES_H +#define LLVM_TARGET_PIC16ABINAMES_H + +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetMachine.h" +#include <cassert> +#include <sstream> +#include <cstring> +#include <string> + +namespace llvm { + class PIC16TargetMachine; + class FunctionPass; + class MachineCodeEmitter; + class formatted_raw_ostream; + + // A Central class to manage all ABI naming conventions. + // PAN - [P]ic16 [A]BI [N]ames + class PAN { + public: + // Map the name of the symbol to its section name. + // Current ABI: + // ----------------------------------------------------- + // ALL Names are prefixed with the symobl '@'. + // ------------------------------------------------------ + // Global variables do not have any '.' in their names. + // These are maily function names and global variable names. + // Example - @foo, @i + // Static local variables - @<func>.<var> + // ------------------------------------------------------- + // Functions and auto variables. + // Names are mangled as <prefix><funcname>.<tag>.<varname> + // Where <prefix> is '@' and <tag> 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 start with .lib. + // This id will be used to emit extern decls for libcalls. + // Example - libcall name: @.lib.sra.i8 + // To pass args: @.lib.sra.i8.args. + // To return val: @.lib.sra.i8.ret. + //---------------------------------------------- + // SECTION Names + // uninitialized globals - @udata.<num>.# + // initialized globals - @idata.<num>.# + // Program memory data - @romdata.# + // Variables with user defined section name - <user_defined_section> + // Variables with user defined address - @<var>.user_section.<address>.# + // Function frame - @<func>.frame_section. + // Function autos - @<func>.autos_section. + // Overlay sections - @<color>.## + // Declarations - Enclosed in comments. No section for them. + //---------------------------------------------------------- + + // Tags used to mangle different names. + enum TAGS { + PREFIX_SYMBOL, + GLOBAL, + STATIC_LOCAL, + AUTOS_LABEL, + FRAME_LABEL, + RET_LABEL, + ARGS_LABEL, + TEMPS_LABEL, + + LIBCALL, + + FRAME_SECTION, + AUTOS_SECTION, + CODE_SECTION, + USER_SECTION + }; + + // Textual names of the tags. + inline static const char *getTagName(TAGS tag) { + switch (tag) { + default: return ""; + case PREFIX_SYMBOL: return "@"; + case AUTOS_LABEL: return ".auto."; + case FRAME_LABEL: return ".frame."; + case TEMPS_LABEL: return ".temp."; + case ARGS_LABEL: return ".args."; + case RET_LABEL: return ".ret."; + case LIBCALL: return ".lib."; + case FRAME_SECTION: return ".frame_section."; + case AUTOS_SECTION: return ".autos_section."; + case CODE_SECTION: return ".code_section."; + case USER_SECTION: return ".user_section."; + } + } + + // Get tag type for the Symbol. + inline static TAGS getSymbolTag(const std::string &Sym) { + if (Sym.find(getTagName(TEMPS_LABEL)) != std::string::npos) + return TEMPS_LABEL; + + if (Sym.find(getTagName(FRAME_LABEL)) != std::string::npos) + return FRAME_LABEL; + + if (Sym.find(getTagName(RET_LABEL)) != std::string::npos) + return RET_LABEL; + + if (Sym.find(getTagName(ARGS_LABEL)) != std::string::npos) + return ARGS_LABEL; + + if (Sym.find(getTagName(AUTOS_LABEL)) != std::string::npos) + return AUTOS_LABEL; + + if (Sym.find(getTagName(LIBCALL)) != std::string::npos) + return LIBCALL; + + // It does not have any Tag. So its a true global or static local. + if (Sym.find(".") == std::string::npos) + return GLOBAL; + + // If a . is there, then it may be static local. + // We should mangle these as well in clang. + if (Sym.find(".") != std::string::npos) + return STATIC_LOCAL; + + assert (0 && "Could not determine Symbol's tag"); + return PREFIX_SYMBOL; // Silence warning when assertions are turned off. + } + + // addPrefix - add prefix symbol to a name if there isn't one already. + inline static std::string addPrefix (const std::string &Name) { + std::string prefix = getTagName (PREFIX_SYMBOL); + + // If this name already has a prefix, nothing to do. + if (Name.compare(0, prefix.size(), prefix) == 0) + return Name; + + return prefix + Name; + } + + // Get mangled func name from a mangled sym name. + // In all cases func name is the first component before a '.'. + static inline std::string getFuncNameForSym(const std::string &Sym1) { + assert (getSymbolTag(Sym1) != GLOBAL && "not belongs to a function"); + + std::string Sym = addPrefix(Sym1); + + // Position of the . after func name. That's where func name ends. + size_t func_name_end = Sym.find ('.'); + + return Sym.substr (0, func_name_end); + } + + // Get Frame start label for a func. + static std::string getFrameLabel(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(FRAME_LABEL); + return Func1 + tag; + } + + // Get the retval label for the given function. + static std::string getRetvalLabel(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(RET_LABEL); + return Func1 + tag; + } + + // Get the argument label for the given function. + static std::string getArgsLabel(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(ARGS_LABEL); + return Func1 + tag; + } + + // Get the tempdata label for the given function. + static std::string getTempdataLabel(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(TEMPS_LABEL); + return Func1 + tag; + } + + static std::string getFrameSectionName(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(FRAME_SECTION); + return Func1 + tag + "#"; + } + + static std::string getAutosSectionName(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(AUTOS_SECTION); + return Func1 + tag + "#"; + } + + static std::string getCodeSectionName(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(CODE_SECTION); + return Func1 + tag + "#"; + } + + static std::string getUserSectionName(const std::string &Name) { + std::string sname = addPrefix(Name);; + std::string tag = getTagName(USER_SECTION); + return sname + tag + "#"; + } + + // udata, romdata and idata section names are generated by a given number. + // @udata.<num>.# + static std::string getUdataSectionName(unsigned num, + std::string prefix = "") { + std::ostringstream o; + o << getTagName(PREFIX_SYMBOL) << prefix << "udata." << num + << ".#"; + return o.str(); + } + + static std::string getRomdataSectionName() { + return "romdata.#"; + } + + static std::string getSharedUDataSectionName() { + std::ostringstream o; + o << getTagName(PREFIX_SYMBOL) << "udata_shr" << ".#"; + return o.str(); + } + + static std::string getRomdataSectionName(unsigned num, + std::string prefix = "") { + std::ostringstream o; + o << getTagName(PREFIX_SYMBOL) << prefix << "romdata." << num + << ".#"; + return o.str(); + } + + static std::string getIdataSectionName(unsigned num, + std::string prefix = "") { + std::ostringstream o; + o << getTagName(PREFIX_SYMBOL) << prefix << "idata." << num + << ".#"; + return o.str(); + } + + inline static bool isLocalName (const std::string &Name) { + if (getSymbolTag(Name) == AUTOS_LABEL) + return true; + + return false; + } + + + inline static bool isMemIntrinsic (const std::string &Name) { + if (Name.compare("@memcpy") == 0 || Name.compare("@memset") == 0 || + Name.compare("@memmove") == 0) { + return true; + } + + return false; + } + + // Currently names of libcalls are assigned during TargetLowering + // object construction. There is no provision to change the when the + // code for a function IL function being generated. + // So we have to change these names while printing assembly. + // We need to do that mainly for names related to intrinsics. This + // function returns true if a name needs to be cloned. + inline static bool isIntrinsicStuff(const std::string &Name) { + // Return true if the name contains LIBCALL marker, or a MemIntrinisc. + // these are mainly ARGS_LABEL, RET_LABEL, and the LIBCALL name itself. + if ((Name.find(getTagName(LIBCALL)) != std::string::npos) + || isMemIntrinsic(Name)) + return true; + + return false; + } + + // Rename the name for IL. + inline static std::string Rename(const std::string &Name) { + std::string Newname; + // If its a label (LIBCALL+Func+LABEL), change it to + // (LIBCALL+Func+IL+LABEL). + TAGS id = getSymbolTag(Name); + if (id == ARGS_LABEL || id == RET_LABEL) { + std::size_t pos = Name.find(getTagName(id)); + Newname = Name.substr(0, pos) + ".IL" + getTagName(id); + return Newname; + } + + // Else, just append IL to name. + return Name + ".IL"; + } + + + + + inline static bool isLocalToFunc (std::string &Func, std::string &Var) { + if (! isLocalName(Var)) return false; + + std::string Func1 = addPrefix(Func); + // Extract func name of the varilable. + const std::string &fname = getFuncNameForSym(Var); + + if (fname.compare(Func1) == 0) + return true; + + return false; + } + + + // Get the section for the given external symbol names. + // This tries to find the type (Tag) of the symbol from its mangled name + // and return appropriate section name for it. + static inline std::string getSectionNameForSym(const std::string &Sym1) { + std::string Sym = addPrefix(Sym1); + + std::string SectionName; + + std::string Fname = getFuncNameForSym (Sym); + TAGS id = getSymbolTag (Sym); + + switch (id) { + default : assert (0 && "Could not determine external symbol type"); + case FRAME_LABEL: + case RET_LABEL: + case TEMPS_LABEL: + case ARGS_LABEL: { + return getFrameSectionName(Fname); + } + case AUTOS_LABEL: { + return getAutosSectionName(Fname); + } + } + } + + /// Return Overlay Name for the section. + /// The ABI Convention is: @<Color>.##.<section_tag> + /// The section_tag is retrieved from the SectName parameter and + /// and Color is passed in parameter. + static inline std::string getOverlayName(std::string SectName, int Color) { + // FIXME: Only autos_section and frame_section are colored. + // So check and assert if the passed SectName does not have AUTOS_SECTION + // or FRAME_SECTION tag in it. + std::ostringstream o; + o << getTagName(PREFIX_SYMBOL) << Color << ".##" + << SectName.substr(SectName.find(".")); + + return o.str(); + } + + // Return true if the current function is an ISR + inline static bool isISR(const std::string SectName) { + if (SectName.find("interrupt") != std::string::npos) + return true; + + return false; + } + + // Return the address for ISR starts in rom. + inline static std::string getISRAddr(void) { + return "0x4"; + } + + // Returns the name of clone of a function. + static std::string getCloneFnName(const std::string &Func) { + return (Func + ".IL"); + } + + // Returns the name of clone of a variable. + static std::string getCloneVarName(const std::string &Fn, + const std::string &Var) { + std::string cloneVarName = Var; + // These vars are named like fun.auto.var. + // Just replace the function name, with clone function name. + std::string cloneFnName = getCloneFnName(Fn); + cloneVarName.replace(cloneVarName.find(Fn), Fn.length(), cloneFnName); + return cloneVarName; + } + }; // class PAN. +} // end namespace llvm; + +#endif diff --git a/contrib/llvm/lib/Target/PIC16/PIC16DebugInfo.cpp b/contrib/llvm/lib/Target/PIC16/PIC16DebugInfo.cpp new file mode 100644 index 0000000..7a948de --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16DebugInfo.cpp @@ -0,0 +1,490 @@ + +//===-- PIC16DebugInfo.cpp - Implementation for PIC16 Debug Information ======// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the helper functions for representing debug information. +// +//===----------------------------------------------------------------------===// + +#include "PIC16.h" +#include "PIC16ABINames.h" +#include "PIC16DebugInfo.h" +#include "llvm/GlobalVariable.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/DebugLoc.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +using namespace llvm; + +/// PopulateDebugInfo - Populate the TypeNo, Aux[] and TagName from Ty. +/// +void PIC16DbgInfo::PopulateDebugInfo (DIType Ty, unsigned short &TypeNo, + bool &HasAux, int Aux[], + std::string &TagName) { + if (Ty.isBasicType()) + PopulateBasicTypeInfo (Ty, TypeNo); + else if (Ty.isCompositeType()) + PopulateCompositeTypeInfo (Ty, TypeNo, HasAux, Aux, TagName); + else if (Ty.isDerivedType()) + PopulateDerivedTypeInfo (Ty, TypeNo, HasAux, Aux, TagName); + else { + TypeNo = PIC16Dbg::T_NULL; + HasAux = false; + } + return; +} + +/// PopulateBasicTypeInfo- Populate TypeNo for basic type from Ty. +/// +void PIC16DbgInfo::PopulateBasicTypeInfo (DIType Ty, unsigned short &TypeNo) { + std::string Name = Ty.getName(); + unsigned short BaseTy = GetTypeDebugNumber(Name); + TypeNo = TypeNo << PIC16Dbg::S_BASIC; + TypeNo = TypeNo | (0xffff & BaseTy); +} + +/// PopulateDerivedTypeInfo - Populate TypeNo, Aux[], TagName for derived type +/// from Ty. Derived types are mostly pointers. +/// +void PIC16DbgInfo::PopulateDerivedTypeInfo (DIType Ty, unsigned short &TypeNo, + bool &HasAux, int Aux[], + std::string &TagName) { + + switch(Ty.getTag()) + { + case dwarf::DW_TAG_pointer_type: + TypeNo = TypeNo << PIC16Dbg::S_DERIVED; + TypeNo = TypeNo | PIC16Dbg::DT_PTR; + break; + default: + TypeNo = TypeNo << PIC16Dbg::S_DERIVED; + } + + // We also need to encode the information about the base type of + // pointer in TypeNo. + DIType BaseType = DIDerivedType(Ty).getTypeDerivedFrom(); + PopulateDebugInfo(BaseType, TypeNo, HasAux, Aux, TagName); +} + +/// PopulateArrayTypeInfo - Populate TypeNo, Aux[] for array from Ty. +void PIC16DbgInfo::PopulateArrayTypeInfo (DIType Ty, unsigned short &TypeNo, + bool &HasAux, int Aux[], + std::string &TagName) { + + DICompositeType CTy = DICompositeType(Ty); + DIArray Elements = CTy.getTypeArray(); + unsigned short size = 1; + unsigned short Dimension[4]={0,0,0,0}; + for (unsigned i = 0, N = Elements.getNumElements(); i < N; ++i) { + DIDescriptor Element = Elements.getElement(i); + if (Element.getTag() == dwarf::DW_TAG_subrange_type) { + TypeNo = TypeNo << PIC16Dbg::S_DERIVED; + TypeNo = TypeNo | PIC16Dbg::DT_ARY; + DISubrange SubRange = DISubrange(Element); + Dimension[i] = SubRange.getHi() - SubRange.getLo() + 1; + // Each dimension is represented by 2 bytes starting at byte 9. + Aux[8+i*2+0] = Dimension[i]; + Aux[8+i*2+1] = Dimension[i] >> 8; + size = size * Dimension[i]; + } + } + HasAux = true; + // In auxillary entry for array, 7th and 8th byte represent array size. + Aux[6] = size & 0xff; + Aux[7] = size >> 8; + DIType BaseType = CTy.getTypeDerivedFrom(); + PopulateDebugInfo(BaseType, TypeNo, HasAux, Aux, TagName); +} + +/// PopulateStructOrUnionTypeInfo - Populate TypeNo, Aux[] , TagName for +/// structure or union. +/// +void PIC16DbgInfo::PopulateStructOrUnionTypeInfo (DIType Ty, + unsigned short &TypeNo, + bool &HasAux, int Aux[], + std::string &TagName) { + DICompositeType CTy = DICompositeType(Ty); + TypeNo = TypeNo << PIC16Dbg::S_BASIC; + if (Ty.getTag() == dwarf::DW_TAG_structure_type) + TypeNo = TypeNo | PIC16Dbg::T_STRUCT; + else + TypeNo = TypeNo | PIC16Dbg::T_UNION; + TagName = CTy.getName(); + // UniqueSuffix is .number where number is obtained from + // llvm.dbg.composite<number>. + // FIXME: This will break when composite type is not represented by + // llvm.dbg.composite* global variable. Since we need to revisit + // PIC16DebugInfo implementation anyways after the MDNodes based + // framework is done, let us continue with the way it is. + std::string UniqueSuffix = "." + Ty->getNameStr().substr(18); + TagName += UniqueSuffix; + unsigned short size = CTy.getSizeInBits()/8; + // 7th and 8th byte represent size. + HasAux = true; + Aux[6] = size & 0xff; + Aux[7] = size >> 8; +} + +/// PopulateEnumTypeInfo - Populate TypeNo for enum from Ty. +void PIC16DbgInfo::PopulateEnumTypeInfo (DIType Ty, unsigned short &TypeNo) { + TypeNo = TypeNo << PIC16Dbg::S_BASIC; + TypeNo = TypeNo | PIC16Dbg::T_ENUM; +} + +/// PopulateCompositeTypeInfo - Populate TypeNo, Aux[] and TagName for +/// composite types from Ty. +/// +void PIC16DbgInfo::PopulateCompositeTypeInfo (DIType Ty, unsigned short &TypeNo, + bool &HasAux, int Aux[], + std::string &TagName) { + switch (Ty.getTag()) { + case dwarf::DW_TAG_array_type: { + PopulateArrayTypeInfo (Ty, TypeNo, HasAux, Aux, TagName); + break; + } + case dwarf:: DW_TAG_union_type: + case dwarf::DW_TAG_structure_type: { + PopulateStructOrUnionTypeInfo (Ty, TypeNo, HasAux, Aux, TagName); + break; + } + case dwarf::DW_TAG_enumeration_type: { + PopulateEnumTypeInfo (Ty, TypeNo); + break; + } + default: + TypeNo = TypeNo << PIC16Dbg::S_DERIVED; + } +} + +/// GetTypeDebugNumber - Get debug type number for given type. +/// +unsigned PIC16DbgInfo::GetTypeDebugNumber(std::string &type) { + if (type == "char") + return PIC16Dbg::T_CHAR; + else if (type == "short") + return PIC16Dbg::T_SHORT; + else if (type == "int") + return PIC16Dbg::T_INT; + else if (type == "long") + return PIC16Dbg::T_LONG; + else if (type == "unsigned char") + return PIC16Dbg::T_UCHAR; + else if (type == "unsigned short") + return PIC16Dbg::T_USHORT; + else if (type == "unsigned int") + return PIC16Dbg::T_UINT; + else if (type == "unsigned long") + return PIC16Dbg::T_ULONG; + else + return 0; +} + +/// GetStorageClass - Get storage class for give debug variable. +/// +short PIC16DbgInfo::getStorageClass(DIGlobalVariable DIGV) { + short ClassNo; + if (PAN::isLocalName(DIGV.getName())) { + // Generating C_AUTO here fails due to error in linker. Change it once + // linker is fixed. + ClassNo = PIC16Dbg::C_STAT; + } + else if (DIGV.isLocalToUnit()) + ClassNo = PIC16Dbg::C_STAT; + else + ClassNo = PIC16Dbg::C_EXT; + return ClassNo; +} + +/// BeginModule - Emit necessary debug info to start a Module and do other +/// required initializations. +void PIC16DbgInfo::BeginModule(Module &M) { + // Emit file directive for module. + DebugInfoFinder DbgFinder; + DbgFinder.processModule(M); + if (DbgFinder.compile_unit_count() != 0) { + // FIXME : What if more then one CUs are present in a module ? + MDNode *CU = *DbgFinder.compile_unit_begin(); + EmitDebugDirectives = true; + SwitchToCU(CU); + } + // Emit debug info for decls of composite types. + EmitCompositeTypeDecls(M); +} + +/// Helper to find first valid debug loc for a function. +/// +static const DebugLoc GetDebugLocForFunction(const MachineFunction &MF) { + DebugLoc DL; + for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); + II != E; ++II) { + DL = II->getDebugLoc(); + if (!DL.isUnknown()) + return DL; + } + } + return DL; +} + +/// BeginFunction - Emit necessary debug info to start a function. +/// +void PIC16DbgInfo::BeginFunction(const MachineFunction &MF) { + if (! EmitDebugDirectives) return; + + // Retreive the first valid debug Loc and process it. + const DebugLoc &DL = GetDebugLocForFunction(MF); + // Emit debug info only if valid debug info is available. + if (!DL.isUnknown()) { + ChangeDebugLoc(MF, DL, true); + EmitFunctBeginDI(MF.getFunction()); + } + // Set current line to 0 so that.line directive is genearted after .bf. + CurLine = 0; +} + +/// ChangeDebugLoc - Take necessary steps when DebugLoc changes. +/// CurFile and CurLine may change as a result of this. +/// +void PIC16DbgInfo::ChangeDebugLoc(const MachineFunction &MF, + const DebugLoc &DL, bool IsInBeginFunction) { + if (!EmitDebugDirectives) return; + assert(!DL.isUnknown() && "can't change to invalid debug loc"); + + SwitchToCU(DL.getScope(MF.getFunction()->getContext())); + SwitchToLine(DL.getLine(), IsInBeginFunction); +} + +/// SwitchToLine - Emit line directive for a new line. +/// +void PIC16DbgInfo::SwitchToLine(unsigned Line, bool IsInBeginFunction) { + if (CurLine == Line) return; + if (!IsInBeginFunction) + OS.EmitRawText("\n\t.line " + Twine(Line)); + CurLine = Line; +} + +/// EndFunction - Emit .ef for end of function. +/// +void PIC16DbgInfo::EndFunction(const MachineFunction &MF) { + if (! EmitDebugDirectives) return; + const DebugLoc &DL = GetDebugLocForFunction(MF); + // Emit debug info only if valid debug info is available. + if (!DL.isUnknown()) + EmitFunctEndDI(MF.getFunction(), CurLine); +} + +/// EndModule - Emit .eof for end of module. +/// +void PIC16DbgInfo::EndModule(Module &M) { + if (! EmitDebugDirectives) return; + EmitVarDebugInfo(M); + if (CurFile != "") OS.EmitRawText(StringRef("\n\t.eof")); +} + +/// EmitCompositeTypeElements - Emit debug information for members of a +/// composite type. +/// +void PIC16DbgInfo::EmitCompositeTypeElements (DICompositeType CTy, + std::string SuffixNo) { + unsigned long Value = 0; + DIArray Elements = CTy.getTypeArray(); + for (unsigned i = 0, N = Elements.getNumElements(); i < N; i++) { + DIDescriptor Element = Elements.getElement(i); + unsigned short TypeNo = 0; + bool HasAux = false; + int ElementAux[PIC16Dbg::AuxSize] = { 0 }; + std::string TagName = ""; + DIDerivedType DITy(Element); + unsigned short ElementSize = DITy.getSizeInBits()/8; + // Get mangleddd name for this structure/union element. + std::string MangMemName = DITy.getName().str() + SuffixNo; + PopulateDebugInfo(DITy, TypeNo, HasAux, ElementAux, TagName); + short Class = 0; + if( CTy.getTag() == dwarf::DW_TAG_union_type) + Class = PIC16Dbg::C_MOU; + else if (CTy.getTag() == dwarf::DW_TAG_structure_type) + Class = PIC16Dbg::C_MOS; + EmitSymbol(MangMemName.c_str(), Class, TypeNo, Value); + if (CTy.getTag() == dwarf::DW_TAG_structure_type) + Value += ElementSize; + if (HasAux) + EmitAuxEntry(MangMemName.c_str(), ElementAux, PIC16Dbg::AuxSize, TagName); + } +} + +/// EmitCompositeTypeDecls - Emit composite type declarations like structure +/// and union declarations. +/// +void PIC16DbgInfo::EmitCompositeTypeDecls(Module &M) { + DebugInfoFinder DbgFinder; + DbgFinder.processModule(M); + for (DebugInfoFinder::iterator I = DbgFinder.type_begin(), + E = DbgFinder.type_end(); I != E; ++I) { + DICompositeType CTy(*I); + if (!CTy.Verify()) + continue; + if (CTy.getTag() == dwarf::DW_TAG_union_type || + CTy.getTag() == dwarf::DW_TAG_structure_type ) { + // Get the number after llvm.dbg.composite and make UniqueSuffix from + // it. + std::string DIVar = CTy->getNameStr(); + std::string UniqueSuffix = "." + DIVar.substr(18); + std::string MangledCTyName = CTy.getName().str() + UniqueSuffix; + unsigned short size = CTy.getSizeInBits()/8; + int Aux[PIC16Dbg::AuxSize] = {0}; + // 7th and 8th byte represent size of structure/union. + Aux[6] = size & 0xff; + Aux[7] = size >> 8; + // Emit .def for structure/union tag. + if( CTy.getTag() == dwarf::DW_TAG_union_type) + EmitSymbol(MangledCTyName.c_str(), PIC16Dbg::C_UNTAG); + else if (CTy.getTag() == dwarf::DW_TAG_structure_type) + EmitSymbol(MangledCTyName.c_str(), PIC16Dbg::C_STRTAG); + + // Emit auxiliary debug information for structure/union tag. + EmitAuxEntry(MangledCTyName.c_str(), Aux, PIC16Dbg::AuxSize); + + // Emit members. + EmitCompositeTypeElements (CTy, UniqueSuffix); + + // Emit mangled Symbol for end of structure/union. + std::string EOSSymbol = ".eos" + UniqueSuffix; + EmitSymbol(EOSSymbol.c_str(), PIC16Dbg::C_EOS); + EmitAuxEntry(EOSSymbol.c_str(), Aux, PIC16Dbg::AuxSize, + MangledCTyName.c_str()); + } + } +} + + +/// EmitFunctBeginDI - Emit .bf for function. +/// +void PIC16DbgInfo::EmitFunctBeginDI(const Function *F) { + std::string FunctName = F->getName(); + if (EmitDebugDirectives) { + std::string FunctBeginSym = ".bf." + FunctName; + std::string BlockBeginSym = ".bb." + FunctName; + + int BFAux[PIC16Dbg::AuxSize] = {0}; + BFAux[4] = CurLine; + BFAux[5] = CurLine >> 8; + + // Emit debug directives for beginning of function. + EmitSymbol(FunctBeginSym, PIC16Dbg::C_FCN); + EmitAuxEntry(FunctBeginSym, BFAux, PIC16Dbg::AuxSize); + + EmitSymbol(BlockBeginSym, PIC16Dbg::C_BLOCK); + EmitAuxEntry(BlockBeginSym, BFAux, PIC16Dbg::AuxSize); + } +} + +/// EmitFunctEndDI - Emit .ef for function end. +/// +void PIC16DbgInfo::EmitFunctEndDI(const Function *F, unsigned Line) { + std::string FunctName = F->getName(); + if (EmitDebugDirectives) { + std::string FunctEndSym = ".ef." + FunctName; + std::string BlockEndSym = ".eb." + FunctName; + + // Emit debug directives for end of function. + EmitSymbol(BlockEndSym, PIC16Dbg::C_BLOCK); + int EFAux[PIC16Dbg::AuxSize] = {0}; + // 5th and 6th byte stand for line number. + EFAux[4] = CurLine; + EFAux[5] = CurLine >> 8; + EmitAuxEntry(BlockEndSym, EFAux, PIC16Dbg::AuxSize); + EmitSymbol(FunctEndSym, PIC16Dbg::C_FCN); + EmitAuxEntry(FunctEndSym, EFAux, PIC16Dbg::AuxSize); + } +} + +/// EmitAuxEntry - Emit Auxiliary debug information. +/// +void PIC16DbgInfo::EmitAuxEntry(const std::string VarName, int Aux[], int Num, + std::string TagName) { + std::string Tmp; + // TagName is emitted in case of structure/union objects. + if (!TagName.empty()) Tmp += ", " + TagName; + + for (int i = 0; i<Num; i++) + Tmp += "," + utostr(Aux[i] & 0xff); + + OS.EmitRawText("\n\t.dim " + Twine(VarName) + ", 1" + Tmp); +} + +/// EmitSymbol - Emit .def for a symbol. Value is offset for the member. +/// +void PIC16DbgInfo::EmitSymbol(std::string Name, short Class, + unsigned short Type, unsigned long Value) { + std::string Tmp; + if (Value > 0) + Tmp = ", value = " + utostr(Value); + + OS.EmitRawText("\n\t.def " + Twine(Name) + ", type = " + utostr(Type) + + ", class = " + utostr(Class) + Tmp); +} + +/// EmitVarDebugInfo - Emit debug information for all variables. +/// +void PIC16DbgInfo::EmitVarDebugInfo(Module &M) { + DebugInfoFinder DbgFinder; + DbgFinder.processModule(M); + + for (DebugInfoFinder::iterator I = DbgFinder.global_variable_begin(), + E = DbgFinder.global_variable_end(); I != E; ++I) { + DIGlobalVariable DIGV(*I); + DIType Ty = DIGV.getType(); + unsigned short TypeNo = 0; + bool HasAux = false; + int Aux[PIC16Dbg::AuxSize] = { 0 }; + std::string TagName = ""; + std::string VarName = DIGV.getName(); + VarName = MAI->getGlobalPrefix() + VarName; + PopulateDebugInfo(Ty, TypeNo, HasAux, Aux, TagName); + // Emit debug info only if type information is availaible. + if (TypeNo != PIC16Dbg::T_NULL) { + OS.EmitRawText("\t.type " + Twine(VarName) + ", " + Twine(TypeNo)); + short ClassNo = getStorageClass(DIGV); + OS.EmitRawText("\t.class " + Twine(VarName) + ", " + Twine(ClassNo)); + if (HasAux) + EmitAuxEntry(VarName, Aux, PIC16Dbg::AuxSize, TagName); + } + } +} + +/// SwitchToCU - Switch to a new compilation unit. +/// +void PIC16DbgInfo::SwitchToCU(MDNode *CU) { + // Get the file path from CU. + DICompileUnit cu(CU); + std::string DirName = cu.getDirectory(); + std::string FileName = cu.getFilename(); + std::string FilePath = DirName + "/" + FileName; + + // Nothing to do if source file is still same. + if ( FilePath == CurFile ) return; + + // Else, close the current one and start a new. + if (CurFile != "") + OS.EmitRawText(StringRef("\t.eof")); + OS.EmitRawText("\n\t.file\t\"" + Twine(FilePath) + "\""); + CurFile = FilePath; + CurLine = 0; +} + +/// EmitEOF - Emit .eof for end of file. +/// +void PIC16DbgInfo::EmitEOF() { + if (CurFile != "") + OS.EmitRawText(StringRef("\t.EOF")); +} + diff --git a/contrib/llvm/lib/Target/PIC16/PIC16DebugInfo.h b/contrib/llvm/lib/Target/PIC16/PIC16DebugInfo.h new file mode 100644 index 0000000..031dcf0 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16DebugInfo.h @@ -0,0 +1,156 @@ +//===-- PIC16DebugInfo.h - Interfaces for PIC16 Debug Information ============// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the helper functions for representing debug information. +// +//===----------------------------------------------------------------------===// + +#ifndef PIC16DBG_H +#define PIC16DBG_H + +#include "llvm/Analysis/DebugInfo.h" +#include "llvm/Module.h" + +namespace llvm { + class MachineFunction; + class DebugLoc; + class MCStreamer; + + namespace PIC16Dbg { + enum VarType { + T_NULL, + T_VOID, + T_CHAR, + T_SHORT, + T_INT, + T_LONG, + T_FLOAT, + T_DOUBLE, + T_STRUCT, + T_UNION, + T_ENUM, + T_MOE, + T_UCHAR, + T_USHORT, + T_UINT, + T_ULONG + }; + enum DerivedType { + DT_NONE, + DT_PTR, + DT_FCN, + DT_ARY + }; + enum TypeSize { + S_BASIC = 5, + S_DERIVED = 3 + }; + enum DbgClass { + C_NULL, + C_AUTO, + C_EXT, + C_STAT, + C_REG, + C_EXTDEF, + C_LABEL, + C_ULABEL, + C_MOS, + C_ARG, + C_STRTAG, + C_MOU, + C_UNTAG, + C_TPDEF, + C_USTATIC, + C_ENTAG, + C_MOE, + C_REGPARM, + C_FIELD, + C_AUTOARG, + C_LASTENT, + C_BLOCK = 100, + C_FCN, + C_EOS, + C_FILE, + C_LINE, + C_ALIAS, + C_HIDDEN, + C_EOF, + C_LIST, + C_SECTION, + C_EFCN = 255 + }; + enum SymbolSize { + AuxSize =20 + }; + } + + class PIC16DbgInfo { + MCStreamer &OS; + const MCAsmInfo *MAI; + std::string CurFile; + unsigned CurLine; + + // EmitDebugDirectives is set if debug information is available. Default + // value for it is false. + bool EmitDebugDirectives; + + public: + PIC16DbgInfo(MCStreamer &os, const MCAsmInfo *T) : OS(os), MAI(T) { + CurFile = ""; + CurLine = 0; + EmitDebugDirectives = false; + } + + void BeginModule (Module &M); + void BeginFunction (const MachineFunction &MF); + void ChangeDebugLoc (const MachineFunction &MF, const DebugLoc &DL, + bool IsInBeginFunction = false); + void EndFunction (const MachineFunction &MF); + void EndModule (Module &M); + + + private: + void SwitchToCU (MDNode *CU); + void SwitchToLine (unsigned Line, bool IsInBeginFunction = false); + + void PopulateDebugInfo (DIType Ty, unsigned short &TypeNo, bool &HasAux, + int Aux[], std::string &TypeName); + void PopulateBasicTypeInfo (DIType Ty, unsigned short &TypeNo); + void PopulateDerivedTypeInfo (DIType Ty, unsigned short &TypeNo, + bool &HasAux, int Aux[], + std::string &TypeName); + + void PopulateCompositeTypeInfo (DIType Ty, unsigned short &TypeNo, + bool &HasAux, int Aux[], + std::string &TypeName); + void PopulateArrayTypeInfo (DIType Ty, unsigned short &TypeNo, + bool &HasAux, int Aux[], + std::string &TypeName); + + void PopulateStructOrUnionTypeInfo (DIType Ty, unsigned short &TypeNo, + bool &HasAux, int Aux[], + std::string &TypeName); + void PopulateEnumTypeInfo (DIType Ty, unsigned short &TypeNo); + + unsigned GetTypeDebugNumber(std::string &Type); + short getStorageClass(DIGlobalVariable DIGV); + void EmitFunctBeginDI(const Function *F); + void EmitCompositeTypeDecls(Module &M); + void EmitCompositeTypeElements (DICompositeType CTy, std::string Suffix); + void EmitFunctEndDI(const Function *F, unsigned Line); + void EmitAuxEntry(const std::string VarName, int Aux[], + int num = PIC16Dbg::AuxSize, std::string TagName = ""); + inline void EmitSymbol(std::string Name, short Class, + unsigned short Type = PIC16Dbg::T_NULL, + unsigned long Value = 0); + void EmitVarDebugInfo(Module &M); + void EmitEOF(); + }; +} // end namespace llvm; +#endif diff --git a/contrib/llvm/lib/Target/PIC16/PIC16ISelDAGToDAG.cpp b/contrib/llvm/lib/Target/PIC16/PIC16ISelDAGToDAG.cpp new file mode 100644 index 0000000..6cbd002 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16ISelDAGToDAG.cpp @@ -0,0 +1,50 @@ +//===-- PIC16ISelDAGToDAG.cpp - A dag to dag inst selector for PIC16 ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an instruction selector for the PIC16 target. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "pic16-isel" + +#include "llvm/Support/ErrorHandling.h" +#include "PIC16ISelDAGToDAG.h" +using namespace llvm; + +/// createPIC16ISelDag - This pass converts a legalized DAG into a +/// PIC16-specific DAG, ready for instruction scheduling. +FunctionPass *llvm::createPIC16ISelDag(PIC16TargetMachine &TM) { + return new PIC16DAGToDAGISel(TM); +} + + +/// Select - Select instructions not customized! Used for +/// expanded, promoted and normal instructions. +SDNode* PIC16DAGToDAGISel::Select(SDNode *N) { + + // Select the default instruction. + SDNode *ResNode = SelectCode(N); + + return ResNode; +} + + +// SelectDirectAddr - Match a direct address for DAG. +// A direct address could be a globaladdress or externalsymbol. +bool PIC16DAGToDAGISel::SelectDirectAddr(SDNode *Op, SDValue N, + SDValue &Address) { + // Return true if TGA or ES. + if (N.getOpcode() == ISD::TargetGlobalAddress + || N.getOpcode() == ISD::TargetExternalSymbol) { + Address = N; + return true; + } + + return false; +} diff --git a/contrib/llvm/lib/Target/PIC16/PIC16ISelDAGToDAG.h b/contrib/llvm/lib/Target/PIC16/PIC16ISelDAGToDAG.h new file mode 100644 index 0000000..ecaddd3 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16ISelDAGToDAG.h @@ -0,0 +1,60 @@ +//===-- PIC16ISelDAGToDAG.cpp - A dag to dag inst selector for PIC16 ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an instruction selector for the PIC16 target. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "pic16-isel" + +#include "PIC16.h" +#include "PIC16RegisterInfo.h" +#include "PIC16TargetMachine.h" +#include "PIC16MachineFunctionInfo.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Debug.h" +#include "llvm/Intrinsics.h" +using namespace llvm; + +namespace { + +class LLVM_LIBRARY_VISIBILITY PIC16DAGToDAGISel : public SelectionDAGISel { + + /// TM - Keep a reference to PIC16TargetMachine. + const PIC16TargetMachine &TM; + + /// PIC16Lowering - This object fully describes how to lower LLVM code to an + /// PIC16-specific SelectionDAG. + const PIC16TargetLowering &PIC16Lowering; + +public: + explicit PIC16DAGToDAGISel(PIC16TargetMachine &tm) : + SelectionDAGISel(tm), + TM(tm), PIC16Lowering(*TM.getTargetLowering()) {} + + // Pass Name + virtual const char *getPassName() const { + return "PIC16 DAG->DAG Pattern Instruction Selection"; + } + +private: + // Include the pieces autogenerated from the target description. +#include "PIC16GenDAGISel.inc" + + SDNode *Select(SDNode *N); + + // Match direct address complex pattern. + bool SelectDirectAddr(SDNode *Op, SDValue N, SDValue &Address); + +}; + +} + diff --git a/contrib/llvm/lib/Target/PIC16/PIC16ISelLowering.cpp b/contrib/llvm/lib/Target/PIC16/PIC16ISelLowering.cpp new file mode 100644 index 0000000..527b31d --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16ISelLowering.cpp @@ -0,0 +1,2000 @@ +// +// 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 interfaces that PIC16 uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "pic16-lower" +#include "PIC16ABINames.h" +#include "PIC16ISelLowering.h" +#include "PIC16TargetObjectFile.h" +#include "PIC16TargetMachine.h" +#include "PIC16MachineFunctionInfo.h" +#include "llvm/DerivedTypes.h" +#include "llvm/GlobalValue.h" +#include "llvm/Function.h" +#include "llvm/CallingConv.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/Support/ErrorHandling.h" + + +using namespace llvm; + +static const char *getIntrinsicName(unsigned opcode) { + std::string Basename; + switch(opcode) { + default: llvm_unreachable("do not know intrinsic name"); + // Arithmetic Right shift for integer types. + case PIC16ISD::SRA_I8: Basename = "sra.i8"; break; + case RTLIB::SRA_I16: Basename = "sra.i16"; break; + case RTLIB::SRA_I32: Basename = "sra.i32"; break; + + // Left shift for integer types. + case PIC16ISD::SLL_I8: Basename = "sll.i8"; break; + case RTLIB::SHL_I16: Basename = "sll.i16"; break; + case RTLIB::SHL_I32: Basename = "sll.i32"; break; + + // Logical Right Shift for integer types. + case PIC16ISD::SRL_I8: Basename = "srl.i8"; break; + case RTLIB::SRL_I16: Basename = "srl.i16"; break; + case RTLIB::SRL_I32: Basename = "srl.i32"; break; + + // Multiply for integer types. + case PIC16ISD::MUL_I8: Basename = "mul.i8"; break; + case RTLIB::MUL_I16: Basename = "mul.i16"; break; + case RTLIB::MUL_I32: Basename = "mul.i32"; break; + + // Signed division for integers. + case RTLIB::SDIV_I16: Basename = "sdiv.i16"; break; + case RTLIB::SDIV_I32: Basename = "sdiv.i32"; break; + + // Unsigned division for integers. + case RTLIB::UDIV_I16: Basename = "udiv.i16"; break; + case RTLIB::UDIV_I32: Basename = "udiv.i32"; break; + + // Signed Modulas for integers. + case RTLIB::SREM_I16: Basename = "srem.i16"; break; + case RTLIB::SREM_I32: Basename = "srem.i32"; break; + + // Unsigned Modulas for integers. + case RTLIB::UREM_I16: Basename = "urem.i16"; break; + case RTLIB::UREM_I32: Basename = "urem.i32"; break; + + ////////////////////// + // LIBCALLS FOR FLOATS + ////////////////////// + + // Float to signed integrals + case RTLIB::FPTOSINT_F32_I8: Basename = "f32_to_si32"; break; + case RTLIB::FPTOSINT_F32_I16: Basename = "f32_to_si32"; break; + case RTLIB::FPTOSINT_F32_I32: Basename = "f32_to_si32"; break; + + // Signed integrals to float. char and int are first sign extended to i32 + // before being converted to float, so an I8_F32 or I16_F32 isn't required. + case RTLIB::SINTTOFP_I32_F32: Basename = "si32_to_f32"; break; + + // Float to Unsigned conversions. + // Signed conversion can be used for unsigned conversion as well. + // In signed and unsigned versions only the interpretation of the + // MSB is different. Bit representation remains the same. + case RTLIB::FPTOUINT_F32_I8: Basename = "f32_to_si32"; break; + case RTLIB::FPTOUINT_F32_I16: Basename = "f32_to_si32"; break; + case RTLIB::FPTOUINT_F32_I32: Basename = "f32_to_si32"; break; + + // Unsigned to Float conversions. char and int are first zero extended + // before being converted to float. + case RTLIB::UINTTOFP_I32_F32: Basename = "ui32_to_f32"; break; + + // Floating point add, sub, mul, div. + case RTLIB::ADD_F32: Basename = "add.f32"; break; + case RTLIB::SUB_F32: Basename = "sub.f32"; break; + case RTLIB::MUL_F32: Basename = "mul.f32"; break; + case RTLIB::DIV_F32: Basename = "div.f32"; break; + + // Floating point comparison + case RTLIB::O_F32: Basename = "unordered.f32"; break; + case RTLIB::UO_F32: Basename = "unordered.f32"; break; + case RTLIB::OLE_F32: Basename = "le.f32"; break; + case RTLIB::OGE_F32: Basename = "ge.f32"; break; + case RTLIB::OLT_F32: Basename = "lt.f32"; break; + case RTLIB::OGT_F32: Basename = "gt.f32"; break; + case RTLIB::OEQ_F32: Basename = "eq.f32"; break; + case RTLIB::UNE_F32: Basename = "neq.f32"; break; + } + + std::string prefix = PAN::getTagName(PAN::PREFIX_SYMBOL); + std::string tagname = PAN::getTagName(PAN::LIBCALL); + std::string Fullname = prefix + tagname + Basename; + + // The name has to live through program life. + return ESNames::createESName(Fullname); +} + +// getStdLibCallName - Get the name for the standard library function. +static const char *getStdLibCallName(unsigned opcode) { + std::string BaseName; + switch(opcode) { + case RTLIB::COS_F32: BaseName = "cos"; + break; + case RTLIB::SIN_F32: BaseName = "sin"; + break; + case RTLIB::MEMCPY: BaseName = "memcpy"; + break; + case RTLIB::MEMSET: BaseName = "memset"; + break; + case RTLIB::MEMMOVE: BaseName = "memmove"; + break; + default: llvm_unreachable("do not know std lib call name"); + } + std::string prefix = PAN::getTagName(PAN::PREFIX_SYMBOL); + std::string LibCallName = prefix + BaseName; + + // The name has to live through program life. + return ESNames::createESName(LibCallName); +} + +// PIC16TargetLowering Constructor. +PIC16TargetLowering::PIC16TargetLowering(PIC16TargetMachine &TM) + : TargetLowering(TM, new PIC16TargetObjectFile()) { + + Subtarget = &TM.getSubtarget<PIC16Subtarget>(); + + addRegisterClass(MVT::i8, PIC16::GPRRegisterClass); + + setShiftAmountType(MVT::i8); + + // Std lib call names + setLibcallName(RTLIB::COS_F32, getStdLibCallName(RTLIB::COS_F32)); + setLibcallName(RTLIB::SIN_F32, getStdLibCallName(RTLIB::SIN_F32)); + setLibcallName(RTLIB::MEMCPY, getStdLibCallName(RTLIB::MEMCPY)); + setLibcallName(RTLIB::MEMSET, getStdLibCallName(RTLIB::MEMSET)); + setLibcallName(RTLIB::MEMMOVE, getStdLibCallName(RTLIB::MEMMOVE)); + + // SRA library call names + setPIC16LibcallName(PIC16ISD::SRA_I8, getIntrinsicName(PIC16ISD::SRA_I8)); + setLibcallName(RTLIB::SRA_I16, getIntrinsicName(RTLIB::SRA_I16)); + setLibcallName(RTLIB::SRA_I32, getIntrinsicName(RTLIB::SRA_I32)); + + // SHL library call names + setPIC16LibcallName(PIC16ISD::SLL_I8, getIntrinsicName(PIC16ISD::SLL_I8)); + setLibcallName(RTLIB::SHL_I16, getIntrinsicName(RTLIB::SHL_I16)); + setLibcallName(RTLIB::SHL_I32, getIntrinsicName(RTLIB::SHL_I32)); + + // SRL library call names + setPIC16LibcallName(PIC16ISD::SRL_I8, getIntrinsicName(PIC16ISD::SRL_I8)); + setLibcallName(RTLIB::SRL_I16, getIntrinsicName(RTLIB::SRL_I16)); + setLibcallName(RTLIB::SRL_I32, getIntrinsicName(RTLIB::SRL_I32)); + + // MUL Library call names + setPIC16LibcallName(PIC16ISD::MUL_I8, getIntrinsicName(PIC16ISD::MUL_I8)); + setLibcallName(RTLIB::MUL_I16, getIntrinsicName(RTLIB::MUL_I16)); + setLibcallName(RTLIB::MUL_I32, getIntrinsicName(RTLIB::MUL_I32)); + + // Signed division lib call names + setLibcallName(RTLIB::SDIV_I16, getIntrinsicName(RTLIB::SDIV_I16)); + setLibcallName(RTLIB::SDIV_I32, getIntrinsicName(RTLIB::SDIV_I32)); + + // Unsigned division lib call names + setLibcallName(RTLIB::UDIV_I16, getIntrinsicName(RTLIB::UDIV_I16)); + setLibcallName(RTLIB::UDIV_I32, getIntrinsicName(RTLIB::UDIV_I32)); + + // Signed remainder lib call names + setLibcallName(RTLIB::SREM_I16, getIntrinsicName(RTLIB::SREM_I16)); + setLibcallName(RTLIB::SREM_I32, getIntrinsicName(RTLIB::SREM_I32)); + + // Unsigned remainder lib call names + setLibcallName(RTLIB::UREM_I16, getIntrinsicName(RTLIB::UREM_I16)); + setLibcallName(RTLIB::UREM_I32, getIntrinsicName(RTLIB::UREM_I32)); + + // Floating point to signed int conversions. + setLibcallName(RTLIB::FPTOSINT_F32_I8, + getIntrinsicName(RTLIB::FPTOSINT_F32_I8)); + setLibcallName(RTLIB::FPTOSINT_F32_I16, + getIntrinsicName(RTLIB::FPTOSINT_F32_I16)); + setLibcallName(RTLIB::FPTOSINT_F32_I32, + getIntrinsicName(RTLIB::FPTOSINT_F32_I32)); + + // Signed int to floats. + setLibcallName(RTLIB::SINTTOFP_I32_F32, + getIntrinsicName(RTLIB::SINTTOFP_I32_F32)); + + // Floating points to unsigned ints. + setLibcallName(RTLIB::FPTOUINT_F32_I8, + getIntrinsicName(RTLIB::FPTOUINT_F32_I8)); + setLibcallName(RTLIB::FPTOUINT_F32_I16, + getIntrinsicName(RTLIB::FPTOUINT_F32_I16)); + setLibcallName(RTLIB::FPTOUINT_F32_I32, + getIntrinsicName(RTLIB::FPTOUINT_F32_I32)); + + // Unsigned int to floats. + setLibcallName(RTLIB::UINTTOFP_I32_F32, + getIntrinsicName(RTLIB::UINTTOFP_I32_F32)); + + // Floating point add, sub, mul ,div. + setLibcallName(RTLIB::ADD_F32, getIntrinsicName(RTLIB::ADD_F32)); + setLibcallName(RTLIB::SUB_F32, getIntrinsicName(RTLIB::SUB_F32)); + setLibcallName(RTLIB::MUL_F32, getIntrinsicName(RTLIB::MUL_F32)); + setLibcallName(RTLIB::DIV_F32, getIntrinsicName(RTLIB::DIV_F32)); + + // Floationg point comparison + setLibcallName(RTLIB::O_F32, getIntrinsicName(RTLIB::O_F32)); + setLibcallName(RTLIB::UO_F32, getIntrinsicName(RTLIB::UO_F32)); + setLibcallName(RTLIB::OLE_F32, getIntrinsicName(RTLIB::OLE_F32)); + setLibcallName(RTLIB::OGE_F32, getIntrinsicName(RTLIB::OGE_F32)); + setLibcallName(RTLIB::OLT_F32, getIntrinsicName(RTLIB::OLT_F32)); + setLibcallName(RTLIB::OGT_F32, getIntrinsicName(RTLIB::OGT_F32)); + setLibcallName(RTLIB::OEQ_F32, getIntrinsicName(RTLIB::OEQ_F32)); + setLibcallName(RTLIB::UNE_F32, getIntrinsicName(RTLIB::UNE_F32)); + + // Return value comparisons of floating point calls. + setCmpLibcallCC(RTLIB::OEQ_F32, ISD::SETNE); + setCmpLibcallCC(RTLIB::UNE_F32, ISD::SETNE); + setCmpLibcallCC(RTLIB::OLT_F32, ISD::SETNE); + setCmpLibcallCC(RTLIB::OLE_F32, ISD::SETNE); + setCmpLibcallCC(RTLIB::OGE_F32, ISD::SETNE); + setCmpLibcallCC(RTLIB::OGT_F32, ISD::SETNE); + setCmpLibcallCC(RTLIB::UO_F32, ISD::SETNE); + setCmpLibcallCC(RTLIB::O_F32, ISD::SETEQ); + + setOperationAction(ISD::GlobalAddress, MVT::i16, Custom); + setOperationAction(ISD::ExternalSymbol, MVT::i16, Custom); + + setOperationAction(ISD::LOAD, MVT::i8, Legal); + setOperationAction(ISD::LOAD, MVT::i16, Custom); + setOperationAction(ISD::LOAD, MVT::i32, Custom); + + setOperationAction(ISD::STORE, MVT::i8, Legal); + setOperationAction(ISD::STORE, MVT::i16, Custom); + setOperationAction(ISD::STORE, MVT::i32, Custom); + setOperationAction(ISD::STORE, MVT::i64, Custom); + + setOperationAction(ISD::ADDE, MVT::i8, Custom); + setOperationAction(ISD::ADDC, MVT::i8, Custom); + setOperationAction(ISD::SUBE, MVT::i8, Custom); + setOperationAction(ISD::SUBC, MVT::i8, Custom); + setOperationAction(ISD::SUB, MVT::i8, Custom); + setOperationAction(ISD::ADD, MVT::i8, Custom); + setOperationAction(ISD::ADD, MVT::i16, Custom); + + setOperationAction(ISD::OR, MVT::i8, Custom); + setOperationAction(ISD::AND, MVT::i8, Custom); + setOperationAction(ISD::XOR, MVT::i8, Custom); + + setOperationAction(ISD::FrameIndex, MVT::i16, Custom); + + setOperationAction(ISD::MUL, MVT::i8, Custom); + + setOperationAction(ISD::SMUL_LOHI, MVT::i8, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i8, Expand); + setOperationAction(ISD::MULHU, MVT::i8, Expand); + setOperationAction(ISD::MULHS, MVT::i8, Expand); + + setOperationAction(ISD::SRA, MVT::i8, Custom); + setOperationAction(ISD::SHL, MVT::i8, Custom); + setOperationAction(ISD::SRL, MVT::i8, Custom); + + setOperationAction(ISD::ROTL, MVT::i8, Expand); + setOperationAction(ISD::ROTR, MVT::i8, Expand); + + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + + // PIC16 does not support shift parts + setOperationAction(ISD::SRA_PARTS, MVT::i8, Expand); + setOperationAction(ISD::SHL_PARTS, MVT::i8, Expand); + setOperationAction(ISD::SRL_PARTS, MVT::i8, Expand); + + + // PIC16 does not have a SETCC, expand it to SELECT_CC. + setOperationAction(ISD::SETCC, MVT::i8, Expand); + setOperationAction(ISD::SELECT, MVT::i8, Expand); + setOperationAction(ISD::BRCOND, MVT::Other, Expand); + setOperationAction(ISD::BRIND, MVT::Other, Expand); + + setOperationAction(ISD::SELECT_CC, MVT::i8, Custom); + setOperationAction(ISD::BR_CC, MVT::i8, Custom); + + //setOperationAction(ISD::TRUNCATE, MVT::i16, Custom); + setTruncStoreAction(MVT::i16, MVT::i8, Custom); + + // Now deduce the information based on the above mentioned + // actions + computeRegisterProperties(); +} + +std::pair<const TargetRegisterClass*, uint8_t> +PIC16TargetLowering::findRepresentativeClass(EVT VT) const { + switch (VT.getSimpleVT().SimpleTy) { + default: + return TargetLowering::findRepresentativeClass(VT); + case MVT::i16: + return std::make_pair(PIC16::FSR16RegisterClass, 1); + } +} + +// getOutFlag - Extract the flag result if the Op has it. +static SDValue getOutFlag(SDValue &Op) { + // Flag is the last value of the node. + SDValue Flag = Op.getValue(Op.getNode()->getNumValues() - 1); + + assert (Flag.getValueType() == MVT::Flag + && "Node does not have an out Flag"); + + return Flag; +} +// Get the TmpOffset for FrameIndex +unsigned PIC16TargetLowering::GetTmpOffsetForFI(unsigned FI, unsigned size, + MachineFunction &MF) const { + PIC16MachineFunctionInfo *FuncInfo = MF.getInfo<PIC16MachineFunctionInfo>(); + std::map<unsigned, unsigned> &FiTmpOffsetMap = FuncInfo->getFiTmpOffsetMap(); + + std::map<unsigned, unsigned>::iterator + MapIt = FiTmpOffsetMap.find(FI); + if (MapIt != FiTmpOffsetMap.end()) + return MapIt->second; + + // This FI (FrameIndex) is not yet mapped, so map it + FiTmpOffsetMap[FI] = FuncInfo->getTmpSize(); + FuncInfo->setTmpSize(FuncInfo->getTmpSize() + size); + return FiTmpOffsetMap[FI]; +} + +void PIC16TargetLowering::ResetTmpOffsetMap(SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + PIC16MachineFunctionInfo *FuncInfo = MF.getInfo<PIC16MachineFunctionInfo>(); + FuncInfo->getFiTmpOffsetMap().clear(); + FuncInfo->setTmpSize(0); +} + +// To extract chain value from the SDValue Nodes +// This function will help to maintain the chain extracting +// code at one place. In case of any change in future it will +// help maintain the code. +static SDValue getChain(SDValue &Op) { + SDValue Chain = Op.getValue(Op.getNode()->getNumValues() - 1); + + // If the last value returned in Flag then the chain is + // second last value returned. + if (Chain.getValueType() == MVT::Flag) + Chain = Op.getValue(Op.getNode()->getNumValues() - 2); + + // All nodes may not produce a chain. Therefore following assert + // verifies that the node is returning a chain only. + assert (Chain.getValueType() == MVT::Other + && "Node does not have a chain"); + + return Chain; +} + +/// PopulateResults - Helper function to LowerOperation. +/// If a node wants to return multiple results after lowering, +/// it stuffs them into an array of SDValue called Results. + +static void PopulateResults(SDValue N, SmallVectorImpl<SDValue>&Results) { + if (N.getOpcode() == ISD::MERGE_VALUES) { + int NumResults = N.getNumOperands(); + for( int i = 0; i < NumResults; i++) + Results.push_back(N.getOperand(i)); + } + else + Results.push_back(N); +} + +MVT::SimpleValueType +PIC16TargetLowering::getSetCCResultType(EVT ValType) const { + return MVT::i8; +} + +MVT::SimpleValueType +PIC16TargetLowering::getCmpLibcallReturnType() const { + return MVT::i8; +} + +/// The type legalizer framework of generating legalizer can generate libcalls +/// only when the operand/result types are illegal. +/// PIC16 needs to generate libcalls even for the legal types (i8) for some ops. +/// For example an arithmetic right shift. These functions are used to lower +/// such operations that generate libcall for legal types. + +void +PIC16TargetLowering::setPIC16LibcallName(PIC16ISD::PIC16Libcall Call, + const char *Name) { + PIC16LibcallNames[Call] = Name; +} + +const char * +PIC16TargetLowering::getPIC16LibcallName(PIC16ISD::PIC16Libcall Call) const { + return PIC16LibcallNames[Call]; +} + +SDValue +PIC16TargetLowering::MakePIC16Libcall(PIC16ISD::PIC16Libcall Call, + EVT RetVT, const SDValue *Ops, + unsigned NumOps, bool isSigned, + SelectionDAG &DAG, DebugLoc dl) const { + + TargetLowering::ArgListTy Args; + Args.reserve(NumOps); + + TargetLowering::ArgListEntry Entry; + for (unsigned i = 0; i != NumOps; ++i) { + Entry.Node = Ops[i]; + Entry.Ty = Entry.Node.getValueType().getTypeForEVT(*DAG.getContext()); + Entry.isSExt = isSigned; + Entry.isZExt = !isSigned; + Args.push_back(Entry); + } + + SDValue Callee = DAG.getExternalSymbol(getPIC16LibcallName(Call), MVT::i16); + + const Type *RetTy = RetVT.getTypeForEVT(*DAG.getContext()); + std::pair<SDValue,SDValue> CallInfo = + LowerCallTo(DAG.getEntryNode(), RetTy, isSigned, !isSigned, false, + false, 0, CallingConv::C, false, + /*isReturnValueUsed=*/true, + Callee, Args, DAG, dl); + + return CallInfo.first; +} + +const char *PIC16TargetLowering::getTargetNodeName(unsigned Opcode) const { + switch (Opcode) { + default: return NULL; + case PIC16ISD::Lo: return "PIC16ISD::Lo"; + case PIC16ISD::Hi: return "PIC16ISD::Hi"; + case PIC16ISD::MTLO: return "PIC16ISD::MTLO"; + case PIC16ISD::MTHI: return "PIC16ISD::MTHI"; + case PIC16ISD::MTPCLATH: return "PIC16ISD::MTPCLATH"; + case PIC16ISD::PIC16Connect: return "PIC16ISD::PIC16Connect"; + case PIC16ISD::Banksel: return "PIC16ISD::Banksel"; + case PIC16ISD::PIC16Load: return "PIC16ISD::PIC16Load"; + case PIC16ISD::PIC16LdArg: return "PIC16ISD::PIC16LdArg"; + case PIC16ISD::PIC16LdWF: return "PIC16ISD::PIC16LdWF"; + case PIC16ISD::PIC16Store: return "PIC16ISD::PIC16Store"; + case PIC16ISD::PIC16StWF: return "PIC16ISD::PIC16StWF"; + case PIC16ISD::BCF: return "PIC16ISD::BCF"; + case PIC16ISD::LSLF: return "PIC16ISD::LSLF"; + case PIC16ISD::LRLF: return "PIC16ISD::LRLF"; + case PIC16ISD::RLF: return "PIC16ISD::RLF"; + case PIC16ISD::RRF: return "PIC16ISD::RRF"; + case PIC16ISD::CALL: return "PIC16ISD::CALL"; + case PIC16ISD::CALLW: return "PIC16ISD::CALLW"; + case PIC16ISD::SUBCC: return "PIC16ISD::SUBCC"; + case PIC16ISD::SELECT_ICC: return "PIC16ISD::SELECT_ICC"; + case PIC16ISD::BRCOND: return "PIC16ISD::BRCOND"; + case PIC16ISD::RET: return "PIC16ISD::RET"; + case PIC16ISD::Dummy: return "PIC16ISD::Dummy"; + } +} + +void PIC16TargetLowering::ReplaceNodeResults(SDNode *N, + SmallVectorImpl<SDValue>&Results, + SelectionDAG &DAG) const { + + switch (N->getOpcode()) { + case ISD::GlobalAddress: + Results.push_back(ExpandGlobalAddress(N, DAG)); + return; + case ISD::ExternalSymbol: + Results.push_back(ExpandExternalSymbol(N, DAG)); + return; + case ISD::STORE: + Results.push_back(ExpandStore(N, DAG)); + return; + case ISD::LOAD: + PopulateResults(ExpandLoad(N, DAG), Results); + return; + case ISD::ADD: + // Results.push_back(ExpandAdd(N, DAG)); + return; + case ISD::FrameIndex: + Results.push_back(ExpandFrameIndex(N, DAG)); + return; + default: + assert (0 && "not implemented"); + return; + } +} + +SDValue PIC16TargetLowering::ExpandFrameIndex(SDNode *N, + SelectionDAG &DAG) const { + + // Currently handling FrameIndex of size MVT::i16 only + // One example of this scenario is when return value is written on + // FrameIndex#0 + + if (N->getValueType(0) != MVT::i16) + return SDValue(); + + // Expand the FrameIndex into ExternalSymbol and a Constant node + // The constant will represent the frame index number + // Get the current function frame + MachineFunction &MF = DAG.getMachineFunction(); + const Function *Func = MF.getFunction(); + const std::string Name = Func->getName(); + + FrameIndexSDNode *FR = dyn_cast<FrameIndexSDNode>(SDValue(N,0)); + // FIXME there isn't really debug info here + DebugLoc dl = FR->getDebugLoc(); + + // Expand FrameIndex like GlobalAddress and ExternalSymbol + // Also use Offset field for lo and hi parts. The default + // offset is zero. + + SDValue ES; + int FrameOffset; + SDValue FI = SDValue(N,0); + LegalizeFrameIndex(FI, DAG, ES, FrameOffset); + SDValue Offset = DAG.getConstant(FrameOffset, MVT::i8); + SDValue Lo = DAG.getNode(PIC16ISD::Lo, dl, MVT::i8, ES, Offset); + SDValue Hi = DAG.getNode(PIC16ISD::Hi, dl, MVT::i8, ES, Offset); + return DAG.getNode(ISD::BUILD_PAIR, dl, N->getValueType(0), Lo, Hi); +} + + +SDValue PIC16TargetLowering::ExpandStore(SDNode *N, SelectionDAG &DAG) const { + StoreSDNode *St = cast<StoreSDNode>(N); + SDValue Chain = St->getChain(); + SDValue Src = St->getValue(); + SDValue Ptr = St->getBasePtr(); + EVT ValueType = Src.getValueType(); + unsigned StoreOffset = 0; + DebugLoc dl = N->getDebugLoc(); + + SDValue PtrLo, PtrHi; + LegalizeAddress(Ptr, DAG, PtrLo, PtrHi, StoreOffset, dl); + + if (ValueType == MVT::i8) { + return DAG.getNode (PIC16ISD::PIC16Store, dl, MVT::Other, Chain, Src, + PtrLo, PtrHi, + DAG.getConstant (0 + StoreOffset, MVT::i8)); + } + else if (ValueType == MVT::i16) { + // Get the Lo and Hi parts from MERGE_VALUE or BUILD_PAIR. + SDValue SrcLo, SrcHi; + GetExpandedParts(Src, DAG, SrcLo, SrcHi); + SDValue ChainLo = Chain, ChainHi = Chain; + // FIXME: This makes unsafe assumptions. The Chain may be a TokenFactor + // created for an unrelated purpose, in which case it may not have + // exactly two operands. Also, even if it does have two operands, they + // may not be the low and high parts of an aligned load that was split. + if (Chain.getOpcode() == ISD::TokenFactor) { + ChainLo = Chain.getOperand(0); + ChainHi = Chain.getOperand(1); + } + SDValue Store1 = DAG.getNode(PIC16ISD::PIC16Store, dl, MVT::Other, + ChainLo, + SrcLo, PtrLo, PtrHi, + DAG.getConstant (0 + StoreOffset, MVT::i8)); + + SDValue Store2 = DAG.getNode(PIC16ISD::PIC16Store, dl, MVT::Other, ChainHi, + SrcHi, PtrLo, PtrHi, + DAG.getConstant (1 + StoreOffset, MVT::i8)); + + return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, getChain(Store1), + getChain(Store2)); + } + else if (ValueType == MVT::i32) { + // Get the Lo and Hi parts from MERGE_VALUE or BUILD_PAIR. + SDValue SrcLo, SrcHi; + GetExpandedParts(Src, DAG, SrcLo, SrcHi); + + // Get the expanded parts of each of SrcLo and SrcHi. + SDValue SrcLo1, SrcLo2, SrcHi1, SrcHi2; + GetExpandedParts(SrcLo, DAG, SrcLo1, SrcLo2); + GetExpandedParts(SrcHi, DAG, SrcHi1, SrcHi2); + + SDValue ChainLo = Chain, ChainHi = Chain; + // FIXME: This makes unsafe assumptions; see the FIXME above. + if (Chain.getOpcode() == ISD::TokenFactor) { + ChainLo = Chain.getOperand(0); + ChainHi = Chain.getOperand(1); + } + SDValue ChainLo1 = ChainLo, ChainLo2 = ChainLo, ChainHi1 = ChainHi, + ChainHi2 = ChainHi; + // FIXME: This makes unsafe assumptions; see the FIXME above. + if (ChainLo.getOpcode() == ISD::TokenFactor) { + ChainLo1 = ChainLo.getOperand(0); + ChainLo2 = ChainLo.getOperand(1); + } + // FIXME: This makes unsafe assumptions; see the FIXME above. + if (ChainHi.getOpcode() == ISD::TokenFactor) { + ChainHi1 = ChainHi.getOperand(0); + ChainHi2 = ChainHi.getOperand(1); + } + SDValue Store1 = DAG.getNode(PIC16ISD::PIC16Store, dl, MVT::Other, + ChainLo1, + SrcLo1, PtrLo, PtrHi, + DAG.getConstant (0 + StoreOffset, MVT::i8)); + + SDValue Store2 = DAG.getNode(PIC16ISD::PIC16Store, dl, MVT::Other, ChainLo2, + SrcLo2, PtrLo, PtrHi, + DAG.getConstant (1 + StoreOffset, MVT::i8)); + + SDValue Store3 = DAG.getNode(PIC16ISD::PIC16Store, dl, MVT::Other, ChainHi1, + SrcHi1, PtrLo, PtrHi, + DAG.getConstant (2 + StoreOffset, MVT::i8)); + + SDValue Store4 = DAG.getNode(PIC16ISD::PIC16Store, dl, MVT::Other, ChainHi2, + SrcHi2, PtrLo, PtrHi, + DAG.getConstant (3 + StoreOffset, MVT::i8)); + + SDValue RetLo = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + getChain(Store1), getChain(Store2)); + SDValue RetHi = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + getChain(Store3), getChain(Store4)); + return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, RetLo, RetHi); + + } else if (ValueType == MVT::i64) { + SDValue SrcLo, SrcHi; + GetExpandedParts(Src, DAG, SrcLo, SrcHi); + SDValue ChainLo = Chain, ChainHi = Chain; + // FIXME: This makes unsafe assumptions; see the FIXME above. + if (Chain.getOpcode() == ISD::TokenFactor) { + ChainLo = Chain.getOperand(0); + ChainHi = Chain.getOperand(1); + } + SDValue Store1 = DAG.getStore(ChainLo, dl, SrcLo, Ptr, NULL, + 0 + StoreOffset, false, false, 0); + + Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, + DAG.getConstant(4, Ptr.getValueType())); + SDValue Store2 = DAG.getStore(ChainHi, dl, SrcHi, Ptr, NULL, + 1 + StoreOffset, false, false, 0); + + return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Store1, + Store2); + } else { + assert (0 && "value type not supported"); + return SDValue(); + } +} + +SDValue PIC16TargetLowering::ExpandExternalSymbol(SDNode *N, + SelectionDAG &DAG) + const { + ExternalSymbolSDNode *ES = dyn_cast<ExternalSymbolSDNode>(SDValue(N, 0)); + // FIXME there isn't really debug info here + DebugLoc dl = ES->getDebugLoc(); + + SDValue TES = DAG.getTargetExternalSymbol(ES->getSymbol(), MVT::i8); + SDValue Offset = DAG.getConstant(0, MVT::i8); + SDValue Lo = DAG.getNode(PIC16ISD::Lo, dl, MVT::i8, TES, Offset); + SDValue Hi = DAG.getNode(PIC16ISD::Hi, dl, MVT::i8, TES, Offset); + + return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i16, Lo, Hi); +} + +// ExpandGlobalAddress - +SDValue PIC16TargetLowering::ExpandGlobalAddress(SDNode *N, + SelectionDAG &DAG) const { + GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(SDValue(N, 0)); + // FIXME there isn't really debug info here + DebugLoc dl = G->getDebugLoc(); + + SDValue TGA = DAG.getTargetGlobalAddress(G->getGlobal(), N->getDebugLoc(), + MVT::i8, + G->getOffset()); + + SDValue Offset = DAG.getConstant(0, MVT::i8); + SDValue Lo = DAG.getNode(PIC16ISD::Lo, dl, MVT::i8, TGA, Offset); + SDValue Hi = DAG.getNode(PIC16ISD::Hi, dl, MVT::i8, TGA, Offset); + + return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i16, Lo, Hi); +} + +bool PIC16TargetLowering::isDirectAddress(const SDValue &Op) const { + assert (Op.getNode() != NULL && "Can't operate on NULL SDNode!!"); + + if (Op.getOpcode() == ISD::BUILD_PAIR) { + if (Op.getOperand(0).getOpcode() == PIC16ISD::Lo) + return true; + } + return false; +} + +// Return true if DirectAddress is in ROM_SPACE +bool PIC16TargetLowering::isRomAddress(const SDValue &Op) const { + + // RomAddress is a GlobalAddress in ROM_SPACE_ + // If the Op is not a GlobalAddress return NULL without checking + // anything further. + if (!isDirectAddress(Op)) + return false; + + // Its a GlobalAddress. + // It is BUILD_PAIR((PIC16Lo TGA), (PIC16Hi TGA)) and Op is BUILD_PAIR + SDValue TGA = Op.getOperand(0).getOperand(0); + GlobalAddressSDNode *GSDN = dyn_cast<GlobalAddressSDNode>(TGA); + + if (GSDN->getAddressSpace() == PIC16ISD::ROM_SPACE) + return true; + + // Any other address space return it false + return false; +} + + +// GetExpandedParts - This function is on the similiar lines as +// the GetExpandedInteger in type legalizer is. This returns expanded +// parts of Op in Lo and Hi. + +void PIC16TargetLowering::GetExpandedParts(SDValue Op, SelectionDAG &DAG, + SDValue &Lo, SDValue &Hi) const { + SDNode *N = Op.getNode(); + DebugLoc dl = N->getDebugLoc(); + EVT NewVT = getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); + + // Extract the lo component. + Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, NewVT, Op, + DAG.getConstant(0, MVT::i8)); + + // extract the hi component + Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, NewVT, Op, + DAG.getConstant(1, MVT::i8)); +} + +// Legalize FrameIndex into ExternalSymbol and offset. +void +PIC16TargetLowering::LegalizeFrameIndex(SDValue Op, SelectionDAG &DAG, + SDValue &ES, int &Offset) const { + + MachineFunction &MF = DAG.getMachineFunction(); + const Function *Func = MF.getFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + PIC16MachineFunctionInfo *FuncInfo = MF.getInfo<PIC16MachineFunctionInfo>(); + const std::string Name = Func->getName(); + + FrameIndexSDNode *FR = dyn_cast<FrameIndexSDNode>(Op); + + // FrameIndices are not stack offsets. But they represent the request + // for space on stack. That space requested may be more than one byte. + // Therefore, to calculate the stack offset that a FrameIndex aligns + // with, we need to traverse all the FrameIndices available earlier in + // the list and add their requested size. + unsigned FIndex = FR->getIndex(); + const char *tmpName; + if (FIndex < FuncInfo->getReservedFrameCount()) { + tmpName = ESNames::createESName(PAN::getFrameLabel(Name)); + ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8); + Offset = 0; + for (unsigned i=0; i<FIndex ; ++i) { + Offset += MFI->getObjectSize(i); + } + } else { + // FrameIndex has been made for some temporary storage + tmpName = ESNames::createESName(PAN::getTempdataLabel(Name)); + ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8); + Offset = GetTmpOffsetForFI(FIndex, MFI->getObjectSize(FIndex), MF); + } + + return; +} + +// This function legalizes the PIC16 Addresses. If the Pointer is +// -- Direct address variable residing +// --> then a Banksel for that variable will be created. +// -- Rom variable +// --> then it will be treated as an indirect address. +// -- Indirect address +// --> then the address will be loaded into FSR +// -- ADD with constant operand +// --> then constant operand of ADD will be returned as Offset +// and non-constant operand of ADD will be treated as pointer. +// Returns the high and lo part of the address, and the offset(in case of ADD). + +void PIC16TargetLowering::LegalizeAddress(SDValue Ptr, SelectionDAG &DAG, + SDValue &Lo, SDValue &Hi, + unsigned &Offset, DebugLoc dl) const { + + // Offset, by default, should be 0 + Offset = 0; + + // If the pointer is ADD with constant, + // return the constant value as the offset + if (Ptr.getOpcode() == ISD::ADD) { + SDValue OperLeft = Ptr.getOperand(0); + SDValue OperRight = Ptr.getOperand(1); + if ((OperLeft.getOpcode() == ISD::Constant) && + (dyn_cast<ConstantSDNode>(OperLeft)->getZExtValue() < 32 )) { + Offset = dyn_cast<ConstantSDNode>(OperLeft)->getZExtValue(); + Ptr = OperRight; + } else if ((OperRight.getOpcode() == ISD::Constant) && + (dyn_cast<ConstantSDNode>(OperRight)->getZExtValue() < 32 )){ + Offset = dyn_cast<ConstantSDNode>(OperRight)->getZExtValue(); + Ptr = OperLeft; + } + } + + // If the pointer is Type i8 and an external symbol + // then treat it as direct address. + // One example for such case is storing and loading + // from function frame during a call + if (Ptr.getValueType() == MVT::i8) { + switch (Ptr.getOpcode()) { + case ISD::TargetExternalSymbol: + Lo = Ptr; + Hi = DAG.getConstant(1, MVT::i8); + return; + } + } + + // Expansion of FrameIndex has Lo/Hi parts + if (isDirectAddress(Ptr)) { + SDValue TFI = Ptr.getOperand(0).getOperand(0); + int FrameOffset; + if (TFI.getOpcode() == ISD::TargetFrameIndex) { + LegalizeFrameIndex(TFI, DAG, Lo, FrameOffset); + Hi = DAG.getConstant(1, MVT::i8); + Offset += FrameOffset; + return; + } else if (TFI.getOpcode() == ISD::TargetExternalSymbol) { + // FrameIndex has already been expanded. + // Now just make use of its expansion + Lo = TFI; + Hi = DAG.getConstant(1, MVT::i8); + SDValue FOffset = Ptr.getOperand(0).getOperand(1); + assert (FOffset.getOpcode() == ISD::Constant && + "Invalid operand of PIC16ISD::Lo"); + Offset += dyn_cast<ConstantSDNode>(FOffset)->getZExtValue(); + return; + } + } + + if (isDirectAddress(Ptr) && !isRomAddress(Ptr)) { + // Direct addressing case for RAM variables. The Hi part is constant + // and the Lo part is the TGA itself. + Lo = Ptr.getOperand(0).getOperand(0); + + // For direct addresses Hi is a constant. Value 1 for the constant + // signifies that banksel needs to generated for it. Value 0 for + // the constant signifies that banksel does not need to be generated + // for it. Mark it as 1 now and optimize later. + Hi = DAG.getConstant(1, MVT::i8); + return; + } + + // Indirect addresses. Get the hi and lo parts of ptr. + GetExpandedParts(Ptr, DAG, Lo, Hi); + + // Put the hi and lo parts into FSR. + Lo = DAG.getNode(PIC16ISD::MTLO, dl, MVT::i8, Lo); + Hi = DAG.getNode(PIC16ISD::MTHI, dl, MVT::i8, Hi); + + return; +} + +SDValue PIC16TargetLowering::ExpandLoad(SDNode *N, SelectionDAG &DAG) const { + LoadSDNode *LD = dyn_cast<LoadSDNode>(SDValue(N, 0)); + SDValue Chain = LD->getChain(); + SDValue Ptr = LD->getBasePtr(); + DebugLoc dl = LD->getDebugLoc(); + + SDValue Load, Offset; + SDVTList Tys; + EVT VT, NewVT; + SDValue PtrLo, PtrHi; + unsigned LoadOffset; + + // Legalize direct/indirect addresses. This will give the lo and hi parts + // of the address and the offset. + LegalizeAddress(Ptr, DAG, PtrLo, PtrHi, LoadOffset, dl); + + // Load from the pointer (direct address or FSR) + VT = N->getValueType(0); + unsigned NumLoads = VT.getSizeInBits() / 8; + std::vector<SDValue> PICLoads; + unsigned iter; + EVT MemVT = LD->getMemoryVT(); + if(ISD::isNON_EXTLoad(N)) { + for (iter=0; iter<NumLoads ; ++iter) { + // Add the pointer offset if any + Offset = DAG.getConstant(iter + LoadOffset, MVT::i8); + Tys = DAG.getVTList(MVT::i8, MVT::Other); + Load = DAG.getNode(PIC16ISD::PIC16Load, dl, Tys, Chain, PtrLo, PtrHi, + Offset); + PICLoads.push_back(Load); + } + } else { + // If it is extended load then use PIC16Load for Memory Bytes + // and for all extended bytes perform action based on type of + // extention - i.e. SignExtendedLoad or ZeroExtendedLoad + + + // For extended loads this is the memory value type + // i.e. without any extension + EVT MemVT = LD->getMemoryVT(); + unsigned MemBytes = MemVT.getSizeInBits() / 8; + // if MVT::i1 is extended to MVT::i8 then MemBytes will be zero + // So set it to one + if (MemBytes == 0) MemBytes = 1; + + unsigned ExtdBytes = VT.getSizeInBits() / 8; + Offset = DAG.getConstant(LoadOffset, MVT::i8); + + Tys = DAG.getVTList(MVT::i8, MVT::Other); + // For MemBytes generate PIC16Load with proper offset + for (iter=0; iter < MemBytes; ++iter) { + // Add the pointer offset if any + Offset = DAG.getConstant(iter + LoadOffset, MVT::i8); + Load = DAG.getNode(PIC16ISD::PIC16Load, dl, Tys, Chain, PtrLo, PtrHi, + Offset); + PICLoads.push_back(Load); + } + + // For SignExtendedLoad + if (ISD::isSEXTLoad(N)) { + // For all ExtdBytes use the Right Shifted(Arithmetic) Value of the + // highest MemByte + SDValue SRA = DAG.getNode(ISD::SRA, dl, MVT::i8, Load, + DAG.getConstant(7, MVT::i8)); + for (iter=MemBytes; iter<ExtdBytes; ++iter) { + PICLoads.push_back(SRA); + } + } else if (ISD::isZEXTLoad(N) || ISD::isEXTLoad(N)) { + //} else if (ISD::isZEXTLoad(N)) { + // ZeroExtendedLoad -- For all ExtdBytes use constant 0 + SDValue ConstZero = DAG.getConstant(0, MVT::i8); + for (iter=MemBytes; iter<ExtdBytes; ++iter) { + PICLoads.push_back(ConstZero); + } + } + } + SDValue BP; + + if (VT == MVT::i8) { + // Operand of Load is illegal -- Load itself is legal + return PICLoads[0]; + } + else if (VT == MVT::i16) { + BP = DAG.getNode(ISD::BUILD_PAIR, dl, VT, PICLoads[0], PICLoads[1]); + if ((MemVT == MVT::i8) || (MemVT == MVT::i1)) + Chain = getChain(PICLoads[0]); + else + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + getChain(PICLoads[0]), getChain(PICLoads[1])); + } else if (VT == MVT::i32) { + SDValue BPs[2]; + BPs[0] = DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i16, + PICLoads[0], PICLoads[1]); + BPs[1] = DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i16, + PICLoads[2], PICLoads[3]); + BP = DAG.getNode(ISD::BUILD_PAIR, dl, VT, BPs[0], BPs[1]); + if ((MemVT == MVT::i8) || (MemVT == MVT::i1)) + Chain = getChain(PICLoads[0]); + else if (MemVT == MVT::i16) + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + getChain(PICLoads[0]), getChain(PICLoads[1])); + else { + SDValue Chains[2]; + Chains[0] = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + getChain(PICLoads[0]), getChain(PICLoads[1])); + Chains[1] = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + getChain(PICLoads[2]), getChain(PICLoads[3])); + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + Chains[0], Chains[1]); + } + } + Tys = DAG.getVTList(VT, MVT::Other); + return DAG.getNode(ISD::MERGE_VALUES, dl, Tys, BP, Chain); +} + +SDValue PIC16TargetLowering::LowerShift(SDValue Op, SelectionDAG &DAG) const { + // We should have handled larger operands in type legalizer itself. + assert (Op.getValueType() == MVT::i8 && "illegal shift to lower"); + + SDNode *N = Op.getNode(); + SDValue Value = N->getOperand(0); + SDValue Amt = N->getOperand(1); + PIC16ISD::PIC16Libcall CallCode; + switch (N->getOpcode()) { + case ISD::SRA: + CallCode = PIC16ISD::SRA_I8; + break; + case ISD::SHL: + CallCode = PIC16ISD::SLL_I8; + break; + case ISD::SRL: + CallCode = PIC16ISD::SRL_I8; + break; + default: + assert ( 0 && "This shift is not implemented yet."); + return SDValue(); + } + SmallVector<SDValue, 2> Ops(2); + Ops[0] = Value; + Ops[1] = Amt; + SDValue Call = MakePIC16Libcall(CallCode, N->getValueType(0), &Ops[0], 2, + true, DAG, N->getDebugLoc()); + return Call; +} + +SDValue PIC16TargetLowering::LowerMUL(SDValue Op, SelectionDAG &DAG) const { + // We should have handled larger operands in type legalizer itself. + assert (Op.getValueType() == MVT::i8 && "illegal multiply to lower"); + + SDNode *N = Op.getNode(); + SmallVector<SDValue, 2> Ops(2); + Ops[0] = N->getOperand(0); + Ops[1] = N->getOperand(1); + SDValue Call = MakePIC16Libcall(PIC16ISD::MUL_I8, N->getValueType(0), + &Ops[0], 2, true, DAG, N->getDebugLoc()); + return Call; +} + +void +PIC16TargetLowering::LowerOperationWrapper(SDNode *N, + SmallVectorImpl<SDValue>&Results, + SelectionDAG &DAG) const { + SDValue Op = SDValue(N, 0); + SDValue Res; + unsigned i; + switch (Op.getOpcode()) { + case ISD::LOAD: + Res = ExpandLoad(Op.getNode(), DAG); break; + default: { + // All other operations are handled in LowerOperation. + Res = LowerOperation(Op, DAG); + if (Res.getNode()) + Results.push_back(Res); + + return; + } + } + + N = Res.getNode(); + unsigned NumValues = N->getNumValues(); + for (i = 0; i < NumValues ; i++) { + Results.push_back(SDValue(N, i)); + } +} + +SDValue PIC16TargetLowering::LowerOperation(SDValue Op, + SelectionDAG &DAG) const { + switch (Op.getOpcode()) { + case ISD::ADD: + case ISD::ADDC: + case ISD::ADDE: + return LowerADD(Op, DAG); + case ISD::SUB: + case ISD::SUBC: + case ISD::SUBE: + return LowerSUB(Op, DAG); + case ISD::LOAD: + return ExpandLoad(Op.getNode(), DAG); + case ISD::STORE: + return ExpandStore(Op.getNode(), DAG); + case ISD::MUL: + return LowerMUL(Op, DAG); + case ISD::SHL: + case ISD::SRA: + case ISD::SRL: + return LowerShift(Op, DAG); + case ISD::OR: + case ISD::AND: + case ISD::XOR: + return LowerBinOp(Op, DAG); + case ISD::BR_CC: + return LowerBR_CC(Op, DAG); + case ISD::SELECT_CC: + return LowerSELECT_CC(Op, DAG); + } + return SDValue(); +} + +SDValue PIC16TargetLowering::ConvertToMemOperand(SDValue Op, + SelectionDAG &DAG, + DebugLoc dl) const { + assert (Op.getValueType() == MVT::i8 + && "illegal value type to store on stack."); + + MachineFunction &MF = DAG.getMachineFunction(); + const Function *Func = MF.getFunction(); + const std::string FuncName = Func->getName(); + + + // Put the value on stack. + // Get a stack slot index and convert to es. + int FI = MF.getFrameInfo()->CreateStackObject(1, 1, false); + const char *tmpName = ESNames::createESName(PAN::getTempdataLabel(FuncName)); + SDValue ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8); + + // Store the value to ES. + SDValue Store = DAG.getNode (PIC16ISD::PIC16Store, dl, MVT::Other, + DAG.getEntryNode(), + Op, ES, + DAG.getConstant (1, MVT::i8), // Banksel. + DAG.getConstant (GetTmpOffsetForFI(FI, 1, MF), + MVT::i8)); + + // Load the value from ES. + SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Other); + SDValue Load = DAG.getNode(PIC16ISD::PIC16Load, dl, Tys, Store, + ES, DAG.getConstant (1, MVT::i8), + DAG.getConstant (GetTmpOffsetForFI(FI, 1, MF), + MVT::i8)); + + return Load.getValue(0); +} + +SDValue PIC16TargetLowering:: +LowerIndirectCallArguments(SDValue Chain, SDValue InFlag, + SDValue DataAddr_Lo, SDValue DataAddr_Hi, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG) const { + unsigned NumOps = Outs.size(); + + // If call has no arguments then do nothing and return. + if (NumOps == 0) + return Chain; + + std::vector<SDValue> Ops; + SDVTList Tys = DAG.getVTList(MVT::Other, MVT::Flag); + SDValue Arg, StoreRet; + + // For PIC16 ABI the arguments come after the return value. + unsigned RetVals = Ins.size(); + for (unsigned i = 0, ArgOffset = RetVals; i < NumOps; i++) { + // Get the arguments + Arg = OutVals[i]; + + Ops.clear(); + Ops.push_back(Chain); + Ops.push_back(Arg); + Ops.push_back(DataAddr_Lo); + Ops.push_back(DataAddr_Hi); + Ops.push_back(DAG.getConstant(ArgOffset, MVT::i8)); + Ops.push_back(InFlag); + + StoreRet = DAG.getNode (PIC16ISD::PIC16StWF, dl, Tys, &Ops[0], Ops.size()); + + Chain = getChain(StoreRet); + InFlag = getOutFlag(StoreRet); + ArgOffset++; + } + return Chain; +} + +SDValue PIC16TargetLowering:: +LowerDirectCallArguments(SDValue ArgLabel, SDValue Chain, SDValue InFlag, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + DebugLoc dl, SelectionDAG &DAG) const { + unsigned NumOps = Outs.size(); + std::string Name; + SDValue Arg, StoreAt; + EVT ArgVT; + unsigned Size=0; + + // If call has no arguments then do nothing and return. + if (NumOps == 0) + return Chain; + + // FIXME: This portion of code currently assumes only + // primitive types being passed as arguments. + + // Legalize the address before use + SDValue PtrLo, PtrHi; + unsigned AddressOffset; + int StoreOffset = 0; + LegalizeAddress(ArgLabel, DAG, PtrLo, PtrHi, AddressOffset, dl); + SDValue StoreRet; + + std::vector<SDValue> Ops; + SDVTList Tys = DAG.getVTList(MVT::Other, MVT::Flag); + for (unsigned i=0, Offset = 0; i<NumOps; i++) { + // Get the argument + Arg = OutVals[i]; + StoreOffset = (Offset + AddressOffset); + + // Store the argument on frame + + Ops.clear(); + Ops.push_back(Chain); + Ops.push_back(Arg); + Ops.push_back(PtrLo); + Ops.push_back(PtrHi); + Ops.push_back(DAG.getConstant(StoreOffset, MVT::i8)); + Ops.push_back(InFlag); + + StoreRet = DAG.getNode (PIC16ISD::PIC16StWF, dl, Tys, &Ops[0], Ops.size()); + + Chain = getChain(StoreRet); + InFlag = getOutFlag(StoreRet); + + // Update the frame offset to be used for next argument + ArgVT = Arg.getValueType(); + Size = ArgVT.getSizeInBits(); + Size = Size/8; // Calculate size in bytes + Offset += Size; // Increase the frame offset + } + return Chain; +} + +SDValue PIC16TargetLowering:: +LowerIndirectCallReturn(SDValue Chain, SDValue InFlag, + SDValue DataAddr_Lo, SDValue DataAddr_Hi, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const { + unsigned RetVals = Ins.size(); + + // If call does not have anything to return + // then do nothing and go back. + if (RetVals == 0) + return Chain; + + // Call has something to return + SDValue LoadRet; + + SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Other, MVT::Flag); + for(unsigned i=0;i<RetVals;i++) { + LoadRet = DAG.getNode(PIC16ISD::PIC16LdWF, dl, Tys, Chain, DataAddr_Lo, + DataAddr_Hi, DAG.getConstant(i, MVT::i8), + InFlag); + InFlag = getOutFlag(LoadRet); + Chain = getChain(LoadRet); + InVals.push_back(LoadRet); + } + return Chain; +} + +SDValue PIC16TargetLowering:: +LowerDirectCallReturn(SDValue RetLabel, SDValue Chain, SDValue InFlag, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const { + + // Currently handling primitive types only. They will come in + // i8 parts + unsigned RetVals = Ins.size(); + + // Return immediately if the return type is void + if (RetVals == 0) + return Chain; + + // Call has something to return + + // Legalize the address before use + SDValue LdLo, LdHi; + unsigned LdOffset; + LegalizeAddress(RetLabel, DAG, LdLo, LdHi, LdOffset, dl); + + SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Other, MVT::Flag); + SDValue LoadRet; + + for(unsigned i=0, Offset=0;i<RetVals;i++) { + + LoadRet = DAG.getNode(PIC16ISD::PIC16LdWF, dl, Tys, Chain, LdLo, LdHi, + DAG.getConstant(LdOffset + Offset, MVT::i8), + InFlag); + + InFlag = getOutFlag(LoadRet); + + Chain = getChain(LoadRet); + Offset++; + InVals.push_back(LoadRet); + } + + return Chain; +} + +SDValue +PIC16TargetLowering::LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + DebugLoc dl, SelectionDAG &DAG) const { + + // Number of values to return + unsigned NumRet = Outs.size(); + + // Function returns value always on stack with the offset starting + // from 0 + MachineFunction &MF = DAG.getMachineFunction(); + const Function *F = MF.getFunction(); + std::string FuncName = F->getName(); + + const char *tmpName = ESNames::createESName(PAN::getFrameLabel(FuncName)); + SDValue ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8); + SDValue BS = DAG.getConstant(1, MVT::i8); + SDValue RetVal; + for(unsigned i=0;i<NumRet; ++i) { + RetVal = OutVals[i]; + Chain = DAG.getNode (PIC16ISD::PIC16Store, dl, MVT::Other, Chain, RetVal, + ES, BS, + DAG.getConstant (i, MVT::i8)); + + } + return DAG.getNode(PIC16ISD::RET, dl, MVT::Other, Chain); +} + +void PIC16TargetLowering:: +GetDataAddress(DebugLoc dl, SDValue Callee, SDValue &Chain, + SDValue &DataAddr_Lo, SDValue &DataAddr_Hi, + SelectionDAG &DAG) const { + assert (Callee.getOpcode() == PIC16ISD::PIC16Connect + && "Don't know what to do of such callee!!"); + SDValue ZeroOperand = DAG.getConstant(0, MVT::i8); + SDValue SeqStart = DAG.getCALLSEQ_START(Chain, ZeroOperand); + Chain = getChain(SeqStart); + SDValue OperFlag = getOutFlag(SeqStart); // To manage the data dependency + + // Get the Lo and Hi part of code address + SDValue Lo = Callee.getOperand(0); + SDValue Hi = Callee.getOperand(1); + + SDValue Data_Lo, Data_Hi; + SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Other, MVT::Flag); + // Subtract 2 from Address to get the Lower part of DataAddress. + SDVTList VTList = DAG.getVTList(MVT::i8, MVT::Flag); + Data_Lo = DAG.getNode(ISD::SUBC, dl, VTList, Lo, + DAG.getConstant(2, MVT::i8)); + SDValue Ops[3] = { Hi, DAG.getConstant(0, MVT::i8), Data_Lo.getValue(1)}; + Data_Hi = DAG.getNode(ISD::SUBE, dl, VTList, Ops, 3); + SDValue PCLATH = DAG.getNode(PIC16ISD::MTPCLATH, dl, MVT::i8, Data_Hi); + Callee = DAG.getNode(PIC16ISD::PIC16Connect, dl, MVT::i8, Data_Lo, PCLATH); + SDValue Call = DAG.getNode(PIC16ISD::CALLW, dl, Tys, Chain, Callee, + OperFlag); + Chain = getChain(Call); + OperFlag = getOutFlag(Call); + SDValue SeqEnd = DAG.getCALLSEQ_END(Chain, ZeroOperand, ZeroOperand, + OperFlag); + Chain = getChain(SeqEnd); + OperFlag = getOutFlag(SeqEnd); + + // Low part of Data Address + DataAddr_Lo = DAG.getNode(PIC16ISD::MTLO, dl, MVT::i8, Call, OperFlag); + + // Make the second call. + SeqStart = DAG.getCALLSEQ_START(Chain, ZeroOperand); + Chain = getChain(SeqStart); + OperFlag = getOutFlag(SeqStart); // To manage the data dependency + + // Subtract 1 from Address to get high part of data address. + Data_Lo = DAG.getNode(ISD::SUBC, dl, VTList, Lo, + DAG.getConstant(1, MVT::i8)); + SDValue HiOps[3] = { Hi, DAG.getConstant(0, MVT::i8), Data_Lo.getValue(1)}; + Data_Hi = DAG.getNode(ISD::SUBE, dl, VTList, HiOps, 3); + PCLATH = DAG.getNode(PIC16ISD::MTPCLATH, dl, MVT::i8, Data_Hi); + + // Use new Lo to make another CALLW + Callee = DAG.getNode(PIC16ISD::PIC16Connect, dl, MVT::i8, Data_Lo, PCLATH); + Call = DAG.getNode(PIC16ISD::CALLW, dl, Tys, Chain, Callee, OperFlag); + Chain = getChain(Call); + OperFlag = getOutFlag(Call); + SeqEnd = DAG.getCALLSEQ_END(Chain, ZeroOperand, ZeroOperand, + OperFlag); + Chain = getChain(SeqEnd); + OperFlag = getOutFlag(SeqEnd); + // Hi part of Data Address + DataAddr_Hi = DAG.getNode(PIC16ISD::MTHI, dl, MVT::i8, Call, OperFlag); +} + +SDValue +PIC16TargetLowering::LowerCall(SDValue Chain, SDValue Callee, + CallingConv::ID CallConv, bool isVarArg, + bool &isTailCall, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const { + // PIC16 target does not yet support tail call optimization. + isTailCall = false; + + assert(Callee.getValueType() == MVT::i16 && + "Don't know how to legalize this call node!!!"); + + // The flag to track if this is a direct or indirect call. + bool IsDirectCall = true; + unsigned RetVals = Ins.size(); + unsigned NumArgs = Outs.size(); + + SDValue DataAddr_Lo, DataAddr_Hi; + if (!isa<GlobalAddressSDNode>(Callee) && + !isa<ExternalSymbolSDNode>(Callee)) { + IsDirectCall = false; // This is indirect call + + // If this is an indirect call then to pass the arguments + // and read the return value back, we need the data address + // of the function being called. + // To get the data address two more calls need to be made. + + // Come here for indirect calls + SDValue Lo, Hi; + // Indirect addresses. Get the hi and lo parts of ptr. + GetExpandedParts(Callee, DAG, Lo, Hi); + // Connect Lo and Hi parts of the callee with the PIC16Connect + Callee = DAG.getNode(PIC16ISD::PIC16Connect, dl, MVT::i8, Lo, Hi); + + // Read DataAddress only if we have to pass arguments or + // read return value. + if ((RetVals > 0) || (NumArgs > 0)) + GetDataAddress(dl, Callee, Chain, DataAddr_Lo, DataAddr_Hi, DAG); + } + + SDValue ZeroOperand = DAG.getConstant(0, MVT::i8); + + // Start the call sequence. + // Carring the Constant 0 along the CALLSEQSTART + // because there is nothing else to carry. + SDValue SeqStart = DAG.getCALLSEQ_START(Chain, ZeroOperand); + Chain = getChain(SeqStart); + SDValue OperFlag = getOutFlag(SeqStart); // To manage the data dependency + std::string Name; + + // For any direct call - callee will be GlobalAddressNode or + // ExternalSymbol + SDValue ArgLabel, RetLabel; + if (IsDirectCall) { + // Considering the GlobalAddressNode case here. + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) { + const GlobalValue *GV = G->getGlobal(); + Callee = DAG.getTargetGlobalAddress(GV, dl, MVT::i8); + Name = G->getGlobal()->getName(); + } else {// Considering the ExternalSymbol case here + ExternalSymbolSDNode *ES = dyn_cast<ExternalSymbolSDNode>(Callee); + Callee = DAG.getTargetExternalSymbol(ES->getSymbol(), MVT::i8); + Name = ES->getSymbol(); + } + + // Label for argument passing + const char *argFrame = ESNames::createESName(PAN::getArgsLabel(Name)); + ArgLabel = DAG.getTargetExternalSymbol(argFrame, MVT::i8); + + // Label for reading return value + const char *retName = ESNames::createESName(PAN::getRetvalLabel(Name)); + RetLabel = DAG.getTargetExternalSymbol(retName, MVT::i8); + } else { + // if indirect call + SDValue CodeAddr_Lo = Callee.getOperand(0); + SDValue CodeAddr_Hi = Callee.getOperand(1); + + /*CodeAddr_Lo = DAG.getNode(ISD::ADD, dl, MVT::i8, CodeAddr_Lo, + DAG.getConstant(2, MVT::i8));*/ + + // move Hi part in PCLATH + CodeAddr_Hi = DAG.getNode(PIC16ISD::MTPCLATH, dl, MVT::i8, CodeAddr_Hi); + Callee = DAG.getNode(PIC16ISD::PIC16Connect, dl, MVT::i8, CodeAddr_Lo, + CodeAddr_Hi); + } + + // Pass the argument to function before making the call. + SDValue CallArgs; + if (IsDirectCall) { + CallArgs = LowerDirectCallArguments(ArgLabel, Chain, OperFlag, + Outs, OutVals, dl, DAG); + Chain = getChain(CallArgs); + OperFlag = getOutFlag(CallArgs); + } else { + CallArgs = LowerIndirectCallArguments(Chain, OperFlag, DataAddr_Lo, + DataAddr_Hi, Outs, OutVals, Ins, + dl, DAG); + Chain = getChain(CallArgs); + OperFlag = getOutFlag(CallArgs); + } + + SDVTList Tys = DAG.getVTList(MVT::Other, MVT::Flag); + SDValue PICCall = DAG.getNode(PIC16ISD::CALL, dl, Tys, Chain, Callee, + OperFlag); + Chain = getChain(PICCall); + OperFlag = getOutFlag(PICCall); + + + // Carrying the Constant 0 along the CALLSEQSTART + // because there is nothing else to carry. + SDValue SeqEnd = DAG.getCALLSEQ_END(Chain, ZeroOperand, ZeroOperand, + OperFlag); + Chain = getChain(SeqEnd); + OperFlag = getOutFlag(SeqEnd); + + // Lower the return value reading after the call. + if (IsDirectCall) + return LowerDirectCallReturn(RetLabel, Chain, OperFlag, + Ins, dl, DAG, InVals); + else + return LowerIndirectCallReturn(Chain, OperFlag, DataAddr_Lo, + DataAddr_Hi, Ins, dl, DAG, InVals); +} + +bool PIC16TargetLowering::isDirectLoad(const SDValue Op) const { + if (Op.getOpcode() == PIC16ISD::PIC16Load) + if (Op.getOperand(1).getOpcode() == ISD::TargetGlobalAddress + || Op.getOperand(1).getOpcode() == ISD::TargetExternalSymbol) + return true; + return false; +} + +// NeedToConvertToMemOp - Returns true if one of the operands of the +// operation 'Op' needs to be put into memory. Also returns the +// operand no. of the operand to be converted in 'MemOp'. Remember, PIC16 has +// no instruction that can operation on two registers. Most insns take +// one register and one memory operand (addwf) / Constant (addlw). +bool PIC16TargetLowering::NeedToConvertToMemOp(SDValue Op, unsigned &MemOp, + SelectionDAG &DAG) const { + // If one of the operand is a constant, return false. + if (Op.getOperand(0).getOpcode() == ISD::Constant || + Op.getOperand(1).getOpcode() == ISD::Constant) + return false; + + // Return false if one of the operands is already a direct + // load and that operand has only one use. + if (isDirectLoad(Op.getOperand(0))) { + if (Op.getOperand(0).hasOneUse()) { + // Legal and profitable folding check uses the NodeId of DAG nodes. + // This NodeId is assigned by topological order. Therefore first + // assign topological order then perform legal and profitable check. + // Note:- Though this ordering is done before begining with legalization, + // newly added node during legalization process have NodeId=-1 (NewNode) + // therefore before performing any check proper ordering of the node is + // required. + DAG.AssignTopologicalOrder(); + + // Direct load operands are folded in binary operations. But before folding + // verify if this folding is legal. Fold only if it is legal otherwise + // convert this direct load to a separate memory operation. + if (SelectionDAGISel::IsLegalToFold(Op.getOperand(0), + Op.getNode(), Op.getNode(), + CodeGenOpt::Default)) + return false; + else + MemOp = 0; + } + } + + // For operations that are non-cummutative there is no need to check + // for right operand because folding right operand may result in + // incorrect operation. + if (! SelectionDAG::isCommutativeBinOp(Op.getOpcode())) + return true; + + if (isDirectLoad(Op.getOperand(1))) { + if (Op.getOperand(1).hasOneUse()) { + // Legal and profitable folding check uses the NodeId of DAG nodes. + // This NodeId is assigned by topological order. Therefore first + // assign topological order then perform legal and profitable check. + // Note:- Though this ordering is done before begining with legalization, + // newly added node during legalization process have NodeId=-1 (NewNode) + // therefore before performing any check proper ordering of the node is + // required. + DAG.AssignTopologicalOrder(); + + // Direct load operands are folded in binary operations. But before folding + // verify if this folding is legal. Fold only if it is legal otherwise + // convert this direct load to a separate memory operation. + if (SelectionDAGISel::IsLegalToFold(Op.getOperand(1), + Op.getNode(), Op.getNode(), + CodeGenOpt::Default)) + return false; + else + MemOp = 1; + } + } + return true; +} + +// LowerBinOp - Lower a commutative binary operation that does not +// affect status flag carry. +SDValue PIC16TargetLowering::LowerBinOp(SDValue Op, SelectionDAG &DAG) const { + DebugLoc dl = Op.getDebugLoc(); + + // We should have handled larger operands in type legalizer itself. + assert (Op.getValueType() == MVT::i8 && "illegal Op to lower"); + + unsigned MemOp = 1; + if (NeedToConvertToMemOp(Op, MemOp, DAG)) { + // Put one value on stack. + SDValue NewVal = ConvertToMemOperand (Op.getOperand(MemOp), DAG, dl); + + return DAG.getNode(Op.getOpcode(), dl, MVT::i8, Op.getOperand(MemOp ^ 1), + NewVal); + } + else { + return Op; + } +} + +// LowerADD - Lower all types of ADD operations including the ones +// that affects carry. +SDValue PIC16TargetLowering::LowerADD(SDValue Op, SelectionDAG &DAG) const { + // We should have handled larger operands in type legalizer itself. + assert (Op.getValueType() == MVT::i8 && "illegal add to lower"); + DebugLoc dl = Op.getDebugLoc(); + unsigned MemOp = 1; + if (NeedToConvertToMemOp(Op, MemOp, DAG)) { + // Put one value on stack. + SDValue NewVal = ConvertToMemOperand (Op.getOperand(MemOp), DAG, dl); + + // ADDC and ADDE produce two results. + SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Flag); + + // ADDE has three operands, the last one is the carry bit. + if (Op.getOpcode() == ISD::ADDE) + return DAG.getNode(Op.getOpcode(), dl, Tys, Op.getOperand(MemOp ^ 1), + NewVal, Op.getOperand(2)); + // ADDC has two operands. + else if (Op.getOpcode() == ISD::ADDC) + return DAG.getNode(Op.getOpcode(), dl, Tys, Op.getOperand(MemOp ^ 1), + NewVal); + // ADD it is. It produces only one result. + else + return DAG.getNode(Op.getOpcode(), dl, MVT::i8, Op.getOperand(MemOp ^ 1), + NewVal); + } + else + return Op; +} + +SDValue PIC16TargetLowering::LowerSUB(SDValue Op, SelectionDAG &DAG) const { + DebugLoc dl = Op.getDebugLoc(); + // We should have handled larger operands in type legalizer itself. + assert (Op.getValueType() == MVT::i8 && "illegal sub to lower"); + unsigned MemOp = 1; + SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Flag); + + // Since we don't have an instruction for X - c , + // we can change it to X + (-c) + ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op.getOperand(1)); + if (C && (Op.getOpcode() == ISD::SUB)) + { + return DAG.getNode(ISD::ADD, + dl, MVT::i8, Op.getOperand(0), + DAG.getConstant(0-(C->getZExtValue()), MVT::i8)); + } + + if (NeedToConvertToMemOp(Op, MemOp, DAG) || + (isDirectLoad(Op.getOperand(1)) && + (!isDirectLoad(Op.getOperand(0))) && + (Op.getOperand(0).getOpcode() != ISD::Constant))) + { + // Put first operand on stack. + SDValue NewVal = ConvertToMemOperand (Op.getOperand(0), DAG, dl); + + switch (Op.getOpcode()) { + default: + assert (0 && "Opcode unknown."); + case ISD::SUBE: + return DAG.getNode(Op.getOpcode(), + dl, Tys, NewVal, Op.getOperand(1), + Op.getOperand(2)); + break; + case ISD::SUBC: + return DAG.getNode(Op.getOpcode(), + dl, Tys, NewVal, Op.getOperand(1)); + break; + case ISD::SUB: + return DAG.getNode(Op.getOpcode(), + dl, MVT::i8, NewVal, Op.getOperand(1)); + break; + } + } + else + return Op; +} + +void PIC16TargetLowering::InitReservedFrameCount(const Function *F, + SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + PIC16MachineFunctionInfo *FuncInfo = MF.getInfo<PIC16MachineFunctionInfo>(); + + unsigned NumArgs = F->arg_size(); + + bool isVoidFunc = (F->getReturnType()->getTypeID() == Type::VoidTyID); + + if (isVoidFunc) + FuncInfo->setReservedFrameCount(NumArgs); + else + FuncInfo->setReservedFrameCount(NumArgs + 1); +} + +// LowerFormalArguments - Argument values are loaded from the +// <fname>.args + offset. All arguments are already broken to leaglized +// types, so the offset just runs from 0 to NumArgVals - 1. + +SDValue +PIC16TargetLowering::LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, + SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) + const { + unsigned NumArgVals = Ins.size(); + + // Get the callee's name to create the <fname>.args label to pass args. + MachineFunction &MF = DAG.getMachineFunction(); + const Function *F = MF.getFunction(); + std::string FuncName = F->getName(); + + // Reset the map of FI and TmpOffset + ResetTmpOffsetMap(DAG); + // Initialize the ReserveFrameCount + InitReservedFrameCount(F, DAG); + + // Create the <fname>.args external symbol. + const char *tmpName = ESNames::createESName(PAN::getArgsLabel(FuncName)); + SDValue ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8); + + // Load arg values from the label + offset. + SDVTList VTs = DAG.getVTList (MVT::i8, MVT::Other); + SDValue BS = DAG.getConstant(1, MVT::i8); + for (unsigned i = 0; i < NumArgVals ; ++i) { + SDValue Offset = DAG.getConstant(i, MVT::i8); + SDValue PICLoad = DAG.getNode(PIC16ISD::PIC16LdArg, dl, VTs, Chain, ES, BS, + Offset); + Chain = getChain(PICLoad); + InVals.push_back(PICLoad); + } + + return Chain; +} + +// Perform DAGCombine of PIC16Load. +// FIXME - Need a more elaborate comment here. +SDValue PIC16TargetLowering:: +PerformPIC16LoadCombine(SDNode *N, DAGCombinerInfo &DCI) const { + SelectionDAG &DAG = DCI.DAG; + SDValue Chain = N->getOperand(0); + if (N->hasNUsesOfValue(0, 0)) { + DAG.ReplaceAllUsesOfValueWith(SDValue(N,1), Chain); + } + return SDValue(); +} + +// For all the functions with arguments some STORE nodes are generated +// that store the argument on the frameindex. However in PIC16 the arguments +// are passed on stack only. Therefore these STORE nodes are redundant. +// To remove these STORE nodes will be removed in PerformStoreCombine +// +// Currently this function is doint nothing and will be updated for removing +// unwanted store operations +SDValue PIC16TargetLowering:: +PerformStoreCombine(SDNode *N, DAGCombinerInfo &DCI) const { + return SDValue(N, 0); + /* + // Storing an undef value is of no use, so remove it + if (isStoringUndef(N, Chain, DAG)) { + return Chain; // remove the store and return the chain + } + //else everything is ok. + return SDValue(N, 0); + */ +} + +SDValue PIC16TargetLowering::PerformDAGCombine(SDNode *N, + DAGCombinerInfo &DCI) const { + switch (N->getOpcode()) { + case ISD::STORE: + return PerformStoreCombine(N, DCI); + case PIC16ISD::PIC16Load: + return PerformPIC16LoadCombine(N, DCI); + } + return SDValue(); +} + +static PIC16CC::CondCodes IntCCToPIC16CC(ISD::CondCode CC) { + switch (CC) { + default: llvm_unreachable("Unknown condition code!"); + case ISD::SETNE: return PIC16CC::NE; + case ISD::SETEQ: return PIC16CC::EQ; + case ISD::SETGT: return PIC16CC::GT; + case ISD::SETGE: return PIC16CC::GE; + case ISD::SETLT: return PIC16CC::LT; + case ISD::SETLE: return PIC16CC::LE; + case ISD::SETULT: return PIC16CC::ULT; + case ISD::SETULE: return PIC16CC::ULE; + case ISD::SETUGE: return PIC16CC::UGE; + case ISD::SETUGT: return PIC16CC::UGT; + } +} + +// Look at LHS/RHS/CC and see if they are a lowered setcc instruction. If so +// set LHS/RHS and SPCC to the LHS/RHS of the setcc and SPCC to the condition. +static void LookThroughSetCC(SDValue &LHS, SDValue &RHS, + ISD::CondCode CC, unsigned &SPCC) { + if (isa<ConstantSDNode>(RHS) && + cast<ConstantSDNode>(RHS)->isNullValue() && + CC == ISD::SETNE && + (LHS.getOpcode() == PIC16ISD::SELECT_ICC && + LHS.getOperand(3).getOpcode() == PIC16ISD::SUBCC) && + isa<ConstantSDNode>(LHS.getOperand(0)) && + isa<ConstantSDNode>(LHS.getOperand(1)) && + cast<ConstantSDNode>(LHS.getOperand(0))->isOne() && + cast<ConstantSDNode>(LHS.getOperand(1))->isNullValue()) { + SDValue CMPCC = LHS.getOperand(3); + SPCC = cast<ConstantSDNode>(LHS.getOperand(2))->getZExtValue(); + LHS = CMPCC.getOperand(0); + RHS = CMPCC.getOperand(1); + } +} + +// Returns appropriate CMP insn and corresponding condition code in PIC16CC +SDValue PIC16TargetLowering::getPIC16Cmp(SDValue LHS, SDValue RHS, + unsigned CC, SDValue &PIC16CC, + SelectionDAG &DAG, DebugLoc dl) const { + PIC16CC::CondCodes CondCode = (PIC16CC::CondCodes) CC; + + // PIC16 sub is literal - W. So Swap the operands and condition if needed. + // i.e. a < 12 can be rewritten as 12 > a. + if (RHS.getOpcode() == ISD::Constant) { + + SDValue Tmp = LHS; + LHS = RHS; + RHS = Tmp; + + switch (CondCode) { + default: break; + case PIC16CC::LT: + CondCode = PIC16CC::GT; + break; + case PIC16CC::GT: + CondCode = PIC16CC::LT; + break; + case PIC16CC::ULT: + CondCode = PIC16CC::UGT; + break; + case PIC16CC::UGT: + CondCode = PIC16CC::ULT; + break; + case PIC16CC::GE: + CondCode = PIC16CC::LE; + break; + case PIC16CC::LE: + CondCode = PIC16CC::GE; + break; + case PIC16CC::ULE: + CondCode = PIC16CC::UGE; + break; + case PIC16CC::UGE: + CondCode = PIC16CC::ULE; + break; + } + } + + PIC16CC = DAG.getConstant(CondCode, MVT::i8); + + // These are signed comparisons. + SDValue Mask = DAG.getConstant(128, MVT::i8); + if (isSignedComparison(CondCode)) { + LHS = DAG.getNode (ISD::XOR, dl, MVT::i8, LHS, Mask); + RHS = DAG.getNode (ISD::XOR, dl, MVT::i8, RHS, Mask); + } + + SDVTList VTs = DAG.getVTList (MVT::i8, MVT::Flag); + // We can use a subtract operation to set the condition codes. But + // we need to put one operand in memory if required. + // Nothing to do if the first operand is already a valid type (direct load + // for subwf and literal for sublw) and it is used by this operation only. + if ((LHS.getOpcode() == ISD::Constant || isDirectLoad(LHS)) + && LHS.hasOneUse()) + return DAG.getNode(PIC16ISD::SUBCC, dl, VTs, LHS, RHS); + + // else convert the first operand to mem. + LHS = ConvertToMemOperand (LHS, DAG, dl); + return DAG.getNode(PIC16ISD::SUBCC, dl, VTs, LHS, RHS); +} + + +SDValue PIC16TargetLowering::LowerSELECT_CC(SDValue Op, + SelectionDAG &DAG) const { + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get(); + SDValue TrueVal = Op.getOperand(2); + SDValue FalseVal = Op.getOperand(3); + unsigned ORIGCC = ~0; + DebugLoc dl = Op.getDebugLoc(); + + // If this is a select_cc of a "setcc", and if the setcc got lowered into + // an CMP[IF]CC/SELECT_[IF]CC pair, find the original compared values. + // i.e. + // A setcc: lhs, rhs, cc is expanded by llvm to + // select_cc: result of setcc, 0, 1, 0, setne + // We can think of it as: + // select_cc: lhs, rhs, 1, 0, cc + LookThroughSetCC(LHS, RHS, CC, ORIGCC); + if (ORIGCC == ~0U) ORIGCC = IntCCToPIC16CC (CC); + + SDValue PIC16CC; + SDValue Cmp = getPIC16Cmp(LHS, RHS, ORIGCC, PIC16CC, DAG, dl); + + return DAG.getNode (PIC16ISD::SELECT_ICC, dl, TrueVal.getValueType(), TrueVal, + FalseVal, PIC16CC, Cmp.getValue(1)); +} + +MachineBasicBlock * +PIC16TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo(); + unsigned CC = (PIC16CC::CondCodes)MI->getOperand(3).getImm(); + DebugLoc dl = MI->getDebugLoc(); + + // To "insert" a SELECT_CC instruction, we actually have to insert the diamond + // control-flow pattern. The incoming instruction knows the destination vreg + // to set, the condition code register to branch on, the true/false values to + // select between, and a branch opcode to use. + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = BB; + ++It; + + // thisMBB: + // ... + // TrueVal = ... + // [f]bCC copy1MBB + // fallthrough --> copy0MBB + MachineBasicBlock *thisMBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); + BuildMI(BB, dl, TII.get(PIC16::pic16brcond)).addMBB(sinkMBB).addImm(CC); + F->insert(It, copy0MBB); + F->insert(It, sinkMBB); + + // Transfer the remainder of BB and its successor edges to sinkMBB. + sinkMBB->splice(sinkMBB->begin(), BB, + llvm::next(MachineBasicBlock::iterator(MI)), + BB->end()); + sinkMBB->transferSuccessorsAndUpdatePHIs(BB); + + // Next, add the true and fallthrough blocks as its successors. + BB->addSuccessor(copy0MBB); + BB->addSuccessor(sinkMBB); + + // copy0MBB: + // %FalseValue = ... + // # fallthrough to sinkMBB + BB = copy0MBB; + + // Update machine-CFG edges + BB->addSuccessor(sinkMBB); + + // sinkMBB: + // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ] + // ... + BB = sinkMBB; + BuildMI(*BB, BB->begin(), dl, + TII.get(PIC16::PHI), MI->getOperand(0).getReg()) + .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB) + .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + + +SDValue PIC16TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); + ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get(); + SDValue LHS = Op.getOperand(2); // LHS of the condition. + SDValue RHS = Op.getOperand(3); // RHS of the condition. + SDValue Dest = Op.getOperand(4); // BB to jump to + unsigned ORIGCC = ~0; + DebugLoc dl = Op.getDebugLoc(); + + // If this is a br_cc of a "setcc", and if the setcc got lowered into + // an CMP[IF]CC/SELECT_[IF]CC pair, find the original compared values. + LookThroughSetCC(LHS, RHS, CC, ORIGCC); + if (ORIGCC == ~0U) ORIGCC = IntCCToPIC16CC (CC); + + // Get the Compare insn and condition code. + SDValue PIC16CC; + SDValue Cmp = getPIC16Cmp(LHS, RHS, ORIGCC, PIC16CC, DAG, dl); + + return DAG.getNode(PIC16ISD::BRCOND, dl, MVT::Other, Chain, Dest, PIC16CC, + Cmp.getValue(1)); +} + diff --git a/contrib/llvm/lib/Target/PIC16/PIC16ISelLowering.h b/contrib/llvm/lib/Target/PIC16/PIC16ISelLowering.h new file mode 100644 index 0000000..d942af4 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16ISelLowering.h @@ -0,0 +1,253 @@ +//===-- PIC16ISelLowering.h - PIC16 DAG Lowering Interface ------*- C++ -*-===// +// +// 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 interfaces that PIC16 uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef PIC16ISELLOWERING_H +#define PIC16ISELLOWERING_H + +#include "PIC16.h" +#include "PIC16Subtarget.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/Target/TargetLowering.h" +#include <map> + +namespace llvm { + namespace PIC16ISD { + enum NodeType { + // Start the numbering from where ISD NodeType finishes. + FIRST_NUMBER = ISD::BUILTIN_OP_END, + + Lo, // Low 8-bits of GlobalAddress. + Hi, // High 8-bits of GlobalAddress. + PIC16Load, + PIC16LdArg, // This is replica of PIC16Load but used to load function + // arguments and is being used for facilitating for some + // store removal optimizations. + + PIC16LdWF, + PIC16Store, + PIC16StWF, + Banksel, + MTLO, // Move to low part of FSR + MTHI, // Move to high part of FSR + MTPCLATH, // Move to PCLATCH + PIC16Connect, // General connector for PIC16 nodes + BCF, + LSLF, // PIC16 Logical shift left + LRLF, // PIC16 Logical shift right + RLF, // Rotate left through carry + RRF, // Rotate right through carry + CALL, // PIC16 Call instruction + CALLW, // PIC16 CALLW instruction + SUBCC, // Compare for equality or inequality. + SELECT_ICC, // Pseudo to be caught in scheduler and expanded to brcond. + BRCOND, // Conditional branch. + RET, // Return. + Dummy + }; + + // Keep track of different address spaces. + enum AddressSpace { + RAM_SPACE = 0, // RAM address space + ROM_SPACE = 1 // ROM address space number is 1 + }; + enum PIC16Libcall { + MUL_I8 = RTLIB::UNKNOWN_LIBCALL + 1, + SRA_I8, + SLL_I8, + SRL_I8, + PIC16UnknownCall + }; + } + + + //===--------------------------------------------------------------------===// + // TargetLowering Implementation + //===--------------------------------------------------------------------===// + class PIC16TargetLowering : public TargetLowering { + public: + explicit PIC16TargetLowering(PIC16TargetMachine &TM); + + /// getTargetNodeName - This method returns the name of a target specific + /// DAG node. + virtual const char *getTargetNodeName(unsigned Opcode) const; + /// getSetCCResultType - Return the ISD::SETCC ValueType + virtual MVT::SimpleValueType getSetCCResultType(EVT ValType) const; + virtual MVT::SimpleValueType getCmpLibcallReturnType() const; + SDValue LowerShift(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerMUL(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerADD(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSUB(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerBinOp(SDValue Op, SelectionDAG &DAG) const; + // Call returns + SDValue + LowerDirectCallReturn(SDValue RetLabel, SDValue Chain, SDValue InFlag, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + SDValue + LowerIndirectCallReturn(SDValue Chain, SDValue InFlag, + SDValue DataAddr_Lo, SDValue DataAddr_Hi, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + + // Call arguments + SDValue + LowerDirectCallArguments(SDValue ArgLabel, SDValue Chain, SDValue InFlag, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + DebugLoc dl, SelectionDAG &DAG) const; + + SDValue + LowerIndirectCallArguments(SDValue Chain, SDValue InFlag, + SDValue DataAddr_Lo, SDValue DataAddr_Hi, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG) const; + + SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue getPIC16Cmp(SDValue LHS, SDValue RHS, unsigned OrigCC, SDValue &CC, + SelectionDAG &DAG, DebugLoc dl) const; + virtual MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *MBB) const; + + virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const; + virtual void ReplaceNodeResults(SDNode *N, + SmallVectorImpl<SDValue> &Results, + SelectionDAG &DAG) const; + virtual void LowerOperationWrapper(SDNode *N, + SmallVectorImpl<SDValue> &Results, + SelectionDAG &DAG) const; + + virtual SDValue + LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + + virtual SDValue + LowerCall(SDValue Chain, SDValue Callee, + CallingConv::ID CallConv, bool isVarArg, bool &isTailCall, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + + virtual SDValue + LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + DebugLoc dl, SelectionDAG &DAG) const; + + SDValue ExpandStore(SDNode *N, SelectionDAG &DAG) const; + SDValue ExpandLoad(SDNode *N, SelectionDAG &DAG) const; + SDValue ExpandGlobalAddress(SDNode *N, SelectionDAG &DAG) const; + SDValue ExpandExternalSymbol(SDNode *N, SelectionDAG &DAG) const; + SDValue ExpandFrameIndex(SDNode *N, SelectionDAG &DAG) const; + + SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const; + SDValue PerformPIC16LoadCombine(SDNode *N, DAGCombinerInfo &DCI) const; + SDValue PerformStoreCombine(SDNode *N, DAGCombinerInfo &DCI) const; + + // This function returns the Tmp Offset for FrameIndex. If any TmpOffset + // already exists for the FI then it returns the same else it creates the + // new offset and returns. + unsigned GetTmpOffsetForFI(unsigned FI, unsigned slot_size, + MachineFunction &MF) const; + void ResetTmpOffsetMap(SelectionDAG &DAG) const; + void InitReservedFrameCount(const Function *F, + SelectionDAG &DAG) const; + + /// getFunctionAlignment - Return the Log2 alignment of this function. + virtual unsigned getFunctionAlignment(const Function *) const { + // FIXME: The function never seems to be aligned. + return 1; + } + protected: + std::pair<const TargetRegisterClass*, uint8_t> + findRepresentativeClass(EVT VT) const; + private: + // If the Node is a BUILD_PAIR representing a direct Address, + // then this function will return true. + bool isDirectAddress(const SDValue &Op) const; + + // If the Node is a DirectAddress in ROM_SPACE then this + // function will return true + bool isRomAddress(const SDValue &Op) const; + + // Extract the Lo and Hi component of Op. + void GetExpandedParts(SDValue Op, SelectionDAG &DAG, SDValue &Lo, + SDValue &Hi) const; + + + // Load pointer can be a direct or indirect address. In PIC16 direct + // addresses need Banksel and Indirect addresses need to be loaded to + // FSR first. Handle address specific cases here. + void LegalizeAddress(SDValue Ptr, SelectionDAG &DAG, SDValue &Chain, + SDValue &NewPtr, unsigned &Offset, DebugLoc dl) const; + + // FrameIndex should be broken down into ExternalSymbol and FrameOffset. + void LegalizeFrameIndex(SDValue Op, SelectionDAG &DAG, SDValue &ES, + int &Offset) const; + + // For indirect calls data address of the callee frame need to be + // extracted. This function fills the arguments DataAddr_Lo and + // DataAddr_Hi with the address of the callee frame. + void GetDataAddress(DebugLoc dl, SDValue Callee, SDValue &Chain, + SDValue &DataAddr_Lo, SDValue &DataAddr_Hi, + SelectionDAG &DAG) const; + + // We can not have both operands of a binary operation in W. + // This function is used to put one operand on stack and generate a load. + SDValue ConvertToMemOperand(SDValue Op, SelectionDAG &DAG, + DebugLoc dl) const; + + // This function checks if we need to put an operand of an operation on + // stack and generate a load or not. + // DAG parameter is required to access DAG information during + // analysis. + bool NeedToConvertToMemOp(SDValue Op, unsigned &MemOp, + SelectionDAG &DAG) const; + + /// Subtarget - Keep a pointer to the PIC16Subtarget around so that we can + /// make the right decision when generating code for different targets. + const PIC16Subtarget *Subtarget; + + + // Extending the LIB Call framework of LLVM + // to hold the names of PIC16Libcalls. + const char *PIC16LibcallNames[PIC16ISD::PIC16UnknownCall]; + + // To set and retrieve the lib call names. + void setPIC16LibcallName(PIC16ISD::PIC16Libcall Call, const char *Name); + const char *getPIC16LibcallName(PIC16ISD::PIC16Libcall Call) const; + + // Make PIC16 Libcall. + SDValue MakePIC16Libcall(PIC16ISD::PIC16Libcall Call, EVT RetVT, + const SDValue *Ops, unsigned NumOps, bool isSigned, + SelectionDAG &DAG, DebugLoc dl) const; + + // Check if operation has a direct load operand. + inline bool isDirectLoad(const SDValue Op) const; + }; +} // namespace llvm + +#endif // PIC16ISELLOWERING_H diff --git a/contrib/llvm/lib/Target/PIC16/PIC16InstrFormats.td b/contrib/llvm/lib/Target/PIC16/PIC16InstrFormats.td new file mode 100644 index 0000000..e213ea8 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16InstrFormats.td @@ -0,0 +1,117 @@ +//===- PIC16InstrFormats.td - PIC16 Instruction Formats-------*- tblgen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Describe PIC16 instructions format +// +// All the possible PIC16 fields are: +// +// opcode - operation code. +// f - 7-bit register file address. +// d - 1-bit direction specifier +// k - 8/11 bit literals +// b - 3 bits bit num specifier +// +//===----------------------------------------------------------------------===// + +// Generic PIC16 Format +// PIC16 Instructions are 14-bit wide. + +// FIXME: Add Cooper Specific Formats if any. + +class PIC16Inst<dag outs, dag ins, string asmstr, list<dag> pattern> + : Instruction { + field bits<14> Inst; + + let Namespace = "PIC16"; + dag OutOperandList = outs; + dag InOperandList = ins; + let AsmString = asmstr; + let Pattern = pattern; +} + + +//===----------------------------------------------------------------------===// +// Byte Oriented instruction class in PIC16 : <|opcode|d|f|> +// opcode = 6 bits. +// d = direction = 1 bit. +// f = file register address = 7 bits. +//===----------------------------------------------------------------------===// + +class ByteFormat<bits<6> opcode, dag outs, dag ins, string asmstr, + list<dag> pattern> + :PIC16Inst<outs, ins, asmstr, pattern> { + bits<1> d; + bits<7> f; + + let Inst{13-8} = opcode; + + let Inst{7} = d; + let Inst{6-0} = f; +} + +//===----------------------------------------------------------------------===// +// Bit Oriented instruction class in PIC16 : <|opcode|b|f|> +// opcode = 4 bits. +// b = bit specifier = 3 bits. +// f = file register address = 7 bits. +//===----------------------------------------------------------------------===// + +class BitFormat<bits<4> opcode, dag outs, dag ins, string asmstr, + list<dag> pattern> + : PIC16Inst<outs, ins, asmstr, pattern> { + bits<3> b; + bits<7> f; + + let Inst{13-10} = opcode; + + let Inst{9-7} = b; + let Inst{6-0} = f; +} + +//===----------------------------------------------------------------------===// +// Literal Format instruction class in PIC16 : <|opcode|k|> +// opcode = 6 bits +// k = literal = 8 bits +//===----------------------------------------------------------------------===// + +class LiteralFormat<bits<6> opcode, dag outs, dag ins, string asmstr, + list<dag> pattern> + : PIC16Inst<outs, ins, asmstr, pattern> { + bits<8> k; + + let Inst{13-8} = opcode; + + let Inst{7-0} = k; +} + +//===----------------------------------------------------------------------===// +// Control Format instruction class in PIC16 : <|opcode|k|> +// opcode = 3 bits. +// k = jump address = 11 bits. +//===----------------------------------------------------------------------===// + +class ControlFormat<bits<3> opcode, dag outs, dag ins, string asmstr, + list<dag> pattern> + : PIC16Inst<outs, ins, asmstr, pattern> { + bits<11> k; + + let Inst{13-11} = opcode; + + let Inst{10-0} = k; +} + +//===----------------------------------------------------------------------===// +// Pseudo instruction class in PIC16 +//===----------------------------------------------------------------------===// + +class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern> + : PIC16Inst<outs, ins, asmstr, pattern> { + let Inst{13-6} = 0; +} diff --git a/contrib/llvm/lib/Target/PIC16/PIC16InstrInfo.cpp b/contrib/llvm/lib/Target/PIC16/PIC16InstrInfo.cpp new file mode 100644 index 0000000..81257f3 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16InstrInfo.cpp @@ -0,0 +1,224 @@ +//===- PIC16InstrInfo.cpp - PIC16 Instruction Information -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the PIC16 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "PIC16.h" +#include "PIC16ABINames.h" +#include "PIC16InstrInfo.h" +#include "PIC16TargetMachine.h" +#include "PIC16GenInstrInfo.inc" +#include "llvm/Function.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include <cstdio> + + +using namespace llvm; + +// FIXME: Add the subtarget support on this constructor. +PIC16InstrInfo::PIC16InstrInfo(PIC16TargetMachine &tm) + : TargetInstrInfoImpl(PIC16Insts, array_lengthof(PIC16Insts)), + TM(tm), + RegInfo(*this, *TM.getSubtargetImpl()) {} + + +/// isStoreToStackSlot - If the specified machine instruction is a direct +/// store to a stack slot, return the virtual or physical register number of +/// the source reg along with the FrameIndex of the loaded stack slot. +/// If not, return 0. This predicate must return 0 if the instruction has +/// any side effects other than storing to the stack slot. +unsigned PIC16InstrInfo::isStoreToStackSlot(const MachineInstr *MI, + int &FrameIndex) const { + if (MI->getOpcode() == PIC16::movwf + && MI->getOperand(0).isReg() + && MI->getOperand(1).isSymbol()) { + FrameIndex = MI->getOperand(1).getIndex(); + return MI->getOperand(0).getReg(); + } + return 0; +} + +/// isLoadFromStackSlot - If the specified machine instruction is a direct +/// load from a stack slot, return the virtual or physical register number of +/// the dest reg along with the FrameIndex of the stack slot. +/// If not, return 0. This predicate must return 0 if the instruction has +/// any side effects other than storing to the stack slot. +unsigned PIC16InstrInfo::isLoadFromStackSlot(const MachineInstr *MI, + int &FrameIndex) const { + if (MI->getOpcode() == PIC16::movf + && MI->getOperand(0).isReg() + && MI->getOperand(1).isSymbol()) { + FrameIndex = MI->getOperand(1).getIndex(); + return MI->getOperand(0).getReg(); + } + return 0; +} + + +void PIC16InstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned SrcReg, bool isKill, int FI, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + const PIC16TargetLowering *PTLI = TM.getTargetLowering(); + DebugLoc DL; + if (I != MBB.end()) DL = I->getDebugLoc(); + + const Function *Func = MBB.getParent()->getFunction(); + const std::string FuncName = Func->getName(); + + const char *tmpName = ESNames::createESName(PAN::getTempdataLabel(FuncName)); + + // On the order of operands here: think "movwf SrcReg, tmp_slot, offset". + if (RC == PIC16::GPRRegisterClass) { + //MachineFunction &MF = *MBB.getParent(); + //MachineRegisterInfo &RI = MF.getRegInfo(); + BuildMI(MBB, I, DL, get(PIC16::movwf)) + .addReg(SrcReg, getKillRegState(isKill)) + .addImm(PTLI->GetTmpOffsetForFI(FI, 1, *MBB.getParent())) + .addExternalSymbol(tmpName) + .addImm(1); // Emit banksel for it. + } + else if (RC == PIC16::FSR16RegisterClass) { + // This is a 16-bit register and the frameindex given by llvm is of + // size two here. Break this index N into two zero based indexes and + // put one into the map. The second one is always obtained by adding 1 + // to the first zero based index. In fact it is going to use 3 slots + // as saving FSRs corrupts W also and hence we need to save/restore W also. + + unsigned opcode = (SrcReg == PIC16::FSR0) ? PIC16::save_fsr0 + : PIC16::save_fsr1; + BuildMI(MBB, I, DL, get(opcode)) + .addReg(SrcReg, getKillRegState(isKill)) + .addImm(PTLI->GetTmpOffsetForFI(FI, 3, *MBB.getParent())) + .addExternalSymbol(tmpName) + .addImm(1); // Emit banksel for it. + } + else + llvm_unreachable("Can't store this register to stack slot"); +} + +void PIC16InstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned DestReg, int FI, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + const PIC16TargetLowering *PTLI = TM.getTargetLowering(); + DebugLoc DL; + if (I != MBB.end()) DL = I->getDebugLoc(); + + const Function *Func = MBB.getParent()->getFunction(); + const std::string FuncName = Func->getName(); + + const char *tmpName = ESNames::createESName(PAN::getTempdataLabel(FuncName)); + + // On the order of operands here: think "movf FrameIndex, W". + if (RC == PIC16::GPRRegisterClass) { + //MachineFunction &MF = *MBB.getParent(); + //MachineRegisterInfo &RI = MF.getRegInfo(); + BuildMI(MBB, I, DL, get(PIC16::movf), DestReg) + .addImm(PTLI->GetTmpOffsetForFI(FI, 1, *MBB.getParent())) + .addExternalSymbol(tmpName) + .addImm(1); // Emit banksel for it. + } + else if (RC == PIC16::FSR16RegisterClass) { + // This is a 16-bit register and the frameindex given by llvm is of + // size two here. Break this index N into two zero based indexes and + // put one into the map. The second one is always obtained by adding 1 + // to the first zero based index. In fact it is going to use 3 slots + // as saving FSRs corrupts W also and hence we need to save/restore W also. + + unsigned opcode = (DestReg == PIC16::FSR0) ? PIC16::restore_fsr0 + : PIC16::restore_fsr1; + BuildMI(MBB, I, DL, get(opcode), DestReg) + .addImm(PTLI->GetTmpOffsetForFI(FI, 3, *MBB.getParent())) + .addExternalSymbol(tmpName) + .addImm(1); // Emit banksel for it. + } + else + llvm_unreachable("Can't load this register from stack slot"); +} + +void PIC16InstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const { + unsigned Opc; + if (PIC16::FSR16RegClass.contains(DestReg, SrcReg)) + Opc = PIC16::copy_fsr; + else if (PIC16::GPRRegClass.contains(DestReg, SrcReg)) + Opc = PIC16::copy_w; + else + llvm_unreachable("Impossible reg-to-reg copy"); + + BuildMI(MBB, I, DL, get(Opc), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)); +} + +/// InsertBranch - Insert a branch into the end of the specified +/// MachineBasicBlock. This operands to this method are the same as those +/// returned by AnalyzeBranch. This is invoked in cases where AnalyzeBranch +/// returns success and when an unconditional branch (TBB is non-null, FBB is +/// null, Cond is empty) needs to be inserted. It returns the number of +/// instructions inserted. +unsigned PIC16InstrInfo:: +InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond, + DebugLoc DL) const { + // Shouldn't be a fall through. + assert(TBB && "InsertBranch must not be told to insert a fallthrough"); + + if (FBB == 0) { // One way branch. + if (Cond.empty()) { + // Unconditional branch? + BuildMI(&MBB, DL, get(PIC16::br_uncond)).addMBB(TBB); + } + return 1; + } + + // FIXME: If the there are some conditions specified then conditional branch + // should be generated. + // For the time being no instruction is being generated therefore + // returning NULL. + return 0; +} + +bool PIC16InstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const { + MachineBasicBlock::iterator I = MBB.end(); + if (I == MBB.begin()) + return true; + + // Get the terminator instruction. + --I; + while (I->isDebugValue()) { + if (I == MBB.begin()) + return true; + --I; + } + // Handle unconditional branches. If the unconditional branch's target is + // successor basic block then remove the unconditional branch. + if (I->getOpcode() == PIC16::br_uncond && AllowModify) { + if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) { + TBB = 0; + I->eraseFromParent(); + } + } + return true; +} diff --git a/contrib/llvm/lib/Target/PIC16/PIC16InstrInfo.h b/contrib/llvm/lib/Target/PIC16/PIC16InstrInfo.h new file mode 100644 index 0000000..661b335 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16InstrInfo.h @@ -0,0 +1,76 @@ +//===- PIC16InstrInfo.h - PIC16 Instruction Information----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the niversity of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the PIC16 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef PIC16INSTRUCTIONINFO_H +#define PIC16INSTRUCTIONINFO_H + +#include "PIC16.h" +#include "PIC16RegisterInfo.h" +#include "llvm/Target/TargetInstrInfo.h" + +namespace llvm { + + +class PIC16InstrInfo : public TargetInstrInfoImpl +{ + PIC16TargetMachine &TM; + const PIC16RegisterInfo RegInfo; +public: + explicit PIC16InstrInfo(PIC16TargetMachine &TM); + + virtual const PIC16RegisterInfo &getRegisterInfo() const { return RegInfo; } + + /// isLoadFromStackSlot - If the specified machine instruction is a direct + /// load from a stack slot, return the virtual or physical register number of + /// the destination along with the FrameIndex of the loaded stack slot. If + /// not, return 0. This predicate must return 0 if the instruction has + /// any side effects other than loading from the stack slot. + virtual unsigned isLoadFromStackSlot(const MachineInstr *MI, + int &FrameIndex) const; + + /// isStoreToStackSlot - If the specified machine instruction is a direct + /// store to a stack slot, return the virtual or physical register number of + /// the source reg along with the FrameIndex of the loaded stack slot. If + /// not, return 0. This predicate must return 0 if the instruction has + /// any side effects other than storing to the stack slot. + virtual unsigned isStoreToStackSlot(const MachineInstr *MI, + int &FrameIndex) const; + + virtual void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const; + + virtual void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const; + virtual void copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const; + virtual + unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond, + DebugLoc DL) const; + virtual bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const; + }; +} // namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/PIC16/PIC16InstrInfo.td b/contrib/llvm/lib/Target/PIC16/PIC16InstrInfo.td new file mode 100644 index 0000000..86d36cb --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16InstrInfo.td @@ -0,0 +1,540 @@ +//===- PIC16InstrInfo.td - PIC16 Instruction defs -------------*- tblgen-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the PIC16 instructions in TableGen format. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// PIC16 Specific Type Constraints. +//===----------------------------------------------------------------------===// +class SDTCisI8<int OpNum> : SDTCisVT<OpNum, i8>; +class SDTCisI16<int OpNum> : SDTCisVT<OpNum, i16>; + +//===----------------------------------------------------------------------===// +// PIC16 Specific Type Profiles. +//===----------------------------------------------------------------------===// + +// Generic type profiles for i8/i16 unary/binary operations. +// Taking one i8 or i16 and producing void. +def SDTI8VoidOp : SDTypeProfile<0, 1, [SDTCisI8<0>]>; +def SDTI16VoidOp : SDTypeProfile<0, 1, [SDTCisI16<0>]>; + +// Taking one value and producing an output of same type. +def SDTI8UnaryOp : SDTypeProfile<1, 1, [SDTCisI8<0>, SDTCisI8<1>]>; +def SDTI16UnaryOp : SDTypeProfile<1, 1, [SDTCisI16<0>, SDTCisI16<1>]>; + +// Taking two values and producing an output of same type. +def SDTI8BinOp : SDTypeProfile<1, 2, [SDTCisI8<0>, SDTCisI8<1>, SDTCisI8<2>]>; +def SDTI16BinOp : SDTypeProfile<1, 2, [SDTCisI16<0>, SDTCisI16<1>, + SDTCisI16<2>]>; + +// Node specific type profiles. +def SDT_PIC16Load : SDTypeProfile<1, 3, [SDTCisI8<0>, SDTCisI8<1>, + SDTCisI8<2>, SDTCisI8<3>]>; + +def SDT_PIC16Store : SDTypeProfile<0, 4, [SDTCisI8<0>, SDTCisI8<1>, + SDTCisI8<2>, SDTCisI8<3>]>; + +def SDT_PIC16Connect : SDTypeProfile<1, 2, [SDTCisI8<0>, SDTCisI8<1>, + SDTCisI8<2>]>; + +// PIC16ISD::CALL type prorile +def SDT_PIC16call : SDTypeProfile<0, -1, [SDTCisInt<0>]>; +def SDT_PIC16callw : SDTypeProfile<1, -1, [SDTCisInt<0>]>; + +// PIC16ISD::BRCOND +def SDT_PIC16Brcond: SDTypeProfile<0, 2, + [SDTCisVT<0, OtherVT>, SDTCisI8<1>]>; + +// PIC16ISD::BRCOND +def SDT_PIC16Selecticc: SDTypeProfile<1, 3, + [SDTCisI8<0>, SDTCisI8<1>, SDTCisI8<2>, + SDTCisI8<3>]>; + +//===----------------------------------------------------------------------===// +// PIC16 addressing modes matching via DAG. +//===----------------------------------------------------------------------===// +def diraddr : ComplexPattern<i8, 1, "SelectDirectAddr", [], []>; + +//===----------------------------------------------------------------------===// +// PIC16 Specific Node Definitions. +//===----------------------------------------------------------------------===// +def PIC16callseq_start : SDNode<"ISD::CALLSEQ_START", SDTI8VoidOp, + [SDNPHasChain, SDNPOutFlag]>; +def PIC16callseq_end : SDNode<"ISD::CALLSEQ_END", SDTI8VoidOp, + [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>; + +// Low 8-bits of GlobalAddress. +def PIC16Lo : SDNode<"PIC16ISD::Lo", SDTI8BinOp>; + +// High 8-bits of GlobalAddress. +def PIC16Hi : SDNode<"PIC16ISD::Hi", SDTI8BinOp>; + +// The MTHI and MTLO nodes are used only to match them in the incoming +// DAG for replacement by corresponding set_fsrhi, set_fsrlo insntructions. +// These nodes are not used for defining any instructions. +def MTLO : SDNode<"PIC16ISD::MTLO", SDTI8UnaryOp>; +def MTHI : SDNode<"PIC16ISD::MTHI", SDTI8UnaryOp>; +def MTPCLATH : SDNode<"PIC16ISD::MTPCLATH", SDTI8UnaryOp>; + +// Node to generate Bank Select for a GlobalAddress. +def Banksel : SDNode<"PIC16ISD::Banksel", SDTI8UnaryOp>; + +// Node to match a direct store operation. +def PIC16Store : SDNode<"PIC16ISD::PIC16Store", SDT_PIC16Store, [SDNPHasChain]>; +def PIC16StWF : SDNode<"PIC16ISD::PIC16StWF", SDT_PIC16Store, + [SDNPHasChain, SDNPInFlag, SDNPOutFlag]>; + +// Node to match a direct load operation. +def PIC16Load : SDNode<"PIC16ISD::PIC16Load", SDT_PIC16Load, [SDNPHasChain]>; +def PIC16LdArg : SDNode<"PIC16ISD::PIC16LdArg", SDT_PIC16Load, [SDNPHasChain]>; +def PIC16LdWF : SDNode<"PIC16ISD::PIC16LdWF", SDT_PIC16Load, + [SDNPHasChain, SDNPInFlag, SDNPOutFlag]>; +def PIC16Connect: SDNode<"PIC16ISD::PIC16Connect", SDT_PIC16Connect, []>; + +// Node to match PIC16 call +def PIC16call : SDNode<"PIC16ISD::CALL", SDT_PIC16call, + [SDNPHasChain , SDNPOptInFlag, SDNPOutFlag]>; +def PIC16callw : SDNode<"PIC16ISD::CALLW", SDT_PIC16callw, + [SDNPHasChain , SDNPOptInFlag, SDNPOutFlag]>; + +// Node to match a comparison instruction. +def PIC16Subcc : SDNode<"PIC16ISD::SUBCC", SDTI8BinOp, [SDNPOutFlag]>; + +// Node to match a conditional branch. +def PIC16Brcond : SDNode<"PIC16ISD::BRCOND", SDT_PIC16Brcond, + [SDNPHasChain, SDNPInFlag]>; + +def PIC16Selecticc : SDNode<"PIC16ISD::SELECT_ICC", SDT_PIC16Selecticc, + [SDNPInFlag]>; + +def PIC16ret : SDNode<"PIC16ISD::RET", SDTNone, [SDNPHasChain]>; + +//===----------------------------------------------------------------------===// +// PIC16 Operand Definitions. +//===----------------------------------------------------------------------===// +def i8mem : Operand<i8>; +def brtarget: Operand<OtherVT>; + +// Operand for printing out a condition code. +let PrintMethod = "printCCOperand" in + def CCOp : Operand<i8>; + +include "PIC16InstrFormats.td" + +//===----------------------------------------------------------------------===// +// PIC16 Common Classes. +//===----------------------------------------------------------------------===// + +// W = W Op F : Load the value from F and do Op to W. +let Constraints = "$src = $dst", mayLoad = 1 in +class BinOpFW<bits<6> OpCode, string OpcStr, SDNode OpNode>: + ByteFormat<OpCode, (outs GPR:$dst), + (ins GPR:$src, i8imm:$offset, i8mem:$ptrlo, i8imm:$ptrhi), + !strconcat(OpcStr, " $ptrlo + $offset, W"), + [(set GPR:$dst, (OpNode GPR:$src, (PIC16Load diraddr:$ptrlo, + (i8 imm:$ptrhi), + (i8 imm:$offset))))]>; + +// F = F Op W : Load the value from F, do op with W and store in F. +// This insn class is not marked as TwoAddress because the reg is +// being used as a source operand only. (Remember a TwoAddress insn +// needs a copy.) +let mayStore = 1 in +class BinOpWF<bits<6> OpCode, string OpcStr, SDNode OpNode>: + ByteFormat<OpCode, (outs), + (ins GPR:$src, i8imm:$offset, i8mem:$ptrlo, i8imm:$ptrhi), + !strconcat(OpcStr, " $ptrlo + $offset, F"), + [(PIC16Store (OpNode GPR:$src, (PIC16Load diraddr:$ptrlo, + (i8 imm:$ptrhi), + (i8 imm:$offset))), + diraddr:$ptrlo, + (i8 imm:$ptrhi), (i8 imm:$offset) + )]>; + +// W = W Op L : Do Op of L with W and place result in W. +let Constraints = "$src = $dst" in +class BinOpWL<bits<6> opcode, string OpcStr, SDNode OpNode> : + LiteralFormat<opcode, (outs GPR:$dst), + (ins GPR:$src, i8imm:$literal), + !strconcat(OpcStr, " $literal"), + [(set GPR:$dst, (OpNode GPR:$src, (i8 imm:$literal)))]>; + +//===----------------------------------------------------------------------===// +// PIC16 Instructions. +//===----------------------------------------------------------------------===// + +// Pseudo-instructions. +def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i8imm:$amt), + "!ADJCALLSTACKDOWN $amt", + [(PIC16callseq_start imm:$amt)]>; + +def ADJCALLSTACKUP : Pseudo<(outs), (ins i8imm:$amt), + "!ADJCALLSTACKUP $amt", + [(PIC16callseq_end imm:$amt)]>; + +//----------------------------------- +// Vaious movlw insn patterns. +//----------------------------------- +let isReMaterializable = 1 in { +// Move 8-bit literal to W. +def movlw : BitFormat<12, (outs GPR:$dst), (ins i8imm:$src), + "movlw $src", + [(set GPR:$dst, (i8 imm:$src))]>; + +// Move a Lo(TGA) to W. +def movlw_lo_1 : BitFormat<12, (outs GPR:$dst), (ins i8imm:$src, i8imm:$src2), + "movlw LOW(${src} + ${src2})", + [(set GPR:$dst, (PIC16Lo tglobaladdr:$src, imm:$src2 ))]>; + +// Move a Lo(TES) to W. +def movlw_lo_2 : BitFormat<12, (outs GPR:$dst), (ins i8imm:$src, i8imm:$src2), + "movlw LOW(${src} + ${src2})", + [(set GPR:$dst, (PIC16Lo texternalsym:$src, imm:$src2 ))]>; + +// Move a Hi(TGA) to W. +def movlw_hi_1 : BitFormat<12, (outs GPR:$dst), (ins i8imm:$src, i8imm:$src2), + "movlw HIGH(${src} + ${src2})", + [(set GPR:$dst, (PIC16Hi tglobaladdr:$src, imm:$src2))]>; + +// Move a Hi(TES) to W. +def movlw_hi_2 : BitFormat<12, (outs GPR:$dst), (ins i8imm:$src, i8imm:$src2), + "movlw HIGH(${src} + ${src2})", + [(set GPR:$dst, (PIC16Hi texternalsym:$src, imm:$src2))]>; +} + +//------------------- +// FSR setting insns. +//------------------- +// These insns are matched via a DAG replacement pattern. +def set_fsrlo: + ByteFormat<0, (outs FSR16:$fsr), + (ins GPR:$val), + "movwf ${fsr}L", + []>; + +let Constraints = "$src = $dst" in +def set_fsrhi: + ByteFormat<0, (outs FSR16:$dst), + (ins FSR16:$src, GPR:$val), + "movwf ${dst}H", + []>; + +def set_pclath: + ByteFormat<0, (outs PCLATHR:$dst), + (ins GPR:$val), + "movwf ${dst}", + [(set PCLATHR:$dst , (MTPCLATH GPR:$val))]>; + +//---------------------------- +// copyPhysReg +// copyPhysReg insns. These are dummy. They should always be deleted +// by the optimizer and never be present in the final generated code. +// if they are, then we have to write correct macros for these insns. +//---------------------------- +def copy_fsr: + Pseudo<(outs FSR16:$dst), (ins FSR16:$src), "copy_fsr $dst, $src", []>; + +def copy_w: + Pseudo<(outs GPR:$dst), (ins GPR:$src), "copy_w $dst, $src", []>; + +class SAVE_FSR<string OpcStr>: + Pseudo<(outs), + (ins FSR16:$src, i8imm:$offset, i8mem:$ptrlo, i8imm:$ptrhi), + !strconcat(OpcStr, " $ptrlo, $offset"), + []>; + +def save_fsr0: SAVE_FSR<"save_fsr0">; +def save_fsr1: SAVE_FSR<"save_fsr1">; + +class RESTORE_FSR<string OpcStr>: + Pseudo<(outs FSR16:$dst), + (ins i8imm:$offset, i8mem:$ptrlo, i8imm:$ptrhi), + !strconcat(OpcStr, " $ptrlo, $offset"), + []>; + +def restore_fsr0: RESTORE_FSR<"restore_fsr0">; +def restore_fsr1: RESTORE_FSR<"restore_fsr1">; + +//-------------------------- +// Store to memory +//------------------------- + +// Direct store. +// Input operands are: val = W, ptrlo = GA, offset = offset, ptrhi = banksel. +let mayStore = 1 in +class MOVWF_INSN<bits<6> OpCode, SDNode OpNodeDest, SDNode Op>: + ByteFormat<0, (outs), + (ins GPR:$val, i8imm:$offset, i8mem:$ptrlo, i8imm:$ptrhi), + "movwf ${ptrlo} + ${offset}", + [(Op GPR:$val, OpNodeDest:$ptrlo, (i8 imm:$ptrhi), + (i8 imm:$offset))]>; + +// Store W to a Global Address. +def movwf : MOVWF_INSN<0, tglobaladdr, PIC16Store>; + +// Store W to an External Symobol. +def movwf_1 : MOVWF_INSN<0, texternalsym, PIC16Store>; + +// Store with InFlag and OutFlag +// This is same as movwf_1 but has a flag. A flag is required to +// order the stores while passing the params to function. +def movwf_2 : MOVWF_INSN<0, texternalsym, PIC16StWF>; + +// Indirect store. Matched via a DAG replacement pattern. +def store_indirect : + ByteFormat<0, (outs), + (ins GPR:$val, FSR16:$fsr, i8imm:$offset), + "movwi $offset[$fsr]", + []>; + +//---------------------------- +// Load from memory +//---------------------------- +// Direct load. +// Input Operands are: ptrlo = GA, offset = offset, ptrhi = banksel. +// Output: dst = W +let Defs = [STATUS], mayLoad = 1 in +class MOVF_INSN<bits<6> OpCode, SDNode OpNodeSrc, SDNode Op>: + ByteFormat<0, (outs GPR:$dst), + (ins i8imm:$offset, i8mem:$ptrlo, i8imm:$ptrhi), + "movf ${ptrlo} + ${offset}, W", + [(set GPR:$dst, + (Op OpNodeSrc:$ptrlo, (i8 imm:$ptrhi), + (i8 imm:$offset)))]>; + +// Load from a GA. +def movf : MOVF_INSN<0, tglobaladdr, PIC16Load>; + +// Load from an ES. +def movf_1 : MOVF_INSN<0, texternalsym, PIC16Load>; +def movf_1_1 : MOVF_INSN<0, texternalsym, PIC16LdArg>; + +// Load with InFlag and OutFlag +// This is same as movf_1 but has a flag. A flag is required to +// order the loads while copying the return value of a function. +def movf_2 : MOVF_INSN<0, texternalsym, PIC16LdWF>; + +// Indirect load. Matched via a DAG replacement pattern. +def load_indirect : + ByteFormat<0, (outs GPR:$dst), + (ins FSR16:$fsr, i8imm:$offset), + "moviw $offset[$fsr]", + []>; + +//------------------------- +// Bitwise operations patterns +//-------------------------- +// W = W op [F] +let Defs = [STATUS] in { +def OrFW : BinOpFW<0, "iorwf", or>; +def XOrFW : BinOpFW<0, "xorwf", xor>; +def AndFW : BinOpFW<0, "andwf", and>; + +// F = W op [F] +def OrWF : BinOpWF<0, "iorwf", or>; +def XOrWF : BinOpWF<0, "xorwf", xor>; +def AndWF : BinOpWF<0, "andwf", and>; + +//------------------------- +// Various add/sub patterns. +//------------------------- + +// W = W + [F] +def addfw_1: BinOpFW<0, "addwf", add>; +def addfw_2: BinOpFW<0, "addwf", addc>; + +let Uses = [STATUS] in +def addfwc: BinOpFW<0, "addwfc", adde>; // With Carry. + +// F = W + [F] +def addwf_1: BinOpWF<0, "addwf", add>; +def addwf_2: BinOpWF<0, "addwf", addc>; +let Uses = [STATUS] in +def addwfc: BinOpWF<0, "addwfc", adde>; // With Carry. +} + +// W -= [F] ; load from F and sub the value from W. +let Constraints = "$src = $dst", mayLoad = 1 in +class SUBFW<bits<6> OpCode, string OpcStr, SDNode OpNode>: + ByteFormat<OpCode, (outs GPR:$dst), + (ins GPR:$src, i8imm:$offset, i8mem:$ptrlo, i8imm:$ptrhi), + !strconcat(OpcStr, " $ptrlo + $offset, W"), + [(set GPR:$dst, (OpNode (PIC16Load diraddr:$ptrlo, + (i8 imm:$ptrhi), (i8 imm:$offset)), + GPR:$src))]>; +let Defs = [STATUS] in { +def subfw_1: SUBFW<0, "subwf", sub>; +def subfw_2: SUBFW<0, "subwf", subc>; + +let Uses = [STATUS] in +def subfwb: SUBFW<0, "subwfb", sube>; // With Borrow. + +} +let Defs = [STATUS], isTerminator = 1 in +def subfw_cc: SUBFW<0, "subwf", PIC16Subcc>; + +// [F] -= W ; +let mayStore = 1 in +class SUBWF<bits<6> OpCode, string OpcStr, SDNode OpNode>: + ByteFormat<OpCode, (outs), + (ins GPR:$src, i8imm:$offset, i8mem:$ptrlo, i8imm:$ptrhi), + !strconcat(OpcStr, " $ptrlo + $offset"), + [(PIC16Store (OpNode (PIC16Load diraddr:$ptrlo, + (i8 imm:$ptrhi), (i8 imm:$offset)), + GPR:$src), diraddr:$ptrlo, + (i8 imm:$ptrhi), (i8 imm:$offset))]>; + +let Defs = [STATUS] in { +def subwf_1: SUBWF<0, "subwf", sub>; +def subwf_2: SUBWF<0, "subwf", subc>; + +let Uses = [STATUS] in + def subwfb: SUBWF<0, "subwfb", sube>; // With Borrow. + +def subwf_cc: SUBWF<0, "subwf", PIC16Subcc>; +} + +// addlw +let Defs = [STATUS] in { +def addlw_1 : BinOpWL<0, "addlw", add>; +def addlw_2 : BinOpWL<0, "addlw", addc>; + +let Uses = [STATUS] in +def addlwc : BinOpWL<0, "addlwc", adde>; // With Carry. (Assembler macro). + +// bitwise operations involving a literal and w. +def andlw : BinOpWL<0, "andlw", and>; +def xorlw : BinOpWL<0, "xorlw", xor>; +def orlw : BinOpWL<0, "iorlw", or>; +} + +// sublw +// W = C - W ; sub W from literal. (Without borrow). +let Constraints = "$src = $dst" in +class SUBLW<bits<6> opcode, string OpcStr, SDNode OpNode> : + LiteralFormat<opcode, (outs GPR:$dst), + (ins GPR:$src, i8imm:$literal), + !strconcat(OpcStr, " $literal"), + [(set GPR:$dst, (OpNode (i8 imm:$literal), GPR:$src))]>; +// subwl +// W = W - C ; sub literal from W (Without borrow). +let Constraints = "$src = $dst" in +class SUBWL<bits<6> opcode, string OpcStr, SDNode OpNode> : + LiteralFormat<opcode, (outs GPR:$dst), + (ins GPR:$src, i8imm:$literal), + !strconcat(OpcStr, " $literal"), + [(set GPR:$dst, (OpNode GPR:$src, (i8 imm:$literal)))]>; + +let Defs = [STATUS] in { +def sublw_1 : SUBLW<0, "sublw", sub>; +def sublw_2 : SUBLW<0, "sublw", subc>; +def sublw_3 : SUBLW<0, "sublwb", sube>; // With borrow (Assembler macro). + +def sublw_4 : SUBWL<0, "subwl", sub>; // Assembler macro replace with addlw +def sublw_5 : SUBWL<0, "subwl", subc>; // Assembler macro replace with addlw +def sublw_6 : SUBWL<0, "subwlb", sube>; // With borrow (Assembler macro). +} +let Defs = [STATUS], isTerminator = 1 in +def sublw_cc : SUBLW<0, "sublw", PIC16Subcc>; + +// Call instruction. +let isCall = 1, + Defs = [W, FSR0, FSR1] in { + def CALL: LiteralFormat<0x1, (outs), (ins i8imm:$func), + //"call ${func} + 2", + "call ${func}", + [(PIC16call diraddr:$func)]>; +} + +let isCall = 1, + Defs = [W, FSR0, FSR1] in { + def CALL_1: LiteralFormat<0x1, (outs), (ins GPR:$func, PCLATHR:$pc), + "callw", + [(PIC16call (PIC16Connect GPR:$func, PCLATHR:$pc))]>; +} + +let isCall = 1, + Defs = [FSR0, FSR1] in { + def CALLW: LiteralFormat<0x1, (outs GPR:$dest), + (ins GPR:$func, PCLATHR:$pc), + "callw", + [(set GPR:$dest, (PIC16callw (PIC16Connect GPR:$func, PCLATHR:$pc)))]>; +} + +let Uses = [STATUS], isBranch = 1, isTerminator = 1, hasDelaySlot = 0 in +def pic16brcond: ControlFormat<0x0, (outs), (ins brtarget:$dst, CCOp:$cc), + "b$cc $dst", + [(PIC16Brcond bb:$dst, imm:$cc)]>; + +// Unconditional branch. +let isBranch = 1, isTerminator = 1, hasDelaySlot = 0 in +def br_uncond: ControlFormat<0x0, (outs), (ins brtarget:$dst), + "goto $dst", + [(br bb:$dst)]>; + +// SELECT_CC_* - Used to implement the SELECT_CC DAG operation. Expanded after +// instruction selection into a branch sequence. +let usesCustomInserter = 1 in { // Expanded after instruction selection. + def SELECT_CC_Int_ICC + : Pseudo<(outs GPR:$dst), (ins GPR:$T, GPR:$F, i8imm:$Cond), + "; SELECT_CC_Int_ICC PSEUDO!", + [(set GPR:$dst, (PIC16Selecticc GPR:$T, GPR:$F, + imm:$Cond))]>; +} + + +// Banksel. +def banksel : + Pseudo<(outs), + (ins i8mem:$ptr), + "banksel $ptr", + []>; + +def pagesel : + Pseudo<(outs), + (ins i8mem:$ptr), + "movlp $ptr", + []>; + + +// Return insn. +let isTerminator = 1, isBarrier = 1, isReturn = 1 in +def Return : + ControlFormat<0, (outs), (ins), "return", [(PIC16ret)]>; + +//===----------------------------------------------------------------------===// +// PIC16 Replacment Patterns. +//===----------------------------------------------------------------------===// + +// Identify an indirect store and select insns for it. +def : Pat<(PIC16Store GPR:$val, (MTLO GPR:$loaddr), (MTHI GPR:$hiaddr), + imm:$offset), + (store_indirect GPR:$val, + (set_fsrhi (set_fsrlo GPR:$loaddr), GPR:$hiaddr), + imm:$offset)>; + +def : Pat<(PIC16StWF GPR:$val, (MTLO GPR:$loaddr), (MTHI GPR:$hiaddr), + imm:$offset), + (store_indirect GPR:$val, + (set_fsrhi (set_fsrlo GPR:$loaddr), GPR:$hiaddr), + imm:$offset)>; + +// Identify an indirect load and select insns for it. +def : Pat<(PIC16Load (MTLO GPR:$loaddr), (MTHI GPR:$hiaddr), + imm:$offset), + (load_indirect (set_fsrhi (set_fsrlo GPR:$loaddr), GPR:$hiaddr), + imm:$offset)>; + +def : Pat<(PIC16LdWF (MTLO GPR:$loaddr), (MTHI GPR:$hiaddr), + imm:$offset), + (load_indirect (set_fsrhi (set_fsrlo GPR:$loaddr), GPR:$hiaddr), + imm:$offset)>; + diff --git a/contrib/llvm/lib/Target/PIC16/PIC16MCAsmInfo.cpp b/contrib/llvm/lib/Target/PIC16/PIC16MCAsmInfo.cpp new file mode 100644 index 0000000..1bcc497 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16MCAsmInfo.cpp @@ -0,0 +1,59 @@ +//===-- PIC16MCAsmInfo.cpp - PIC16 asm properties -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declarations of the PIC16MCAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "PIC16MCAsmInfo.h" + +// FIXME: Layering violation to get enums and static function, should be moved +// to separate headers. +#include "PIC16.h" +#include "PIC16ABINames.h" +#include "PIC16ISelLowering.h" +using namespace llvm; + +PIC16MCAsmInfo::PIC16MCAsmInfo(const Target &T, StringRef TT) { + CommentString = ";"; + GlobalPrefix = PAN::getTagName(PAN::PREFIX_SYMBOL); + GlobalDirective = "\tglobal\t"; + ExternDirective = "\textern\t"; + + Data8bitsDirective = " db "; + Data16bitsDirective = " dw "; + Data32bitsDirective = " dl "; + Data64bitsDirective = NULL; + ZeroDirective = NULL; + AsciiDirective = " dt "; + AscizDirective = NULL; + + RomData8bitsDirective = " dw "; + RomData16bitsDirective = " rom_di "; + RomData32bitsDirective = " rom_dl "; + HasSetDirective = false; + + // Set it to false because we weed to generate c file name and not bc file + // name. + HasSingleParameterDotFile = false; +} + +const char *PIC16MCAsmInfo::getDataASDirective(unsigned Size, + unsigned AS) const { + if (AS != PIC16ISD::ROM_SPACE) + return 0; + + switch (Size) { + case 8: return RomData8bitsDirective; + case 16: return RomData16bitsDirective; + case 32: return RomData32bitsDirective; + default: return NULL; + } +} + diff --git a/contrib/llvm/lib/Target/PIC16/PIC16MCAsmInfo.h b/contrib/llvm/lib/Target/PIC16/PIC16MCAsmInfo.h new file mode 100644 index 0000000..6e1c111 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16MCAsmInfo.h @@ -0,0 +1,35 @@ +//=====-- PIC16MCAsmInfo.h - PIC16 asm properties -------------*- C++ -*--====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the PIC16MCAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef PIC16TARGETASMINFO_H +#define PIC16TARGETASMINFO_H + +#include "llvm/MC/MCAsmInfo.h" + +namespace llvm { + class Target; + class StringRef; + + class PIC16MCAsmInfo : public MCAsmInfo { + const char *RomData8bitsDirective; + const char *RomData16bitsDirective; + const char *RomData32bitsDirective; + public: + PIC16MCAsmInfo(const Target &T, StringRef TT); + + virtual const char *getDataASDirective(unsigned size, unsigned AS) const; + }; + +} // namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/PIC16/PIC16MachineFunctionInfo.h b/contrib/llvm/lib/Target/PIC16/PIC16MachineFunctionInfo.h new file mode 100644 index 0000000..bdf5086 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16MachineFunctionInfo.h @@ -0,0 +1,52 @@ +//====- PIC16MachineFuctionInfo.h - PIC16 machine function info -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares PIC16-specific per-machine-function information. +// +//===----------------------------------------------------------------------===// + +#ifndef PIC16MACHINEFUNCTIONINFO_H +#define PIC16MACHINEFUNCTIONINFO_H + +#include "llvm/CodeGen/MachineFunction.h" + +namespace llvm { + +/// PIC16MachineFunctionInfo - This class is derived from MachineFunction +/// private PIC16 target-specific information for each MachineFunction. +class PIC16MachineFunctionInfo : public MachineFunctionInfo { + // The frameindexes generated for spill/reload are stack based. + // This maps maintain zero based indexes for these FIs. + std::map<unsigned, unsigned> FiTmpOffsetMap; + unsigned TmpSize; + + // These are the frames for return value and argument passing + // These FrameIndices will be expanded to foo.frame external symbol + // and all others will be expanded to foo.tmp external symbol. + unsigned ReservedFrameCount; + +public: + PIC16MachineFunctionInfo() + : TmpSize(0), ReservedFrameCount(0) {} + + explicit PIC16MachineFunctionInfo(MachineFunction &MF) + : TmpSize(0), ReservedFrameCount(0) {} + + std::map<unsigned, unsigned> &getFiTmpOffsetMap() { return FiTmpOffsetMap; } + + unsigned getTmpSize() const { return TmpSize; } + void setTmpSize(unsigned Size) { TmpSize = Size; } + + unsigned getReservedFrameCount() const { return ReservedFrameCount; } + void setReservedFrameCount(unsigned Count) { ReservedFrameCount = Count; } +}; + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/PIC16/PIC16MemSelOpt.cpp b/contrib/llvm/lib/Target/PIC16/PIC16MemSelOpt.cpp new file mode 100644 index 0000000..b6aa38f --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16MemSelOpt.cpp @@ -0,0 +1,254 @@ +//===-- PIC16MemSelOpt.cpp - PIC16 banksel optimizer --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the pass which optimizes the emitting of banksel +// instructions before accessing data memory. This currently works within +// a basic block only and keep tracks of the last accessed memory bank. +// If memory access continues to be in the same bank it just makes banksel +// immediate, which is a part of the insn accessing the data memory, from 1 +// to zero. The asm printer emits a banksel only if that immediate is 1. +// +// FIXME: this is not implemented yet. The banksel pass only works on local +// basic blocks. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "pic16-codegen" +#include "PIC16.h" +#include "PIC16ABINames.h" +#include "PIC16InstrInfo.h" +#include "PIC16MCAsmInfo.h" +#include "PIC16TargetMachine.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/GlobalValue.h" +#include "llvm/DerivedTypes.h" + +using namespace llvm; + +namespace { + struct MemSelOpt : public MachineFunctionPass { + static char ID; + MemSelOpt() : MachineFunctionPass(ID) {} + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addPreservedID(MachineLoopInfoID); + AU.addPreservedID(MachineDominatorsID); + MachineFunctionPass::getAnalysisUsage(AU); + } + + virtual bool runOnMachineFunction(MachineFunction &MF); + + virtual const char *getPassName() const { + return "PIC16 Memsel Optimizer"; + } + + bool processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB); + bool processInstruction(MachineInstr *MI); + + private: + const TargetInstrInfo *TII; // Machine instruction info. + MachineBasicBlock *MBB; // Current basic block + std::string CurBank; + int PageChanged; + + }; + char MemSelOpt::ID = 0; +} + +FunctionPass *llvm::createPIC16MemSelOptimizerPass() { + return new MemSelOpt(); +} + + +/// runOnMachineFunction - Loop over all of the basic blocks, transforming FP +/// register references into FP stack references. +/// +bool MemSelOpt::runOnMachineFunction(MachineFunction &MF) { + TII = MF.getTarget().getInstrInfo(); + bool Changed = false; + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + Changed |= processBasicBlock(MF, *I); + } + + return Changed; +} + +/// processBasicBlock - Loop over all of the instructions in the basic block, +/// transforming FP instructions into their stack form. +/// +bool MemSelOpt::processBasicBlock(MachineFunction &MF, MachineBasicBlock &BB) { + bool Changed = false; + MBB = &BB; + + // Let us assume that when entering a basic block now bank is selected. + // Ideally we should look at the predecessors for this information. + CurBank=""; + PageChanged=0; + + MachineBasicBlock::iterator I; + for (I = BB.begin(); I != BB.end(); ++I) { + Changed |= processInstruction(I); + + // if the page has changed insert a page sel before + // any instruction that needs one + if (PageChanged == 1) + { + // Restore the page if it was changed, before leaving the basic block, + // because it may be required by the goto terminator or the fall thru + // basic blcok. + // If the terminator is return, we don't need to restore since there + // is no goto or fall thru basic block. + if ((I->getOpcode() == PIC16::sublw_3) || //macro has goto + (I->getOpcode() == PIC16::sublw_6) || //macro has goto + (I->getOpcode() == PIC16::addlwc) || //macro has goto + (TII->get(I->getOpcode()).isBranch())) + { + DebugLoc dl = I->getDebugLoc(); + BuildMI(*MBB, I, dl, TII->get(PIC16::pagesel)).addExternalSymbol("$"); + Changed = true; + PageChanged = 0; + } + } + } + + // The basic block is over, but if we did not find any goto yet, + // we haven't restored the page. + // Restore the page if it was changed, before leaving the basic block, + // because it may be required by fall thru basic blcok. + // If the terminator is return, we don't need to restore since there + // is fall thru basic block. + if (PageChanged == 1) { + // save the end pointer before we move back to last insn. + MachineBasicBlock::iterator J = I; + I--; + const TargetInstrDesc &TID = TII->get(I->getOpcode()); + if (! TID.isReturn()) + { + DebugLoc dl = I->getDebugLoc(); + BuildMI(*MBB, J, dl, + TII->get(PIC16::pagesel)).addExternalSymbol("$"); + Changed = true; + PageChanged = 0; + } + } + + + return Changed; +} + +bool MemSelOpt::processInstruction(MachineInstr *MI) { + bool Changed = false; + + unsigned NumOperands = MI->getNumOperands(); + if (NumOperands == 0) return false; + + + // If this insn is not going to access any memory, return. + const TargetInstrDesc &TID = TII->get(MI->getOpcode()); + if (!(TID.isBranch() || TID.isCall() || TID.mayLoad() || TID.mayStore())) + return false; + + // The first thing we should do is that record if banksel/pagesel are + // changed in an unknown way. This can happend via any type of call. + // We do it here first before scanning of MemOp / BBOp as the indirect + // call insns do not have any operands, but they still may change bank/page. + if (TID.isCall()) { + // Record that we have changed the page, so that we can restore it + // before basic block ends. + // We require to signal that a page anc bank change happened even for + // indirect calls. + PageChanged = 1; + + // When a call is made, there may be banksel for variables in callee. + // Hence the banksel in caller needs to be reset. + CurBank = ""; + } + + // Scan for the memory address operand. + // FIXME: Should we use standard interfaces like memoperands_iterator, + // hasMemOperand() etc ? + int MemOpPos = -1; + int BBOpPos = -1; + for (unsigned i = 0; i < NumOperands; i++) { + MachineOperand Op = MI->getOperand(i); + if (Op.getType() == MachineOperand::MO_GlobalAddress || + Op.getType() == MachineOperand::MO_ExternalSymbol) { + // We found one mem operand. Next one may be BS. + MemOpPos = i; + } + if (Op.getType() == MachineOperand::MO_MachineBasicBlock) { + // We found one BB operand. Next one may be pagesel. + BBOpPos = i; + } + } + + // If we did not find an insn accessing memory. Continue. + if ((MemOpPos == -1) && + (BBOpPos == -1)) + return false; + assert ((BBOpPos != MemOpPos) && "operand can only be of one type"); + + + // If this is a pagesel material, handle it first. + // CALL and br_ucond insns use MemOp (GA or ES) and not BBOp. + // Pagesel is required only for a direct call. + if ((MI->getOpcode() == PIC16::CALL)) { + // Get the BBOp. + MachineOperand &MemOp = MI->getOperand(MemOpPos); + DebugLoc dl = MI->getDebugLoc(); + BuildMI(*MBB, MI, dl, TII->get(PIC16::pagesel)).addOperand(MemOp); + + // CALL and br_ucond needs only pagesel. so we are done. + return true; + } + + // Pagesel is handled. Now, add a Banksel if needed. + if (MemOpPos == -1) return Changed; + // Get the MemOp. + MachineOperand &Op = MI->getOperand(MemOpPos); + + // Get the section name(NewBank) for MemOp. + // This assumes that the section names for globals are already set by + // AsmPrinter->doInitialization. + std::string NewBank = CurBank; + bool hasExternalLinkage = false; + if (Op.getType() == MachineOperand::MO_GlobalAddress && + Op.getGlobal()->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) { + if (Op.getGlobal()->hasExternalLinkage()) + hasExternalLinkage= true; + NewBank = Op.getGlobal()->getSection(); + } else if (Op.getType() == MachineOperand::MO_ExternalSymbol) { + // External Symbol is generated for temp data and arguments. They are + // in fpdata.<functionname>.# section. + std::string Sym = Op.getSymbolName(); + NewBank = PAN::getSectionNameForSym(Sym); + } + + // If the section is shared section, do not emit banksel. + if (NewBank == PAN::getSharedUDataSectionName()) + return Changed; + + // If the previous and new section names are same, we don't need to + // emit banksel. + if (NewBank.compare(CurBank) != 0 || hasExternalLinkage) { + DebugLoc dl = MI->getDebugLoc(); + BuildMI(*MBB, MI, dl, TII->get(PIC16::banksel)). + addOperand(Op); + Changed = true; + CurBank = NewBank; + } + + return Changed; +} + diff --git a/contrib/llvm/lib/Target/PIC16/PIC16Passes/Makefile b/contrib/llvm/lib/Target/PIC16/PIC16Passes/Makefile new file mode 100644 index 0000000..9684b8d --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16Passes/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/PIC16/PIC16Passes/Makefile -----------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../../.. +TARGET = PIC16 +LIBRARYNAME = LLVMpic16passes +BUILD_ARCHIVE = 1 + +include $(LEVEL)/Makefile.common + diff --git a/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Cloner.cpp b/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Cloner.cpp new file mode 100644 index 0000000..56f0211 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Cloner.cpp @@ -0,0 +1,299 @@ +//===-- PIC16Cloner.cpp - PIC16 LLVM Cloner for shared functions -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code to clone all functions that are shared between +// the main line code (ML) and interrupt line code (IL). It clones all such +// shared functions and their automatic global vars by adding the .IL suffix. +// +// This pass is supposed to be run on the linked .bc module. +// It traveses the module call graph twice. Once starting from the main function +// and marking each reached function as "ML". Again, starting from the ISR +// and cloning any reachable function that was marked as "ML". After cloning +// the function, it remaps all the call sites in IL functions to call the +// cloned functions. +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/CallGraph.h" +#include "llvm/Pass.h" +#include "llvm/Module.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "PIC16Cloner.h" +#include "../PIC16ABINames.h" +#include <vector> + +using namespace llvm; +using std::vector; +using std::string; +using std::map; + +namespace llvm { + char PIC16Cloner::ID = 0; + + ModulePass *createPIC16ClonerPass() { return new PIC16Cloner(); } +} + +// We currently intend to run these passes in opt, which does not have any +// diagnostic support. So use these functions for now. In future +// we will probably write our own driver tool. +// +void PIC16Cloner::reportError(string ErrorString) { + errs() << "ERROR : " << ErrorString << "\n"; + exit(1); +} + +void PIC16Cloner:: +reportError (string ErrorString, vector<string> &Values) { + unsigned ValCount = Values.size(); + string TargetString; + for (unsigned i=0; i<ValCount; ++i) { + TargetString = "%"; + TargetString += ((char)i + '0'); + ErrorString.replace(ErrorString.find(TargetString), TargetString.length(), + Values[i]); + } + errs() << "ERROR : " << ErrorString << "\n"; + exit(1); +} + + +// Entry point +// +bool PIC16Cloner::runOnModule(Module &M) { + CallGraph &CG = getAnalysis<CallGraph>(); + + // Search for the "main" and "ISR" functions. + CallGraphNode *mainCGN = NULL, *isrCGN = NULL; + for (CallGraph::iterator it = CG.begin() ; it != CG.end(); it++) + { + // External calling node doesn't have any function associated with it. + if (! it->first) + continue; + + if (it->first->getName().str() == "main") { + mainCGN = it->second; + } + + if (PAN::isISR(it->first->getSection())) { + isrCGN = it->second; + } + + // Don't search further if we've found both. + if (mainCGN && isrCGN) + break; + } + + // We have nothing to do if any of the main or ISR is missing. + if (! mainCGN || ! isrCGN) return false; + + // Time for some diagnostics. + // See if the main itself is interrupt function then report an error. + if (PAN::isISR(mainCGN->getFunction()->getSection())) { + reportError("Function 'main' can't be interrupt function"); + } + + + // Mark all reachable functions from main as ML. + markCallGraph(mainCGN, "ML"); + + // And then all the functions reachable from ISR will be cloned. + cloneSharedFunctions(isrCGN); + + return true; +} + +// Mark all reachable functions from the given node, with the given mark. +// +void PIC16Cloner::markCallGraph(CallGraphNode *CGN, string StringMark) { + // Mark the top node first. + Function *thisF = CGN->getFunction(); + + thisF->setSection(StringMark); + + // Mark all the called functions + for(CallGraphNode::iterator cgn_it = CGN->begin(); + cgn_it != CGN->end(); ++cgn_it) { + Function *CalledF = cgn_it->second->getFunction(); + + // If calling an external function then CallGraphNode + // will not be associated with any function. + if (! CalledF) + continue; + + // Issue diagnostic if interrupt function is being called. + if (PAN::isISR(CalledF->getSection())) { + vector<string> Values; + Values.push_back(CalledF->getName().str()); + reportError("Interrupt function (%0) can't be called", Values); + } + + // Has already been mark + if (CalledF->getSection().find(StringMark) != string::npos) { + // Should we do anything here? + } else { + // Mark now + CalledF->setSection(StringMark); + } + + // Before going any further mark all the called function by current + // function. + markCallGraph(cgn_it->second ,StringMark); + } // end of loop of all called functions. +} + + +// For PIC16, automatic variables of a function are emitted as globals. +// Clone the auto variables of a function and put them in VMap, +// this VMap will be used while +// Cloning the code of function itself. +// +void PIC16Cloner::CloneAutos(Function *F) { + // We'll need to update module's globals list as well. So keep a reference + // handy. + Module *M = F->getParent(); + Module::GlobalListType &Globals = M->getGlobalList(); + + // Clear the leftovers in VMap by any previous cloning. + VMap.clear(); + + // Find the auto globls for this function and clone them, and put them + // in VMap. + std::string FnName = F->getName().str(); + std::string VarName, ClonedVarName; + for (Module::global_iterator I = M->global_begin(), E = M->global_end(); + I != E; ++I) { + VarName = I->getName().str(); + if (PAN::isLocalToFunc(FnName, VarName)) { + // Auto variable for current function found. Clone it. + const GlobalVariable *GV = I; + + const Type *InitTy = GV->getInitializer()->getType(); + GlobalVariable *ClonedGV = + new GlobalVariable(InitTy, false, GV->getLinkage(), + GV->getInitializer()); + ClonedGV->setName(PAN::getCloneVarName(FnName, VarName)); + // Add these new globals to module's globals list. + Globals.push_back(ClonedGV); + + // Update VMap. + VMap[GV] = ClonedGV; + } + } +} + + +// Clone all functions that are reachable from ISR and are already +// marked as ML. +// +void PIC16Cloner::cloneSharedFunctions(CallGraphNode *CGN) { + + // Check all the called functions from ISR. + for(CallGraphNode::iterator cgn_it = CGN->begin(); + cgn_it != CGN->end(); ++cgn_it) { + Function *CalledF = cgn_it->second->getFunction(); + + // If calling an external function then CallGraphNode + // will not be associated with any function. + if (!CalledF) + continue; + + // Issue diagnostic if interrupt function is being called. + if (PAN::isISR(CalledF->getSection())) { + vector<string> Values; + Values.push_back(CalledF->getName().str()); + reportError("Interrupt function (%0) can't be called", Values); + } + + if (CalledF->getSection().find("ML") != string::npos) { + // Function is alternatively marked. It should be a shared one. + // Create IL copy. Passing called function as first argument + // and the caller as the second argument. + + // Before making IL copy, first ensure that this function has a + // body. If the function does have a body. It can't be cloned. + // Such a case may occur when the function has been declarated + // in the C source code but its body exists in assembly file. + if (!CalledF->isDeclaration()) { + Function *cf = cloneFunction(CalledF); + remapAllSites(CGN->getFunction(), CalledF, cf); + } else { + // It is called only from ISR. Still mark it as we need this info + // in code gen while calling intrinsics.Function is not marked. + CalledF->setSection("IL"); + } + } + // Before going any further clone all the shared function reachaable + // by current function. + cloneSharedFunctions(cgn_it->second); + } // end of loop of all called functions. +} + +// Clone the given function and return it. +// Note: it uses the VMap member of the class, which is already populated +// by cloneAutos by the time we reach here. +// FIXME: Should we just pass VMap's ref as a parameter here? rather +// than keeping the VMap as a member. +Function * +PIC16Cloner::cloneFunction(Function *OrgF) { + Function *ClonedF; + + // See if we already cloned it. Return that. + cloned_map_iterator cm_it = ClonedFunctionMap.find(OrgF); + if(cm_it != ClonedFunctionMap.end()) { + ClonedF = cm_it->second; + return ClonedF; + } + + // Clone does not exist. + // First clone the autos, and populate VMap. + CloneAutos(OrgF); + + // Now create the clone. + ClonedF = CloneFunction(OrgF, VMap, /*ModuleLevelChanges=*/false); + + // The new function should be for interrupt line. Therefore should have + // the name suffixed with IL and section attribute marked with IL. + ClonedF->setName(PAN::getCloneFnName(OrgF->getName())); + ClonedF->setSection("IL"); + + // Add the newly created function to the module. + OrgF->getParent()->getFunctionList().push_back(ClonedF); + + // Update the ClonedFunctionMap to record this cloning activity. + ClonedFunctionMap[OrgF] = ClonedF; + + return ClonedF; +} + + +// Remap the call sites of shared functions, that are in IL. +// Change the IL call site of a shared function to its clone. +// +void PIC16Cloner:: +remapAllSites(Function *Caller, Function *OrgF, Function *Clone) { + // First find the caller to update. If the caller itself is cloned + // then use the cloned caller. Otherwise use it. + cloned_map_iterator cm_it = ClonedFunctionMap.find(Caller); + if (cm_it != ClonedFunctionMap.end()) + Caller = cm_it->second; + + // For the lack of a better call site finding mechanism, iterate over + // all insns to find the uses of original fn. + for (Function::iterator BI = Caller->begin(); BI != Caller->end(); ++BI) { + BasicBlock &BB = *BI; + for (BasicBlock::iterator II = BB.begin(); II != BB.end(); ++II) { + if (II->getNumOperands() > 0 && II->getOperand(0) == OrgF) + II->setOperand(0, Clone); + } + } +} + + + diff --git a/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Cloner.h b/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Cloner.h new file mode 100644 index 0000000..e7d67ce --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Cloner.h @@ -0,0 +1,83 @@ +//===-- PIC16Cloner.h - PIC16 LLVM Cloner for shared functions --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains declaration of a cloner class clone all functions that +// are shared between the main line code (ML) and interrupt line code (IL). +// +//===----------------------------------------------------------------------===// + +#ifndef PIC16CLONER_H +#define PIC16CLONER_H + +#include "llvm/ADT/ValueMap.h" + +using namespace llvm; +using std::vector; +using std::string; +using std::map; + +namespace llvm { + // forward classes. + class Value; + class Function; + class Module; + class ModulePass; + class CallGraph; + class CallGraphNode; + class AnalysisUsage; + + class PIC16Cloner : public ModulePass { + public: + static char ID; // Class identification + PIC16Cloner() : ModulePass(ID) {} + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired<CallGraph>(); + } + virtual bool runOnModule(Module &M); + + private: // Functions + // Mark reachable functions for the MainLine or InterruptLine. + void markCallGraph(CallGraphNode *CGN, string StringMark); + + // Clone auto variables of function specified. + void CloneAutos(Function *F); + + // Clone the body of a function. + Function *cloneFunction(Function *F); + + // Clone all shared functions. + void cloneSharedFunctions(CallGraphNode *isrCGN); + + // Remap all call sites to the shared function. + void remapAllSites(Function *Caller, Function *OrgF, Function *Clone); + + // Error reporting for PIC16Pass + void reportError(string ErrorString, vector<string> &Values); + void reportError(string ErrorString); + + private: //data + // Records if the interrupt function has already been found. + // If more than one interrupt function is found then an error + // should be thrown. + bool foundISR; + + // This ValueMap maps the auto variables of the original functions with + // the corresponding cloned auto variable of the cloned function. + // This value map is passed during the function cloning so that all the + // uses of auto variables be updated properly. + ValueMap<const Value*, Value*> VMap; + + // Map of a already cloned functions. + map<Function *, Function *> ClonedFunctionMap; + typedef map<Function *, Function *>::iterator cloned_map_iterator; + }; +} // End of anonymous namespace + +#endif diff --git a/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp b/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp new file mode 100644 index 0000000..0f8928a --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp @@ -0,0 +1,182 @@ +//===-- PIC16Overlay.cpp - Implementation for PIC16 Frame Overlay===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the PIC16 Frame Overlay implementation. +// +//===----------------------------------------------------------------------===// + + +#include "llvm/Analysis/CallGraph.h" +#include "llvm/Pass.h" +#include "llvm/Module.h" +#include "llvm/Instructions.h" +#include "llvm/Value.h" +#include "PIC16Overlay.h" +#include "llvm/Function.h" +#include <cstdlib> +#include <sstream> +using namespace llvm; + +namespace llvm { + char PIC16Overlay::ID = 0; + ModulePass *createPIC16OverlayPass() { return new PIC16Overlay(); } +} + +void PIC16Overlay::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired<CallGraph>(); +} + +void PIC16Overlay::DFSTraverse(CallGraphNode *CGN, unsigned Depth) { + // Do not set any color for external calling node. + if (Depth != 0 && CGN->getFunction()) { + unsigned Color = getColor(CGN->getFunction()); + + // Handle indirectly called functions + if (Color >= PIC16OVERLAY::StartIndirectCallColor || + Depth >= PIC16OVERLAY::StartIndirectCallColor) { + // All functions called from an indirectly called function are given + // an unique color. + if (Color < PIC16OVERLAY::StartIndirectCallColor && + Depth >= PIC16OVERLAY::StartIndirectCallColor) + setColor(CGN->getFunction(), Depth); + + for (unsigned int i = 0; i < CGN->size(); i++) + DFSTraverse((*CGN)[i], ++IndirectCallColor); + return; + } + // Just return if the node already has a color greater than the current + // depth. A node must be colored with the maximum depth that it has. + if (Color >= Depth) + return; + + Depth = ModifyDepthForInterrupt(CGN, Depth); + setColor(CGN->getFunction(), Depth); + } + + // Color all children of this node with color depth+1. + for (unsigned int i = 0; i < CGN->size(); i++) + DFSTraverse((*CGN)[i], Depth+1); +} + +unsigned PIC16Overlay::ModifyDepthForInterrupt(CallGraphNode *CGN, + unsigned Depth) { + Function *Fn = CGN->getFunction(); + + // Return original Depth if function or section for function do not exist. + if (!Fn || !Fn->hasSection()) + return Depth; + + // Return original Depth if this function is not marked as interrupt. + if (Fn->getSection().find("interrupt") == string::npos) + return Depth; + + Depth = Depth + InterruptDepth; + return Depth; +} + +void PIC16Overlay::setColor(Function *Fn, unsigned Color) { + std::string Section = ""; + if (Fn->hasSection()) + Section = Fn->getSection(); + + size_t Pos = Section.find(OverlayStr); + + // Convert Color to string. + std::stringstream ss; + ss << Color; + std::string ColorString = ss.str(); + + // If color is already set then reset it with the new value. Else append + // the Color string to section. + if (Pos != std::string::npos) { + Pos += OverlayStr.length(); + char c = Section.at(Pos); + unsigned OldColorLength = 0; + while (c >= '0' && c<= '9') { + OldColorLength++; + if (Pos < Section.length() - 1) + Pos++; + else + break; + c = Section.at(Pos); + } + // Replace old color with new one. + Section.replace(Pos-OldColorLength +1, OldColorLength, ColorString); + } + else { + // Append Color information to section string. + if (Fn->hasSection()) + Section.append(" "); + Section.append(OverlayStr + ColorString); + } + Fn->setSection(Section); +} + +unsigned PIC16Overlay::getColor(Function *Fn) { + int Color = 0; + if (!Fn->hasSection()) + return 0; + + std::string Section = Fn->getSection(); + size_t Pos = Section.find(OverlayStr); + + // Return 0 if Color is not set. + if (Pos == std::string::npos) + return 0; + + // Set Pos to after "Overlay=". + Pos += OverlayStr.length(); + char c = Section.at(Pos); + std::string ColorString = ""; + + // Find the string representing Color. A Color can only consist of digits. + while (c >= '0' && c<= '9') { + ColorString.append(1,c); + if (Pos < Section.length() - 1) + Pos++; + else + break; + c = Section.at(Pos); + } + Color = atoi(ColorString.c_str()); + + return Color; +} + +bool PIC16Overlay::runOnModule(Module &M) { + CallGraph &CG = getAnalysis<CallGraph>(); + CallGraphNode *ECN = CG.getExternalCallingNode(); + + MarkIndirectlyCalledFunctions(M); + // Since External Calling Node is the base function, do a depth first + // traversal of CallGraph with ECN as root. Each node with be marked with + // a color that is max(color(callers)) + 1. + if(ECN) { + DFSTraverse(ECN, 0); + } + return false; +} + +void PIC16Overlay::MarkIndirectlyCalledFunctions(Module &M) { + // If the use of a function is not a call instruction then this + // function might be called indirectly. In that case give it + // an unique color. + for (Module::iterator MI = M.begin(), E = M.end(); MI != E; ++MI) { + for (Value::use_iterator I = MI->use_begin(), E = MI->use_end(); I != E; + ++I) { + User *U = *I; + if ((!isa<CallInst>(U) && !isa<InvokeInst>(U)) + || !CallSite(cast<Instruction>(U)).isCallee(I)) { + setColor(MI, ++IndirectCallColor); + break; + } + } + } +} diff --git a/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Overlay.h b/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Overlay.h new file mode 100644 index 0000000..2f611e6 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16Passes/PIC16Overlay.h @@ -0,0 +1,60 @@ +//===-- PIC16Overlay.h - Interface for PIC16 Frame Overlay -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the PIC16 Overlay infrastructure. +// +//===----------------------------------------------------------------------===// + +#ifndef PIC16FRAMEOVERLAY_H +#define PIC16FRAMEOVERLAY_H + + +using std::string; +using namespace llvm; + +namespace llvm { + // Forward declarations. + class Function; + class Module; + class ModulePass; + class AnalysisUsage; + class CallGraphNode; + class CallGraph; + + namespace PIC16OVERLAY { + enum OverlayConsts { + StartInterruptColor = 200, + StartIndirectCallColor = 300 + }; + } + class PIC16Overlay : public ModulePass { + std::string OverlayStr; + unsigned InterruptDepth; + unsigned IndirectCallColor; + public: + static char ID; // Class identification + PIC16Overlay() : ModulePass(ID) { + OverlayStr = "Overlay="; + InterruptDepth = PIC16OVERLAY::StartInterruptColor; + IndirectCallColor = PIC16OVERLAY::StartIndirectCallColor; + } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const; + virtual bool runOnModule(Module &M); + + private: + unsigned getColor(Function *Fn); + void setColor(Function *Fn, unsigned Color); + unsigned ModifyDepthForInterrupt(CallGraphNode *CGN, unsigned Depth); + void MarkIndirectlyCalledFunctions(Module &M); + void DFSTraverse(CallGraphNode *CGN, unsigned Depth); + }; +} // End of namespace + +#endif diff --git a/contrib/llvm/lib/Target/PIC16/PIC16RegisterInfo.cpp b/contrib/llvm/lib/Target/PIC16/PIC16RegisterInfo.cpp new file mode 100644 index 0000000..76de47f --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16RegisterInfo.cpp @@ -0,0 +1,84 @@ +//===- PIC16RegisterInfo.cpp - PIC16 Register Information -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the PIC16 implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "pic16-reg-info" + +#include "PIC16.h" +#include "PIC16RegisterInfo.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +PIC16RegisterInfo::PIC16RegisterInfo(const TargetInstrInfo &tii, + const PIC16Subtarget &st) + : PIC16GenRegisterInfo(PIC16::ADJCALLSTACKDOWN, PIC16::ADJCALLSTACKUP), + TII(tii), + ST(st) {} + +#include "PIC16GenRegisterInfo.inc" + +/// PIC16 Callee Saved Registers +const unsigned* PIC16RegisterInfo:: +getCalleeSavedRegs(const MachineFunction *MF) const { + static const unsigned CalleeSavedRegs[] = { 0 }; + return CalleeSavedRegs; +} + +BitVector PIC16RegisterInfo::getReservedRegs(const MachineFunction &MF) const { + BitVector Reserved(getNumRegs()); + return Reserved; +} + +bool PIC16RegisterInfo::hasFP(const MachineFunction &MF) const { + return false; +} + +void PIC16RegisterInfo:: +eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, + RegScavenger *RS) const +{ /* NOT YET IMPLEMENTED */ } + +void PIC16RegisterInfo::emitPrologue(MachineFunction &MF) const +{ /* NOT YET IMPLEMENTED */ } + +void PIC16RegisterInfo:: +emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const +{ /* NOT YET IMPLEMENTED */ } + +int PIC16RegisterInfo:: +getDwarfRegNum(unsigned RegNum, bool isEH) const { + llvm_unreachable("Not keeping track of debug information yet!!"); + return -1; +} + +unsigned PIC16RegisterInfo::getFrameRegister(const MachineFunction &MF) const { + llvm_unreachable("PIC16 Does not have any frame register"); + return 0; +} + +unsigned PIC16RegisterInfo::getRARegister() const { + llvm_unreachable("PIC16 Does not have any return address register"); + return 0; +} + +// This function eliminates ADJCALLSTACKDOWN, +// ADJCALLSTACKUP pseudo instructions +void PIC16RegisterInfo:: +eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + // Simply discard ADJCALLSTACKDOWN, + // ADJCALLSTACKUP instructions. + MBB.erase(I); +} + diff --git a/contrib/llvm/lib/Target/PIC16/PIC16RegisterInfo.h b/contrib/llvm/lib/Target/PIC16/PIC16RegisterInfo.h new file mode 100644 index 0000000..20052b0 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16RegisterInfo.h @@ -0,0 +1,64 @@ +//===- PIC16RegisterInfo.h - PIC16 Register Information Impl ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the PIC16 implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef PIC16REGISTERINFO_H +#define PIC16REGISTERINFO_H + +#include "PIC16GenRegisterInfo.h.inc" +#include "llvm/Target/TargetRegisterInfo.h" + +namespace llvm { + +// Forward Declarations. + class PIC16Subtarget; + class TargetInstrInfo; + +class PIC16RegisterInfo : public PIC16GenRegisterInfo { + private: + const TargetInstrInfo &TII; + const PIC16Subtarget &ST; + + public: + PIC16RegisterInfo(const TargetInstrInfo &tii, + const PIC16Subtarget &st); + + + //------------------------------------------------------ + // Pure virtual functions from TargetRegisterInfo + //------------------------------------------------------ + + // PIC16 callee saved registers + virtual const unsigned* + getCalleeSavedRegs(const MachineFunction *MF = 0) const; + + virtual BitVector getReservedRegs(const MachineFunction &MF) const; + virtual bool hasFP(const MachineFunction &MF) const; + + virtual void eliminateFrameIndex(MachineBasicBlock::iterator MI, + int SPAdj, RegScavenger *RS=NULL) const; + + void eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + virtual void emitPrologue(MachineFunction &MF) const; + virtual void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; + virtual int getDwarfRegNum(unsigned RegNum, bool isEH) const; + virtual unsigned getFrameRegister(const MachineFunction &MF) const; + virtual unsigned getRARegister() const; + +}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/PIC16/PIC16RegisterInfo.td b/contrib/llvm/lib/Target/PIC16/PIC16RegisterInfo.td new file mode 100644 index 0000000..2959d91 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16RegisterInfo.td @@ -0,0 +1,33 @@ +//===- PIC16RegisterInfo.td - PIC16 Register defs ------------*- tblgen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Declarations that describe the PIC16 register file +//===----------------------------------------------------------------------===// + +class PIC16Reg<string n> : Register<n> { + let Namespace = "PIC16"; +} + +// PIC16 Registers. +def W : PIC16Reg<"W">; +def FSR0 : PIC16Reg<"FSR0">; +def FSR1 : PIC16Reg<"FSR1">; +def BS : PIC16Reg<"BS">; +def PCLATH : PIC16Reg<"PCLATH">; + +def STATUS : PIC16Reg<"STATUS">; + +// PIC16 Register classes. +def GPR : RegisterClass<"PIC16", [i8], 8, [W]>; +def FSR16 : RegisterClass<"PIC16", [i16], 8, [FSR0, FSR1]>; +def BSR : RegisterClass<"PIC16", [i8], 8, [BS]>; +def PCLATHR : RegisterClass<"PIC16", [i8], 8, [PCLATH]>; +def STATUSR : RegisterClass<"PIC16", [i8], 8, [STATUS]>; + diff --git a/contrib/llvm/lib/Target/PIC16/PIC16Section.cpp b/contrib/llvm/lib/Target/PIC16/PIC16Section.cpp new file mode 100644 index 0000000..2505b11 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16Section.cpp @@ -0,0 +1,104 @@ +//===-- PIC16Section.cpp - PIC16 Section ----------- --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PIC16.h" +#include "PIC16ABINames.h" +#include "PIC16Section.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + + +// This is the only way to create a PIC16Section. Sections created here +// do not need to be explicitly deleted as they are managed by auto_ptrs. +PIC16Section *PIC16Section::Create(StringRef Name, PIC16SectionType Ty, + StringRef Address, int Color, + MCContext &Ctx) { + + /// Determine the internal SectionKind info. + /// Users of PIC16Section class should not need to know the internal + /// SectionKind. They should work only with PIC16SectionType. + /// + /// PIC16 Terminology for section kinds is as below. + /// UDATA - BSS + /// IDATA - initialized data (equiv to Metadata) + /// ROMDATA - ReadOnly. + /// UDATA_OVR - Sections that can be overlaid. Section of such type is + /// used to contain function autos an frame. We can think of + /// it as equiv to llvm ThreadBSS) + /// UDATA_SHR - Shared RAM. Memory area that is mapped to all banks. + + SectionKind K; + switch (Ty) { + default: llvm_unreachable ("can not create unknown section type"); + case UDATA_OVR: { + K = SectionKind::getThreadBSS(); + break; + } + case UDATA_SHR: + case UDATA: { + K = SectionKind::getBSS(); + break; + } + case ROMDATA: + case IDATA: { + K = SectionKind::getMetadata(); + break; + } + case CODE: { + K = SectionKind::getText(); + break; + } + + } + + // Copy strings into context allocated memory so they get free'd when the + // context is destroyed. + char *NameCopy = static_cast<char*>(Ctx.Allocate(Name.size(), 1)); + memcpy(NameCopy, Name.data(), Name.size()); + char *AddressCopy = static_cast<char*>(Ctx.Allocate(Address.size(), 1)); + memcpy(AddressCopy, Address.data(), Address.size()); + + // Create the Section. + PIC16Section *S = + new (Ctx) PIC16Section(StringRef(NameCopy, Name.size()), K, + StringRef(AddressCopy, Address.size()), Color); + S->T = Ty; + return S; +} + +// A generic way to print all types of sections. +void PIC16Section::PrintSwitchToSection(const MCAsmInfo &MAI, + raw_ostream &OS) const { + + // If the section is overlaid(i.e. it has a color), print overlay name for + // it. Otherwise print its normal name. + if (Color != -1) + OS << PAN::getOverlayName(getName(), Color) << '\t'; + else + OS << getName() << '\t'; + + // Print type. + switch (getType()) { + default : llvm_unreachable ("unknown section type"); + case UDATA: OS << "UDATA"; break; + case IDATA: OS << "IDATA"; break; + case ROMDATA: OS << "ROMDATA"; break; + case UDATA_SHR: OS << "UDATA_SHR"; break; + case UDATA_OVR: OS << "UDATA_OVR"; break; + case CODE: OS << "CODE"; break; + } + + OS << '\t'; + + // Print Address. + OS << Address; + + OS << '\n'; +} diff --git a/contrib/llvm/lib/Target/PIC16/PIC16Section.h b/contrib/llvm/lib/Target/PIC16/PIC16Section.h new file mode 100644 index 0000000..5b33b51 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16Section.h @@ -0,0 +1,99 @@ +//===- PIC16Section.h - PIC16-specific section representation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the PIC16Section class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PIC16SECTION_H +#define LLVM_PIC16SECTION_H + +#include "llvm/MC/MCSection.h" +#include "llvm/GlobalVariable.h" +#include <vector> + +namespace llvm { + /// PIC16Section - Represents a physical section in PIC16 COFF. + /// Contains data objects. + /// + class PIC16Section : public MCSection { + /// PIC16 Sections does not really use the SectionKind class to + /// to distinguish between various types of sections. PIC16 maintain + /// its own Section Type info. See the PIC16SectionType enum in PIC16.h + /// for various section types. + PIC16SectionType T; + + /// Name of the section to uniquely identify it. + StringRef Name; + + /// User can specify an address at which a section should be placed. + /// Negative value here means user hasn't specified any. + StringRef Address; + + /// Overlay information - Sections with same color can be overlaid on + /// one another. + int Color; + + /// Total size of all data objects contained here. + unsigned Size; + + PIC16Section(StringRef name, SectionKind K, StringRef addr, int color) + : MCSection(SV_PIC16, K), Name(name), Address(addr), + Color(color), Size(0) { + } + + public: + /// Return the name of the section. + StringRef getName() const { return Name; } + + /// Return the Address of the section. + StringRef getAddress() const { return Address; } + + /// Return the Color of the section. + int getColor() const { return Color; } + void setColor(int color) { Color = color; } + + /// Return the size of the section. + unsigned getSize() const { return Size; } + void setSize(unsigned size) { Size = size; } + + /// Conatined data objects. + // FIXME: This vector is leaked because sections are allocated with a + // BumpPtrAllocator. + std::vector<const GlobalVariable *>Items; + + /// Check section type. + bool isUDATA_Type() const { return T == UDATA; } + bool isIDATA_Type() const { return T == IDATA; } + bool isROMDATA_Type() const { return T == ROMDATA; } + bool isUDATA_OVR_Type() const { return T == UDATA_OVR; } + bool isUDATA_SHR_Type() const { return T == UDATA_SHR; } + bool isCODE_Type() const { return T == CODE; } + + PIC16SectionType getType() const { return T; } + + /// This would be the only way to create a section. + static PIC16Section *Create(StringRef Name, PIC16SectionType Ty, + StringRef Address, int Color, + MCContext &Ctx); + + /// Override this as PIC16 has its own way of printing switching + /// to a section. + virtual void PrintSwitchToSection(const MCAsmInfo &MAI, + raw_ostream &OS) const; + + static bool classof(const MCSection *S) { + return S->getVariant() == SV_PIC16; + } + static bool classof(const PIC16Section *) { return true; } + }; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/PIC16/PIC16SelectionDAGInfo.cpp b/contrib/llvm/lib/Target/PIC16/PIC16SelectionDAGInfo.cpp new file mode 100644 index 0000000..995955a --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16SelectionDAGInfo.cpp @@ -0,0 +1,23 @@ +//===-- PIC16SelectionDAGInfo.cpp - PIC16 SelectionDAG Info ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the PIC16SelectionDAGInfo class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "pic16-selectiondag-info" +#include "PIC16TargetMachine.h" +using namespace llvm; + +PIC16SelectionDAGInfo::PIC16SelectionDAGInfo(const PIC16TargetMachine &TM) + : TargetSelectionDAGInfo(TM) { +} + +PIC16SelectionDAGInfo::~PIC16SelectionDAGInfo() { +} diff --git a/contrib/llvm/lib/Target/PIC16/PIC16SelectionDAGInfo.h b/contrib/llvm/lib/Target/PIC16/PIC16SelectionDAGInfo.h new file mode 100644 index 0000000..c67fd8b --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16SelectionDAGInfo.h @@ -0,0 +1,31 @@ +//===-- PIC16SelectionDAGInfo.h - PIC16 SelectionDAG Info -------*- C++ -*-===// +// +// 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 PIC16 subclass for TargetSelectionDAGInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef PIC16SELECTIONDAGINFO_H +#define PIC16SELECTIONDAGINFO_H + +#include "llvm/Target/TargetSelectionDAGInfo.h" + +namespace llvm { + +class PIC16TargetMachine; + +class PIC16SelectionDAGInfo : public TargetSelectionDAGInfo { +public: + explicit PIC16SelectionDAGInfo(const PIC16TargetMachine &TM); + ~PIC16SelectionDAGInfo(); +}; + +} + +#endif diff --git a/contrib/llvm/lib/Target/PIC16/PIC16Subtarget.cpp b/contrib/llvm/lib/Target/PIC16/PIC16Subtarget.cpp new file mode 100644 index 0000000..33fc3fb --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16Subtarget.cpp @@ -0,0 +1,27 @@ +//===- PIC16Subtarget.cpp - PIC16 Subtarget Information -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the PIC16 specific subclass of TargetSubtarget. +// +//===----------------------------------------------------------------------===// + +#include "PIC16Subtarget.h" +#include "PIC16GenSubtarget.inc" + +using namespace llvm; + +PIC16Subtarget::PIC16Subtarget(const std::string &TT, const std::string &FS, + bool Cooper) + :IsCooper(Cooper) +{ + std::string CPU = "generic"; + + // Parse features string. + ParseSubtargetFeatures(FS, CPU); +} diff --git a/contrib/llvm/lib/Target/PIC16/PIC16Subtarget.h b/contrib/llvm/lib/Target/PIC16/PIC16Subtarget.h new file mode 100644 index 0000000..81e3783 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16Subtarget.h @@ -0,0 +1,44 @@ +//=====-- PIC16Subtarget.h - Define Subtarget for the PIC16 ---*- C++ -*--====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the PIC16 specific subclass of TargetSubtarget. +// +//===----------------------------------------------------------------------===// + +#ifndef PIC16SUBTARGET_H +#define PIC16SUBTARGET_H + +#include "llvm/Target/TargetSubtarget.h" + +#include <string> + +namespace llvm { + +class PIC16Subtarget : public TargetSubtarget { + + // IsCooper - Target ISA is Cooper. + bool IsCooper; + +public: + /// This constructor initializes the data members to match that + /// of the specified triple. + /// + PIC16Subtarget(const std::string &TT, const std::string &FS, bool Cooper); + + /// isCooper - Returns true if the target ISA is Cooper. + bool isCooper() const { return IsCooper; } + + /// ParseSubtargetFeatures - Parses features string setting specified + /// subtarget options. Definition of function is auto generated by tblgen. + std::string ParseSubtargetFeatures(const std::string &FS, + const std::string &CPU); +}; +} // End llvm namespace + +#endif // PIC16SUBTARGET_H diff --git a/contrib/llvm/lib/Target/PIC16/PIC16TargetMachine.cpp b/contrib/llvm/lib/Target/PIC16/PIC16TargetMachine.cpp new file mode 100644 index 0000000..82b69be --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16TargetMachine.cpp @@ -0,0 +1,55 @@ +//===-- PIC16TargetMachine.cpp - Define TargetMachine for PIC16 -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Top-level implementation for the PIC16 target. +// +//===----------------------------------------------------------------------===// + +#include "PIC16.h" +#include "PIC16MCAsmInfo.h" +#include "PIC16TargetMachine.h" +#include "llvm/PassManager.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Target/TargetRegistry.h" + +using namespace llvm; + +extern "C" void LLVMInitializePIC16Target() { + // Register the target. Curretnly the codegen works for + // enhanced pic16 mid-range. + RegisterTargetMachine<PIC16TargetMachine> X(ThePIC16Target); + RegisterAsmInfo<PIC16MCAsmInfo> A(ThePIC16Target); +} + + +// PIC16TargetMachine - Enhanced PIC16 mid-range Machine. May also represent +// a Traditional Machine if 'Trad' is true. +PIC16TargetMachine::PIC16TargetMachine(const Target &T, const std::string &TT, + const std::string &FS, bool Trad) +: LLVMTargetMachine(T, TT), + Subtarget(TT, FS, Trad), + DataLayout("e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-n8"), + InstrInfo(*this), TLInfo(*this), TSInfo(*this), + FrameInfo(TargetFrameInfo::StackGrowsUp, 8, 0) { } + + +bool PIC16TargetMachine::addInstSelector(PassManagerBase &PM, + CodeGenOpt::Level OptLevel) { + // Install an instruction selector. + PM.add(createPIC16ISelDag(*this)); + return false; +} + +bool PIC16TargetMachine::addPreEmitPass(PassManagerBase &PM, + CodeGenOpt::Level OptLevel) { + PM.add(createPIC16MemSelOptimizerPass()); + return true; // -print-machineinstr should print after this. +} + + diff --git a/contrib/llvm/lib/Target/PIC16/PIC16TargetMachine.h b/contrib/llvm/lib/Target/PIC16/PIC16TargetMachine.h new file mode 100644 index 0000000..dae5d31 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16TargetMachine.h @@ -0,0 +1,70 @@ +//===-- PIC16TargetMachine.h - Define TargetMachine for PIC16 ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the PIC16 specific subclass of TargetMachine. +// +//===----------------------------------------------------------------------===// + + +#ifndef PIC16_TARGETMACHINE_H +#define PIC16_TARGETMACHINE_H + +#include "PIC16InstrInfo.h" +#include "PIC16ISelLowering.h" +#include "PIC16SelectionDAGInfo.h" +#include "PIC16RegisterInfo.h" +#include "PIC16Subtarget.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + +/// PIC16TargetMachine +/// +class PIC16TargetMachine : public LLVMTargetMachine { + PIC16Subtarget Subtarget; + const TargetData DataLayout; // Calculates type size & alignment + PIC16InstrInfo InstrInfo; + PIC16TargetLowering TLInfo; + PIC16SelectionDAGInfo TSInfo; + + // PIC16 does not have any call stack frame, therefore not having + // any PIC16 specific FrameInfo class. + TargetFrameInfo FrameInfo; + +public: + PIC16TargetMachine(const Target &T, const std::string &TT, + const std::string &FS, bool Cooper = false); + + virtual const TargetFrameInfo *getFrameInfo() const { return &FrameInfo; } + virtual const PIC16InstrInfo *getInstrInfo() const { return &InstrInfo; } + virtual const TargetData *getTargetData() const { return &DataLayout;} + virtual const PIC16Subtarget *getSubtargetImpl() const { return &Subtarget; } + + virtual const PIC16RegisterInfo *getRegisterInfo() const { + return &(InstrInfo.getRegisterInfo()); + } + + virtual const PIC16TargetLowering *getTargetLowering() const { + return &TLInfo; + } + + virtual const PIC16SelectionDAGInfo* getSelectionDAGInfo() const { + return &TSInfo; + } + + virtual bool addInstSelector(PassManagerBase &PM, + CodeGenOpt::Level OptLevel); + virtual bool addPreEmitPass(PassManagerBase &PM, CodeGenOpt::Level OptLevel); +}; // PIC16TargetMachine. + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/PIC16/PIC16TargetObjectFile.cpp b/contrib/llvm/lib/Target/PIC16/PIC16TargetObjectFile.cpp new file mode 100644 index 0000000..ff0f971 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16TargetObjectFile.cpp @@ -0,0 +1,384 @@ +//===-- PIC16TargetObjectFile.cpp - PIC16 object files --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PIC16TargetObjectFile.h" +#include "PIC16TargetMachine.h" +#include "PIC16Section.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Module.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + + +PIC16TargetObjectFile::PIC16TargetObjectFile() { +} + +PIC16TargetObjectFile::~PIC16TargetObjectFile() { +} + +/// Find a pic16 section. Return null if not found. Do not create one. +PIC16Section *PIC16TargetObjectFile:: +findPIC16Section(const std::string &Name) const { + /// Return if we have an already existing one. + PIC16Section *Entry = SectionsByName[Name]; + if (Entry) + return Entry; + + return NULL; +} + + +/// Find a pic16 section. If not found, create one. +PIC16Section *PIC16TargetObjectFile:: +getPIC16Section(const std::string &Name, PIC16SectionType Ty, + const std::string &Address, int Color) const { + + /// Return if we have an already existing one. + PIC16Section *&Entry = SectionsByName[Name]; + if (Entry) + return Entry; + + + Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext()); + return Entry; +} + +/// Find a standard pic16 data section. If not found, create one and keep +/// track of it by adding it to appropriate std section list. +PIC16Section *PIC16TargetObjectFile:: +getPIC16DataSection(const std::string &Name, PIC16SectionType Ty, + const std::string &Address, int Color) const { + + /// Return if we have an already existing one. + PIC16Section *&Entry = SectionsByName[Name]; + if (Entry) + return Entry; + + + /// Else create a new one and add it to appropriate section list. + Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext()); + + switch (Ty) { + default: llvm_unreachable ("unknow standard section type."); + case UDATA: UDATASections_.push_back(Entry); break; + case IDATA: IDATASections_.push_back(Entry); break; + case ROMDATA: ROMDATASection_ = Entry; break; + case UDATA_SHR: SHAREDUDATASection_ = Entry; break; + } + + return Entry; +} + + +/// Find a standard pic16 autos section. If not found, create one and keep +/// track of it by adding it to appropriate std section list. +PIC16Section *PIC16TargetObjectFile:: +getPIC16AutoSection(const std::string &Name, PIC16SectionType Ty, + const std::string &Address, int Color) const { + + /// Return if we have an already existing one. + PIC16Section *&Entry = SectionsByName[Name]; + if (Entry) + return Entry; + + + /// Else create a new one and add it to appropriate section list. + Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext()); + + assert (Ty == UDATA_OVR && "incorrect section type for autos"); + AUTOSections_.push_back(Entry); + + return Entry; +} + +/// Find a pic16 user section. If not found, create one and keep +/// track of it by adding it to appropriate std section list. +PIC16Section *PIC16TargetObjectFile:: +getPIC16UserSection(const std::string &Name, PIC16SectionType Ty, + const std::string &Address, int Color) const { + + /// Return if we have an already existing one. + PIC16Section *&Entry = SectionsByName[Name]; + if (Entry) + return Entry; + + + /// Else create a new one and add it to appropriate section list. + Entry = PIC16Section::Create(Name, Ty, Address, Color, getContext()); + + USERSections_.push_back(Entry); + + return Entry; +} + +/// Do some standard initialization. +void PIC16TargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &tm){ + TargetLoweringObjectFile::Initialize(Ctx, tm); + TM = &tm; + + ROMDATASection_ = NULL; + SHAREDUDATASection_ = NULL; +} + +/// allocateUDATA - Allocate a un-initialized global to an existing or new UDATA +/// section and return that section. +const MCSection * +PIC16TargetObjectFile::allocateUDATA(const GlobalVariable *GV) const { + assert(GV->hasInitializer() && "This global doesn't need space"); + const 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->getTypeAllocSize(Ty); + + // Go through all UDATA Sections and assign this variable + // to the first available section having enough space. + PIC16Section *Found = NULL; + for (unsigned i = 0; i < UDATASections_.size(); i++) { + if (DataBankSize - UDATASections_[i]->getSize() >= ValSize) { + Found = UDATASections_[i]; + break; + } + } + + // No UDATA section spacious enough was found. Crate a new one. + if (!Found) { + std::string name = PAN::getUdataSectionName(UDATASections_.size()); + Found = getPIC16DataSection(name.c_str(), UDATA); + } + + // Insert the GV into this UDATA section. + Found->Items.push_back(GV); + Found->setSize(Found->getSize() + ValSize); + return Found; +} + +/// allocateIDATA - allocate an initialized global into an existing +/// or new section and return that section. +const MCSection * +PIC16TargetObjectFile::allocateIDATA(const GlobalVariable *GV) const{ + assert(GV->hasInitializer() && "This global doesn't need space"); + const Constant *C = GV->getInitializer(); + assert(!C->isNullValue() && "initialized globals has zero initializer"); + assert(GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE && + "can allocate initialized RAM data only"); + + // Find how much space this global needs. + const TargetData *TD = TM->getTargetData(); + const Type *Ty = C->getType(); + unsigned ValSize = TD->getTypeAllocSize(Ty); + + // Go through all IDATA Sections and assign this variable + // to the first available section having enough space. + PIC16Section *Found = NULL; + for (unsigned i = 0; i < IDATASections_.size(); i++) { + if (DataBankSize - IDATASections_[i]->getSize() >= ValSize) { + Found = IDATASections_[i]; + break; + } + } + + // No IDATA section spacious enough was found. Crate a new one. + if (!Found) { + std::string name = PAN::getIdataSectionName(IDATASections_.size()); + Found = getPIC16DataSection(name.c_str(), IDATA); + } + + // Insert the GV into this IDATA. + Found->Items.push_back(GV); + Found->setSize(Found->getSize() + ValSize); + return Found; +} + +// Allocate a program memory variable into ROMDATA section. +const MCSection * +PIC16TargetObjectFile::allocateROMDATA(const GlobalVariable *GV) const { + + std::string name = PAN::getRomdataSectionName(); + PIC16Section *S = getPIC16DataSection(name.c_str(), ROMDATA); + + S->Items.push_back(GV); + return S; +} + +// Get the section for an automatic variable of a function. +// For PIC16 they are globals only with mangled names. +const MCSection * +PIC16TargetObjectFile::allocateAUTO(const GlobalVariable *GV) const { + + const std::string name = PAN::getSectionNameForSym(GV->getName()); + PIC16Section *S = getPIC16AutoSection(name.c_str()); + + S->Items.push_back(GV); + return S; +} + + +// Override default implementation to put the true globals into +// multiple data sections if required. +const MCSection * +PIC16TargetObjectFile::SelectSectionForGlobal(const GlobalValue *GV1, + SectionKind Kind, + Mangler *Mang, + const TargetMachine &TM) const { + // We select the section based on the initializer here, so it really + // has to be a GlobalVariable. + const GlobalVariable *GV = dyn_cast<GlobalVariable>(GV1); + if (!GV) + return TargetLoweringObjectFile::SelectSectionForGlobal(GV1, Kind, Mang,TM); + + assert(GV->hasInitializer() && "A def without initializer?"); + + // First, if this is an automatic variable for a function, get the section + // name for it and return. + std::string name = GV->getName(); + if (PAN::isLocalName(name)) + return allocateAUTO(GV); + + // See if this is an uninitialized global. + const Constant *C = GV->getInitializer(); + if (C->isNullValue()) + return allocateUDATA(GV); + + // If this is initialized data in RAM. Put it in the correct IDATA section. + if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) + return allocateIDATA(GV); + + // This is initialized data in rom, put it in the readonly section. + if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) + return allocateROMDATA(GV); + + // Else let the default implementation take care of it. + return TargetLoweringObjectFile::SelectSectionForGlobal(GV, Kind, Mang,TM); +} + + + + +/// getExplicitSectionGlobal - Allow the target to completely override +/// section assignment of a global. +const MCSection *PIC16TargetObjectFile:: +getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, + Mangler *Mang, const TargetMachine &TM) const { + assert(GV->hasSection()); + + if (const GlobalVariable *GVar = cast<GlobalVariable>(GV)) { + std::string SectName = GVar->getSection(); + // If address for a variable is specified, get the address and create + // section. + // FIXME: move this attribute checking in PAN. + std::string AddrStr = "Address="; + if (SectName.compare(0, AddrStr.length(), AddrStr) == 0) { + std::string SectAddr = SectName.substr(AddrStr.length()); + if (SectAddr.compare("NEAR") == 0) + return allocateSHARED(GVar, Mang); + else + return allocateAtGivenAddress(GVar, SectAddr); + } + + // Create the section specified with section attribute. + return allocateInGivenSection(GVar); + } + + return getPIC16DataSection(GV->getSection().c_str(), UDATA); +} + +const MCSection * +PIC16TargetObjectFile::allocateSHARED(const GlobalVariable *GV, + Mangler *Mang) const { + // Make sure that this is an uninitialized global. + assert(GV->hasInitializer() && "This global doesn't need space"); + if (!GV->getInitializer()->isNullValue()) { + // FIXME: Generate a warning in this case that near qualifier will be + // ignored. + return SelectSectionForGlobal(GV, SectionKind::getDataRel(), Mang, *TM); + } + std::string Name = PAN::getSharedUDataSectionName(); + + PIC16Section *SharedUDataSect = getPIC16DataSection(Name.c_str(), UDATA_SHR); + // Insert the GV into shared section. + SharedUDataSect->Items.push_back(GV); + return SharedUDataSect; +} + + +// Interface used by AsmPrinter to get a code section for a function. +const PIC16Section * +PIC16TargetObjectFile::SectionForCode(const std::string &FnName, + bool isISR) const { + const std::string &sec_name = PAN::getCodeSectionName(FnName); + // If it is ISR, its code section starts at a specific address. + if (isISR) + return getPIC16Section(sec_name, CODE, PAN::getISRAddr()); + return getPIC16Section(sec_name, CODE); +} + +// Interface used by AsmPrinter to get a frame section for a function. +const PIC16Section * +PIC16TargetObjectFile::SectionForFrame(const std::string &FnName) const { + const std::string &sec_name = PAN::getFrameSectionName(FnName); + return getPIC16Section(sec_name, UDATA_OVR); +} + +// Allocate a global var in existing or new section of given name. +const MCSection * +PIC16TargetObjectFile::allocateInGivenSection(const GlobalVariable *GV) const { + // Determine the type of section that we need to create. + PIC16SectionType SecTy; + + // See if this is an uninitialized global. + const Constant *C = GV->getInitializer(); + if (C->isNullValue()) + SecTy = UDATA; + // If this is initialized data in RAM. Put it in the correct IDATA section. + else if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) + SecTy = IDATA; + // This is initialized data in rom, put it in the readonly section. + else if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) + SecTy = ROMDATA; + else + llvm_unreachable ("Could not determine section type for global"); + + PIC16Section *S = getPIC16UserSection(GV->getSection().c_str(), SecTy); + S->Items.push_back(GV); + return S; +} + +// Allocate a global var in a new absolute sections at given address. +const MCSection * +PIC16TargetObjectFile::allocateAtGivenAddress(const GlobalVariable *GV, + const std::string &Addr) const { + // Determine the type of section that we need to create. + PIC16SectionType SecTy; + + // See if this is an uninitialized global. + const Constant *C = GV->getInitializer(); + if (C->isNullValue()) + SecTy = UDATA; + // If this is initialized data in RAM. Put it in the correct IDATA section. + else if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) + SecTy = IDATA; + // This is initialized data in rom, put it in the readonly section. + else if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) + SecTy = ROMDATA; + else + llvm_unreachable ("Could not determine section type for global"); + + std::string Prefix = GV->getNameStr() + "." + Addr + "."; + std::string SName = PAN::getUserSectionName(Prefix); + PIC16Section *S = getPIC16UserSection(SName.c_str(), SecTy, Addr.c_str()); + S->Items.push_back(GV); + return S; +} + + diff --git a/contrib/llvm/lib/Target/PIC16/PIC16TargetObjectFile.h b/contrib/llvm/lib/Target/PIC16/PIC16TargetObjectFile.h new file mode 100644 index 0000000..b1eb9f9 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/PIC16TargetObjectFile.h @@ -0,0 +1,168 @@ +//===-- PIC16TargetObjectFile.h - PIC16 Object Info -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_PIC16_TARGETOBJECTFILE_H +#define LLVM_TARGET_PIC16_TARGETOBJECTFILE_H + +#include "PIC16.h" +#include "PIC16ABINames.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/ADT/StringMap.h" +#include <vector> +#include <string> + +namespace llvm { + class GlobalVariable; + class Module; + class PIC16TargetMachine; + class PIC16Section; + + enum { DataBankSize = 80 }; + + /// 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. + /// + /// FIXME: MOVE ALL THIS STUFF TO PIC16Section. + /// + + /// PIC16TargetObjectFile - PIC16 Object file. Contains data and code + /// sections. + // PIC16 Object File has two types of sections. + // 1. Standard Sections + // 1.1 un-initialized global data + // 1.2 initialized global data + // 1.3 program memory data + // 1.4 local variables of functions. + // 2. User defined sections + // 2.1 Objects placed in a specific section. (By _Section() macro) + // 2.2 Objects placed at a specific address. (By _Address() macro) + class PIC16TargetObjectFile : public TargetLoweringObjectFile { + /// SectionsByName - Bindings of names to allocated sections. + mutable StringMap<PIC16Section*> SectionsByName; + + const TargetMachine *TM; + + /// Lists of sections. + /// Standard Data Sections. + mutable std::vector<PIC16Section *> UDATASections_; + mutable std::vector<PIC16Section *> IDATASections_; + mutable PIC16Section * ROMDATASection_; + mutable PIC16Section * SHAREDUDATASection_; + + /// Standard Auto Sections. + mutable std::vector<PIC16Section *> AUTOSections_; + + /// User specified sections. + mutable std::vector<PIC16Section *> USERSections_; + + + /// Find or Create a PIC16 Section, without adding it to any + /// section list. + PIC16Section *getPIC16Section(const std::string &Name, + PIC16SectionType Ty, + const std::string &Address = "", + int Color = -1) const; + + /// Convenience functions. These wrappers also take care of adding + /// the newly created section to the appropriate sections list. + + /// Find or Create PIC16 Standard Data Section. + PIC16Section *getPIC16DataSection(const std::string &Name, + PIC16SectionType Ty, + const std::string &Address = "", + int Color = -1) const; + + /// Find or Create PIC16 Standard Auto Section. + PIC16Section *getPIC16AutoSection(const std::string &Name, + PIC16SectionType Ty = UDATA_OVR, + const std::string &Address = "", + int Color = -1) const; + + /// Find or Create PIC16 Standard Auto Section. + PIC16Section *getPIC16UserSection(const std::string &Name, + PIC16SectionType Ty, + const std::string &Address = "", + int Color = -1) const; + + /// Allocate Un-initialized data to a standard UDATA section. + const MCSection *allocateUDATA(const GlobalVariable *GV) const; + + /// Allocate Initialized data to a standard IDATA section. + const MCSection *allocateIDATA(const GlobalVariable *GV) const; + + /// Allocate ROM data to the standard ROMDATA section. + const MCSection *allocateROMDATA(const GlobalVariable *GV) const; + + /// Allocate an AUTO variable to an AUTO section. + const MCSection *allocateAUTO(const GlobalVariable *GV) const; + + /// Allocate DATA in user specified section. + const MCSection *allocateInGivenSection(const GlobalVariable *GV) const; + + /// Allocate DATA at user specified address. + const MCSection *allocateAtGivenAddress(const GlobalVariable *GV, + const std::string &Addr) const; + + /// Allocate a shared variable to SHARED section. + const MCSection *allocateSHARED(const GlobalVariable *GV, + Mangler *Mang) const; + + public: + PIC16TargetObjectFile(); + ~PIC16TargetObjectFile(); + void Initialize(MCContext &Ctx, const TargetMachine &TM); + + /// Return the section with the given Name. Null if not found. + PIC16Section *findPIC16Section(const std::string &Name) const; + + /// Override section allocations for user specified sections. + virtual const MCSection * + getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, + Mangler *Mang, const TargetMachine &TM) const; + + /// Select sections for Data and Auto variables(globals). + virtual const MCSection *SelectSectionForGlobal(const GlobalValue *GV, + SectionKind Kind, + Mangler *Mang, + const TargetMachine&) const; + + + /// Return a code section for a function. + const PIC16Section *SectionForCode (const std::string &FnName, + bool isISR) const; + + /// Return a frame section for a function. + const PIC16Section *SectionForFrame (const std::string &FnName) const; + + /// Accessors for various section lists. + const std::vector<PIC16Section *> &UDATASections() const { + return UDATASections_; + } + const std::vector<PIC16Section *> &IDATASections() const { + return IDATASections_; + } + const PIC16Section *ROMDATASection() const { + return ROMDATASection_; + } + const PIC16Section *SHAREDUDATASection() const { + return SHAREDUDATASection_; + } + const std::vector<PIC16Section *> &AUTOSections() const { + return AUTOSections_; + } + const std::vector<PIC16Section *> &USERSections() const { + return USERSections_; + } + }; +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/PIC16/TargetInfo/CMakeLists.txt b/contrib/llvm/lib/Target/PIC16/TargetInfo/CMakeLists.txt new file mode 100644 index 0000000..bfc6ff4 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/TargetInfo/CMakeLists.txt @@ -0,0 +1,7 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_library(LLVMPIC16Info + PIC16TargetInfo.cpp + ) + +add_dependencies(LLVMPIC16Info PIC16Table_gen) diff --git a/contrib/llvm/lib/Target/PIC16/TargetInfo/Makefile b/contrib/llvm/lib/Target/PIC16/TargetInfo/Makefile new file mode 100644 index 0000000..76609f6 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/TargetInfo/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/PIC16/TargetInfo/Makefile ----------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../../.. +LIBRARYNAME = LLVMPIC16Info + +# Hack: we need to include 'main' target directory to grab private headers +CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/contrib/llvm/lib/Target/PIC16/TargetInfo/PIC16TargetInfo.cpp b/contrib/llvm/lib/Target/PIC16/TargetInfo/PIC16TargetInfo.cpp new file mode 100644 index 0000000..f1bdb12 --- /dev/null +++ b/contrib/llvm/lib/Target/PIC16/TargetInfo/PIC16TargetInfo.cpp @@ -0,0 +1,22 @@ +//===-- PIC16TargetInfo.cpp - PIC16 Target Implementation -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PIC16.h" +#include "llvm/Module.h" +#include "llvm/Target/TargetRegistry.h" +using namespace llvm; + +Target llvm::ThePIC16Target, llvm::TheCooperTarget; + +extern "C" void LLVMInitializePIC16TargetInfo() { + RegisterTarget<Triple::pic16> X(ThePIC16Target, "pic16", + "PIC16 14-bit [experimental]"); + + RegisterTarget<> Y(TheCooperTarget, "cooper", "PIC16 Cooper [experimental]"); +} |