diff options
Diffstat (limited to 'lib/Target/PIC16')
26 files changed, 5216 insertions, 0 deletions
diff --git a/lib/Target/PIC16/CMakeLists.txt b/lib/Target/PIC16/CMakeLists.txt new file mode 100644 index 0000000000000..00d737af4c2ef --- /dev/null +++ b/lib/Target/PIC16/CMakeLists.txt @@ -0,0 +1,24 @@ +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(PIC16 + PIC16AsmPrinter.cpp + PIC16DebugInfo.cpp + PIC16InstrInfo.cpp + PIC16ISelDAGToDAG.cpp + PIC16ISelLowering.cpp + PIC16MemSelOpt.cpp + PIC16RegisterInfo.cpp + PIC16Subtarget.cpp + PIC16TargetAsmInfo.cpp + PIC16TargetMachine.cpp + ) diff --git a/lib/Target/PIC16/Makefile b/lib/Target/PIC16/Makefile new file mode 100644 index 0000000000000..c429324cc2d13 --- /dev/null +++ b/lib/Target/PIC16/Makefile @@ -0,0 +1,21 @@ +##===- 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 = LLVMPIC16 +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 + +include $(LEVEL)/Makefile.common + diff --git a/lib/Target/PIC16/PIC16.h b/lib/Target/PIC16/PIC16.h new file mode 100644 index 0000000000000..40bed2f50e102 --- /dev/null +++ b/lib/Target/PIC16/PIC16.h @@ -0,0 +1,345 @@ +//===-- 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/Target/TargetMachine.h" +#include <iosfwd> +#include <cassert> +#include <sstream> +#include <cstring> +#include <string> + +namespace llvm { + class PIC16TargetMachine; + class FunctionPass; + class MachineCodeEmitter; + class raw_ostream; + +namespace PIC16CC { + enum CondCodes { + EQ, + NE, + LT, + LE, + GT, + GE, + ULT, + UGT, + ULE, + UGE + }; +} + // 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 + // ------------------------------------------------------- + // 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>.# + // Function frame - @<func>.frame_section. + // Function autos - @<func>.autos_section. + // Declarations - @section.0 + //---------------------------------------------------------- + + // 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 + }; + + // 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."; + } + } + + // 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"); + } + + // 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; + } + + static std::string getRetvalLabel(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(RET_LABEL); + return Func1 + tag; + } + + static std::string getArgsLabel(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(ARGS_LABEL); + return Func1 + tag; + } + + 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 + "# UDATA_OVR"; + } + + static std::string getAutosSectionName(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(AUTOS_SECTION); + return Func1 + tag + "# UDATA_OVR"; + } + + static std::string getCodeSectionName(const std::string &Func) { + std::string Func1 = addPrefix(Func); + std::string tag = getTagName(CODE_SECTION); + return Func1 + tag + "# CODE"; + } + + // udata and idata section names are generated by a given number. + // @udata.<num>.# + static std::string getUdataSectionName(unsigned num) { + std::ostringstream o; + o << getTagName(PREFIX_SYMBOL) << "udata." << num << ".# UDATA"; + return o.str(); + } + + static std::string getIdataSectionName(unsigned num) { + std::ostringstream o; + o << getTagName(PREFIX_SYMBOL) << "idata." << num << ".# IDATA"; + return o.str(); + } + + inline static bool isLocalName (const std::string &Name) { + if (getSymbolTag(Name) == AUTOS_LABEL) + return true; + + return false; + } + + 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); + } + } + } + }; // class PAN. + + + // External symbol names require memory to live till the program end. + // So we have to allocate it and keep. + inline static const char *createESName (const std::string &name) { + char *tmpName = new char[name.size() + 1]; + strcpy (tmpName, name.c_str()); + return tmpName; + } + + + + inline static const char *PIC16CondCodeToString(PIC16CC::CondCodes CC) { + switch (CC) { + default: assert(0 && "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::GT: return "gt"; + case PIC16CC::UGT: return "gt"; + case PIC16CC::GE: return "ge"; + } + } + + inline static bool isSignedComparison(PIC16CC::CondCodes CC) { + switch (CC) { + default: assert(0 && "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); + FunctionPass *createPIC16CodePrinterPass(raw_ostream &OS, + PIC16TargetMachine &TM, + CodeGenOpt::Level OptLevel, + bool Verbose); + // Banksel optimzer pass. + FunctionPass *createPIC16MemSelOptimizerPass(); +} // 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/lib/Target/PIC16/PIC16.td b/lib/Target/PIC16/PIC16.td new file mode 100644 index 0000000000000..b2b9b1cd171ee --- /dev/null +++ b/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/lib/Target/PIC16/PIC16AsmPrinter.cpp b/lib/Target/PIC16/PIC16AsmPrinter.cpp new file mode 100644 index 0000000000000..ef3bc4b52a96f --- /dev/null +++ b/lib/Target/PIC16/PIC16AsmPrinter.cpp @@ -0,0 +1,404 @@ +//===-- 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 "PIC16AsmPrinter.h" +#include "PIC16TargetAsmInfo.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/Module.h" +#include "llvm/CodeGen/DwarfWriter.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Mangler.h" +#include "llvm/CodeGen/DwarfWriter.h" +#include "llvm/CodeGen/MachineModuleInfo.h" + +using namespace llvm; + +#include "PIC16GenAsmWriter.inc" + +bool PIC16AsmPrinter::printMachineInstruction(const MachineInstr *MI) { + printInstruction(MI); + return true; +} + +/// runOnMachineFunction - This uses the printInstruction() +/// method to print assembly for each instruction. +/// +bool PIC16AsmPrinter::runOnMachineFunction(MachineFunction &MF) { + this->MF = &MF; + + // This calls the base class function required to be called at beginning + // of runOnMachineFunction. + SetupMachineFunction(MF); + + // Get the mangled name. + const Function *F = MF.getFunction(); + CurrentFnName = Mang->getValueName(F); + + // Emit the function variables. + EmitFunctionFrame(MF); + + // Emit function begin debug directives + DbgInfo.EmitFunctBeginDI(F); + + EmitAutos(CurrentFnName); + const char *codeSection = PAN::getCodeSectionName(CurrentFnName).c_str(); + + const Section *fCodeSection = TAI->getNamedSection(codeSection, + SectionFlags::Code); + O << "\n"; + // Start the Code Section. + SwitchToSection (fCodeSection); + + // Emit the frame address of the function at the beginning of code. + O << "\tretlw low(" << PAN::getFrameLabel(CurrentFnName) << ")\n"; + O << "\tretlw high(" << PAN::getFrameLabel(CurrentFnName) << ")\n"; + + // Emit function start label. + O << CurrentFnName << ":\n"; + + // For emitting line directives, we need to keep track of the current + // source line. When it changes then only emit the line directive. + unsigned CurLine = 0; + O << "\n"; + // 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()) { + printBasicBlockLabel(I, true); + O << '\n'; + } + + for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); + II != E; ++II) { + // Emit the line directive if source line changed. + const DebugLoc DL = II->getDebugLoc(); + if (!DL.isUnknown()) { + unsigned line = MF.getDebugLocTuple(DL).Line; + if (line != CurLine) { + O << "\t.line " << line << "\n"; + CurLine = line; + } + } + + // Print the assembly for the instruction. + printMachineInstruction(II); + } + } + + // Emit function end debug directives. + DbgInfo.EmitFunctEndDI(F, CurLine); + return false; // we didn't modify anything. +} + +/// createPIC16CodePrinterPass - Returns a pass that prints the PIC16 +/// assembly code for a MachineFunction to the given output stream, +/// using the given target machine description. This should work +/// regardless of whether the function is in SSA form. +/// +FunctionPass *llvm::createPIC16CodePrinterPass(raw_ostream &o, + PIC16TargetMachine &tm, + CodeGenOpt::Level OptLevel, + bool verbose) { + return new PIC16AsmPrinter(o, tm, tm.getTargetAsmInfo(), OptLevel, verbose); +} + + +// printOperand - print operand of insn. +void PIC16AsmPrinter::printOperand(const MachineInstr *MI, int opNum) { + const MachineOperand &MO = MI->getOperand(opNum); + + switch (MO.getType()) { + case MachineOperand::MO_Register: + if (TargetRegisterInfo::isPhysicalRegister(MO.getReg())) + O << TM.getRegisterInfo()->get(MO.getReg()).AsmName; + else + assert(0 && "not implemented"); + return; + + case MachineOperand::MO_Immediate: + O << (int)MO.getImm(); + return; + + case MachineOperand::MO_GlobalAddress: { + O << Mang->getValueName(MO.getGlobal()); + break; + } + case MachineOperand::MO_ExternalSymbol: { + const char *Sname = MO.getSymbolName(); + + // If its a libcall name, record it to decls section. + if (PAN::getSymbolTag(Sname) == PAN::LIBCALL) { + LibcallDecls.push_back(Sname); + } + + O << Sname; + break; + } + case MachineOperand::MO_MachineBasicBlock: + printBasicBlockLabel(MO.getMBB()); + return; + + default: + assert(0 && " Operand type not supported."); + } +} + +void PIC16AsmPrinter::printCCOperand(const MachineInstr *MI, int opNum) { + int CC = (int)MI->getOperand(opNum).getImm(); + O << PIC16CondCodeToString((PIC16CC::CondCodes)CC); +} + +void PIC16AsmPrinter::printLibcallDecls(void) { + // If no libcalls used, return. + if (LibcallDecls.empty()) return; + + O << TAI->getCommentString() << "External decls for libcalls - BEGIN." <<"\n"; + // Remove duplicate entries. + LibcallDecls.sort(); + LibcallDecls.unique(); + for (std::list<const char*>::const_iterator I = LibcallDecls.begin(); + I != LibcallDecls.end(); I++) { + O << TAI->getExternDirective() << *I << "\n"; + O << TAI->getExternDirective() << PAN::getArgsLabel(*I) << "\n"; + O << TAI->getExternDirective() << PAN::getRetvalLabel(*I) << "\n"; + } + O << TAI->getCommentString() << "External decls for libcalls - END." <<"\n"; +} + +bool PIC16AsmPrinter::doInitialization (Module &M) { + bool Result = AsmPrinter::doInitialization(M); + DbgInfo.EmitFileDirective(M); + + // FIXME:: This is temporary solution to generate the include file. + // The processor should be passed to llc as in input and the header file + // should be generated accordingly. + O << "\n\t#include P16F1937.INC\n"; + MachineModuleInfo *MMI = getAnalysisIfAvailable<MachineModuleInfo>(); + assert(MMI); + DwarfWriter *DW = getAnalysisIfAvailable<DwarfWriter>(); + assert(DW && "Dwarf Writer is not available"); + DW->BeginModule(&M, MMI, O, this, TAI); + + // Set the section names for all globals. + for (Module::global_iterator I = M.global_begin(), E = M.global_end(); + I != E; ++I) { + I->setSection(TAI->SectionForGlobal(I)->getName()); + } + + EmitFunctionDecls(M); + EmitUndefinedVars(M); + EmitDefinedVars(M); + EmitIData(M); + EmitUData(M); + EmitRomData(M); + DbgInfo.PopulateFunctsDI(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. + O << TAI->getCommentString() << "Function Declarations - BEGIN." <<"\n"; + for (Module::iterator I = M.begin(), E = M.end(); I != E; I++) { + std::string Name = Mang->getValueName(I); + if (Name.compare("@abort") == 0) + continue; + + // If it is llvm intrinsic call then don't emit + if (Name.find("llvm.") != std::string::npos) + continue; + + if (! (I->isDeclaration() || I->hasExternalLinkage())) + continue; + + const char *directive = I->isDeclaration() ? TAI->getExternDirective() : + TAI->getGlobalDirective(); + + O << directive << Name << "\n"; + O << directive << PAN::getRetvalLabel(Name) << "\n"; + O << directive << PAN::getArgsLabel(Name) << "\n"; + } + + O << TAI->getCommentString() << "Function Declarations - END." <<"\n"; +} + +// Emit variables imported from other Modules. +void PIC16AsmPrinter::EmitUndefinedVars (Module &M) +{ + std::vector<const GlobalVariable*> Items = PTAI->ExternalVarDecls->Items; + if (! Items.size()) return; + + O << "\n" << TAI->getCommentString() << "Imported Variables - BEGIN" << "\n"; + for (unsigned j = 0; j < Items.size(); j++) { + O << TAI->getExternDirective() << Mang->getValueName(Items[j]) << "\n"; + } + O << TAI->getCommentString() << "Imported Variables - END" << "\n"; +} + +// Emit variables defined in this module and are available to other modules. +void PIC16AsmPrinter::EmitDefinedVars (Module &M) +{ + std::vector<const GlobalVariable*> Items = PTAI->ExternalVarDefs->Items; + if (! Items.size()) return; + + O << "\n" << TAI->getCommentString() << "Exported Variables - BEGIN" << "\n"; + for (unsigned j = 0; j < Items.size(); j++) { + O << TAI->getGlobalDirective() << Mang->getValueName(Items[j]) << "\n"; + } + O << TAI->getCommentString() << "Exported Variables - END" << "\n"; +} + +// Emit initialized data placed in ROM. +void PIC16AsmPrinter::EmitRomData (Module &M) +{ + + std::vector<const GlobalVariable*> Items = PTAI->ROSection->Items; + if (! Items.size()) return; + + // Print ROData ection. + O << "\n"; + SwitchToSection(PTAI->ROSection->S_); + for (unsigned j = 0; j < Items.size(); j++) { + O << Mang->getValueName(Items[j]); + Constant *C = Items[j]->getInitializer(); + int AddrSpace = Items[j]->getType()->getAddressSpace(); + EmitGlobalConstant(C, AddrSpace); + } +} + +bool PIC16AsmPrinter::doFinalization(Module &M) { + printLibcallDecls(); + DbgInfo.EmitVarDebugInfo(M); + O << "\n\t" << ".EOF"; + O << "\n\t" << "END\n"; + bool Result = AsmPrinter::doFinalization(M); + return Result; +} + +void PIC16AsmPrinter::EmitFunctionFrame(MachineFunction &MF) { + const Function *F = MF.getFunction(); + std::string FuncName = Mang->getValueName(F); + const TargetData *TD = TM.getTargetData(); + // Emit the data section name. + O << "\n"; + const char *SectionName = PAN::getFrameSectionName(CurrentFnName).c_str(); + + const Section *fPDataSection = TAI->getNamedSection(SectionName, + SectionFlags::Writeable); + SwitchToSection(fPDataSection); + + // Emit function frame label + O << PAN::getFrameLabel(CurrentFnName) << ":\n"; + + 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) + O << PAN::getRetvalLabel(CurrentFnName) << " RES " << RetSize << "\n"; + else + O << PAN::getRetvalLabel(CurrentFnName) << ": \n"; + + // 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); + } + + O << PAN::getArgsLabel(CurrentFnName) << " RES " << ArgSize << "\n"; + + // Emit temporary space + int TempSize = PTLI->GetTmpSize(); + if (TempSize > 0 ) + O << PAN::getTempdataLabel(CurrentFnName) << " RES " << TempSize <<"\n"; +} + +void PIC16AsmPrinter::EmitIData (Module &M) { + + // Print all IDATA sections. + std::vector <PIC16Section *>IDATASections = PTAI->IDATASections; + for (unsigned i = 0; i < IDATASections.size(); i++) { + O << "\n"; + SwitchToSection(IDATASections[i]->S_); + std::vector<const GlobalVariable*> Items = IDATASections[i]->Items; + for (unsigned j = 0; j < Items.size(); j++) { + std::string Name = Mang->getValueName(Items[j]); + Constant *C = Items[j]->getInitializer(); + int AddrSpace = Items[j]->getType()->getAddressSpace(); + O << Name; + EmitGlobalConstant(C, AddrSpace); + } + } +} + +void PIC16AsmPrinter::EmitUData (Module &M) { + const TargetData *TD = TM.getTargetData(); + + // Print all BSS sections. + std::vector <PIC16Section *>BSSSections = PTAI->BSSSections; + for (unsigned i = 0; i < BSSSections.size(); i++) { + O << "\n"; + SwitchToSection(BSSSections[i]->S_); + std::vector<const GlobalVariable*> Items = BSSSections[i]->Items; + for (unsigned j = 0; j < Items.size(); j++) { + std::string Name = Mang->getValueName(Items[j]); + Constant *C = Items[j]->getInitializer(); + const Type *Ty = C->getType(); + unsigned Size = TD->getTypeAllocSize(Ty); + + O << Name << " " <<"RES"<< " " << Size ; + O << "\n"; + } + } +} + +void PIC16AsmPrinter::EmitAutos (std::string FunctName) +{ + // Section names for all globals are already set. + + const TargetData *TD = TM.getTargetData(); + + // Now print Autos section for this function. + std::string SectionName = PAN::getAutosSectionName(FunctName); + std::vector <PIC16Section *>AutosSections = PTAI->AutosSections; + for (unsigned i = 0; i < AutosSections.size(); i++) { + O << "\n"; + if (AutosSections[i]->S_->getName() == SectionName) { + SwitchToSection(AutosSections[i]->S_); + std::vector<const GlobalVariable*> Items = AutosSections[i]->Items; + for (unsigned j = 0; j < Items.size(); j++) { + std::string VarName = Mang->getValueName(Items[j]); + Constant *C = Items[j]->getInitializer(); + const Type *Ty = C->getType(); + unsigned Size = TD->getTypeAllocSize(Ty); + // Emit memory reserve directive. + O << VarName << " RES " << Size << "\n"; + } + break; + } + } +} + diff --git a/lib/Target/PIC16/PIC16AsmPrinter.h b/lib/Target/PIC16/PIC16AsmPrinter.h new file mode 100644 index 0000000000000..2545dfd680a8c --- /dev/null +++ b/lib/Target/PIC16/PIC16AsmPrinter.h @@ -0,0 +1,70 @@ +//===-- PIC16AsmPrinter.h - 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. +// +//===----------------------------------------------------------------------===// + +#ifndef PIC16ASMPRINTER_H +#define PIC16ASMPRINTER_H + +#include "PIC16.h" +#include "PIC16TargetMachine.h" +#include "PIC16DebugInfo.h" +#include "llvm/Analysis/DebugInfo.h" +#include "PIC16TargetAsmInfo.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/TargetMachine.h" +#include <list> +#include <string> + +namespace llvm { + struct VISIBILITY_HIDDEN PIC16AsmPrinter : public AsmPrinter { + explicit PIC16AsmPrinter(raw_ostream &O, PIC16TargetMachine &TM, + const TargetAsmInfo *T, CodeGenOpt::Level OL, + bool V) + : AsmPrinter(O, TM, T, OL, V), DbgInfo(O,T) { + PTLI = TM.getTargetLowering(); + PTAI = static_cast<const PIC16TargetAsmInfo *> (T); + } + private : + virtual const char *getPassName() const { + return "PIC16 Assembly Printer"; + } + + bool runOnMachineFunction(MachineFunction &F); + void printOperand(const MachineInstr *MI, int opNum); + void printCCOperand(const MachineInstr *MI, int opNum); + bool printInstruction(const MachineInstr *MI); // definition autogenerated. + bool printMachineInstruction(const MachineInstr *MI); + void EmitFunctionDecls (Module &M); + void EmitUndefinedVars (Module &M); + void EmitDefinedVars (Module &M); + void EmitIData (Module &M); + void EmitUData (Module &M); + void EmitAutos (std::string FunctName); + void EmitRomData (Module &M); + void EmitFunctionFrame(MachineFunction &MF); + void printLibcallDecls(void); + protected: + bool doInitialization(Module &M); + bool doFinalization(Module &M); + + private: + PIC16TargetLowering *PTLI; + PIC16DbgInfo DbgInfo; + const PIC16TargetAsmInfo *PTAI; + std::list<const char *> LibcallDecls; // List of extern decls. + }; +} // end of namespace + +#endif diff --git a/lib/Target/PIC16/PIC16DebugInfo.cpp b/lib/Target/PIC16/PIC16DebugInfo.cpp new file mode 100644 index 0000000000000..4d43811f24a6f --- /dev/null +++ b/lib/Target/PIC16/PIC16DebugInfo.cpp @@ -0,0 +1,270 @@ +//===-- 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 "PIC16DebugInfo.h" +#include "llvm/GlobalVariable.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +PIC16DbgInfo::~PIC16DbgInfo() { + for(std::map<std::string, DISubprogram *>::iterator i = FunctNameMap.begin(); + i!=FunctNameMap.end(); i++) + delete i->second; + FunctNameMap.clear(); +} + +void PIC16DbgInfo::PopulateDebugInfo(DIType Ty, unsigned short &TypeNo, + bool &HasAux, int Aux[], + std::string &TypeName) { + if (Ty.isBasicType(Ty.getTag())) { + std::string Name = ""; + Ty.getName(Name); + unsigned short BaseTy = GetTypeDebugNumber(Name); + TypeNo = TypeNo << PIC16Dbg::S_BASIC; + TypeNo = TypeNo | (0xffff & BaseTy); + } + else if (Ty.isDerivedType(Ty.getTag())) { + 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; + } + DIType BaseType = DIDerivedType(Ty.getGV()).getTypeDerivedFrom(); + PopulateDebugInfo(BaseType, TypeNo, HasAux, Aux, TypeName); + } + else if (Ty.isCompositeType(Ty.getTag())) { + switch (Ty.getTag()) { + case dwarf::DW_TAG_array_type: { + DICompositeType CTy = DICompositeType(Ty.getGV()); + 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.getGV()); + 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; + Aux[7] = size >> 8; + DIType BaseType = CTy.getTypeDerivedFrom(); + PopulateDebugInfo(BaseType, TypeNo, HasAux, Aux, TypeName); + + break; + } + case dwarf:: DW_TAG_union_type: + case dwarf::DW_TAG_structure_type: { + DICompositeType CTy = DICompositeType(Ty.getGV()); + TypeNo = TypeNo << PIC16Dbg::S_BASIC; + if (Ty.getTag() == dwarf::DW_TAG_structure_type) + TypeNo = TypeNo | PIC16Dbg::T_STRUCT; + else + TypeNo = TypeNo | PIC16Dbg::T_UNION; + CTy.getName(TypeName); + unsigned size = CTy.getSizeInBits()/8; + // 7th and 8th byte represent size. + HasAux = true; + Aux[6] = size; + Aux[7] = size >> 8; + break; + } + case dwarf::DW_TAG_enumeration_type: { + TypeNo = TypeNo << PIC16Dbg::S_BASIC; + TypeNo = TypeNo | PIC16Dbg::T_ENUM; + break; + } + default: + TypeNo = TypeNo << PIC16Dbg::S_DERIVED; + } + } + else { + TypeNo = PIC16Dbg::T_NULL; + HasAux = false; + } + return; +} + + +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; +} + +short PIC16DbgInfo::getClass(DIGlobalVariable DIGV) { + short ClassNo; + if (PAN::isLocalName(DIGV.getGlobal()->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; +} + +void PIC16DbgInfo::PopulateFunctsDI(Module &M) { + GlobalVariable *Root = M.getGlobalVariable("llvm.dbg.subprograms"); + if (!Root) + return; + Constant *RootC = cast<Constant>(*Root->use_begin()); + + for (Value::use_iterator UI = RootC->use_begin(), UE = Root->use_end(); + UI != UE; ++UI) + for (Value::use_iterator UUI = UI->use_begin(), UUE = UI->use_end(); + UUI != UUE; ++UUI) { + GlobalVariable *GVSP = cast<GlobalVariable>(*UUI); + DISubprogram *SP = new DISubprogram(GVSP); + std::string Name; + SP->getLinkageName(Name); + FunctNameMap[Name] = SP; + } + return; +} + +DISubprogram* PIC16DbgInfo::getFunctDI(std::string FunctName) { + return FunctNameMap[FunctName]; +} + +void PIC16DbgInfo::EmitFunctBeginDI(const Function *F) { + std::string FunctName = F->getName(); + DISubprogram *SP = getFunctDI(FunctName); + if (SP) { + std::string FunctBeginSym = ".bf." + FunctName; + std::string BlockBeginSym = ".bb." + FunctName; + + int FunctBeginLine = SP->getLineNumber(); + int BFAux[PIC16Dbg::AuxSize] = {0}; + BFAux[4] = FunctBeginLine; + BFAux[5] = FunctBeginLine >> 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); + } +} + +void PIC16DbgInfo::EmitFunctEndDI(const Function *F, unsigned Line) { + std::string FunctName = F->getName(); + DISubprogram *SP = getFunctDI(FunctName); + if (SP) { + 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] = Line; + EFAux[5] = Line >> 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) { + O << "\n\t.dim " << VarName << ", 1" ; + for (int i = 0; i<num; i++) + O << "," << Aux[i]; +} + +void PIC16DbgInfo::EmitSymbol(std::string Name, int Class) { + O << "\n\t" << ".def "<< Name << ", debug, class = " << Class; +} + +void PIC16DbgInfo::EmitVarDebugInfo(Module &M) { + GlobalVariable *Root = M.getGlobalVariable("llvm.dbg.global_variables"); + if (!Root) + return; + + Constant *RootC = cast<Constant>(*Root->use_begin()); + for (Value::use_iterator UI = RootC->use_begin(), UE = Root->use_end(); + UI != UE; ++UI) { + for (Value::use_iterator UUI = UI->use_begin(), UUE = UI->use_end(); + UUI != UUE; ++UUI) { + DIGlobalVariable DIGV(cast<GlobalVariable>(*UUI)); + DIType Ty = DIGV.getType(); + unsigned short TypeNo = 0; + bool HasAux = false; + int Aux[PIC16Dbg::AuxSize] = { 0 }; + std::string TypeName = ""; + std::string VarName = TAI->getGlobalPrefix()+DIGV.getGlobal()->getName(); + PopulateDebugInfo(Ty, TypeNo, HasAux, Aux, TypeName); + // Emit debug info only if type information is availaible. + if (TypeNo != PIC16Dbg::T_NULL) { + O << "\n\t.type " << VarName << ", " << TypeNo; + short ClassNo = getClass(DIGV); + O << "\n\t.class " << VarName << ", " << ClassNo; + if (HasAux) { + if (TypeName != "") { + // Emit debug info for structure and union objects after + // .dim directive supports structure/union tag name in aux entry. + /* O << "\n\t.dim " << VarName << ", 1," << TypeName; + for (int i = 0; i<PIC16Dbg::AuxSize; i++) + O << "," << Aux[i];*/ + } + else { + EmitAuxEntry(VarName, Aux, PIC16Dbg::AuxSize); + } + } + } + } + } + O << "\n"; +} + +void PIC16DbgInfo::EmitFileDirective(Module &M) { + GlobalVariable *CU = M.getNamedGlobal("llvm.dbg.compile_unit"); + if (CU) { + DICompileUnit DIUnit(CU); + std::string Dir, FN; + O << "\n\t.file\t\"" << DIUnit.getDirectory(Dir) <<"/" + << DIUnit.getFilename(FN) << "\"" ; + } +} diff --git a/lib/Target/PIC16/PIC16DebugInfo.h b/lib/Target/PIC16/PIC16DebugInfo.h new file mode 100644 index 0000000000000..96b23da403c3c --- /dev/null +++ b/lib/Target/PIC16/PIC16DebugInfo.h @@ -0,0 +1,114 @@ +//===-- 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" +#include "llvm/Target/TargetAsmInfo.h" +#include <map> + +namespace llvm { + 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 raw_ostream; + + class PIC16DbgInfo { + std::map <std::string, DISubprogram *> FunctNameMap; + raw_ostream &O; + const TargetAsmInfo *TAI; + public: + PIC16DbgInfo(raw_ostream &o, const TargetAsmInfo *T) : O(o), TAI(T) {} + ~PIC16DbgInfo(); + void PopulateDebugInfo(DIType Ty, unsigned short &TypeNo, bool &HasAux, + int Aux[], std::string &TypeName); + unsigned GetTypeDebugNumber(std::string &type); + short getClass(DIGlobalVariable DIGV); + void PopulateFunctsDI(Module &M); + DISubprogram *getFunctDI(std::string FunctName); + void EmitFunctBeginDI(const Function *F); + void EmitFunctEndDI(const Function *F, unsigned Line); + void EmitAuxEntry(const std::string VarName, int Aux[], int num); + inline void EmitSymbol(std::string Name, int Class); + void EmitVarDebugInfo(Module &M); + void EmitFileDirective(Module &M); + }; +} // end namespace llvm; +#endif diff --git a/lib/Target/PIC16/PIC16ISelDAGToDAG.cpp b/lib/Target/PIC16/PIC16ISelDAGToDAG.cpp new file mode 100644 index 0000000000000..6c2b8ec9747a8 --- /dev/null +++ b/lib/Target/PIC16/PIC16ISelDAGToDAG.cpp @@ -0,0 +1,59 @@ +//===-- 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 "PIC16ISelDAGToDAG.h" +#include "llvm/Support/Debug.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); +} + + +/// InstructionSelect - This callback is invoked by +/// SelectionDAGISel when it has created a SelectionDAG for us to codegen. +void PIC16DAGToDAGISel::InstructionSelect() { + DEBUG(BB->dump()); + SelectRoot(*CurDAG); + CurDAG->RemoveDeadNodes(); +} + +/// Select - Select instructions not customized! Used for +/// expanded, promoted and normal instructions. +SDNode* PIC16DAGToDAGISel::Select(SDValue 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(SDValue 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/lib/Target/PIC16/PIC16ISelDAGToDAG.h b/lib/Target/PIC16/PIC16ISelDAGToDAG.h new file mode 100644 index 0000000000000..83abed3958a4a --- /dev/null +++ b/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 "PIC16ISelLowering.h" +#include "PIC16RegisterInfo.h" +#include "PIC16TargetMachine.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Intrinsics.h" +using namespace llvm; + +namespace { + +class VISIBILITY_HIDDEN PIC16DAGToDAGISel : public SelectionDAGISel { + + /// TM - Keep a reference to PIC16TargetMachine. + PIC16TargetMachine &TM; + + /// PIC16Lowering - This object fully describes how to lower LLVM code to an + /// PIC16-specific SelectionDAG. + 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"; + } + + virtual void InstructionSelect(); + +private: + // Include the pieces autogenerated from the target description. +#include "PIC16GenDAGISel.inc" + + SDNode *Select(SDValue N); + + // Match direct address complex pattern. + bool SelectDirectAddr(SDValue Op, SDValue N, SDValue &Address); + +}; + +} + diff --git a/lib/Target/PIC16/PIC16ISelLowering.cpp b/lib/Target/PIC16/PIC16ISelLowering.cpp new file mode 100644 index 0000000000000..92fdcb2c0c150 --- /dev/null +++ b/lib/Target/PIC16/PIC16ISelLowering.cpp @@ -0,0 +1,1756 @@ +// +// 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 "PIC16ISelLowering.h" +#include "PIC16TargetMachine.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" + + +using namespace llvm; + +static const char *getIntrinsicName(unsigned opcode) { + std::string Basename; + switch(opcode) { + default: assert (0 && "do not know intrinsic name"); + case PIC16ISD::SRA_I8: Basename = "sra.i8"; break; + case RTLIB::SRA_I16: Basename = "sra.i16"; break; + case RTLIB::SRA_I32: Basename = "sra.i32"; break; + + case PIC16ISD::SLL_I8: Basename = "sll.i8"; break; + case RTLIB::SHL_I16: Basename = "sll.i16"; break; + case RTLIB::SHL_I32: Basename = "sll.i32"; break; + + case PIC16ISD::SRL_I8: Basename = "srl.i8"; break; + case RTLIB::SRL_I16: Basename = "srl.i16"; break; + case RTLIB::SRL_I32: Basename = "srl.i32"; break; + + case PIC16ISD::MUL_I8: Basename = "mul.i8"; break; + case RTLIB::MUL_I16: Basename = "mul.i16"; break; + case RTLIB::MUL_I32: Basename = "mul.i32"; 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. + char *tmp = new char[Fullname.size() + 1]; + strcpy (tmp, Fullname.c_str()); + + return tmp; +} + +// PIC16TargetLowering Constructor. +PIC16TargetLowering::PIC16TargetLowering(PIC16TargetMachine &TM) + : TargetLowering(TM), TmpSize(0) { + + Subtarget = &TM.getSubtarget<PIC16Subtarget>(); + + addRegisterClass(MVT::i8, PIC16::GPRRegisterClass); + + setShiftAmountType(MVT::i8); + setShiftAmountFlavor(Extend); + + // 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)); + + 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::ADDE, MVT::i8, Custom); + setOperationAction(ISD::ADDC, MVT::i8, Custom); + setOperationAction(ISD::SUBE, MVT::i8, Custom); + setOperationAction(ISD::SUBC, 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::CALL, MVT::i16, Custom); + setOperationAction(ISD::RET, MVT::Other, Custom); + + setOperationAction(ISD::MUL, MVT::i8, Custom); + setOperationAction(ISD::MUL, MVT::i16, Expand); + setOperationAction(ISD::MUL, MVT::i32, Expand); + + setOperationAction(ISD::SMUL_LOHI, MVT::i8, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i16, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i8, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i16, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::MULHU, MVT::i8, Expand); + setOperationAction(ISD::MULHU, MVT::i16, Expand); + setOperationAction(ISD::MULHU, MVT::i32, Expand); + setOperationAction(ISD::MULHS, MVT::i8, Expand); + setOperationAction(ISD::MULHS, MVT::i16, Expand); + setOperationAction(ISD::MULHS, MVT::i32, Expand); + + setOperationAction(ISD::SRA, MVT::i8, Custom); + setOperationAction(ISD::SRA, MVT::i16, Expand); + setOperationAction(ISD::SRA, MVT::i32, Expand); + setOperationAction(ISD::SHL, MVT::i8, Custom); + setOperationAction(ISD::SHL, MVT::i16, Expand); + setOperationAction(ISD::SHL, MVT::i32, Expand); + setOperationAction(ISD::SRL, MVT::i8, Custom); + setOperationAction(ISD::SRL, MVT::i16, Expand); + setOperationAction(ISD::SRL, MVT::i32, Expand); + + // PIC16 does not support shift parts + setOperationAction(ISD::SRA_PARTS, MVT::i8, Expand); + setOperationAction(ISD::SRA_PARTS, MVT::i16, Expand); + setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand); + setOperationAction(ISD::SHL_PARTS, MVT::i8, Expand); + setOperationAction(ISD::SHL_PARTS, MVT::i16, Expand); + setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand); + setOperationAction(ISD::SRL_PARTS, MVT::i8, Expand); + setOperationAction(ISD::SRL_PARTS, MVT::i16, Expand); + setOperationAction(ISD::SRL_PARTS, MVT::i32, 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(); +} + +// 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) { + 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] = TmpSize; + TmpSize += size; + return FiTmpOffsetMap[FI]; +} + +// 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 PIC16TargetLowering::getSetCCResultType(MVT ValType) 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) { + return PIC16LibcallNames[Call]; +} + +SDValue +PIC16TargetLowering::MakePIC16Libcall(PIC16ISD::PIC16Libcall Call, + MVT RetVT, const SDValue *Ops, + unsigned NumOps, bool isSigned, + SelectionDAG &DAG, DebugLoc dl) { + + 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().getTypeForMVT(); + Entry.isSExt = isSigned; + Entry.isZExt = !isSigned; + Args.push_back(Entry); + } + SDValue Callee = DAG.getExternalSymbol(getPIC16LibcallName(Call), MVT::i8); + + const Type *RetTy = RetVT.getTypeForMVT(); + std::pair<SDValue,SDValue> CallInfo = + LowerCallTo(DAG.getEntryNode(), RetTy, isSigned, !isSigned, false, + false, CallingConv::C, false, 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::Dummy: return "PIC16ISD::Dummy"; + } +} + +void PIC16TargetLowering::ReplaceNodeResults(SDNode *N, + SmallVectorImpl<SDValue>&Results, + SelectionDAG &DAG) { + + 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) { + + // 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(); + int Index = FR->getIndex(); + + // Expand FrameIndex like GlobalAddress and ExternalSymbol + // Also use Offset field for lo and hi parts. The default + // offset is zero. + SDValue Offset = DAG.getConstant(0, MVT::i8); + SDValue FI = DAG.getTargetFrameIndex(Index, MVT::i8); + SDValue Lo = DAG.getNode(PIC16ISD::Lo, dl, MVT::i8, FI, Offset); + SDValue Hi = DAG.getNode(PIC16ISD::Hi, dl, MVT::i8, FI, Offset); + return DAG.getNode(ISD::BUILD_PAIR, dl, N->getValueType(0), Lo, Hi); +} + + +SDValue PIC16TargetLowering::ExpandStore(SDNode *N, SelectionDAG &DAG) { + StoreSDNode *St = cast<StoreSDNode>(N); + SDValue Chain = St->getChain(); + SDValue Src = St->getValue(); + SDValue Ptr = St->getBasePtr(); + MVT 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; + 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; + if (Chain.getOpcode() == ISD::TokenFactor) { + ChainLo = Chain.getOperand(0); + ChainHi = Chain.getOperand(1); + } + SDValue ChainLo1 = ChainLo, ChainLo2 = ChainLo, ChainHi1 = ChainHi, + ChainHi2 = ChainHi; + if (ChainLo.getOpcode() == ISD::TokenFactor) { + ChainLo1 = ChainLo.getOperand(0); + ChainLo2 = ChainLo.getOperand(1); + } + 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 { + assert (0 && "value type not supported"); + return SDValue(); + } +} + +SDValue PIC16TargetLowering::ExpandExternalSymbol(SDNode *N, SelectionDAG &DAG) +{ + 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) { + 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(), 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) { + 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) { + + // 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) { + SDNode *N = Op.getNode(); + DebugLoc dl = N->getDebugLoc(); + MVT NewVT = getTypeToTransformTo(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) { + + MachineFunction &MF = DAG.getMachineFunction(); + const Function *Func = MF.getFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + 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 < ReservedFrameCount) { + tmpName = 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 = createESName(PAN::getTempdataLabel(Name)); + ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8); + Offset = GetTmpOffsetForFI(FIndex, MFI->getObjectSize(FIndex)); + } + + 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) { + + // 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) { + Offset = dyn_cast<ConstantSDNode>(OperLeft)->getZExtValue(); + Ptr = OperRight; + } else if (OperRight.getOpcode() == ISD::Constant) { + 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); + if (TFI.getOpcode() == ISD::TargetFrameIndex) { + int FrameOffset; + LegalizeFrameIndex(TFI, DAG, Lo, FrameOffset); + Hi = DAG.getConstant(1, MVT::i8); + Offset += FrameOffset; + 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) { + 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; + MVT 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; + MVT 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 + MVT MemVT = LD->getMemoryVT(); + unsigned MemBytes = MemVT.getSizeInBits() / 8; + 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)) { + // 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) + 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) + 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) { + // 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; +} + +void +PIC16TargetLowering::LowerOperationWrapper(SDNode *N, + SmallVectorImpl<SDValue>&Results, + SelectionDAG &DAG) { + SDValue Op = SDValue(N, 0); + SDValue Res; + unsigned i; + switch (Op.getOpcode()) { + case ISD::FORMAL_ARGUMENTS: + Res = LowerFORMAL_ARGUMENTS(Op, DAG); break; + case ISD::LOAD: + Res = ExpandLoad(Op.getNode(), DAG); break; + case ISD::CALL: + Res = LowerCALL(Op, 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) { + switch (Op.getOpcode()) { + case ISD::FORMAL_ARGUMENTS: + return LowerFORMAL_ARGUMENTS(Op, DAG); + 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::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::CALL: + return LowerCALL(Op, DAG); + case ISD::RET: + return LowerRET(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) { + 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); + const char *tmpName = 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), + 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), + MVT::i8)); + + return Load.getValue(0); +} + +SDValue PIC16TargetLowering:: +LowerIndirectCallArguments(SDValue Op, SDValue Chain, SDValue InFlag, + SDValue DataAddr_Lo, SDValue DataAddr_Hi, + SelectionDAG &DAG) { + CallSDNode *TheCall = dyn_cast<CallSDNode>(Op); + unsigned NumOps = TheCall->getNumArgs(); + DebugLoc dl = TheCall->getDebugLoc(); + + // 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 = TheCall->getNumRetVals(); + for (unsigned i = 0, ArgOffset = RetVals; i < NumOps; i++) { + // Get the arguments + Arg = TheCall->getArg(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 Op, SDValue Chain, SDValue ArgLabel, + SDValue InFlag, SelectionDAG &DAG) { + CallSDNode *TheCall = dyn_cast<CallSDNode>(Op); + unsigned NumOps = TheCall->getNumArgs(); + DebugLoc dl = TheCall->getDebugLoc(); + std::string Name; + SDValue Arg, StoreAt; + MVT ArgVT; + unsigned Size=0; + unsigned ArgCount=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=ArgCount, Offset = 0; i<NumOps; i++) { + // Get the argument + Arg = TheCall->getArg(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 Op, SDValue Chain, SDValue InFlag, + SDValue DataAddr_Lo, SDValue DataAddr_Hi, + SelectionDAG &DAG) { + CallSDNode *TheCall = dyn_cast<CallSDNode>(Op); + DebugLoc dl = TheCall->getDebugLoc(); + unsigned RetVals = TheCall->getNumRetVals(); + + // If call does not have anything to return + // then do nothing and go back. + if (RetVals == 0) + return Chain; + + // Call has something to return + std::vector<SDValue> ResultVals; + 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); + ResultVals.push_back(LoadRet); + } + ResultVals.push_back(Chain); + SDValue Res = DAG.getMergeValues(&ResultVals[0], ResultVals.size(), dl); + return Res; +} + +SDValue PIC16TargetLowering:: +LowerDirectCallReturn(SDValue Op, SDValue Chain, SDValue RetLabel, + SDValue InFlag, SelectionDAG &DAG) { + CallSDNode *TheCall = dyn_cast<CallSDNode>(Op); + DebugLoc dl = TheCall->getDebugLoc(); + // Currently handling primitive types only. They will come in + // i8 parts + unsigned RetVals = TheCall->getNumRetVals(); + + std::vector<SDValue> ResultVals; + + // 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++; + ResultVals.push_back(LoadRet); + } + + // To return use MERGE_VALUES + ResultVals.push_back(Chain); + SDValue Res = DAG.getMergeValues(&ResultVals[0], ResultVals.size(), dl); + return Res; +} + +SDValue PIC16TargetLowering::LowerRET(SDValue Op, SelectionDAG &DAG) { + SDValue Chain = Op.getOperand(0); + DebugLoc dl = Op.getDebugLoc(); + + if (Op.getNumOperands() == 1) // return void + return Op; + + // return should have odd number of operands + if ((Op.getNumOperands() % 2) == 0 ) { + assert(0 && "Do not know how to return this many arguments!"); + abort(); + } + + // Number of values to return + unsigned NumRet = (Op.getNumOperands() / 2); + + // 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 = createESName(PAN::getFrameLabel(FuncName)); + SDVTList VTs = DAG.getVTList (MVT::i8, MVT::Other); + SDValue ES = DAG.getTargetExternalSymbol(tmpName, MVT::i8); + SDValue BS = DAG.getConstant(1, MVT::i8); + SDValue RetVal; + for(unsigned i=0;i<NumRet; ++i) { + RetVal = Op.getNode()->getOperand(2*i + 1); + Chain = DAG.getNode (PIC16ISD::PIC16Store, dl, MVT::Other, Chain, RetVal, + ES, BS, + DAG.getConstant (i, MVT::i8)); + + } + return DAG.getNode(ISD::RET, dl, MVT::Other, Chain); +} + +// CALL node may have some operands non-legal to PIC16. Generate new CALL +// node with all the operands legal. +// Currently only Callee operand of the CALL node is non-legal. This function +// legalizes the Callee operand and uses all other operands as are to generate +// new CALL node. + +SDValue PIC16TargetLowering::LegalizeCALL(SDValue Op, SelectionDAG &DAG) { + CallSDNode *TheCall = dyn_cast<CallSDNode>(Op); + SDValue Chain = TheCall->getChain(); + SDValue Callee = TheCall->getCallee(); + DebugLoc dl = TheCall->getDebugLoc(); + unsigned i =0; + + assert(Callee.getValueType() == MVT::i16 && + "Don't know how to legalize this call node!!!"); + assert(Callee.getOpcode() == ISD::BUILD_PAIR && + "Don't know how to legalize this call node!!!"); + + if (isDirectAddress(Callee)) { + // Come here for direct calls + Callee = Callee.getOperand(0).getOperand(0); + } else { + // 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); + } + std::vector<SDValue> Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + + // Add the call arguments and their flags + unsigned NumArgs = TheCall->getNumArgs(); + for(i=0;i<NumArgs;i++) { + Ops.push_back(TheCall->getArg(i)); + Ops.push_back(TheCall->getArgFlagsVal(i)); + } + std::vector<MVT> NodeTys; + unsigned NumRets = TheCall->getNumRetVals(); + for(i=0;i<NumRets;i++) + NodeTys.push_back(TheCall->getRetValType(i)); + + // Return a Chain as well + NodeTys.push_back(MVT::Other); + + SDVTList VTs = DAG.getVTList(&NodeTys[0], NodeTys.size()); + // Generate new call with all the operands legal + return DAG.getCall(TheCall->getCallingConv(), dl, + TheCall->isVarArg(), TheCall->isTailCall(), + TheCall->isInreg(), VTs, &Ops[0], Ops.size()); +} + +void PIC16TargetLowering:: +GetDataAddress(DebugLoc dl, SDValue Callee, SDValue &Chain, + SDValue &DataAddr_Lo, SDValue &DataAddr_Hi, + SelectionDAG &DAG) { + 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 Op, SelectionDAG &DAG) { + CallSDNode *TheCall = dyn_cast<CallSDNode>(Op); + SDValue Chain = TheCall->getChain(); + SDValue Callee = TheCall->getCallee(); + DebugLoc dl = TheCall->getDebugLoc(); + if (Callee.getValueType() == MVT::i16 && + Callee.getOpcode() == ISD::BUILD_PAIR) { + // Control should come here only from TypeLegalizer for lowering + + // Legalize the non-legal arguments of call and return the + // new call with legal arguments. + return LegalizeCALL(Op, DAG); + } + // Control should come here from Legalize DAG. + // Here all the operands of CALL node should be legal. + + // 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. + + // The flag to track if this is a direct or indirect call. + bool IsDirectCall = true; + unsigned RetVals = TheCall->getNumRetVals(); + unsigned NumArgs = TheCall->getNumArgs(); + + SDValue DataAddr_Lo, DataAddr_Hi; + if (Callee.getOpcode() == PIC16ISD::PIC16Connect) { + IsDirectCall = false; // This is indirect call + // 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)) { + GlobalValue *GV = G->getGlobal(); + Callee = DAG.getTargetGlobalAddress(GV, 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 = createESName(PAN::getArgsLabel(Name)); + ArgLabel = DAG.getTargetExternalSymbol(argFrame, MVT::i8); + + // Label for reading return value + const char *retName = 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(Op, Chain, ArgLabel, OperFlag, DAG); + Chain = getChain(CallArgs); + OperFlag = getOutFlag(CallArgs); + } else { + CallArgs = LowerIndirectCallArguments(Op, Chain, OperFlag, DataAddr_Lo, + DataAddr_Hi, 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(Op, Chain, RetLabel, OperFlag, DAG); + else + return LowerIndirectCallReturn(Op, Chain, OperFlag, DataAddr_Lo, + DataAddr_Hi, DAG); +} + +bool PIC16TargetLowering::isDirectLoad(const SDValue Op) { + 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) { + // 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()) + return false; + else + MemOp = 0; + } + if (isDirectLoad(Op.getOperand(1))) { + if (Op.getOperand(1).hasOneUse()) + 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) { + 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)) { + // 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) { + // 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)) { + // 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) { + DebugLoc dl = Op.getDebugLoc(); + // We should have handled larger operands in type legalizer itself. + assert (Op.getValueType() == MVT::i8 && "illegal sub to lower"); + + // Nothing to do if the first operand is already a direct load and it has + // only one use. + if (isDirectLoad(Op.getOperand(0)) && Op.getOperand(0).hasOneUse()) + return Op; + + // Put first operand on stack. + SDValue NewVal = ConvertToMemOperand (Op.getOperand(0), DAG, dl); + + SDVTList Tys = DAG.getVTList(MVT::i8, MVT::Flag); + if (Op.getOpcode() == ISD::SUBE) + return DAG.getNode(Op.getOpcode(), dl, Tys, NewVal, Op.getOperand(1), + Op.getOperand(2)); + else + return DAG.getNode(Op.getOpcode(), dl, Tys, NewVal, Op.getOperand(1)); +} + +void PIC16TargetLowering::InitReservedFrameCount(const Function *F) { + unsigned NumArgs = F->arg_size(); + + bool isVoidFunc = (F->getReturnType()->getTypeID() == Type::VoidTyID); + + if (isVoidFunc) + ReservedFrameCount = NumArgs; + else + ReservedFrameCount = NumArgs + 1; +} + +// LowerFORMAL_ARGUMENTS - 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::LowerFORMAL_ARGUMENTS(SDValue Op, + SelectionDAG &DAG) { + SmallVector<SDValue, 8> ArgValues; + unsigned NumArgVals = Op.getNode()->getNumValues() - 1; + DebugLoc dl = Op.getDebugLoc(); + SDValue Chain = Op.getOperand(0); // Formal arguments' chain + + + // 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(); + // Initialize the ReserveFrameCount + InitReservedFrameCount(F); + + // Create the <fname>.args external symbol. + const char *tmpName = 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); + ArgValues.push_back(PICLoad); + } + + // Return a MERGE_VALUE node. + ArgValues.push_back(Op.getOperand(0)); + return DAG.getNode(ISD::MERGE_VALUES, dl, Op.getNode()->getVTList(), + &ArgValues[0], ArgValues.size()).getValue(Op.getResNo()); +} + +// 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: assert(0 && "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::LE; + case ISD::SETUGE: return PIC16CC::GE; + 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)->getZExtValue() == 0 && + 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))->getZExtValue() == 1 && + cast<ConstantSDNode>(LHS.getOperand(1))->getZExtValue() == 0) { + 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) { + 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) { + 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); + + // Update machine-CFG edges by transferring all successors of the current + // block to the new block which will contain the Phi node for the select. + sinkMBB->transferSuccessors(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, dl, TII.get(PIC16::PHI), MI->getOperand(0).getReg()) + .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB) + .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB); + + F->DeleteMachineInstr(MI); // The pseudo instruction is gone now. + return BB; +} + + +SDValue PIC16TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) { + 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/lib/Target/PIC16/PIC16ISelLowering.h b/lib/Target/PIC16/PIC16ISelLowering.h new file mode 100644 index 0000000000000..ca9650d6b19e4 --- /dev/null +++ b/lib/Target/PIC16/PIC16ISelLowering.h @@ -0,0 +1,227 @@ +//===-- 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, // Psuedo to be caught in schedular and expanded to brcond. + BRCOND, // Conditional branch. + 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 getSetCCResultType(MVT ValType) const; + SDValue LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG); + SDValue LowerShift(SDValue Op, SelectionDAG &DAG); + SDValue LowerADD(SDValue Op, SelectionDAG &DAG); + SDValue LowerSUB(SDValue Op, SelectionDAG &DAG); + SDValue LowerBinOp(SDValue Op, SelectionDAG &DAG); + SDValue LowerCALL(SDValue Op, SelectionDAG &DAG); + SDValue LowerRET(SDValue Op, SelectionDAG &DAG); + // Call returns + SDValue + LowerDirectCallReturn(SDValue Op, SDValue Chain, SDValue FrameAddress, + SDValue InFlag, SelectionDAG &DAG); + SDValue + LowerIndirectCallReturn(SDValue Op, SDValue Chain, SDValue InFlag, + SDValue DataAddr_Lo, SDValue DataAddr_Hi, + SelectionDAG &DAG); + + // Call arguments + SDValue + LowerDirectCallArguments(SDValue Op, SDValue Chain, SDValue FrameAddress, + SDValue InFlag, SelectionDAG &DAG); + + SDValue + LowerIndirectCallArguments(SDValue Op, SDValue Chain, SDValue InFlag, + SDValue DataAddr_Lo, SDValue DataAddr_Hi, + SelectionDAG &DAG); + + SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG); + SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG); + SDValue getPIC16Cmp(SDValue LHS, SDValue RHS, unsigned OrigCC, SDValue &CC, + SelectionDAG &DAG, DebugLoc dl); + virtual MachineBasicBlock *EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *MBB) const; + + + virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG); + virtual void ReplaceNodeResults(SDNode *N, + SmallVectorImpl<SDValue> &Results, + SelectionDAG &DAG); + virtual void LowerOperationWrapper(SDNode *N, + SmallVectorImpl<SDValue> &Results, + SelectionDAG &DAG); + + SDValue ExpandStore(SDNode *N, SelectionDAG &DAG); + SDValue ExpandLoad(SDNode *N, SelectionDAG &DAG); + SDValue ExpandGlobalAddress(SDNode *N, SelectionDAG &DAG); + SDValue ExpandExternalSymbol(SDNode *N, SelectionDAG &DAG); + SDValue ExpandFrameIndex(SDNode *N, SelectionDAG &DAG); + + 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); + void ResetTmpOffsetMap() { FiTmpOffsetMap.clear(); SetTmpSize(0); } + void InitReservedFrameCount(const Function *F); + + // Return the size of Tmp variable + unsigned GetTmpSize() { return TmpSize; } + void SetTmpSize(unsigned Size) { TmpSize = Size; } + + private: + // If the Node is a BUILD_PAIR representing a direct Address, + // then this function will return true. + bool isDirectAddress(const SDValue &Op); + + // If the Node is a DirectAddress in ROM_SPACE then this + // function will return true + bool isRomAddress(const SDValue &Op); + + // Extract the Lo and Hi component of Op. + void GetExpandedParts(SDValue Op, SelectionDAG &DAG, SDValue &Lo, + SDValue &Hi); + + + // 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); + + // FrameIndex should be broken down into ExternalSymbol and FrameOffset. + void LegalizeFrameIndex(SDValue Op, SelectionDAG &DAG, SDValue &ES, + int &Offset); + + + // CALL node should have all legal operands only. Legalize all non-legal + // operands of CALL node and then return the new call will all operands + // legal. + SDValue LegalizeCALL(SDValue Op, SelectionDAG &DAG); + + // 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); + + // 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); + + // This function checks if we need to put an operand of an operation on + // stack and generate a load or not. + bool NeedToConvertToMemOp(SDValue Op, unsigned &MemOp); + + /// 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); + + // Make PIC16 Libcall. + SDValue MakePIC16Libcall(PIC16ISD::PIC16Libcall Call, MVT RetVT, + const SDValue *Ops, unsigned NumOps, bool isSigned, + SelectionDAG &DAG, DebugLoc dl); + + // Check if operation has a direct load operand. + inline bool isDirectLoad(const SDValue Op); + + private: + // 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; + }; +} // namespace llvm + +#endif // PIC16ISELLOWERING_H diff --git a/lib/Target/PIC16/PIC16InstrFormats.td b/lib/Target/PIC16/PIC16InstrFormats.td new file mode 100644 index 0000000000000..e213ea847fc82 --- /dev/null +++ b/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/lib/Target/PIC16/PIC16InstrInfo.cpp b/lib/Target/PIC16/PIC16InstrInfo.cpp new file mode 100644 index 0000000000000..2a769e8ad16e4 --- /dev/null +++ b/lib/Target/PIC16/PIC16InstrInfo.cpp @@ -0,0 +1,186 @@ +//===- 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 "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 <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 { + PIC16TargetLowering *PTLI = TM.getTargetLowering(); + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (I != MBB.end()) DL = I->getDebugLoc(); + + const Function *Func = MBB.getParent()->getFunction(); + const std::string FuncName = Func->getName(); + + const char *tmpName = 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)) + .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)) + .addExternalSymbol(tmpName) + .addImm(1); // Emit banksel for it. + } + else + assert(0 && "Can't store this register to stack slot"); +} + +void PIC16InstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned DestReg, int FI, + const TargetRegisterClass *RC) const { + PIC16TargetLowering *PTLI = TM.getTargetLowering(); + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (I != MBB.end()) DL = I->getDebugLoc(); + + const Function *Func = MBB.getParent()->getFunction(); + const std::string FuncName = Func->getName(); + + const char *tmpName = 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)) + .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)) + .addExternalSymbol(tmpName) + .addImm(1); // Emit banksel for it. + } + else + assert(0 && "Can't load this register from stack slot"); +} + +bool PIC16InstrInfo::copyRegToReg (MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned DestReg, unsigned SrcReg, + const TargetRegisterClass *DestRC, + const TargetRegisterClass *SrcRC) const { + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (I != MBB.end()) DL = I->getDebugLoc(); + + if (DestRC == PIC16::FSR16RegisterClass) { + BuildMI(MBB, I, DL, get(PIC16::copy_fsr), DestReg).addReg(SrcReg); + return true; + } + + if (DestRC == PIC16::GPRRegisterClass) { + BuildMI(MBB, I, DL, get(PIC16::copy_w), DestReg).addReg(SrcReg); + return true; + } + + // Not yet supported. + return false; +} + +bool PIC16InstrInfo::isMoveInstr(const MachineInstr &MI, + unsigned &SrcReg, unsigned &DestReg, + unsigned &SrcSubIdx, unsigned &DstSubIdx) const { + SrcSubIdx = DstSubIdx = 0; // No sub-registers. + + if (MI.getOpcode() == PIC16::copy_fsr + || MI.getOpcode() == PIC16::copy_w) { + DestReg = MI.getOperand(0).getReg(); + SrcReg = MI.getOperand(1).getReg(); + return true; + } + + return false; +} + diff --git a/lib/Target/PIC16/PIC16InstrInfo.h b/lib/Target/PIC16/PIC16InstrInfo.h new file mode 100644 index 0000000000000..0b67679698753 --- /dev/null +++ b/lib/Target/PIC16/PIC16InstrInfo.h @@ -0,0 +1,70 @@ +//===- 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; + + virtual void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC) const; + virtual bool copyRegToReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, unsigned SrcReg, + const TargetRegisterClass *DestRC, + const TargetRegisterClass *SrcRC) const; + virtual bool isMoveInstr(const MachineInstr &MI, + unsigned &SrcReg, unsigned &DstReg, + unsigned &SrcSubIdx, unsigned &DstSubIdx) const; + + }; +} // namespace llvm + +#endif diff --git a/lib/Target/PIC16/PIC16InstrInfo.td b/lib/Target/PIC16/PIC16InstrInfo.td new file mode 100644 index 0000000000000..c572188cef226 --- /dev/null +++ b/lib/Target/PIC16/PIC16InstrInfo.td @@ -0,0 +1,522 @@ +//===- 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]>; + +//===----------------------------------------------------------------------===// +// 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 isTwoAddress = 1, 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 copyRegToReg.) +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"), + [(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 isTwoAddress = 1 in +class BinOpLW<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 isTwoAddress = 1 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))]>; + +//---------------------------- +// copyRegToReg +// copyRegToReg 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 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 isTwoAddress = 1, 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. + +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 : BinOpLW<0, "addlw", add>; +def addlw_2 : BinOpLW<0, "addlw", addc>; + +let Uses = [STATUS] in +def addlwc : BinOpLW<0, "addlwc", adde>; // With Carry. (Assembler macro). + +// bitwise operations involving a literal and w. +def andlw : BinOpLW<0, "andlw", and>; +def xorlw : BinOpLW<0, "xorlw", xor>; +def orlw : BinOpLW<0, "iorlw", or>; +} + +// sublw +// W = C - W ; sub W from literal. (Without borrow). +let isTwoAddress = 1 in +class SUBLW<bits<6> opcode, SDNode OpNode> : + LiteralFormat<opcode, (outs GPR:$dst), + (ins GPR:$src, i8imm:$literal), + "sublw $literal", + [(set GPR:$dst, (OpNode (i8 imm:$literal), GPR:$src))]>; + +let Defs = [STATUS] in { +def sublw_1 : SUBLW<0, sub>; +def sublw_2 : SUBLW<0, subc>; +def sublw_cc : SUBLW<0, 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 by the +// scheduler into a branch sequence. +let usesCustomDAGSchedInserter = 1 in { // Expanded by the scheduler. + 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. +def Return : + ControlFormat<0, (outs), (ins), "return", [(ret)]>; + +//===----------------------------------------------------------------------===// +// 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/lib/Target/PIC16/PIC16MemSelOpt.cpp b/lib/Target/PIC16/PIC16MemSelOpt.cpp new file mode 100644 index 0000000000000..20f926def398d --- /dev/null +++ b/lib/Target/PIC16/PIC16MemSelOpt.cpp @@ -0,0 +1,169 @@ +//===-- PIC16MemSelOpt.cpp - PIC16 banksel optimizer --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the pass which optimizes the emitting of banksel +// instructions before accessing data memory. This currently works within +// a basic block only and keep tracks of the last accessed memory bank. +// If memory access continues to be in the same bank it just makes banksel +// immediate, which is a part of the insn accessing the data memory, from 1 +// to zero. The asm printer emits a banksel only if that immediate is 1. +// +// FIXME: this is not implemented yet. The banksel pass only works on local +// basic blocks. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "pic16-codegen" +#include "PIC16.h" +#include "PIC16InstrInfo.h" +#include "PIC16TargetAsmInfo.h" +#include "PIC16TargetMachine.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/GlobalValue.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Support/Compiler.h" + +using namespace llvm; + +namespace { + struct VISIBILITY_HIDDEN MemSelOpt : public MachineFunctionPass { + static char ID; + MemSelOpt() : MachineFunctionPass(&ID) {} + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addPreservedID(MachineLoopInfoID); + AU.addPreservedID(MachineDominatorsID); + MachineFunctionPass::getAnalysisUsage(AU); + } + + virtual bool runOnMachineFunction(MachineFunction &MF); + + virtual const char *getPassName() const { + return "PIC16 Memsel Optimizer"; + } + + bool processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB); + bool processInstruction(MachineInstr *MI); + + private: + const TargetInstrInfo *TII; // Machine instruction info. + MachineBasicBlock *MBB; // Current basic block + std::string CurBank; + + }; + char MemSelOpt::ID = 0; +} + +FunctionPass *llvm::createPIC16MemSelOptimizerPass() { + return new MemSelOpt(); +} + + +/// runOnMachineFunction - Loop over all of the basic blocks, transforming FP +/// register references into FP stack references. +/// +bool MemSelOpt::runOnMachineFunction(MachineFunction &MF) { + TII = MF.getTarget().getInstrInfo(); + bool Changed = false; + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + Changed |= processBasicBlock(MF, *I); + } + + return Changed; +} + +/// processBasicBlock - Loop over all of the instructions in the basic block, +/// transforming FP instructions into their stack form. +/// +bool MemSelOpt::processBasicBlock(MachineFunction &MF, MachineBasicBlock &BB) { + bool Changed = false; + MBB = &BB; + + // Let us assume that when entering a basic block now bank is selected. + // Ideally we should look at the predecessors for this information. + CurBank=""; + + for (MachineBasicBlock::iterator I = BB.begin(); I != BB.end(); ++I) { + Changed |= processInstruction(I); + } + return Changed; +} + +bool MemSelOpt::processInstruction(MachineInstr *MI) { + bool Changed = false; + + unsigned NumOperands = MI->getNumOperands(); + if (NumOperands == 0) return false; + + + // If this insn is not going to access any memory, return. + const TargetInstrDesc &TID = TII->get(MI->getOpcode()); + if (! (TID.isCall() || TID.mayLoad() || TID.mayStore())) + return false; + + // Scan for the memory address operand. + // FIXME: Should we use standard interfaces like memoperands_iterator, + // hasMemOperand() etc ? + int MemOpPos = -1; + for (unsigned i = 0; i < NumOperands; i++) { + MachineOperand Op = MI->getOperand(i); + if (Op.getType() == MachineOperand::MO_GlobalAddress || + Op.getType() == MachineOperand::MO_ExternalSymbol) { + // We found one mem operand. Next one should be BS. + MemOpPos = i; + break; + } + } + + // If we did not find an insn accessing memory. Continue. + if (MemOpPos == -1) return Changed; + + // Get the MemOp. + MachineOperand &Op = MI->getOperand(MemOpPos); + + // If this is a pagesel material, handle it first. + if (MI->getOpcode() == PIC16::CALL) { + DebugLoc dl = MI->getDebugLoc(); + BuildMI(*MBB, MI, dl, TII->get(PIC16::pagesel)). + addOperand(Op); + return true; + } + + // Get the section name(NewBank) for MemOp. + // This assumes that the section names for globals are laready set by + // AsmPrinter->doInitialization. + std::string NewBank = CurBank; + if (Op.getType() == MachineOperand::MO_GlobalAddress && + Op.getGlobal()->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) { + NewBank = Op.getGlobal()->getSection(); + } else if (Op.getType() == MachineOperand::MO_ExternalSymbol) { + // External Symbol is generated for temp data and arguments. They are + // in fpdata.<functionname>.# section. + std::string Sym = Op.getSymbolName(); + NewBank = PAN::getSectionNameForSym(Sym); + } + + // If the previous and new section names are same, we don't need to + // emit banksel. + if (NewBank.compare(CurBank) != 0 ) { + DebugLoc dl = MI->getDebugLoc(); + BuildMI(*MBB, MI, dl, TII->get(PIC16::banksel)). + addOperand(Op); + Changed = true; + CurBank = NewBank; + } + + return Changed; +} + diff --git a/lib/Target/PIC16/PIC16RegisterInfo.cpp b/lib/Target/PIC16/PIC16RegisterInfo.cpp new file mode 100644 index 0000000000000..eb758d8543d07 --- /dev/null +++ b/lib/Target/PIC16/PIC16RegisterInfo.cpp @@ -0,0 +1,91 @@ +//===- 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" + + +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; +} + +// PIC16 Callee Saved Reg Classes +const TargetRegisterClass* const* +PIC16RegisterInfo::getCalleeSavedRegClasses(const MachineFunction *MF) const { + static const TargetRegisterClass * const CalleeSavedRegClasses[] = { 0 }; + return CalleeSavedRegClasses; +} + +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 { + assert(0 && "Not keeping track of debug information yet!!"); + return -1; +} + +unsigned PIC16RegisterInfo::getFrameRegister(MachineFunction &MF) const { + assert(0 && "PIC16 Does not have any frame register"); + return 0; +} + +unsigned PIC16RegisterInfo::getRARegister() const { + assert(0 && "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/lib/Target/PIC16/PIC16RegisterInfo.h b/lib/Target/PIC16/PIC16RegisterInfo.h new file mode 100644 index 0000000000000..83689d0486b13 --- /dev/null +++ b/lib/Target/PIC16/PIC16RegisterInfo.h @@ -0,0 +1,68 @@ +//===- 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; + + // PIC16 callee saved register classes + virtual const TargetRegisterClass* const * + getCalleeSavedRegClasses(const MachineFunction *MF) 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(MachineFunction &MF) const; + virtual unsigned getRARegister() const; + +}; + +} // end namespace llvm + +#endif diff --git a/lib/Target/PIC16/PIC16RegisterInfo.td b/lib/Target/PIC16/PIC16RegisterInfo.td new file mode 100644 index 0000000000000..2959d912ec32f --- /dev/null +++ b/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/lib/Target/PIC16/PIC16Subtarget.cpp b/lib/Target/PIC16/PIC16Subtarget.cpp new file mode 100644 index 0000000000000..db8a5d84a4bff --- /dev/null +++ b/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 Module &M, const std::string &FS, + bool Cooper) + :IsCooper(Cooper) +{ + std::string CPU = "generic"; + + // Parse features string. + ParseSubtargetFeatures(FS, CPU); +} diff --git a/lib/Target/PIC16/PIC16Subtarget.h b/lib/Target/PIC16/PIC16Subtarget.h new file mode 100644 index 0000000000000..e5147a0cf8928 --- /dev/null +++ b/lib/Target/PIC16/PIC16Subtarget.h @@ -0,0 +1,45 @@ +//=====-- 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 Module; + +class PIC16Subtarget : public TargetSubtarget { + + // IsCooper - Target ISA is Cooper. + bool IsCooper; + +public: + /// This constructor initializes the data members to match that + /// of the specified module. + /// + PIC16Subtarget(const Module &M, 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/lib/Target/PIC16/PIC16TargetAsmInfo.cpp b/lib/Target/PIC16/PIC16TargetAsmInfo.cpp new file mode 100644 index 0000000000000..d2657f018f888 --- /dev/null +++ b/lib/Target/PIC16/PIC16TargetAsmInfo.cpp @@ -0,0 +1,264 @@ +//===-- PIC16TargetAsmInfo.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 PIC16TargetAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "PIC16TargetAsmInfo.h" +#include "PIC16TargetMachine.h" +#include "llvm/GlobalValue.h" +#include "llvm/GlobalVariable.h" +#include "llvm/DerivedTypes.h" + +using namespace llvm; + +PIC16TargetAsmInfo:: +PIC16TargetAsmInfo(const PIC16TargetMachine &TM) + : TargetAsmInfo(TM) { + CommentString = ";"; + GlobalPrefix = PAN::getTagName(PAN::PREFIX_SYMBOL); + GlobalDirective = "\tglobal\t"; + ExternDirective = "\textern\t"; + + Data8bitsDirective = " db "; + Data16bitsDirective = " dw "; + Data32bitsDirective = " dl "; + RomData8bitsDirective = " dw "; + RomData16bitsDirective = " rom_di "; + RomData32bitsDirective = " rom_dl "; + ZeroDirective = NULL; + AsciiDirective = " dt "; + AscizDirective = NULL; + BSSSection_ = getNamedSection("udata.# UDATA", + SectionFlags::Writeable | SectionFlags::BSS); + ReadOnlySection = getNamedSection("romdata.# ROMDATA", SectionFlags::None); + DataSection = getNamedSection("idata.# IDATA", SectionFlags::Writeable); + SwitchToSectionDirective = ""; + // Need because otherwise a .text symbol is emitted by DwarfWriter + // in BeginModule, and gpasm cribbs for that .text symbol. + TextSection = getUnnamedSection("", SectionFlags::Code); + ROSection = new PIC16Section(getReadOnlySection()); + ExternalVarDecls = new PIC16Section(getNamedSection("ExternalVarDecls")); + ExternalVarDefs = new PIC16Section(getNamedSection("ExternalVarDefs")); + // Set it to false because we weed to generate c file name and not bc file + // name. + HasSingleParameterDotFile = false; +} + +const char *PIC16TargetAsmInfo::getRomDirective(unsigned size) const +{ + if (size == 8) + return RomData8bitsDirective; + else if (size == 16) + return RomData16bitsDirective; + else if (size == 32) + return RomData32bitsDirective; + else + return NULL; +} + + +const char *PIC16TargetAsmInfo::getASDirective(unsigned size, + unsigned AS) const { + if (AS == PIC16ISD::ROM_SPACE) + return getRomDirective(size); + else + return NULL; +} + +const Section * +PIC16TargetAsmInfo::getBSSSectionForGlobal(const GlobalVariable *GV) const { + assert (GV->hasInitializer() && "This global doesn't need space"); + Constant *C = GV->getInitializer(); + assert (C->isNullValue() && "Unitialized globals has non-zero initializer"); + + // Find how much space this global needs. + const TargetData *TD = TM.getTargetData(); + const Type *Ty = C->getType(); + unsigned ValSize = TD->getTypeAllocSize(Ty); + + // Go through all BSS Sections and assign this variable + // to the first available section having enough space. + PIC16Section *FoundBSS = NULL; + for (unsigned i = 0; i < BSSSections.size(); i++) { + if (DataBankSize - BSSSections[i]->Size >= ValSize) { + FoundBSS = BSSSections[i]; + break; + } + } + + // No BSS section spacious enough was found. Crate a new one. + if (! FoundBSS) { + std::string name = PAN::getUdataSectionName(BSSSections.size()); + const Section *NewSection = getNamedSection (name.c_str()); + + FoundBSS = new PIC16Section(NewSection); + + // Add this newly created BSS section to the list of BSSSections. + BSSSections.push_back(FoundBSS); + } + + // Insert the GV into this BSS. + FoundBSS->Items.push_back(GV); + FoundBSS->Size += ValSize; + + // We can't do this here because GV is const . + // const std::string SName = FoundBSS->S_->getName(); + // GV->setSection(SName); + + return FoundBSS->S_; +} + +const Section * +PIC16TargetAsmInfo::getIDATASectionForGlobal(const GlobalVariable *GV) const { + assert (GV->hasInitializer() && "This global doesn't need space"); + Constant *C = GV->getInitializer(); + assert (!C->isNullValue() && "initialized globals has zero initializer"); + assert (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE && + "can split initialized RAM data only"); + + // Find how much space this global needs. + const TargetData *TD = TM.getTargetData(); + const Type *Ty = C->getType(); + unsigned ValSize = TD->getTypeAllocSize(Ty); + + // Go through all IDATA Sections and assign this variable + // to the first available section having enough space. + PIC16Section *FoundIDATA = NULL; + for (unsigned i = 0; i < IDATASections.size(); i++) { + if ( DataBankSize - IDATASections[i]->Size >= ValSize) { + FoundIDATA = IDATASections[i]; + break; + } + } + + // No IDATA section spacious enough was found. Crate a new one. + if (! FoundIDATA) { + std::string name = PAN::getIdataSectionName(IDATASections.size()); + const Section *NewSection = getNamedSection (name.c_str()); + + FoundIDATA = new PIC16Section(NewSection); + + // Add this newly created IDATA section to the list of IDATASections. + IDATASections.push_back(FoundIDATA); + } + + // Insert the GV into this IDATA. + FoundIDATA->Items.push_back(GV); + FoundIDATA->Size += ValSize; + + // We can't do this here because GV is const . + // GV->setSection(FoundIDATA->S->getName()); + + return FoundIDATA->S_; +} + +// Get the section for an automatic variable of a function. +// For PIC16 they are globals only with mangled names. +const Section * +PIC16TargetAsmInfo::getSectionForAuto(const GlobalVariable *GV) const { + + const std::string name = PAN::getSectionNameForSym(GV->getName()); + + // Go through all Auto Sections and assign this variable + // to the appropriate section. + PIC16Section *FoundAutoSec = NULL; + for (unsigned i = 0; i < AutosSections.size(); i++) { + if ( AutosSections[i]->S_->getName() == name) { + FoundAutoSec = AutosSections[i]; + break; + } + } + + // No Auto section was found. Crate a new one. + if (! FoundAutoSec) { + const Section *NewSection = getNamedSection (name.c_str()); + + FoundAutoSec = new PIC16Section(NewSection); + + // Add this newly created autos section to the list of AutosSections. + AutosSections.push_back(FoundAutoSec); + } + + // Insert the auto into this section. + FoundAutoSec->Items.push_back(GV); + + return FoundAutoSec->S_; +} + + +// Override default implementation to put the true globals into +// multiple data sections if required. +const Section* +PIC16TargetAsmInfo::SelectSectionForGlobal(const GlobalValue *GV1) const { + // We select the section based on the initializer here, so it really + // has to be a GlobalVariable. + const GlobalVariable *GV = dyn_cast<GlobalVariable>(GV1); + + if (!GV) + return TargetAsmInfo::SelectSectionForGlobal(GV1); + + // Record Exteranl Var Decls. + if (GV->isDeclaration()) { + ExternalVarDecls->Items.push_back(GV); + return ExternalVarDecls->S_; + } + + 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. + const std::string name = GV->getName(); + if (PAN::isLocalName(name)) { + return getSectionForAuto(GV); + } + + // Record Exteranl Var Defs. + if (GV->hasExternalLinkage() || GV->hasCommonLinkage()) { + ExternalVarDefs->Items.push_back(GV); + } + + // See if this is an uninitialized global. + const Constant *C = GV->getInitializer(); + if (C->isNullValue()) + return getBSSSectionForGlobal(GV); + + // If this is initialized data in RAM. Put it in the correct IDATA section. + if (GV->getType()->getAddressSpace() == PIC16ISD::RAM_SPACE) + return getIDATASectionForGlobal(GV); + + // This is initialized data in rom, put it in the readonly section. + if (GV->getType()->getAddressSpace() == PIC16ISD::ROM_SPACE) { + ROSection->Items.push_back(GV); + return ROSection->S_; + } + + // Else let the default implementation take care of it. + return TargetAsmInfo::SelectSectionForGlobal(GV); +} + +PIC16TargetAsmInfo::~PIC16TargetAsmInfo() { + + for (unsigned i = 0; i < BSSSections.size(); i++) { + delete BSSSections[i]; + } + + for (unsigned i = 0; i < IDATASections.size(); i++) { + delete IDATASections[i]; + } + + for (unsigned i = 0; i < AutosSections.size(); i++) { + delete AutosSections[i]; + } + + delete ROSection; + delete ExternalVarDecls; + delete ExternalVarDefs; +} diff --git a/lib/Target/PIC16/PIC16TargetAsmInfo.h b/lib/Target/PIC16/PIC16TargetAsmInfo.h new file mode 100644 index 0000000000000..e464e36f7887e --- /dev/null +++ b/lib/Target/PIC16/PIC16TargetAsmInfo.h @@ -0,0 +1,79 @@ +//=====-- PIC16TargetAsmInfo.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 PIC16TargetAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef PIC16TARGETASMINFO_H +#define PIC16TARGETASMINFO_H + +#include "PIC16.h" +#include "llvm/Target/TargetAsmInfo.h" +#include <vector> +#include "llvm/Module.h" +#define DataBankSize 80 +namespace llvm { + + // Forward declaration. + class PIC16TargetMachine; + class GlobalVariable; + + // PIC16 Splits the global data into mulitple udata and idata sections. + // Each udata and idata section needs to contain a list of globals that + // they contain, in order to avoid scanning over all the global values + // again and printing only those that match the current section. + // Keeping values inside the sections make printing a section much easier. + struct PIC16Section { + const Section *S_; // Connection to actual Section. + unsigned Size; // Total size of the objects contained. + std::vector<const GlobalVariable*> Items; + + PIC16Section (const Section *s) { S_ = s; Size = 0; } + }; + + struct PIC16TargetAsmInfo : public TargetAsmInfo { + std::string getSectionNameForSym(const std::string &Sym) const; + PIC16TargetAsmInfo(const PIC16TargetMachine &TM); + mutable std::vector<PIC16Section *> BSSSections; + mutable std::vector<PIC16Section *> IDATASections; + mutable std::vector<PIC16Section *> AutosSections; + mutable PIC16Section *ROSection; + mutable PIC16Section *ExternalVarDecls; + mutable PIC16Section *ExternalVarDefs; + virtual ~PIC16TargetAsmInfo(); + + private: + const char *RomData8bitsDirective; + const char *RomData16bitsDirective; + const char *RomData32bitsDirective; + const char *getRomDirective(unsigned size) const; + virtual const char *getASDirective(unsigned size, unsigned AS) const; + const Section *getBSSSectionForGlobal(const GlobalVariable *GV) const; + const Section *getIDATASectionForGlobal(const GlobalVariable *GV) const; + const Section *getSectionForAuto(const GlobalVariable *GV) const; + virtual const Section *SelectSectionForGlobal(const GlobalValue *GV) const; + + + public: + void SetSectionForGVs(Module &M); + std::vector<PIC16Section *> getBSSSections() const { + return BSSSections; + } + std::vector<PIC16Section *> getIDATASections() const { + return IDATASections; + } + std::vector<PIC16Section *> getAutosSections() const { + return AutosSections; + } + }; + +} // namespace llvm + +#endif diff --git a/lib/Target/PIC16/PIC16TargetMachine.cpp b/lib/Target/PIC16/PIC16TargetMachine.cpp new file mode 100644 index 0000000000000..bda632608ea76 --- /dev/null +++ b/lib/Target/PIC16/PIC16TargetMachine.cpp @@ -0,0 +1,79 @@ +//===-- 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 "PIC16TargetAsmInfo.h" +#include "PIC16TargetMachine.h" +#include "llvm/Module.h" +#include "llvm/PassManager.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/TargetMachineRegistry.h" + +using namespace llvm; + +/// PIC16TargetMachineModule - Note that this is used on hosts that +/// cannot link in a library unless there are references into the +/// library. In particular, it seems that it is not possible to get +/// things to work on Win32 without this. Though it is unused, do not +/// remove it. +extern "C" int PIC16TargetMachineModule; +int PIC16TargetMachineModule = 0; + + +// Register the targets +static RegisterTarget<PIC16TargetMachine> +X("pic16", "PIC16 14-bit [experimental]."); +static RegisterTarget<CooperTargetMachine> +Y("cooper", "PIC16 Cooper [experimental]."); + +// PIC16TargetMachine - Traditional PIC16 Machine. +PIC16TargetMachine::PIC16TargetMachine(const Module &M, const std::string &FS, + bool Cooper) +: Subtarget(M, FS, Cooper), + DataLayout("e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8"), + InstrInfo(*this), TLInfo(*this), + FrameInfo(TargetFrameInfo::StackGrowsUp, 8, 0) { } + +// CooperTargetMachine - Uses the same PIC16TargetMachine, but makes IsCooper +// as true. +CooperTargetMachine::CooperTargetMachine(const Module &M, const std::string &FS) + : PIC16TargetMachine(M, FS, true) {} + + +const TargetAsmInfo *PIC16TargetMachine::createTargetAsmInfo() const { + return new PIC16TargetAsmInfo(*this); +} + +bool PIC16TargetMachine::addInstSelector(PassManagerBase &PM, + CodeGenOpt::Level OptLevel) { + // Install an instruction selector. + PM.add(createPIC16ISelDag(*this)); + return false; +} + +bool PIC16TargetMachine:: +addAssemblyEmitter(PassManagerBase &PM, CodeGenOpt::Level OptLevel, + bool Verbose, raw_ostream &Out) { + // Output assembly language. + PM.add(createPIC16CodePrinterPass(Out, *this, OptLevel, Verbose)); + return false; +} + +bool PIC16TargetMachine::addPostRegAlloc(PassManagerBase &PM, + CodeGenOpt::Level OptLevel) { + PM.add(createPIC16MemSelOptimizerPass()); + return true; // -print-machineinstr should print after this. +} + + diff --git a/lib/Target/PIC16/PIC16TargetMachine.h b/lib/Target/PIC16/PIC16TargetMachine.h new file mode 100644 index 0000000000000..7f62d5c13d64b --- /dev/null +++ b/lib/Target/PIC16/PIC16TargetMachine.h @@ -0,0 +1,76 @@ +//===-- 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 "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; + + // PIC16 does not have any call stack frame, therefore not having + // any PIC16 specific FrameInfo class. + TargetFrameInfo FrameInfo; + +protected: + virtual const TargetAsmInfo *createTargetAsmInfo() const; + +public: + PIC16TargetMachine(const Module &M, 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 PIC16TargetLowering *getTargetLowering() const { + return const_cast<PIC16TargetLowering*>(&TLInfo); + } + + virtual bool addInstSelector(PassManagerBase &PM, + CodeGenOpt::Level OptLevel); + virtual bool addAssemblyEmitter(PassManagerBase &PM, + CodeGenOpt::Level OptLevel, + bool Verbose, raw_ostream &Out); + virtual bool addPostRegAlloc(PassManagerBase &PM, CodeGenOpt::Level OptLevel); +}; // PIC16TargetMachine. + +/// CooperTargetMachine +class CooperTargetMachine : public PIC16TargetMachine { +public: + CooperTargetMachine(const Module &M, const std::string &FS); +}; // CooperTargetMachine. + +} // end namespace llvm + +#endif |