diff options
| author | Stephen Hines <srhines@google.com> | 2014-04-23 16:57:46 -0700 |
|---|---|---|
| committer | Stephen Hines <srhines@google.com> | 2014-04-24 15:53:16 -0700 |
| commit | 36b56886974eae4f9c5ebc96befd3e7bfe5de338 (patch) | |
| tree | e6cfb69fbbd937f450eeb83bfb83b9da3b01275a /lib/Target/XCore | |
| parent | 69a8640022b04415ae9fac62f8ab090601d8f889 (diff) | |
| download | external_llvm-36b56886974eae4f9c5ebc96befd3e7bfe5de338.zip external_llvm-36b56886974eae4f9c5ebc96befd3e7bfe5de338.tar.gz external_llvm-36b56886974eae4f9c5ebc96befd3e7bfe5de338.tar.bz2 | |
Update to LLVM 3.5a.
Change-Id: Ifadecab779f128e62e430c2b4f6ddd84953ed617
Diffstat (limited to 'lib/Target/XCore')
36 files changed, 1567 insertions, 509 deletions
diff --git a/lib/Target/XCore/CMakeLists.txt b/lib/Target/XCore/CMakeLists.txt index 3fa3b34..5ad0754 100644 --- a/lib/Target/XCore/CMakeLists.txt +++ b/lib/Target/XCore/CMakeLists.txt @@ -24,10 +24,9 @@ add_llvm_target(XCoreCodeGen XCoreTargetObjectFile.cpp XCoreTargetTransformInfo.cpp XCoreSelectionDAGInfo.cpp + XCoreFrameToArgsOffsetElim.cpp ) -add_dependencies(LLVMXCoreCodeGen XCoreCommonTableGen intrinsics_gen) - add_subdirectory(Disassembler) add_subdirectory(InstPrinter) add_subdirectory(TargetInfo) diff --git a/lib/Target/XCore/Disassembler/CMakeLists.txt b/lib/Target/XCore/Disassembler/CMakeLists.txt index cdc5d99..1ed10c0 100644 --- a/lib/Target/XCore/Disassembler/CMakeLists.txt +++ b/lib/Target/XCore/Disassembler/CMakeLists.txt @@ -1,5 +1,3 @@ add_llvm_library(LLVMXCoreDisassembler XCoreDisassembler.cpp ) - -add_dependencies(LLVMXCoreDisassembler XCoreCommonTableGen) diff --git a/lib/Target/XCore/InstPrinter/CMakeLists.txt b/lib/Target/XCore/InstPrinter/CMakeLists.txt index 930e733..53cf84d 100644 --- a/lib/Target/XCore/InstPrinter/CMakeLists.txt +++ b/lib/Target/XCore/InstPrinter/CMakeLists.txt @@ -1,7 +1,3 @@ -include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) - add_llvm_library(LLVMXCoreAsmPrinter XCoreInstPrinter.cpp ) - -add_dependencies(LLVMXCoreAsmPrinter XCoreCommonTableGen) diff --git a/lib/Target/XCore/LLVMBuild.txt b/lib/Target/XCore/LLVMBuild.txt index 59e64ad..0504e8a 100644 --- a/lib/Target/XCore/LLVMBuild.txt +++ b/lib/Target/XCore/LLVMBuild.txt @@ -29,5 +29,5 @@ has_disassembler = 1 type = Library name = XCoreCodeGen parent = XCore -required_libraries = AsmPrinter CodeGen Core MC SelectionDAG Support Target XCoreDesc XCoreInfo +required_libraries = Analysis AsmPrinter CodeGen Core MC SelectionDAG Support Target TransformUtils XCoreAsmPrinter XCoreDesc XCoreInfo add_to_library_groups = XCore diff --git a/lib/Target/XCore/MCTargetDesc/CMakeLists.txt b/lib/Target/XCore/MCTargetDesc/CMakeLists.txt index 3a3f5b4..a14cf5c 100644 --- a/lib/Target/XCore/MCTargetDesc/CMakeLists.txt +++ b/lib/Target/XCore/MCTargetDesc/CMakeLists.txt @@ -2,8 +2,3 @@ add_llvm_library(LLVMXCoreDesc XCoreMCTargetDesc.cpp XCoreMCAsmInfo.cpp ) - -add_dependencies(LLVMXCoreDesc XCoreCommonTableGen) - -# Hack: we need to include 'main' target directory to grab private headers -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/..) diff --git a/lib/Target/XCore/MCTargetDesc/LLVMBuild.txt b/lib/Target/XCore/MCTargetDesc/LLVMBuild.txt index 8213f9e..6d390d2 100644 --- a/lib/Target/XCore/MCTargetDesc/LLVMBuild.txt +++ b/lib/Target/XCore/MCTargetDesc/LLVMBuild.txt @@ -19,5 +19,5 @@ type = Library name = XCoreDesc parent = XCore -required_libraries = MC XCoreAsmPrinter XCoreInfo +required_libraries = MC Support XCoreAsmPrinter XCoreInfo add_to_library_groups = XCore diff --git a/lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.cpp b/lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.cpp index 3d1c474..f788c59 100644 --- a/lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.cpp +++ b/lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.cpp @@ -20,8 +20,7 @@ XCoreMCAsmInfo::XCoreMCAsmInfo(StringRef TT) { Data64bitsDirective = 0; ZeroDirective = "\t.space\t"; CommentString = "#"; - - PrivateGlobalPrefix = ".L"; + AscizDirective = ".asciiz"; HiddenVisibilityAttr = MCSA_Invalid; diff --git a/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.cpp b/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.cpp index 10bb6df..439d0ab 100644 --- a/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.cpp +++ b/lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.cpp @@ -14,11 +14,13 @@ #include "XCoreMCTargetDesc.h" #include "InstPrinter/XCoreInstPrinter.h" #include "XCoreMCAsmInfo.h" +#include "XCoreTargetStreamer.h" #include "llvm/MC/MCCodeGenInfo.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" #include "llvm/Support/TargetRegistry.h" #define GET_INSTRINFO_MC_DESC @@ -69,6 +71,12 @@ static MCCodeGenInfo *createXCoreMCCodeGenInfo(StringRef TT, Reloc::Model RM, if (RM == Reloc::Default) { RM = Reloc::Static; } + if (CM == CodeModel::Default) { + CM = CodeModel::Small; + } + if (CM != CodeModel::Small && CM != CodeModel::Large) + report_fatal_error("Target only supports CodeModel Small or Large"); + X->InitMCCodeGenInfo(RM, CM, OL); return X; } @@ -82,6 +90,54 @@ static MCInstPrinter *createXCoreMCInstPrinter(const Target &T, return new XCoreInstPrinter(MAI, MII, MRI); } +XCoreTargetStreamer::XCoreTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {} +XCoreTargetStreamer::~XCoreTargetStreamer() {} + +namespace { + +class XCoreTargetAsmStreamer : public XCoreTargetStreamer { + formatted_raw_ostream &OS; +public: + XCoreTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS); + virtual void emitCCTopData(StringRef Name) override; + virtual void emitCCTopFunction(StringRef Name) override; + virtual void emitCCBottomData(StringRef Name) override; + virtual void emitCCBottomFunction(StringRef Name) override; +}; + +XCoreTargetAsmStreamer::XCoreTargetAsmStreamer(MCStreamer &S, + formatted_raw_ostream &OS) + : XCoreTargetStreamer(S), OS(OS) {} + +void XCoreTargetAsmStreamer::emitCCTopData(StringRef Name) { + OS << "\t.cc_top " << Name << ".data," << Name << '\n'; +} + +void XCoreTargetAsmStreamer::emitCCTopFunction(StringRef Name) { + OS << "\t.cc_top " << Name << ".function," << Name << '\n'; +} + +void XCoreTargetAsmStreamer::emitCCBottomData(StringRef Name) { + OS << "\t.cc_bottom " << Name << ".data\n"; +} + +void XCoreTargetAsmStreamer::emitCCBottomFunction(StringRef Name) { + OS << "\t.cc_bottom " << Name << ".function\n"; +} +} + +static MCStreamer * +createXCoreMCAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS, + bool isVerboseAsm, bool useCFI, bool useDwarfDirectory, + MCInstPrinter *InstPrint, MCCodeEmitter *CE, + MCAsmBackend *TAB, bool ShowInst) { + MCStreamer *S = + llvm::createAsmStreamer(Ctx, OS, isVerboseAsm, useCFI, useDwarfDirectory, + InstPrint, CE, TAB, ShowInst); + new XCoreTargetAsmStreamer(*S, OS); + return S; +} + // Force static initialization. extern "C" void LLVMInitializeXCoreTargetMC() { // Register the MC asm info. @@ -104,4 +160,6 @@ extern "C" void LLVMInitializeXCoreTargetMC() { // Register the MCInstPrinter TargetRegistry::RegisterMCInstPrinter(TheXCoreTarget, createXCoreMCInstPrinter); + + TargetRegistry::RegisterAsmStreamer(TheXCoreTarget, createXCoreMCAsmStreamer); } diff --git a/lib/Target/XCore/TargetInfo/CMakeLists.txt b/lib/Target/XCore/TargetInfo/CMakeLists.txt index 2c34b87..462f2d4 100644 --- a/lib/Target/XCore/TargetInfo/CMakeLists.txt +++ b/lib/Target/XCore/TargetInfo/CMakeLists.txt @@ -1,7 +1,3 @@ -include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) - add_llvm_library(LLVMXCoreInfo XCoreTargetInfo.cpp ) - -add_dependencies(LLVMXCoreInfo XCoreCommonTableGen) diff --git a/lib/Target/XCore/TargetInfo/LLVMBuild.txt b/lib/Target/XCore/TargetInfo/LLVMBuild.txt index 770ba87..45ff75f 100644 --- a/lib/Target/XCore/TargetInfo/LLVMBuild.txt +++ b/lib/Target/XCore/TargetInfo/LLVMBuild.txt @@ -19,5 +19,5 @@ type = Library name = XCoreInfo parent = XCore -required_libraries = MC Support Target +required_libraries = Support add_to_library_groups = XCore diff --git a/lib/Target/XCore/XCore.h b/lib/Target/XCore/XCore.h index 73c310b..d707edc 100644 --- a/lib/Target/XCore/XCore.h +++ b/lib/Target/XCore/XCore.h @@ -27,6 +27,7 @@ namespace llvm { void initializeXCoreLowerThreadLocalPass(PassRegistry &p); + FunctionPass *createXCoreFrameToArgsOffsetEliminationPass(); FunctionPass *createXCoreISelDag(XCoreTargetMachine &TM, CodeGenOpt::Level OptLevel); ModulePass *createXCoreLowerThreadLocalPass(); diff --git a/lib/Target/XCore/XCore.td b/lib/Target/XCore/XCore.td index e9a6d88..04a1dd5 100644 --- a/lib/Target/XCore/XCore.td +++ b/lib/Target/XCore/XCore.td @@ -41,13 +41,7 @@ def : Proc<"xs1b-generic", []>; // Declare the target which we are implementing //===----------------------------------------------------------------------===// -def XCoreAsmWriter : AsmWriter { - string AsmWriterClassName = "InstPrinter"; - bit isMCAsmWriter = 1; -} - def XCore : Target { // Pull in Instruction Info: let InstructionSet = XCoreInstrInfo; - let AssemblyWriters = [XCoreAsmWriter]; } diff --git a/lib/Target/XCore/XCoreAsmPrinter.cpp b/lib/Target/XCore/XCoreAsmPrinter.cpp index c03dfe6..21acedf 100644 --- a/lib/Target/XCore/XCoreAsmPrinter.cpp +++ b/lib/Target/XCore/XCoreAsmPrinter.cpp @@ -19,6 +19,7 @@ #include "XCoreMCInstLower.h" #include "XCoreSubtarget.h" #include "XCoreTargetMachine.h" +#include "XCoreTargetStreamer.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/CodeGen/AsmPrinter.h" @@ -27,20 +28,20 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineModuleInfo.h" -#include "llvm/DebugInfo.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCExpr.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/Mangler.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include <algorithm> #include <cctype> @@ -50,6 +51,8 @@ namespace { class XCoreAsmPrinter : public AsmPrinter { const XCoreSubtarget &Subtarget; XCoreMCInstLower MCInstLowering; + XCoreTargetStreamer &getTargetStreamer(); + public: explicit XCoreAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) : AsmPrinter(TM, Streamer), Subtarget(TM.getSubtarget<XCoreSubtarget>()), @@ -68,6 +71,9 @@ namespace { bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, raw_ostream &O); + bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O) override; void emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV); virtual void EmitGlobalVariable(const GlobalVariable *GV); @@ -79,10 +85,14 @@ namespace { }; } // end of anonymous namespace +XCoreTargetStreamer &XCoreAsmPrinter::getTargetStreamer() { + return static_cast<XCoreTargetStreamer&>(*OutStreamer.getTargetStreamer()); +} + void XCoreAsmPrinter::emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV) { - assert(((GV->hasExternalLinkage() || - GV->hasWeakLinkage()) || - GV->hasLinkOnceLinkage()) && "Unexpected linkage"); + assert( ( GV->hasExternalLinkage() || GV->hasWeakLinkage() || + GV->hasLinkOnceLinkage() || GV->hasCommonLinkage() ) && + "Unexpected linkage"); if (ArrayType *ATy = dyn_cast<ArrayType>( cast<PointerType>(GV->getType())->getElementType())) { @@ -92,7 +102,8 @@ void XCoreAsmPrinter::emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV) { OutStreamer.EmitAssignment(SymGlob, MCConstantExpr::Create(ATy->getNumElements(), OutContext)); - if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) { + if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() || + GV->hasCommonLinkage()) { // TODO Use COMDAT groups for LinkOnceLinkage OutStreamer.EmitSymbolAttribute(SymGlob, MCSA_Weak); } @@ -106,16 +117,15 @@ void XCoreAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { return; const DataLayout *TD = TM.getDataLayout(); - OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(GV, Mang,TM)); + OutStreamer.SwitchSection( + getObjFileLowering().SectionForGlobal(GV, *Mang, TM)); - MCSymbol *GVSym = getSymbol(GV); const Constant *C = GV->getInitializer(); unsigned Align = (unsigned)TD->getPreferredTypeAlignmentShift(C->getType()); // Mark the start of the global - OutStreamer.EmitRawText("\t.cc_top " + Twine(GVSym->getName()) + ".data," + - GVSym->getName()); + getTargetStreamer().emitCCTopData(GVSym->getName()); switch (GV->getLinkage()) { case GlobalValue::AppendingLinkage: @@ -125,20 +135,18 @@ void XCoreAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { case GlobalValue::WeakAnyLinkage: case GlobalValue::WeakODRLinkage: case GlobalValue::ExternalLinkage: + case GlobalValue::CommonLinkage: emitArrayBound(GVSym, GV); OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Global); // TODO Use COMDAT groups for LinkOnceLinkage - if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) + if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() || + GV->hasCommonLinkage()) OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Weak); // FALL THROUGH case GlobalValue::InternalLinkage: case GlobalValue::PrivateLinkage: break; - case GlobalValue::DLLImportLinkage: - llvm_unreachable("DLLImport linkage is not supported by this target!"); - case GlobalValue::DLLExportLinkage: - llvm_unreachable("DLLExport linkage is not supported by this target!"); default: llvm_unreachable("Unknown linkage type!"); } @@ -151,8 +159,7 @@ void XCoreAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { unsigned Size = TD->getTypeAllocSize(C->getType()); if (MAI->hasDotTypeDotSizeDirective()) { OutStreamer.EmitSymbolAttribute(GVSym, MCSA_ELF_TypeObject); - OutStreamer.EmitRawText("\t.size " + Twine(GVSym->getName()) + "," + - Twine(Size)); + OutStreamer.EmitELFSize(GVSym, MCConstantExpr::Create(Size, OutContext)); } OutStreamer.EmitLabel(GVSym); @@ -163,7 +170,7 @@ void XCoreAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { OutStreamer.EmitZeros(4 - Size); // Mark the end of the global - OutStreamer.EmitRawText("\t.cc_bottom " + Twine(GVSym->getName()) + ".data"); + getTargetStreamer().emitCCBottomData(GVSym->getName()); } void XCoreAsmPrinter::EmitFunctionBodyStart() { @@ -174,14 +181,12 @@ void XCoreAsmPrinter::EmitFunctionBodyStart() { /// the last basic block in the function. void XCoreAsmPrinter::EmitFunctionBodyEnd() { // Emit function end directives - OutStreamer.EmitRawText("\t.cc_bottom " + Twine(CurrentFnSym->getName()) + - ".function"); + getTargetStreamer().emitCCBottomFunction(CurrentFnSym->getName()); } void XCoreAsmPrinter::EmitFunctionEntryLabel() { // Mark the start of the function - OutStreamer.EmitRawText("\t.cc_top " + Twine(CurrentFnSym->getName()) + - ".function," + CurrentFnSym->getName()); + getTargetStreamer().emitCCTopFunction(CurrentFnSym->getName()); OutStreamer.EmitLabel(CurrentFnSym); } @@ -204,6 +209,7 @@ printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O, void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum, raw_ostream &O) { + const DataLayout *DL = TM.getDataLayout(); const MachineOperand &MO = MI->getOperand(opNum); switch (MO.getType()) { case MachineOperand::MO_Register: @@ -218,15 +224,8 @@ void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum, case MachineOperand::MO_GlobalAddress: O << *getSymbol(MO.getGlobal()); break; - case MachineOperand::MO_ExternalSymbol: - O << MO.getSymbolName(); - break; case MachineOperand::MO_ConstantPoolIndex: - O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() - << '_' << MO.getIndex(); - break; - case MachineOperand::MO_JumpTableIndex: - O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() + O << DL->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_' << MO.getIndex(); break; case MachineOperand::MO_BlockAddress: @@ -252,6 +251,20 @@ bool XCoreAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O); } +bool XCoreAsmPrinter:: +PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O) { + if (ExtraCode && ExtraCode[0]) { + return true; // Unknown modifier. + } + printOperand(MI, OpNum, O); + O << '['; + printOperand(MI, OpNum + 1, O); + O << ']'; + return false; +} + void XCoreAsmPrinter::EmitInstruction(const MachineInstr *MI) { SmallString<128> Str; raw_svector_ostream O(Str); @@ -284,7 +297,7 @@ void XCoreAsmPrinter::EmitInstruction(const MachineInstr *MI) { MCInst TmpInst; MCInstLowering.Lower(MI, TmpInst); - OutStreamer.EmitInstruction(TmpInst); + EmitToStreamer(OutStreamer, TmpInst); } // Force static initialization. diff --git a/lib/Target/XCore/XCoreCallingConv.td b/lib/Target/XCore/XCoreCallingConv.td index b20d71f..e149e6d 100644 --- a/lib/Target/XCore/XCoreCallingConv.td +++ b/lib/Target/XCore/XCoreCallingConv.td @@ -14,7 +14,11 @@ //===----------------------------------------------------------------------===// def RetCC_XCore : CallingConv<[ // i32 are returned in registers R0, R1, R2, R3 - CCIfType<[i32], CCAssignToReg<[R0, R1, R2, R3]>> + CCIfType<[i32], CCAssignToReg<[R0, R1, R2, R3]>>, + + // Integer values get stored in stack slots that are 4 bytes in + // size and 4-byte aligned. + CCIfType<[i32], CCAssignToStack<4, 4>> ]>; //===----------------------------------------------------------------------===// diff --git a/lib/Target/XCore/XCoreFrameLowering.cpp b/lib/Target/XCore/XCoreFrameLowering.cpp index c34b35c..954fddf 100644 --- a/lib/Target/XCore/XCoreFrameLowering.cpp +++ b/lib/Target/XCore/XCoreFrameLowering.cpp @@ -25,10 +25,15 @@ #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetOptions.h" +#include <algorithm> // std::sort using namespace llvm; +static const unsigned FramePtr = XCore::R10; +static const int MaxImmU16 = (1<<16) - 1; + // helper functions. FIXME: Eliminate. static inline bool isImmU6(unsigned val) { return val < (1 << 6); @@ -38,37 +43,164 @@ static inline bool isImmU16(unsigned val) { return val < (1 << 16); } -static void loadFromStack(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, - unsigned DstReg, int Offset, DebugLoc dl, - const TargetInstrInfo &TII) { - assert(Offset%4 == 0 && "Misaligned stack offset"); - Offset/=4; - bool isU6 = isImmU6(Offset); - if (!isU6 && !isImmU16(Offset)) - report_fatal_error("loadFromStack offset too big " + Twine(Offset)); - int Opcode = isU6 ? XCore::LDWSP_ru6 : XCore::LDWSP_lru6; - BuildMI(MBB, I, dl, TII.get(Opcode), DstReg) - .addImm(Offset); +// Helper structure with compare function for handling stack slots. +namespace { +struct StackSlotInfo { + int FI; + int Offset; + unsigned Reg; + StackSlotInfo(int f, int o, int r) : FI(f), Offset(o), Reg(r){}; +}; +} // end anonymous namespace + +static bool CompareSSIOffset(const StackSlotInfo& a, const StackSlotInfo& b) { + return a.Offset < b.Offset; +} + + +static void EmitDefCfaRegister(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, DebugLoc dl, + const TargetInstrInfo &TII, + MachineModuleInfo *MMI, unsigned DRegNum) { + unsigned CFIIndex = MMI->addFrameInst( + MCCFIInstruction::createDefCfaRegister(nullptr, DRegNum)); + BuildMI(MBB, MBBI, dl, TII.get(XCore::CFI_INSTRUCTION)).addCFIIndex(CFIIndex); +} + +static void EmitDefCfaOffset(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, DebugLoc dl, + const TargetInstrInfo &TII, + MachineModuleInfo *MMI, int Offset) { + unsigned CFIIndex = + MMI->addFrameInst(MCCFIInstruction::createDefCfaOffset(nullptr, -Offset)); + BuildMI(MBB, MBBI, dl, TII.get(XCore::CFI_INSTRUCTION)).addCFIIndex(CFIIndex); +} + +static void EmitCfiOffset(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, DebugLoc dl, + const TargetInstrInfo &TII, MachineModuleInfo *MMI, + unsigned DRegNum, int Offset) { + unsigned CFIIndex = MMI->addFrameInst( + MCCFIInstruction::createOffset(nullptr, DRegNum, Offset)); + BuildMI(MBB, MBBI, dl, TII.get(XCore::CFI_INSTRUCTION)).addCFIIndex(CFIIndex); +} + +/// The SP register is moved in steps of 'MaxImmU16' towards the bottom of the +/// frame. During these steps, it may be necessary to spill registers. +/// IfNeededExtSP emits the necessary EXTSP instructions to move the SP only +/// as far as to make 'OffsetFromBottom' reachable using an STWSP_lru6. +/// \param OffsetFromTop the spill offset from the top of the frame. +/// \param [in,out] Adjusted the current SP offset from the top of the frame. +static void IfNeededExtSP(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, DebugLoc dl, + const TargetInstrInfo &TII, MachineModuleInfo *MMI, + int OffsetFromTop, int &Adjusted, int FrameSize, + bool emitFrameMoves) { + while (OffsetFromTop > Adjusted) { + assert(Adjusted < FrameSize && "OffsetFromTop is beyond FrameSize"); + int remaining = FrameSize - Adjusted; + int OpImm = (remaining > MaxImmU16) ? MaxImmU16 : remaining; + int Opcode = isImmU6(OpImm) ? XCore::EXTSP_u6 : XCore::EXTSP_lu6; + BuildMI(MBB, MBBI, dl, TII.get(Opcode)).addImm(OpImm); + Adjusted += OpImm; + if (emitFrameMoves) + EmitDefCfaOffset(MBB, MBBI, dl, TII, MMI, Adjusted*4); + } +} + +/// The SP register is moved in steps of 'MaxImmU16' towards the top of the +/// frame. During these steps, it may be necessary to re-load registers. +/// IfNeededLDAWSP emits the necessary LDAWSP instructions to move the SP only +/// as far as to make 'OffsetFromTop' reachable using an LDAWSP_lru6. +/// \param OffsetFromTop the spill offset from the top of the frame. +/// \param [in,out] RemainingAdj the current SP offset from the top of the frame. +static void IfNeededLDAWSP(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, DebugLoc dl, + const TargetInstrInfo &TII, int OffsetFromTop, + int &RemainingAdj) { + while (OffsetFromTop < RemainingAdj - MaxImmU16) { + assert(RemainingAdj && "OffsetFromTop is beyond FrameSize"); + int OpImm = (RemainingAdj > MaxImmU16) ? MaxImmU16 : RemainingAdj; + int Opcode = isImmU6(OpImm) ? XCore::LDAWSP_ru6 : XCore::LDAWSP_lru6; + BuildMI(MBB, MBBI, dl, TII.get(Opcode), XCore::SP).addImm(OpImm); + RemainingAdj -= OpImm; + } +} + +/// Creates an ordered list of registers that are spilled +/// during the emitPrologue/emitEpilogue. +/// Registers are ordered according to their frame offset. +/// As offsets are negative, the largest offsets will be first. +static void GetSpillList(SmallVectorImpl<StackSlotInfo> &SpillList, + MachineFrameInfo *MFI, XCoreFunctionInfo *XFI, + bool fetchLR, bool fetchFP) { + if (fetchLR) { + int Offset = MFI->getObjectOffset(XFI->getLRSpillSlot()); + SpillList.push_back(StackSlotInfo(XFI->getLRSpillSlot(), + Offset, + XCore::LR)); + } + if (fetchFP) { + int Offset = MFI->getObjectOffset(XFI->getFPSpillSlot()); + SpillList.push_back(StackSlotInfo(XFI->getFPSpillSlot(), + Offset, + FramePtr)); + } + std::sort(SpillList.begin(), SpillList.end(), CompareSSIOffset); +} + +/// Creates an ordered list of EH info register 'spills'. +/// These slots are only used by the unwinder and calls to llvm.eh.return(). +/// Registers are ordered according to their frame offset. +/// As offsets are negative, the largest offsets will be first. +static void GetEHSpillList(SmallVectorImpl<StackSlotInfo> &SpillList, + MachineFrameInfo *MFI, XCoreFunctionInfo *XFI, + const TargetLowering *TL) { + assert(XFI->hasEHSpillSlot() && "There are no EH register spill slots"); + const int* EHSlot = XFI->getEHSpillSlot(); + SpillList.push_back(StackSlotInfo(EHSlot[0], + MFI->getObjectOffset(EHSlot[0]), + TL->getExceptionPointerRegister())); + SpillList.push_back(StackSlotInfo(EHSlot[0], + MFI->getObjectOffset(EHSlot[1]), + TL->getExceptionSelectorRegister())); + std::sort(SpillList.begin(), SpillList.end(), CompareSSIOffset); } -static void storeToStack(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, - unsigned SrcReg, int Offset, DebugLoc dl, - const TargetInstrInfo &TII) { - assert(Offset%4 == 0 && "Misaligned stack offset"); - Offset/=4; - bool isU6 = isImmU6(Offset); - if (!isU6 && !isImmU16(Offset)) - report_fatal_error("storeToStack offset too big " + Twine(Offset)); - int Opcode = isU6 ? XCore::STWSP_ru6 : XCore::STWSP_lru6; - BuildMI(MBB, I, dl, TII.get(Opcode)) - .addReg(SrcReg) - .addImm(Offset); +static MachineMemOperand * +getFrameIndexMMO(MachineBasicBlock &MBB, int FrameIndex, unsigned flags) { + MachineFunction *MF = MBB.getParent(); + const MachineFrameInfo &MFI = *MF->getFrameInfo(); + MachineMemOperand *MMO = + MF->getMachineMemOperand(MachinePointerInfo::getFixedStack(FrameIndex), + flags, MFI.getObjectSize(FrameIndex), + MFI.getObjectAlignment(FrameIndex)); + return MMO; } +/// Restore clobbered registers with their spill slot value. +/// The SP will be adjusted at the same time, thus the SpillList must be ordered +/// with the largest (negative) offsets first. +static void +RestoreSpillList(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + DebugLoc dl, const TargetInstrInfo &TII, int &RemainingAdj, + SmallVectorImpl<StackSlotInfo> &SpillList) { + for (unsigned i = 0, e = SpillList.size(); i != e; ++i) { + assert(SpillList[i].Offset % 4 == 0 && "Misaligned stack offset"); + assert(SpillList[i].Offset <= 0 && "Unexpected positive stack offset"); + int OffsetFromTop = - SpillList[i].Offset/4; + IfNeededLDAWSP(MBB, MBBI, dl, TII, OffsetFromTop, RemainingAdj); + int Offset = RemainingAdj - OffsetFromTop; + int Opcode = isImmU6(Offset) ? XCore::LDWSP_ru6 : XCore::LDWSP_lru6; + BuildMI(MBB, MBBI, dl, TII.get(Opcode), SpillList[i].Reg) + .addImm(Offset) + .addMemOperand(getFrameIndexMMO(MBB, SpillList[i].FI, + MachineMemOperand::MOLoad)); + } +} + //===----------------------------------------------------------------------===// // XCoreFrameLowering: //===----------------------------------------------------------------------===// @@ -80,7 +212,7 @@ XCoreFrameLowering::XCoreFrameLowering(const XCoreSubtarget &sti) bool XCoreFrameLowering::hasFP(const MachineFunction &MF) const { return MF.getTarget().Options.DisableFramePointerElim(MF) || - MF.getFrameInfo()->hasVarSizedObjects(); + MF.getFrameInfo()->hasVarSizedObjects(); } void XCoreFrameLowering::emitPrologue(MachineFunction &MF) const { @@ -98,213 +230,216 @@ void XCoreFrameLowering::emitPrologue(MachineFunction &MF) const { report_fatal_error("emitPrologue unsupported alignment: " + Twine(MFI->getMaxAlignment())); - bool FP = hasFP(MF); const AttributeSet &PAL = MF.getFunction()->getAttributes(); - if (PAL.hasAttrSomewhere(Attribute::Nest)) - loadFromStack(MBB, MBBI, XCore::R11, 0, dl, TII); + BuildMI(MBB, MBBI, dl, TII.get(XCore::LDWSP_ru6), XCore::R11).addImm(0); + // FIX: Needs addMemOperand() but can't use getFixedStack() or getStack(). // Work out frame sizes. - int FrameSize = MFI->getStackSize(); - assert(FrameSize%4 == 0 && "Misaligned frame size"); - FrameSize/=4; - - bool isU6 = isImmU6(FrameSize); - - if (!isU6 && !isImmU16(FrameSize)) { - // FIXME could emit multiple instructions. - report_fatal_error("emitPrologue Frame size too big: " + Twine(FrameSize)); - } + // We will adjust the SP in stages towards the final FrameSize. + assert(MFI->getStackSize()%4 == 0 && "Misaligned frame size"); + const int FrameSize = MFI->getStackSize() / 4; + int Adjusted = 0; + + bool saveLR = XFI->hasLRSpillSlot(); + bool UseENTSP = saveLR && FrameSize + && (MFI->getObjectOffset(XFI->getLRSpillSlot()) == 0); + if (UseENTSP) + saveLR = false; + bool FP = hasFP(MF); bool emitFrameMoves = XCoreRegisterInfo::needsFrameMoves(MF); - bool saveLR = XFI->getUsesLR(); - // Do we need to allocate space on the stack? - if (FrameSize) { - bool LRSavedOnEntry = false; - int Opcode; - if (saveLR && (MFI->getObjectOffset(XFI->getLRSpillSlot()) == 0)) { - Opcode = (isU6) ? XCore::ENTSP_u6 : XCore::ENTSP_lu6; - MBB.addLiveIn(XCore::LR); - saveLR = false; - LRSavedOnEntry = true; - } else { - Opcode = (isU6) ? XCore::EXTSP_u6 : XCore::EXTSP_lu6; - } - BuildMI(MBB, MBBI, dl, TII.get(Opcode)).addImm(FrameSize); - + if (UseENTSP) { + // Allocate space on the stack at the same time as saving LR. + Adjusted = (FrameSize > MaxImmU16) ? MaxImmU16 : FrameSize; + int Opcode = isImmU6(Adjusted) ? XCore::ENTSP_u6 : XCore::ENTSP_lu6; + MBB.addLiveIn(XCore::LR); + MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII.get(Opcode)); + MIB.addImm(Adjusted); + MIB->addRegisterKilled(XCore::LR, MF.getTarget().getRegisterInfo(), true); if (emitFrameMoves) { - // Show update of SP. - MCSymbol *FrameLabel = MMI->getContext().CreateTempSymbol(); - BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(FrameLabel); - MMI->addFrameInst(MCCFIInstruction::createDefCfaOffset(FrameLabel, - -FrameSize*4)); - if (LRSavedOnEntry) { - unsigned Reg = MRI->getDwarfRegNum(XCore::LR, true); - MMI->addFrameInst(MCCFIInstruction::createOffset(FrameLabel, Reg, 0)); - } + EmitDefCfaOffset(MBB, MBBI, dl, TII, MMI, Adjusted*4); + unsigned DRegNum = MRI->getDwarfRegNum(XCore::LR, true); + EmitCfiOffset(MBB, MBBI, dl, TII, MMI, DRegNum, 0); } } - if (saveLR) { - int LRSpillOffset = MFI->getObjectOffset(XFI->getLRSpillSlot()); - storeToStack(MBB, MBBI, XCore::LR, LRSpillOffset + FrameSize*4, dl, TII); - MBB.addLiveIn(XCore::LR); + // If necessary, save LR and FP to the stack, as we EXTSP. + SmallVector<StackSlotInfo,2> SpillList; + GetSpillList(SpillList, MFI, XFI, saveLR, FP); + // We want the nearest (negative) offsets first, so reverse list. + std::reverse(SpillList.begin(), SpillList.end()); + for (unsigned i = 0, e = SpillList.size(); i != e; ++i) { + assert(SpillList[i].Offset % 4 == 0 && "Misaligned stack offset"); + assert(SpillList[i].Offset <= 0 && "Unexpected positive stack offset"); + int OffsetFromTop = - SpillList[i].Offset/4; + IfNeededExtSP(MBB, MBBI, dl, TII, MMI, OffsetFromTop, Adjusted, FrameSize, + emitFrameMoves); + int Offset = Adjusted - OffsetFromTop; + int Opcode = isImmU6(Offset) ? XCore::STWSP_ru6 : XCore::STWSP_lru6; + MBB.addLiveIn(SpillList[i].Reg); + BuildMI(MBB, MBBI, dl, TII.get(Opcode)) + .addReg(SpillList[i].Reg, RegState::Kill) + .addImm(Offset) + .addMemOperand(getFrameIndexMMO(MBB, SpillList[i].FI, + MachineMemOperand::MOStore)); if (emitFrameMoves) { - MCSymbol *SaveLRLabel = MMI->getContext().CreateTempSymbol(); - BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(SaveLRLabel); - unsigned Reg = MRI->getDwarfRegNum(XCore::LR, true); - MMI->addFrameInst(MCCFIInstruction::createOffset(SaveLRLabel, Reg, - LRSpillOffset)); + unsigned DRegNum = MRI->getDwarfRegNum(SpillList[i].Reg, true); + EmitCfiOffset(MBB, MBBI, dl, TII, MMI, DRegNum, SpillList[i].Offset); } } + // Complete any remaining Stack adjustment. + IfNeededExtSP(MBB, MBBI, dl, TII, MMI, FrameSize, Adjusted, FrameSize, + emitFrameMoves); + assert(Adjusted==FrameSize && "IfNeededExtSP has not completed adjustment"); + if (FP) { - // Save R10 to the stack. - int FPSpillOffset = MFI->getObjectOffset(XFI->getFPSpillSlot()); - storeToStack(MBB, MBBI, XCore::R10, FPSpillOffset + FrameSize*4, dl, TII); - // R10 is live-in. It is killed at the spill. - MBB.addLiveIn(XCore::R10); - if (emitFrameMoves) { - MCSymbol *SaveR10Label = MMI->getContext().CreateTempSymbol(); - BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(SaveR10Label); - unsigned Reg = MRI->getDwarfRegNum(XCore::R10, true); - MMI->addFrameInst(MCCFIInstruction::createOffset(SaveR10Label, Reg, - FPSpillOffset)); - } // Set the FP from the SP. - unsigned FramePtr = XCore::R10; BuildMI(MBB, MBBI, dl, TII.get(XCore::LDAWSP_ru6), FramePtr).addImm(0); - if (emitFrameMoves) { - // Show FP is now valid. - MCSymbol *FrameLabel = MMI->getContext().CreateTempSymbol(); - BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(FrameLabel); - unsigned Reg = MRI->getDwarfRegNum(FramePtr, true); - MMI->addFrameInst(MCCFIInstruction::createDefCfaRegister(FrameLabel, - Reg)); - } + if (emitFrameMoves) + EmitDefCfaRegister(MBB, MBBI, dl, TII, MMI, + MRI->getDwarfRegNum(FramePtr, true)); } if (emitFrameMoves) { // Frame moves for callee saved. - std::vector<std::pair<MCSymbol*, CalleeSavedInfo> >&SpillLabels = - XFI->getSpillLabels(); + auto SpillLabels = XFI->getSpillLabels(); for (unsigned I = 0, E = SpillLabels.size(); I != E; ++I) { - MCSymbol *SpillLabel = SpillLabels[I].first; + MachineBasicBlock::iterator Pos = SpillLabels[I].first; + ++Pos; CalleeSavedInfo &CSI = SpillLabels[I].second; int Offset = MFI->getObjectOffset(CSI.getFrameIdx()); - unsigned Reg = MRI->getDwarfRegNum(CSI.getReg(), true); - MMI->addFrameInst(MCCFIInstruction::createOffset(SpillLabel, Reg, - Offset)); + unsigned DRegNum = MRI->getDwarfRegNum(CSI.getReg(), true); + EmitCfiOffset(MBB, Pos, dl, TII, MMI, DRegNum, Offset); + } + if (XFI->hasEHSpillSlot()) { + // The unwinder requires stack slot & CFI offsets for the exception info. + // We do not save/spill these registers. + SmallVector<StackSlotInfo,2> SpillList; + GetEHSpillList(SpillList, MFI, XFI, MF.getTarget().getTargetLowering()); + assert(SpillList.size()==2 && "Unexpected SpillList size"); + EmitCfiOffset(MBB, MBBI, dl, TII, MMI, + MRI->getDwarfRegNum(SpillList[0].Reg, true), + SpillList[0].Offset); + EmitCfiOffset(MBB, MBBI, dl, TII, MMI, + MRI->getDwarfRegNum(SpillList[1].Reg, true), + SpillList[1].Offset); } } } void XCoreFrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { - MachineFrameInfo *MFI = MF.getFrameInfo(); + MachineFrameInfo *MFI = MF.getFrameInfo(); MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); const XCoreInstrInfo &TII = *static_cast<const XCoreInstrInfo*>(MF.getTarget().getInstrInfo()); XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>(); DebugLoc dl = MBBI->getDebugLoc(); - - bool FP = hasFP(MF); - if (FP) { - // Restore the stack pointer. - unsigned FramePtr = XCore::R10; - BuildMI(MBB, MBBI, dl, TII.get(XCore::SETSP_1r)) - .addReg(FramePtr); - } + unsigned RetOpcode = MBBI->getOpcode(); // Work out frame sizes. - int FrameSize = MFI->getStackSize(); - - assert(FrameSize%4 == 0 && "Misaligned frame size"); - - FrameSize/=4; - - bool isU6 = isImmU6(FrameSize); - - if (!isU6 && !isImmU16(FrameSize)) { - // FIXME could emit multiple instructions. - report_fatal_error("emitEpilogue Frame size too big: " + Twine(FrameSize)); - } - - if (FP) { - // Restore R10 - int FPSpillOffset = MFI->getObjectOffset(XFI->getFPSpillSlot()); - FPSpillOffset += FrameSize*4; - loadFromStack(MBB, MBBI, XCore::R10, FPSpillOffset, dl, TII); + // We will adjust the SP in stages towards the final FrameSize. + int RemainingAdj = MFI->getStackSize(); + assert(RemainingAdj%4 == 0 && "Misaligned frame size"); + RemainingAdj /= 4; + + if (RetOpcode == XCore::EH_RETURN) { + // 'Restore' the exception info the unwinder has placed into the stack slots. + SmallVector<StackSlotInfo,2> SpillList; + GetEHSpillList(SpillList, MFI, XFI, MF.getTarget().getTargetLowering()); + RestoreSpillList(MBB, MBBI, dl, TII, RemainingAdj, SpillList); + + // Return to the landing pad. + unsigned EhStackReg = MBBI->getOperand(0).getReg(); + unsigned EhHandlerReg = MBBI->getOperand(1).getReg(); + BuildMI(MBB, MBBI, dl, TII.get(XCore::SETSP_1r)).addReg(EhStackReg); + BuildMI(MBB, MBBI, dl, TII.get(XCore::BAU_1r)).addReg(EhHandlerReg); + MBB.erase(MBBI); // Erase the previous return instruction. + return; } - bool restoreLR = XFI->getUsesLR(); - if (restoreLR && - (FrameSize == 0 || MFI->getObjectOffset(XFI->getLRSpillSlot()) != 0)) { - int LRSpillOffset = MFI->getObjectOffset(XFI->getLRSpillSlot()); - LRSpillOffset += FrameSize*4; - loadFromStack(MBB, MBBI, XCore::LR, LRSpillOffset, dl, TII); + bool restoreLR = XFI->hasLRSpillSlot(); + bool UseRETSP = restoreLR && RemainingAdj + && (MFI->getObjectOffset(XFI->getLRSpillSlot()) == 0); + if (UseRETSP) restoreLR = false; - } + bool FP = hasFP(MF); - if (FrameSize) { - if (restoreLR) { + if (FP) // Restore the stack pointer. + BuildMI(MBB, MBBI, dl, TII.get(XCore::SETSP_1r)).addReg(FramePtr); + + // If necessary, restore LR and FP from the stack, as we EXTSP. + SmallVector<StackSlotInfo,2> SpillList; + GetSpillList(SpillList, MFI, XFI, restoreLR, FP); + RestoreSpillList(MBB, MBBI, dl, TII, RemainingAdj, SpillList); + + if (RemainingAdj) { + // Complete all but one of the remaining Stack adjustments. + IfNeededLDAWSP(MBB, MBBI, dl, TII, 0, RemainingAdj); + if (UseRETSP) { // Fold prologue into return instruction - assert(MFI->getObjectOffset(XFI->getLRSpillSlot()) == 0); - assert(MBBI->getOpcode() == XCore::RETSP_u6 - || MBBI->getOpcode() == XCore::RETSP_lu6); - int Opcode = (isU6) ? XCore::RETSP_u6 : XCore::RETSP_lu6; - MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII.get(Opcode)).addImm(FrameSize); + assert(RetOpcode == XCore::RETSP_u6 + || RetOpcode == XCore::RETSP_lu6); + int Opcode = isImmU6(RemainingAdj) ? XCore::RETSP_u6 : XCore::RETSP_lu6; + MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII.get(Opcode)) + .addImm(RemainingAdj); for (unsigned i = 3, e = MBBI->getNumOperands(); i < e; ++i) MIB->addOperand(MBBI->getOperand(i)); // copy any variadic operands - MBB.erase(MBBI); + MBB.erase(MBBI); // Erase the previous return instruction. } else { - int Opcode = (isU6) ? XCore::LDAWSP_ru6 : XCore::LDAWSP_lru6; - BuildMI(MBB, MBBI, dl, TII.get(Opcode), XCore::SP).addImm(FrameSize); + int Opcode = isImmU6(RemainingAdj) ? XCore::LDAWSP_ru6 : + XCore::LDAWSP_lru6; + BuildMI(MBB, MBBI, dl, TII.get(Opcode), XCore::SP).addImm(RemainingAdj); + // Don't erase the return instruction. } - } + } // else Don't erase the return instruction. } -bool XCoreFrameLowering::spillCalleeSavedRegisters(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - const std::vector<CalleeSavedInfo> &CSI, - const TargetRegisterInfo *TRI) const { +bool XCoreFrameLowering:: +spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const { if (CSI.empty()) return true; MachineFunction *MF = MBB.getParent(); const TargetInstrInfo &TII = *MF->getTarget().getInstrInfo(); - XCoreFunctionInfo *XFI = MF->getInfo<XCoreFunctionInfo>(); bool emitFrameMoves = XCoreRegisterInfo::needsFrameMoves(*MF); DebugLoc DL; - if (MI != MBB.end()) DL = MI->getDebugLoc(); + if (MI != MBB.end()) + DL = MI->getDebugLoc(); for (std::vector<CalleeSavedInfo>::const_iterator it = CSI.begin(); it != CSI.end(); ++it) { - // Add the callee-saved register as live-in. It's killed at the spill. - MBB.addLiveIn(it->getReg()); - unsigned Reg = it->getReg(); + assert(Reg != XCore::LR && !(Reg == XCore::R10 && hasFP(*MF)) && + "LR & FP are always handled in emitPrologue"); + + // Add the callee-saved register as live-in. It's killed at the spill. + MBB.addLiveIn(Reg); const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); - TII.storeRegToStackSlot(MBB, MI, Reg, true, - it->getFrameIdx(), RC, TRI); + TII.storeRegToStackSlot(MBB, MI, Reg, true, it->getFrameIdx(), RC, TRI); if (emitFrameMoves) { - MCSymbol *SaveLabel = MF->getContext().CreateTempSymbol(); - BuildMI(MBB, MI, DL, TII.get(XCore::PROLOG_LABEL)).addSym(SaveLabel); - XFI->getSpillLabels().push_back(std::make_pair(SaveLabel, *it)); + auto Store = MI; + --Store; + XFI->getSpillLabels().push_back(std::make_pair(Store, *it)); } } return true; } -bool XCoreFrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - const std::vector<CalleeSavedInfo> &CSI, - const TargetRegisterInfo *TRI) const{ +bool XCoreFrameLowering:: +restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const{ MachineFunction *MF = MBB.getParent(); const TargetInstrInfo &TII = *MF->getTarget().getInstrInfo(); - bool AtStart = MI == MBB.begin(); MachineBasicBlock::iterator BeforeI = MI; if (!AtStart) @@ -312,9 +447,11 @@ bool XCoreFrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB, for (std::vector<CalleeSavedInfo>::const_iterator it = CSI.begin(); it != CSI.end(); ++it) { unsigned Reg = it->getReg(); + assert(Reg != XCore::LR && !(Reg == XCore::R10 && hasFP(*MF)) && + "LR & FP are always handled in emitEpilogue"); + const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); - TII.loadRegFromStackSlot(MBB, MI, it->getReg(), it->getFrameIdx(), - RC, TRI); + TII.loadRegFromStackSlot(MBB, MI, Reg, it->getFrameIdx(), RC, TRI); assert(MI != MBB.begin() && "loadRegFromStackSlot didn't insert any code!"); // Insert in reverse order. loadRegFromStackSlot can insert multiple @@ -381,40 +518,58 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MBB.erase(I); } -void -XCoreFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF, - RegScavenger *RS) const { - MachineFrameInfo *MFI = MF.getFrameInfo(); - const TargetRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo(); - bool LRUsed = MF.getRegInfo().isPhysRegUsed(XCore::LR); - const TargetRegisterClass *RC = &XCore::GRRegsRegClass; +void XCoreFrameLowering:: +processFunctionBeforeCalleeSavedScan(MachineFunction &MF, + RegScavenger *RS) const { XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>(); + + bool LRUsed = MF.getRegInfo().isPhysRegUsed(XCore::LR); + + if (!LRUsed && !MF.getFunction()->isVarArg() && + MF.getFrameInfo()->estimateStackSize(MF)) + // If we need to extend the stack it is more efficient to use entsp / retsp. + // We force the LR to be saved so these instructions are used. + LRUsed = true; + + if (MF.getMMI().callsUnwindInit() || MF.getMMI().callsEHReturn()) { + // The unwinder expects to find spill slots for the exception info regs R0 + // & R1. These are used during llvm.eh.return() to 'restore' the exception + // info. N.B. we do not spill or restore R0, R1 during normal operation. + XFI->createEHSpillSlot(MF); + // As we will have a stack, we force the LR to be saved. + LRUsed = true; + } + if (LRUsed) { + // We will handle the LR in the prologue/epilogue + // and allocate space on the stack ourselves. MF.getRegInfo().setPhysRegUnused(XCore::LR); - - bool isVarArg = MF.getFunction()->isVarArg(); - int FrameIdx; - if (! isVarArg) { - // A fixed offset of 0 allows us to save / restore LR using entsp / retsp. - FrameIdx = MFI->CreateFixedObject(RC->getSize(), 0, true); - } else { - FrameIdx = MFI->CreateStackObject(RC->getSize(), RC->getAlignment(), - false); - } - XFI->setUsesLR(FrameIdx); - XFI->setLRSpillSlot(FrameIdx); + XFI->createLRSpillSlot(MF); } - if (RegInfo->requiresRegisterScavenging(MF)) { - // Reserve a slot close to SP or frame pointer. + + if (hasFP(MF)) + // A callee save register is used to hold the FP. + // This needs saving / restoring in the epilogue / prologue. + XFI->createFPSpillSlot(MF); +} + +void XCoreFrameLowering:: +processFunctionBeforeFrameFinalized(MachineFunction &MF, + RegScavenger *RS) const { + assert(RS && "requiresRegisterScavenging failed"); + MachineFrameInfo *MFI = MF.getFrameInfo(); + const TargetRegisterClass *RC = &XCore::GRRegsRegClass; + XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>(); + // Reserve slots close to SP or frame pointer for Scavenging spills. + // When using SP for small frames, we don't need any scratch registers. + // When using SP for large frames, we may need 2 scratch registers. + // When using FP, for large or small frames, we may need 1 scratch register. + if (XFI->isLargeFrame(MF) || hasFP(MF)) + RS->addScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(), + RC->getAlignment(), + false)); + if (XFI->isLargeFrame(MF) && !hasFP(MF)) RS->addScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(), RC->getAlignment(), false)); - } - if (hasFP(MF)) { - // A callee save register is used to hold the FP. - // This needs saving / restoring in the epilogue / prologue. - XFI->setFPSpillSlot(MFI->CreateStackObject(RC->getSize(), - RC->getAlignment(), - false)); - } } diff --git a/lib/Target/XCore/XCoreFrameLowering.h b/lib/Target/XCore/XCoreFrameLowering.h index ebad62f..6cd90c9 100644 --- a/lib/Target/XCore/XCoreFrameLowering.h +++ b/lib/Target/XCore/XCoreFrameLowering.h @@ -48,6 +48,9 @@ namespace llvm { void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, RegScavenger *RS = NULL) const; + void processFunctionBeforeFrameFinalized(MachineFunction &MF, + RegScavenger *RS = NULL) const; + //! Stack slot size (4 bytes) static int stackSlotSize() { return 4; diff --git a/lib/Target/XCore/XCoreFrameToArgsOffsetElim.cpp b/lib/Target/XCore/XCoreFrameToArgsOffsetElim.cpp new file mode 100644 index 0000000..c18eff9 --- /dev/null +++ b/lib/Target/XCore/XCoreFrameToArgsOffsetElim.cpp @@ -0,0 +1,62 @@ +//===-- XCoreFrameToArgsOffsetElim.cpp ----------------------------*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Replace Pseudo FRAME_TO_ARGS_OFFSET with the appropriate real offset. +// +//===----------------------------------------------------------------------===// + +#include "XCore.h" +#include "XCoreInstrInfo.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +using namespace llvm; + +namespace { + struct XCoreFTAOElim : public MachineFunctionPass { + static char ID; + XCoreFTAOElim() : MachineFunctionPass(ID) {} + + virtual bool runOnMachineFunction(MachineFunction &Fn); + + virtual const char *getPassName() const { + return "XCore FRAME_TO_ARGS_OFFSET Elimination"; + } + }; + char XCoreFTAOElim::ID = 0; +} + +/// createXCoreFrameToArgsOffsetEliminationPass - returns an instance of the +/// Frame to args offset elimination pass +FunctionPass *llvm::createXCoreFrameToArgsOffsetEliminationPass() { + return new XCoreFTAOElim(); +} + +bool XCoreFTAOElim::runOnMachineFunction(MachineFunction &MF) { + const XCoreInstrInfo &TII = + *static_cast<const XCoreInstrInfo*>(MF.getTarget().getInstrInfo()); + unsigned StackSize = MF.getFrameInfo()->getStackSize(); + for (MachineFunction::iterator MFI = MF.begin(), E = MF.end(); MFI != E; + ++MFI) { + MachineBasicBlock &MBB = *MFI; + for (MachineBasicBlock::iterator MBBI = MBB.begin(), EE = MBB.end(); + MBBI != EE; ++MBBI) { + if (MBBI->getOpcode() == XCore::FRAME_TO_ARGS_OFFSET) { + MachineInstr *OldInst = MBBI; + unsigned Reg = OldInst->getOperand(0).getReg(); + MBBI = TII.loadImmediate(MBB, MBBI, Reg, StackSize); + OldInst->eraseFromParent(); + } + } + } + return true; +} diff --git a/lib/Target/XCore/XCoreISelDAGToDAG.cpp b/lib/Target/XCore/XCoreISelDAGToDAG.cpp index e28f84f..5b0fcfa 100644 --- a/lib/Target/XCore/XCoreISelDAGToDAG.cpp +++ b/lib/Target/XCore/XCoreISelDAGToDAG.cpp @@ -66,7 +66,10 @@ namespace { // Complex Pattern Selectors. bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset); - + + bool SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, + std::vector<SDValue> &OutOps) override; + virtual const char *getPassName() const { return "XCore DAG->DAG Pattern Instruction Selection"; } @@ -106,6 +109,28 @@ bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base, return false; } +bool XCoreDAGToDAGISel:: +SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, + std::vector<SDValue> &OutOps) { + SDValue Reg; + switch (ConstraintCode) { + default: return true; + case 'm': // Memory. + switch (Op.getOpcode()) { + default: return true; + case XCoreISD::CPRelativeWrapper: + Reg = CurDAG->getRegister(XCore::CP, MVT::i32); + break; + case XCoreISD::DPRelativeWrapper: + Reg = CurDAG->getRegister(XCore::DP, MVT::i32); + break; + } + } + OutOps.push_back(Reg); + OutOps.push_back(Op.getOperand(0)); + return false; +} + SDNode *XCoreDAGToDAGISel::Select(SDNode *N) { SDLoc dl(N); switch (N->getOpcode()) { diff --git a/lib/Target/XCore/XCoreISelLowering.cpp b/lib/Target/XCore/XCoreISelLowering.cpp index 89ad27d..1b74013 100644 --- a/lib/Target/XCore/XCoreISelLowering.cpp +++ b/lib/Target/XCore/XCoreISelLowering.cpp @@ -28,6 +28,7 @@ #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/CodeGen/ValueTypes.h" #include "llvm/IR/CallingConv.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalAlias.h" @@ -49,6 +50,7 @@ getTargetNodeName(unsigned Opcode) const case XCoreISD::PCRelativeWrapper : return "XCoreISD::PCRelativeWrapper"; case XCoreISD::DPRelativeWrapper : return "XCoreISD::DPRelativeWrapper"; case XCoreISD::CPRelativeWrapper : return "XCoreISD::CPRelativeWrapper"; + case XCoreISD::LDWSP : return "XCoreISD::LDWSP"; case XCoreISD::STWSP : return "XCoreISD::STWSP"; case XCoreISD::RETSP : return "XCoreISD::RETSP"; case XCoreISD::LADD : return "XCoreISD::LADD"; @@ -59,6 +61,8 @@ getTargetNodeName(unsigned Opcode) const case XCoreISD::CRC8 : return "XCoreISD::CRC8"; case XCoreISD::BR_JT : return "XCoreISD::BR_JT"; case XCoreISD::BR_JT32 : return "XCoreISD::BR_JT32"; + case XCoreISD::FRAME_TO_ARGS_OFFSET : return "XCoreISD::FRAME_TO_ARGS_OFFSET"; + case XCoreISD::EH_RETURN : return "XCoreISD::EH_RETURN"; case XCoreISD::MEMBARRIER : return "XCoreISD::MEMBARRIER"; default : return NULL; } @@ -150,11 +154,18 @@ XCoreTargetLowering::XCoreTargetLowering(XCoreTargetMachine &XTM) setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand); // Exception handling + setOperationAction(ISD::EH_RETURN, MVT::Other, Custom); setExceptionPointerRegister(XCore::R0); setExceptionSelectorRegister(XCore::R1); + setOperationAction(ISD::FRAME_TO_ARGS_OFFSET, MVT::i32, Custom); // Atomic operations + // We request a fence for ATOMIC_* instructions, to reduce them to Monotonic. + // As we are always Sequential Consistent, an ATOMIC_FENCE becomes a no OP. + setInsertFencesForAtomic(true); setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom); + setOperationAction(ISD::ATOMIC_LOAD, MVT::i32, Custom); + setOperationAction(ISD::ATOMIC_STORE, MVT::i32, Custom); // TRAMPOLINE is custom lowered. setOperationAction(ISD::INIT_TRAMPOLINE, MVT::Other, Custom); @@ -170,8 +181,11 @@ XCoreTargetLowering::XCoreTargetLowering(XCoreTargetMachine &XTM) // We have target-specific dag combine patterns for the following nodes: setTargetDAGCombine(ISD::STORE); setTargetDAGCombine(ISD::ADD); + setTargetDAGCombine(ISD::INTRINSIC_VOID); + setTargetDAGCombine(ISD::INTRINSIC_W_CHAIN); setMinFunctionAlignment(1); + setPrefFunctionAlignment(2); } bool XCoreTargetLowering::isZExtFree(SDValue Val, EVT VT2) const { @@ -196,6 +210,7 @@ SDValue XCoreTargetLowering:: LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { + case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG); case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); case ISD::BlockAddress: return LowerBlockAddress(Op, DAG); case ISD::ConstantPool: return LowerConstantPool(Op, DAG); @@ -211,10 +226,14 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const { case ISD::ADD: case ISD::SUB: return ExpandADDSUB(Op.getNode(), DAG); case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG); + case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG); + case ISD::FRAME_TO_ARGS_OFFSET: return LowerFRAME_TO_ARGS_OFFSET(Op, DAG); case ISD::INIT_TRAMPOLINE: return LowerINIT_TRAMPOLINE(Op, DAG); case ISD::ADJUST_TRAMPOLINE: return LowerADJUST_TRAMPOLINE(Op, DAG); case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG); case ISD::ATOMIC_FENCE: return LowerATOMIC_FENCE(Op, DAG); + case ISD::ATOMIC_LOAD: return LowerATOMIC_LOAD(Op, DAG); + case ISD::ATOMIC_STORE: return LowerATOMIC_STORE(Op, DAG); default: llvm_unreachable("unimplemented operand"); } @@ -258,32 +277,59 @@ getGlobalAddressWrapper(SDValue GA, const GlobalValue *GV, const GlobalValue *UnderlyingGV = GV; // If GV is an alias then use the aliasee to determine the wrapper type if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(GV)) - UnderlyingGV = GA->resolveAliasedGlobal(); + UnderlyingGV = GA->getAliasedGlobal(); if (const GlobalVariable *GVar = dyn_cast<GlobalVariable>(UnderlyingGV)) { - if (GVar->isConstant()) + if ( ( GVar->isConstant() && + UnderlyingGV->isLocalLinkage(GV->getLinkage()) ) + || ( GVar->hasSection() && + StringRef(GVar->getSection()).startswith(".cp.") ) ) return DAG.getNode(XCoreISD::CPRelativeWrapper, dl, MVT::i32, GA); return DAG.getNode(XCoreISD::DPRelativeWrapper, dl, MVT::i32, GA); } return DAG.getNode(XCoreISD::PCRelativeWrapper, dl, MVT::i32, GA); } +static bool IsSmallObject(const GlobalValue *GV, const XCoreTargetLowering &XTL) { + if (XTL.getTargetMachine().getCodeModel() == CodeModel::Small) + return true; + + Type *ObjType = GV->getType()->getPointerElementType(); + if (!ObjType->isSized()) + return false; + + unsigned ObjSize = XTL.getDataLayout()->getTypeAllocSize(ObjType); + return ObjSize < CodeModelLargeSize && ObjSize != 0; +} + SDValue XCoreTargetLowering:: LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const { - SDLoc DL(Op); const GlobalAddressSDNode *GN = cast<GlobalAddressSDNode>(Op); const GlobalValue *GV = GN->getGlobal(); + SDLoc DL(GN); int64_t Offset = GN->getOffset(); - // We can only fold positive offsets that are a multiple of the word size. - int64_t FoldedOffset = std::max(Offset & ~3, (int64_t)0); - SDValue GA = DAG.getTargetGlobalAddress(GV, DL, MVT::i32, FoldedOffset); - GA = getGlobalAddressWrapper(GA, GV, DAG); - // Handle the rest of the offset. - if (Offset != FoldedOffset) { - SDValue Remaining = DAG.getConstant(Offset - FoldedOffset, MVT::i32); - GA = DAG.getNode(ISD::ADD, DL, MVT::i32, GA, Remaining); + if (IsSmallObject(GV, *this)) { + // We can only fold positive offsets that are a multiple of the word size. + int64_t FoldedOffset = std::max(Offset & ~3, (int64_t)0); + SDValue GA = DAG.getTargetGlobalAddress(GV, DL, MVT::i32, FoldedOffset); + GA = getGlobalAddressWrapper(GA, GV, DAG); + // Handle the rest of the offset. + if (Offset != FoldedOffset) { + SDValue Remaining = DAG.getConstant(Offset - FoldedOffset, MVT::i32); + GA = DAG.getNode(ISD::ADD, DL, MVT::i32, GA, Remaining); + } + return GA; + } else { + // Ideally we would not fold in offset with an index <= 11. + Type *Ty = Type::getInt8PtrTy(*DAG.getContext()); + Constant *GA = ConstantExpr::getBitCast(const_cast<GlobalValue*>(GV), Ty); + Ty = Type::getInt32Ty(*DAG.getContext()); + Constant *Idx = ConstantInt::get(Ty, Offset); + Constant *GAI = ConstantExpr::getGetElementPtr(GA, Idx); + SDValue CP = DAG.getConstantPool(GAI, MVT::i32); + return DAG.getLoad(getPointerTy(), DL, DAG.getEntryNode(), CP, + MachinePointerInfo(), false, false, false, 0); } - return GA; } SDValue XCoreTargetLowering:: @@ -307,10 +353,10 @@ LowerConstantPool(SDValue Op, SelectionDAG &DAG) const SDValue Res; if (CP->isMachineConstantPoolEntry()) { Res = DAG.getTargetConstantPool(CP->getMachineCPVal(), PtrVT, - CP->getAlignment()); + CP->getAlignment(), CP->getOffset()); } else { Res = DAG.getTargetConstantPool(CP->getConstVal(), PtrVT, - CP->getAlignment()); + CP->getAlignment(), CP->getOffset()); } return DAG.getNode(XCoreISD::CPRelativeWrapper, dl, MVT::i32, Res); } @@ -767,15 +813,85 @@ LowerVASTART(SDValue Op, SelectionDAG &DAG) const SDValue XCoreTargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { - SDLoc dl(Op); + // This nodes represent llvm.frameaddress on the DAG. + // It takes one operand, the index of the frame address to return. + // An index of zero corresponds to the current function's frame address. + // An index of one to the parent's frame address, and so on. // Depths > 0 not supported yet! if (cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() > 0) return SDValue(); MachineFunction &MF = DAG.getMachineFunction(); const TargetRegisterInfo *RegInfo = getTargetMachine().getRegisterInfo(); - return DAG.getCopyFromReg(DAG.getEntryNode(), dl, + return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), + RegInfo->getFrameRegister(MF), MVT::i32); +} + +SDValue XCoreTargetLowering:: +LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const { + // This nodes represent llvm.returnaddress on the DAG. + // It takes one operand, the index of the return address to return. + // An index of zero corresponds to the current function's return address. + // An index of one to the parent's return address, and so on. + // Depths > 0 not supported yet! + if (cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() > 0) + return SDValue(); + + MachineFunction &MF = DAG.getMachineFunction(); + XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>(); + int FI = XFI->createLRSpillSlot(MF); + SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); + return DAG.getLoad(getPointerTy(), SDLoc(Op), DAG.getEntryNode(), FIN, + MachinePointerInfo::getFixedStack(FI), false, false, + false, 0); +} + +SDValue XCoreTargetLowering:: +LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const { + // This node represents offset from frame pointer to first on-stack argument. + // This is needed for correct stack adjustment during unwind. + // However, we don't know the offset until after the frame has be finalised. + // This is done during the XCoreFTAOElim pass. + return DAG.getNode(XCoreISD::FRAME_TO_ARGS_OFFSET, SDLoc(Op), MVT::i32); +} + +SDValue XCoreTargetLowering:: +LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const { + // OUTCHAIN = EH_RETURN(INCHAIN, OFFSET, HANDLER) + // This node represents 'eh_return' gcc dwarf builtin, which is used to + // return from exception. The general meaning is: adjust stack by OFFSET and + // pass execution to HANDLER. + MachineFunction &MF = DAG.getMachineFunction(); + SDValue Chain = Op.getOperand(0); + SDValue Offset = Op.getOperand(1); + SDValue Handler = Op.getOperand(2); + SDLoc dl(Op); + + // Absolute SP = (FP + FrameToArgs) + Offset + const TargetRegisterInfo *RegInfo = getTargetMachine().getRegisterInfo(); + SDValue Stack = DAG.getCopyFromReg(DAG.getEntryNode(), dl, RegInfo->getFrameRegister(MF), MVT::i32); + SDValue FrameToArgs = DAG.getNode(XCoreISD::FRAME_TO_ARGS_OFFSET, dl, + MVT::i32); + Stack = DAG.getNode(ISD::ADD, dl, MVT::i32, Stack, FrameToArgs); + Stack = DAG.getNode(ISD::ADD, dl, MVT::i32, Stack, Offset); + + // R0=ExceptionPointerRegister R1=ExceptionSelectorRegister + // which leaves 2 caller saved registers, R2 & R3 for us to use. + unsigned StackReg = XCore::R2; + unsigned HandlerReg = XCore::R3; + + SDValue OutChains[] = { + DAG.getCopyToReg(Chain, dl, StackReg, Stack), + DAG.getCopyToReg(Chain, dl, HandlerReg, Handler) + }; + + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains, 2); + + return DAG.getNode(XCoreISD::EH_RETURN, dl, MVT::Other, Chain, + DAG.getRegister(StackReg, MVT::i32), + DAG.getRegister(HandlerReg, MVT::i32)); + } SDValue XCoreTargetLowering:: @@ -862,6 +978,67 @@ LowerATOMIC_FENCE(SDValue Op, SelectionDAG &DAG) const { return DAG.getNode(XCoreISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0)); } +SDValue XCoreTargetLowering:: +LowerATOMIC_LOAD(SDValue Op, SelectionDAG &DAG) const { + AtomicSDNode *N = cast<AtomicSDNode>(Op); + assert(N->getOpcode() == ISD::ATOMIC_LOAD && "Bad Atomic OP"); + assert(N->getOrdering() <= Monotonic && + "setInsertFencesForAtomic(true) and yet greater than Monotonic"); + if (N->getMemoryVT() == MVT::i32) { + if (N->getAlignment() < 4) + report_fatal_error("atomic load must be aligned"); + return DAG.getLoad(getPointerTy(), SDLoc(Op), N->getChain(), + N->getBasePtr(), N->getPointerInfo(), + N->isVolatile(), N->isNonTemporal(), + N->isInvariant(), N->getAlignment(), + N->getTBAAInfo(), N->getRanges()); + } + if (N->getMemoryVT() == MVT::i16) { + if (N->getAlignment() < 2) + report_fatal_error("atomic load must be aligned"); + return DAG.getExtLoad(ISD::EXTLOAD, SDLoc(Op), MVT::i32, N->getChain(), + N->getBasePtr(), N->getPointerInfo(), MVT::i16, + N->isVolatile(), N->isNonTemporal(), + N->getAlignment(), N->getTBAAInfo()); + } + if (N->getMemoryVT() == MVT::i8) + return DAG.getExtLoad(ISD::EXTLOAD, SDLoc(Op), MVT::i32, N->getChain(), + N->getBasePtr(), N->getPointerInfo(), MVT::i8, + N->isVolatile(), N->isNonTemporal(), + N->getAlignment(), N->getTBAAInfo()); + return SDValue(); +} + +SDValue XCoreTargetLowering:: +LowerATOMIC_STORE(SDValue Op, SelectionDAG &DAG) const { + AtomicSDNode *N = cast<AtomicSDNode>(Op); + assert(N->getOpcode() == ISD::ATOMIC_STORE && "Bad Atomic OP"); + assert(N->getOrdering() <= Monotonic && + "setInsertFencesForAtomic(true) and yet greater than Monotonic"); + if (N->getMemoryVT() == MVT::i32) { + if (N->getAlignment() < 4) + report_fatal_error("atomic store must be aligned"); + return DAG.getStore(N->getChain(), SDLoc(Op), N->getVal(), + N->getBasePtr(), N->getPointerInfo(), + N->isVolatile(), N->isNonTemporal(), + N->getAlignment(), N->getTBAAInfo()); + } + if (N->getMemoryVT() == MVT::i16) { + if (N->getAlignment() < 2) + report_fatal_error("atomic store must be aligned"); + return DAG.getTruncStore(N->getChain(), SDLoc(Op), N->getVal(), + N->getBasePtr(), N->getPointerInfo(), MVT::i16, + N->isVolatile(), N->isNonTemporal(), + N->getAlignment(), N->getTBAAInfo()); + } + if (N->getMemoryVT() == MVT::i8) + return DAG.getTruncStore(N->getChain(), SDLoc(Op), N->getVal(), + N->getBasePtr(), N->getPointerInfo(), MVT::i8, + N->isVolatile(), N->isNonTemporal(), + N->getAlignment(), N->getTBAAInfo()); + return SDValue(); +} + //===----------------------------------------------------------------------===// // Calling Convention Implementation //===----------------------------------------------------------------------===// @@ -902,6 +1079,52 @@ XCoreTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, } } +/// LowerCallResult - Lower the result values of a call into the +/// appropriate copies out of appropriate physical registers / memory locations. +static SDValue +LowerCallResult(SDValue Chain, SDValue InFlag, + const SmallVectorImpl<CCValAssign> &RVLocs, + SDLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) { + SmallVector<std::pair<int, unsigned>, 4> ResultMemLocs; + // Copy results out of physical registers. + for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) { + const CCValAssign &VA = RVLocs[i]; + if (VA.isRegLoc()) { + Chain = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), VA.getValVT(), + InFlag).getValue(1); + InFlag = Chain.getValue(2); + InVals.push_back(Chain.getValue(0)); + } else { + assert(VA.isMemLoc()); + ResultMemLocs.push_back(std::make_pair(VA.getLocMemOffset(), + InVals.size())); + // Reserve space for this result. + InVals.push_back(SDValue()); + } + } + + // Copy results out of memory. + SmallVector<SDValue, 4> MemOpChains; + for (unsigned i = 0, e = ResultMemLocs.size(); i != e; ++i) { + int offset = ResultMemLocs[i].first; + unsigned index = ResultMemLocs[i].second; + SDVTList VTs = DAG.getVTList(MVT::i32, MVT::Other); + SDValue Ops[] = { Chain, DAG.getConstant(offset / 4, MVT::i32) }; + SDValue load = DAG.getNode(XCoreISD::LDWSP, dl, VTs, Ops, 2); + InVals[index] = load; + MemOpChains.push_back(load.getValue(1)); + } + + // Transform all loads nodes into one single node because + // all load nodes are independent of each other. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + &MemOpChains[0], MemOpChains.size()); + + return Chain; +} + /// LowerCCCCallTo - functions arguments are copied from virtual /// regs to (physical regs)/(stack frame), CALLSEQ_START and /// CALLSEQ_END are emitted. @@ -927,8 +1150,15 @@ XCoreTargetLowering::LowerCCCCallTo(SDValue Chain, SDValue Callee, CCInfo.AnalyzeCallOperands(Outs, CC_XCore); + SmallVector<CCValAssign, 16> RVLocs; + // Analyze return values to determine the number of bytes of stack required. + CCState RetCCInfo(CallConv, isVarArg, DAG.getMachineFunction(), + getTargetMachine(), RVLocs, *DAG.getContext()); + RetCCInfo.AllocateStack(CCInfo.getNextStackOffset(), 4); + RetCCInfo.AnalyzeCallResult(Ins, RetCC_XCore); + // Get a count of how many bytes are to be pushed on the stack. - unsigned NumBytes = CCInfo.getNextStackOffset(); + unsigned NumBytes = RetCCInfo.getNextStackOffset(); Chain = DAG.getCALLSEQ_START(Chain,DAG.getConstant(NumBytes, getPointerTy(), true), dl); @@ -1026,35 +1256,7 @@ XCoreTargetLowering::LowerCCCCallTo(SDValue Chain, SDValue Callee, // Handle result values, copying them out of physregs into vregs that we // return. - return LowerCallResult(Chain, InFlag, CallConv, isVarArg, - Ins, dl, DAG, InVals); -} - -/// LowerCallResult - Lower the result values of a call into the -/// appropriate copies out of appropriate physical registers. -SDValue -XCoreTargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag, - CallingConv::ID CallConv, bool isVarArg, - const SmallVectorImpl<ISD::InputArg> &Ins, - SDLoc dl, SelectionDAG &DAG, - SmallVectorImpl<SDValue> &InVals) const { - - // Assign locations to each value returned by this call. - SmallVector<CCValAssign, 16> RVLocs; - CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), - getTargetMachine(), RVLocs, *DAG.getContext()); - - CCInfo.AnalyzeCallResult(Ins, RetCC_XCore); - - // Copy all of the result registers out of their specified physreg. - for (unsigned i = 0; i != RVLocs.size(); ++i) { - Chain = DAG.getCopyFromReg(Chain, dl, RVLocs[i].getLocReg(), - RVLocs[i].getValVT(), InFlag).getValue(1); - InFlag = Chain.getValue(2); - InVals.push_back(Chain.getValue(0)); - } - - return Chain; + return LowerCallResult(Chain, InFlag, RVLocs, dl, DAG, InVals); } //===----------------------------------------------------------------------===// @@ -1102,6 +1304,7 @@ XCoreTargetLowering::LowerCCCArguments(SDValue Chain, MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo *MFI = MF.getFrameInfo(); MachineRegisterInfo &RegInfo = MF.getRegInfo(); + XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>(); // Assign locations to all of the incoming arguments. SmallVector<CCValAssign, 16> ArgLocs; @@ -1114,6 +1317,9 @@ XCoreTargetLowering::LowerCCCArguments(SDValue Chain, unsigned LRSaveSize = StackSlotSize; + if (!isVarArg) + XFI->setReturnStackOffset(CCInfo.getNextStackOffset() + LRSaveSize); + // All getCopyFromReg ops must precede any getMemcpys to prevent the // scheduler clobbering a register before it has been copied. // The stages are: @@ -1230,7 +1436,7 @@ XCoreTargetLowering::LowerCCCArguments(SDValue Chain, unsigned Size = ArgDI->Flags.getByValSize(); unsigned Align = std::max(StackSlotSize, ArgDI->Flags.getByValAlign()); // Create a new object on the stack and copy the pointee into it. - int FI = MFI->CreateStackObject(Size, Align, false, false); + int FI = MFI->CreateStackObject(Size, Align, false); SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); InVals.push_back(FIN); MemOps.push_back(DAG.getMemcpy(Chain, dl, FIN, ArgDI->SDV, @@ -1264,7 +1470,11 @@ CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, LLVMContext &Context) const { SmallVector<CCValAssign, 16> RVLocs; CCState CCInfo(CallConv, isVarArg, MF, getTargetMachine(), RVLocs, Context); - return CCInfo.CheckReturn(Outs, RetCC_XCore); + if (!CCInfo.CheckReturn(Outs, RetCC_XCore)) + return false; + if (CCInfo.getNextStackOffset() != 0 && isVarArg) + return false; + return true; } SDValue @@ -1274,6 +1484,10 @@ XCoreTargetLowering::LowerReturn(SDValue Chain, const SmallVectorImpl<SDValue> &OutVals, SDLoc dl, SelectionDAG &DAG) const { + XCoreFunctionInfo *XFI = + DAG.getMachineFunction().getInfo<XCoreFunctionInfo>(); + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + // CCValAssign - represent the assignment of // the return value to a location SmallVector<CCValAssign, 16> RVLocs; @@ -1283,6 +1497,9 @@ XCoreTargetLowering::LowerReturn(SDValue Chain, getTargetMachine(), RVLocs, *DAG.getContext()); // Analyze return values. + if (!isVarArg) + CCInfo.AllocateStack(XFI->getReturnStackOffset(), 4); + CCInfo.AnalyzeReturn(Outs, RetCC_XCore); SDValue Flag; @@ -1291,13 +1508,43 @@ XCoreTargetLowering::LowerReturn(SDValue Chain, // Return on XCore is always a "retsp 0" RetOps.push_back(DAG.getConstant(0, MVT::i32)); - // Copy the result values into the output registers. - for (unsigned i = 0; i != RVLocs.size(); ++i) { + SmallVector<SDValue, 4> MemOpChains; + // Handle return values that must be copied to memory. + for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) { CCValAssign &VA = RVLocs[i]; - assert(VA.isRegLoc() && "Can only return in registers!"); + if (VA.isRegLoc()) + continue; + assert(VA.isMemLoc()); + if (isVarArg) { + report_fatal_error("Can't return value from vararg function in memory"); + } + + int Offset = VA.getLocMemOffset(); + unsigned ObjSize = VA.getLocVT().getSizeInBits() / 8; + // Create the frame index object for the memory location. + int FI = MFI->CreateFixedObject(ObjSize, Offset, false); + + // Create a SelectionDAG node corresponding to a store + // to this memory location. + SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); + MemOpChains.push_back(DAG.getStore(Chain, dl, OutVals[i], FIN, + MachinePointerInfo::getFixedStack(FI), false, false, + 0)); + } + + // Transform all store nodes into one single node because + // all stores are independent of each other. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + &MemOpChains[0], MemOpChains.size()); - Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), - OutVals[i], Flag); + // Now handle return values copied to registers. + for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) { + CCValAssign &VA = RVLocs[i]; + if (!VA.isRegLoc()) + continue; + // Copy the result values into the output registers. + Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), OutVals[i], Flag); // guarantee that all emitted copies are // stuck together, avoiding something bad @@ -1350,8 +1597,7 @@ XCoreTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, // Transfer the remainder of BB and its successor edges to sinkMBB. sinkMBB->splice(sinkMBB->begin(), BB, - llvm::next(MachineBasicBlock::iterator(MI)), - BB->end()); + std::next(MachineBasicBlock::iterator(MI)), BB->end()); sinkMBB->transferSuccessorsAndUpdatePHIs(BB); // Next, add the true and fallthrough blocks as its successors. @@ -1392,6 +1638,46 @@ SDValue XCoreTargetLowering::PerformDAGCombine(SDNode *N, SDLoc dl(N); switch (N->getOpcode()) { default: break; + case ISD::INTRINSIC_VOID: + switch (cast<ConstantSDNode>(N->getOperand(1))->getZExtValue()) { + case Intrinsic::xcore_outt: + case Intrinsic::xcore_outct: + case Intrinsic::xcore_chkct: { + SDValue OutVal = N->getOperand(3); + // These instructions ignore the high bits. + if (OutVal.hasOneUse()) { + unsigned BitWidth = OutVal.getValueSizeInBits(); + APInt DemandedMask = APInt::getLowBitsSet(BitWidth, 8); + APInt KnownZero, KnownOne; + TargetLowering::TargetLoweringOpt TLO(DAG, !DCI.isBeforeLegalize(), + !DCI.isBeforeLegalizeOps()); + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); + if (TLO.ShrinkDemandedConstant(OutVal, DemandedMask) || + TLI.SimplifyDemandedBits(OutVal, DemandedMask, KnownZero, KnownOne, + TLO)) + DCI.CommitTargetLoweringOpt(TLO); + } + break; + } + case Intrinsic::xcore_setpt: { + SDValue Time = N->getOperand(3); + // This instruction ignores the high bits. + if (Time.hasOneUse()) { + unsigned BitWidth = Time.getValueSizeInBits(); + APInt DemandedMask = APInt::getLowBitsSet(BitWidth, 16); + APInt KnownZero, KnownOne; + TargetLowering::TargetLoweringOpt TLO(DAG, !DCI.isBeforeLegalize(), + !DCI.isBeforeLegalizeOps()); + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); + if (TLO.ShrinkDemandedConstant(Time, DemandedMask) || + TLI.SimplifyDemandedBits(Time, DemandedMask, KnownZero, KnownOne, + TLO)) + DCI.CommitTargetLoweringOpt(TLO); + } + break; + } + } + break; case XCoreISD::LADD: { SDValue N0 = N->getOperand(0); SDValue N1 = N->getOperand(1); @@ -1596,6 +1882,34 @@ void XCoreTargetLowering::computeMaskedBitsForTargetNode(const SDValue Op, KnownZero.getBitWidth() - 1); } break; + case ISD::INTRINSIC_W_CHAIN: + { + unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue(); + switch (IntNo) { + case Intrinsic::xcore_getts: + // High bits are known to be zero. + KnownZero = APInt::getHighBitsSet(KnownZero.getBitWidth(), + KnownZero.getBitWidth() - 16); + break; + case Intrinsic::xcore_int: + case Intrinsic::xcore_inct: + // High bits are known to be zero. + KnownZero = APInt::getHighBitsSet(KnownZero.getBitWidth(), + KnownZero.getBitWidth() - 8); + break; + case Intrinsic::xcore_testct: + // Result is either 0 or 1. + KnownZero = APInt::getHighBitsSet(KnownZero.getBitWidth(), + KnownZero.getBitWidth() - 1); + break; + case Intrinsic::xcore_testwct: + // Result is in the range 0 - 4. + KnownZero = APInt::getHighBitsSet(KnownZero.getBitWidth(), + KnownZero.getBitWidth() - 3); + break; + } + } + break; } } diff --git a/lib/Target/XCore/XCoreISelLowering.h b/lib/Target/XCore/XCoreISelLowering.h index bc08497..65e2bad 100644 --- a/lib/Target/XCore/XCoreISelLowering.h +++ b/lib/Target/XCore/XCoreISelLowering.h @@ -42,6 +42,9 @@ namespace llvm { // cp relative address CPRelativeWrapper, + // Load word from stack + LDWSP, + // Store word to stack STWSP, @@ -72,6 +75,13 @@ namespace llvm { // Jumptable branch using long branches for each entry. BR_JT32, + // Offset from frame pointer to the first (possible) on-stack argument + FRAME_TO_ARGS_OFFSET, + + // Exception handler return. The stack is restored to the first + // followed by a jump to the second argument. + EH_RETURN, + // Memory barrier. MEMBARRIER }; @@ -132,11 +142,6 @@ namespace llvm { const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc dl, SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const; - SDValue LowerCallResult(SDValue Chain, SDValue InFlag, - CallingConv::ID CallConv, bool isVarArg, - const SmallVectorImpl<ISD::InputArg> &Ins, - SDLoc dl, SelectionDAG &DAG, - SmallVectorImpl<SDValue> &InVals) const; SDValue getReturnAddressFrameIndex(SelectionDAG &DAG) const; SDValue getGlobalAddressWrapper(SDValue GA, const GlobalValue *GV, SelectionDAG &DAG) const; @@ -147,6 +152,7 @@ namespace llvm { // Lower Operand specifics SDValue LowerLOAD(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSTORE(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const; SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; @@ -158,10 +164,14 @@ namespace llvm { SDValue LowerUMUL_LOHI(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSMUL_LOHI(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; SDValue LowerINIT_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerADJUST_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const; SDValue LowerATOMIC_FENCE(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerATOMIC_LOAD(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerATOMIC_STORE(SDValue Op, SelectionDAG &DAG) const; // Inline asm support std::pair<unsigned, const TargetRegisterClass*> diff --git a/lib/Target/XCore/XCoreInstrInfo.cpp b/lib/Target/XCore/XCoreInstrInfo.cpp index 33c7f31..cea3bbf 100644 --- a/lib/Target/XCore/XCoreInstrInfo.cpp +++ b/lib/Target/XCore/XCoreInstrInfo.cpp @@ -15,8 +15,12 @@ #include "XCore.h" #include "XCoreMachineFunctionInfo.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" #include "llvm/MC/MCContext.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" @@ -371,10 +375,18 @@ void XCoreInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, { DebugLoc DL; if (I != MBB.end()) DL = I->getDebugLoc(); + MachineFunction *MF = MBB.getParent(); + const MachineFrameInfo &MFI = *MF->getFrameInfo(); + MachineMemOperand *MMO = + MF->getMachineMemOperand(MachinePointerInfo::getFixedStack(FrameIndex), + MachineMemOperand::MOStore, + MFI.getObjectSize(FrameIndex), + MFI.getObjectAlignment(FrameIndex)); BuildMI(MBB, I, DL, get(XCore::STWFI)) .addReg(SrcReg, getKillRegState(isKill)) .addFrameIndex(FrameIndex) - .addImm(0); + .addImm(0) + .addMemOperand(MMO); } void XCoreInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, @@ -385,9 +397,17 @@ void XCoreInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, { DebugLoc DL; if (I != MBB.end()) DL = I->getDebugLoc(); + MachineFunction *MF = MBB.getParent(); + const MachineFrameInfo &MFI = *MF->getFrameInfo(); + MachineMemOperand *MMO = + MF->getMachineMemOperand(MachinePointerInfo::getFixedStack(FrameIndex), + MachineMemOperand::MOLoad, + MFI.getObjectSize(FrameIndex), + MFI.getObjectAlignment(FrameIndex)); BuildMI(MBB, I, DL, get(XCore::LDWFI), DestReg) .addFrameIndex(FrameIndex) - .addImm(0); + .addImm(0) + .addMemOperand(MMO); } /// ReverseBranchCondition - Return the inverse opcode of the @@ -399,3 +419,33 @@ ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const { Cond[0].setImm(GetOppositeBranchCondition((XCore::CondCode)Cond[0].getImm())); return false; } + +static inline bool isImmU6(unsigned val) { + return val < (1 << 6); +} + +static inline bool isImmU16(unsigned val) { + return val < (1 << 16); +} + +MachineBasicBlock::iterator XCoreInstrInfo::loadImmediate( + MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned Reg, uint64_t Value) const { + DebugLoc dl; + if (MI != MBB.end()) dl = MI->getDebugLoc(); + if (isMask_32(Value)) { + int N = Log2_32(Value) + 1; + return BuildMI(MBB, MI, dl, get(XCore::MKMSK_rus), Reg).addImm(N); + } + if (isImmU16(Value)) { + int Opcode = isImmU6(Value) ? XCore::LDC_ru6 : XCore::LDC_lru6; + return BuildMI(MBB, MI, dl, get(Opcode), Reg).addImm(Value); + } + MachineConstantPool *ConstantPool = MBB.getParent()->getConstantPool(); + const Constant *C = ConstantInt::get( + Type::getInt32Ty(MBB.getParent()->getFunction()->getContext()), Value); + unsigned Idx = ConstantPool->getConstantPoolIndex(C, 4); + return BuildMI(MBB, MI, dl, get(XCore::LDWCP_lru6), Reg) + .addConstantPoolIndex(Idx); +} diff --git a/lib/Target/XCore/XCoreInstrInfo.h b/lib/Target/XCore/XCoreInstrInfo.h index 4429b07..48c9cb5 100644 --- a/lib/Target/XCore/XCoreInstrInfo.h +++ b/lib/Target/XCore/XCoreInstrInfo.h @@ -81,6 +81,12 @@ public: virtual bool ReverseBranchCondition( SmallVectorImpl<MachineOperand> &Cond) const; + + // Emit code before MBBI to load immediate value into physical register Reg. + // Returns an iterator to the new instruction. + MachineBasicBlock::iterator loadImmediate(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned Reg, uint64_t Value) const; }; } diff --git a/lib/Target/XCore/XCoreInstrInfo.td b/lib/Target/XCore/XCoreInstrInfo.td index 934a707..00cb705 100644 --- a/lib/Target/XCore/XCoreInstrInfo.td +++ b/lib/Target/XCore/XCoreInstrInfo.td @@ -35,6 +35,11 @@ def XCoreBranchLink : SDNode<"XCoreISD::BL",SDT_XCoreBranchLink, def XCoreRetsp : SDNode<"XCoreISD::RETSP", SDTBrind, [SDNPHasChain, SDNPOptInGlue, SDNPMayLoad, SDNPVariadic]>; +def SDT_XCoreEhRet : SDTypeProfile<0, 2, + [SDTCisSameAs<0, 1>, SDTCisPtrTy<0>]>; +def XCoreEhRet : SDNode<"XCoreISD::EH_RETURN", SDT_XCoreEhRet, + [SDNPHasChain, SDNPOptInGlue]>; + def SDT_XCoreBR_JT : SDTypeProfile<0, 2, [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; @@ -56,10 +61,17 @@ def dprelwrapper : SDNode<"XCoreISD::DPRelativeWrapper", SDT_XCoreAddress, def cprelwrapper : SDNode<"XCoreISD::CPRelativeWrapper", SDT_XCoreAddress, []>; +def frametoargsoffset : SDNode<"XCoreISD::FRAME_TO_ARGS_OFFSET", SDTIntLeaf, + []>; + def SDT_XCoreStwsp : SDTypeProfile<0, 2, [SDTCisInt<1>]>; def XCoreStwsp : SDNode<"XCoreISD::STWSP", SDT_XCoreStwsp, [SDNPHasChain, SDNPMayStore]>; +def SDT_XCoreLdwsp : SDTypeProfile<1, 1, [SDTCisInt<1>]>; +def XCoreLdwsp : SDNode<"XCoreISD::LDWSP", SDT_XCoreLdwsp, + [SDNPHasChain, SDNPMayLoad]>; + // These are target-independent nodes, but have target-specific formats. def SDT_XCoreCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>; def SDT_XCoreCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>, @@ -326,6 +338,16 @@ def ADJCALLSTACKUP : PseudoInstXCore<(outs), (ins i32imm:$amt1, i32imm:$amt2), [(callseq_end timm:$amt1, timm:$amt2)]>; } +let isReMaterializable = 1 in +def FRAME_TO_ARGS_OFFSET : PseudoInstXCore<(outs GRRegs:$dst), (ins), + "# FRAME_TO_ARGS_OFFSET $dst", + [(set GRRegs:$dst, (frametoargsoffset))]>; + +let isReturn = 1, isTerminator = 1, isBarrier = 1 in +def EH_RETURN : PseudoInstXCore<(outs), (ins GRRegs:$s, GRRegs:$handler), + "# EH_RETURN $s, $handler", + [(XCoreEhRet GRRegs:$s, GRRegs:$handler)]>; + def LDWFI : PseudoInstXCore<(outs GRRegs:$dst), (ins MEMii:$addr), "# LDWFI $dst, $addr", [(set GRRegs:$dst, (load ADDRspii:$addr))]>; @@ -563,10 +585,12 @@ def STWSP_lru6 : _FLRU6<0b010101, (outs), (ins RRegs:$a, i32imm:$b), let mayLoad=1 in { def LDWSP_ru6 : _FRU6<0b010111, (outs RRegs:$a), (ins i32imm:$b), - "ldw $a, sp[$b]", []>; + "ldw $a, sp[$b]", + [(set RRegs:$a, (XCoreLdwsp immU6:$b))]>; def LDWSP_lru6 : _FLRU6<0b010111, (outs RRegs:$a), (ins i32imm:$b), - "ldw $a, sp[$b]", []>; + "ldw $a, sp[$b]", + [(set RRegs:$a, (XCoreLdwsp immU16:$b))]>; } let neverHasSideEffects = 1 in { @@ -694,10 +718,10 @@ def BLACP_u10 : _FU10<0b111000, (outs), (ins i32imm:$a), "bla cp[$a]", []>; def BLACP_lu10 : _FLU10<0b111000, (outs), (ins i32imm:$a), "bla cp[$a]", []>; def BLRF_u10 : _FU10<0b110100, (outs), (ins pcrel_imm:$a), "bl $a", - [(XCoreBranchLink immU10:$a)]>; + []>; def BLRF_lu10 : _FLU10<0b110100, (outs), (ins pcrel_imm:$a), "bl $a", - [(XCoreBranchLink immU20:$a)]>; + [(XCoreBranchLink tglobaladdr:$a)]>; def BLRB_u10 : _FU10<0b110101, (outs), (ins pcrel_imm_neg:$a), "bl $a", []>; @@ -995,7 +1019,8 @@ def SETEV_1r : _F1R<0b001111, (outs), (ins GRRegs:$a), def DGETREG_1r : _F1R<0b001110, (outs GRRegs:$a), (ins), "dgetreg $a", []>; -def EDU_1r : _F1R<0b000000, (outs), (ins GRRegs:$a), "edu res[$a]", []>; +def EDU_1r : _F1R<0b000000, (outs), (ins GRRegs:$a), "edu res[$a]", + [(int_xcore_edu GRRegs:$a)]>; def EEU_1r : _F1R<0b000001, (outs), (ins GRRegs:$a), "eeu res[$a]", @@ -1009,7 +1034,8 @@ def WAITET_1R : _F1R<0b000010, (outs), (ins GRRegs:$a), "waitet $a", []>; def TSTART_1R : _F1R<0b000110, (outs), (ins GRRegs:$a), "start t[$a]", []>; -def CLRPT_1R : _F1R<0b100000, (outs), (ins GRRegs:$a), "clrpt res[$a]", []>; +def CLRPT_1R : _F1R<0b100000, (outs), (ins GRRegs:$a), "clrpt res[$a]", + [(int_xcore_clrpt GRRegs:$a)]>; // Zero operand short @@ -1087,7 +1113,6 @@ def WAITEU_0R : _F0R<0b0000001100, (outs), (ins), // Non-Instruction Patterns //===----------------------------------------------------------------------===// -def : Pat<(XCoreBranchLink tglobaladdr:$addr), (BLRF_lu10 tglobaladdr:$addr)>; def : Pat<(XCoreBranchLink texternalsym:$addr), (BLRF_lu10 texternalsym:$addr)>; /// sext_inreg @@ -1286,3 +1311,9 @@ def : Pat<(setgt GRRegs:$lhs, -1), def : Pat<(sra (shl GRRegs:$src, immBpwSubBitp:$imm), immBpwSubBitp:$imm), (SEXT_rus GRRegs:$src, (bpwsub_xform immBpwSubBitp:$imm))>; + +def : Pat<(load (cprelwrapper tconstpool:$b)), + (LDWCP_lru6 tconstpool:$b)>; + +def : Pat<(cprelwrapper tconstpool:$b), + (LDAWCP_lu6 tconstpool:$b)>; diff --git a/lib/Target/XCore/XCoreLowerThreadLocal.cpp b/lib/Target/XCore/XCoreLowerThreadLocal.cpp index afce753..b398c2d 100644 --- a/lib/Target/XCore/XCoreLowerThreadLocal.cpp +++ b/lib/Target/XCore/XCoreLowerThreadLocal.cpp @@ -17,13 +17,13 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalVariable.h" -#include "llvm/IR/Intrinsics.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Intrinsics.h" #include "llvm/IR/Module.h" +#include "llvm/IR/NoFolder.h" +#include "llvm/IR/ValueHandle.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/NoFolder.h" -#include "llvm/Support/ValueHandle.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #define DEBUG_TYPE "xcore-lower-thread-local" @@ -127,10 +127,7 @@ createReplacementInstr(ConstantExpr *CE, Instruction *Instr) { static bool replaceConstantExprOp(ConstantExpr *CE, Pass *P) { do { - SmallVector<WeakVH,8> WUsers; - for (Value::use_iterator I = CE->use_begin(), E = CE->use_end(); - I != E; ++I) - WUsers.push_back(WeakVH(*I)); + SmallVector<WeakVH,8> WUsers(CE->user_begin(), CE->user_end()); std::sort(WUsers.begin(), WUsers.end()); WUsers.erase(std::unique(WUsers.begin(), WUsers.end()), WUsers.end()); while (!WUsers.empty()) @@ -154,17 +151,17 @@ static bool replaceConstantExprOp(ConstantExpr *CE, Pass *P) { return false; } } - } while (CE->hasNUsesOrMore(1)); // We need to check becasue a recursive - // sibbling may have used 'CE' when createReplacementInstr was called. + } while (CE->hasNUsesOrMore(1)); // We need to check because a recursive + // sibling may have used 'CE' when createReplacementInstr was called. CE->destroyConstant(); return true; } static bool rewriteNonInstructionUses(GlobalVariable *GV, Pass *P) { SmallVector<WeakVH,8> WUsers; - for (Value::use_iterator I = GV->use_begin(), E = GV->use_end(); I != E; ++I) - if (!isa<Instruction>(*I)) - WUsers.push_back(WeakVH(*I)); + for (User *U : GV->users()) + if (!isa<Instruction>(U)) + WUsers.push_back(WeakVH(U)); while (!WUsers.empty()) if (WeakVH WU = WUsers.pop_back_val()) { ConstantExpr *CE = dyn_cast<ConstantExpr>(WU); @@ -203,7 +200,7 @@ bool XCoreLowerThreadLocal::lowerGlobal(GlobalVariable *GV) { GV->isExternallyInitialized()); // Update uses. - SmallVector<User *, 16> Users(GV->use_begin(), GV->use_end()); + SmallVector<User *, 16> Users(GV->user_begin(), GV->user_end()); for (unsigned I = 0, E = Users.size(); I != E; ++I) { User *U = Users[I]; Instruction *Inst = cast<Instruction>(U); diff --git a/lib/Target/XCore/XCoreMCInstLower.cpp b/lib/Target/XCore/XCoreMCInstLower.cpp index def2673..dfdadcf 100644 --- a/lib/Target/XCore/XCoreMCInstLower.cpp +++ b/lib/Target/XCore/XCoreMCInstLower.cpp @@ -17,10 +17,10 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineOperand.h" +#include "llvm/IR/Mangler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" -#include "llvm/Target/Mangler.h" using namespace llvm; diff --git a/lib/Target/XCore/XCoreMachineFunctionInfo.cpp b/lib/Target/XCore/XCoreMachineFunctionInfo.cpp index 7ca0672..9ef9752 100644 --- a/lib/Target/XCore/XCoreMachineFunctionInfo.cpp +++ b/lib/Target/XCore/XCoreMachineFunctionInfo.cpp @@ -8,7 +8,65 @@ //===----------------------------------------------------------------------===// #include "XCoreMachineFunctionInfo.h" +#include "XCoreInstrInfo.h" +#include "llvm/IR/Function.h" using namespace llvm; void XCoreFunctionInfo::anchor() { } + +bool XCoreFunctionInfo::isLargeFrame(const MachineFunction &MF) const { + if (CachedEStackSize == -1) { + CachedEStackSize = MF.getFrameInfo()->estimateStackSize(MF); + } + // isLargeFrame() is used when deciding if spill slots should be added to + // allow eliminateFrameIndex() to scavenge registers. + // This is only required when there is no FP and offsets are greater than + // ~256KB (~64Kwords). Thus only for code run on the emulator! + // + // The arbitrary value of 0xf000 allows frames of up to ~240KB before spill + // slots are added for the use of eliminateFrameIndex() register scavenging. + // For frames less than 240KB, it is assumed that there will be less than + // 16KB of function arguments. + return CachedEStackSize > 0xf000; +} + +int XCoreFunctionInfo::createLRSpillSlot(MachineFunction &MF) { + if (LRSpillSlotSet) { + return LRSpillSlot; + } + const TargetRegisterClass *RC = &XCore::GRRegsRegClass; + MachineFrameInfo *MFI = MF.getFrameInfo(); + if (! MF.getFunction()->isVarArg()) { + // A fixed offset of 0 allows us to save / restore LR using entsp / retsp. + LRSpillSlot = MFI->CreateFixedObject(RC->getSize(), 0, true); + } else { + LRSpillSlot = MFI->CreateStackObject(RC->getSize(), RC->getAlignment(), true); + } + LRSpillSlotSet = true; + return LRSpillSlot; +} + +int XCoreFunctionInfo::createFPSpillSlot(MachineFunction &MF) { + if (FPSpillSlotSet) { + return FPSpillSlot; + } + const TargetRegisterClass *RC = &XCore::GRRegsRegClass; + MachineFrameInfo *MFI = MF.getFrameInfo(); + FPSpillSlot = MFI->CreateStackObject(RC->getSize(), RC->getAlignment(), true); + FPSpillSlotSet = true; + return FPSpillSlot; +} + +const int* XCoreFunctionInfo::createEHSpillSlot(MachineFunction &MF) { + if (EHSpillSlotSet) { + return EHSpillSlot; + } + const TargetRegisterClass *RC = &XCore::GRRegsRegClass; + MachineFrameInfo *MFI = MF.getFrameInfo(); + EHSpillSlot[0] = MFI->CreateStackObject(RC->getSize(), RC->getAlignment(), true); + EHSpillSlot[1] = MFI->CreateStackObject(RC->getSize(), RC->getAlignment(), true); + EHSpillSlotSet = true; + return EHSpillSlot; +} + diff --git a/lib/Target/XCore/XCoreMachineFunctionInfo.h b/lib/Target/XCore/XCoreMachineFunctionInfo.h index 69d5de3..212a5cf 100644 --- a/lib/Target/XCore/XCoreMachineFunctionInfo.h +++ b/lib/Target/XCore/XCoreMachineFunctionInfo.h @@ -27,40 +27,77 @@ class Function; /// XCore target-specific information for each MachineFunction. class XCoreFunctionInfo : public MachineFunctionInfo { virtual void anchor(); - bool UsesLR; + bool LRSpillSlotSet; int LRSpillSlot; + bool FPSpillSlotSet; int FPSpillSlot; + bool EHSpillSlotSet; + int EHSpillSlot[2]; + unsigned ReturnStackOffset; + bool ReturnStackOffsetSet; int VarArgsFrameIndex; - std::vector<std::pair<MCSymbol*, CalleeSavedInfo> > SpillLabels; + mutable int CachedEStackSize; + std::vector<std::pair<MachineBasicBlock::iterator, CalleeSavedInfo>> + SpillLabels; public: XCoreFunctionInfo() : - UsesLR(false), - LRSpillSlot(0), - FPSpillSlot(0), - VarArgsFrameIndex(0) {} + LRSpillSlotSet(false), + FPSpillSlotSet(false), + EHSpillSlotSet(false), + ReturnStackOffsetSet(false), + VarArgsFrameIndex(0), + CachedEStackSize(-1) {} explicit XCoreFunctionInfo(MachineFunction &MF) : - UsesLR(false), - LRSpillSlot(0), - FPSpillSlot(0), - VarArgsFrameIndex(0) {} + LRSpillSlotSet(false), + FPSpillSlotSet(false), + EHSpillSlotSet(false), + ReturnStackOffsetSet(false), + VarArgsFrameIndex(0), + CachedEStackSize(-1) {} ~XCoreFunctionInfo() {} void setVarArgsFrameIndex(int off) { VarArgsFrameIndex = off; } int getVarArgsFrameIndex() const { return VarArgsFrameIndex; } - - void setUsesLR(bool val) { UsesLR = val; } - bool getUsesLR() const { return UsesLR; } - - void setLRSpillSlot(int off) { LRSpillSlot = off; } - int getLRSpillSlot() const { return LRSpillSlot; } - - void setFPSpillSlot(int off) { FPSpillSlot = off; } - int getFPSpillSlot() const { return FPSpillSlot; } - - std::vector<std::pair<MCSymbol*, CalleeSavedInfo> > &getSpillLabels() { + + int createLRSpillSlot(MachineFunction &MF); + bool hasLRSpillSlot() { return LRSpillSlotSet; } + int getLRSpillSlot() const { + assert(LRSpillSlotSet && "LR Spill slot not set"); + return LRSpillSlot; + } + + int createFPSpillSlot(MachineFunction &MF); + bool hasFPSpillSlot() { return FPSpillSlotSet; } + int getFPSpillSlot() const { + assert(FPSpillSlotSet && "FP Spill slot not set"); + return FPSpillSlot; + } + + const int* createEHSpillSlot(MachineFunction &MF); + bool hasEHSpillSlot() { return EHSpillSlotSet; } + const int* getEHSpillSlot() const { + assert(EHSpillSlotSet && "EH Spill slot not set"); + return EHSpillSlot; + } + + void setReturnStackOffset(unsigned value) { + assert(!ReturnStackOffsetSet && "Return stack offset set twice"); + ReturnStackOffset = value; + ReturnStackOffsetSet = true; + } + + unsigned getReturnStackOffset() const { + assert(ReturnStackOffsetSet && "Return stack offset not set"); + return ReturnStackOffset; + } + + bool isLargeFrame(const MachineFunction &MF) const; + + std::vector<std::pair<MachineBasicBlock::iterator, CalleeSavedInfo>> & + getSpillLabels() { return SpillLabels; } }; diff --git a/lib/Target/XCore/XCoreRegisterInfo.cpp b/lib/Target/XCore/XCoreRegisterInfo.cpp index dbd2f52..d85d717 100644 --- a/lib/Target/XCore/XCoreRegisterInfo.cpp +++ b/lib/Target/XCore/XCoreRegisterInfo.cpp @@ -13,6 +13,7 @@ #include "XCoreRegisterInfo.h" #include "XCore.h" +#include "XCoreInstrInfo.h" #include "XCoreMachineFunctionInfo.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" @@ -26,9 +27,9 @@ #include "llvm/IR/Type.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetFrameLowering.h" -#include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" @@ -54,6 +55,151 @@ static inline bool isImmU16(unsigned val) { return val < (1 << 16); } + +static void InsertFPImmInst(MachineBasicBlock::iterator II, + const XCoreInstrInfo &TII, + unsigned Reg, unsigned FrameReg, int Offset ) { + MachineInstr &MI = *II; + MachineBasicBlock &MBB = *MI.getParent(); + DebugLoc dl = MI.getDebugLoc(); + + switch (MI.getOpcode()) { + case XCore::LDWFI: + BuildMI(MBB, II, dl, TII.get(XCore::LDW_2rus), Reg) + .addReg(FrameReg) + .addImm(Offset) + .addMemOperand(*MI.memoperands_begin()); + break; + case XCore::STWFI: + BuildMI(MBB, II, dl, TII.get(XCore::STW_2rus)) + .addReg(Reg, getKillRegState(MI.getOperand(0).isKill())) + .addReg(FrameReg) + .addImm(Offset) + .addMemOperand(*MI.memoperands_begin()); + break; + case XCore::LDAWFI: + BuildMI(MBB, II, dl, TII.get(XCore::LDAWF_l2rus), Reg) + .addReg(FrameReg) + .addImm(Offset); + break; + default: + llvm_unreachable("Unexpected Opcode"); + } +} + +static void InsertFPConstInst(MachineBasicBlock::iterator II, + const XCoreInstrInfo &TII, + unsigned Reg, unsigned FrameReg, + int Offset, RegScavenger *RS ) { + assert(RS && "requiresRegisterScavenging failed"); + MachineInstr &MI = *II; + MachineBasicBlock &MBB = *MI.getParent(); + DebugLoc dl = MI.getDebugLoc(); + unsigned ScratchOffset = RS->scavengeRegister(&XCore::GRRegsRegClass, II, 0); + RS->setUsed(ScratchOffset); + TII.loadImmediate(MBB, II, ScratchOffset, Offset); + + switch (MI.getOpcode()) { + case XCore::LDWFI: + BuildMI(MBB, II, dl, TII.get(XCore::LDW_3r), Reg) + .addReg(FrameReg) + .addReg(ScratchOffset, RegState::Kill) + .addMemOperand(*MI.memoperands_begin()); + break; + case XCore::STWFI: + BuildMI(MBB, II, dl, TII.get(XCore::STW_l3r)) + .addReg(Reg, getKillRegState(MI.getOperand(0).isKill())) + .addReg(FrameReg) + .addReg(ScratchOffset, RegState::Kill) + .addMemOperand(*MI.memoperands_begin()); + break; + case XCore::LDAWFI: + BuildMI(MBB, II, dl, TII.get(XCore::LDAWF_l3r), Reg) + .addReg(FrameReg) + .addReg(ScratchOffset, RegState::Kill); + break; + default: + llvm_unreachable("Unexpected Opcode"); + } +} + +static void InsertSPImmInst(MachineBasicBlock::iterator II, + const XCoreInstrInfo &TII, + unsigned Reg, int Offset) { + MachineInstr &MI = *II; + MachineBasicBlock &MBB = *MI.getParent(); + DebugLoc dl = MI.getDebugLoc(); + bool isU6 = isImmU6(Offset); + + switch (MI.getOpcode()) { + int NewOpcode; + case XCore::LDWFI: + NewOpcode = (isU6) ? XCore::LDWSP_ru6 : XCore::LDWSP_lru6; + BuildMI(MBB, II, dl, TII.get(NewOpcode), Reg) + .addImm(Offset) + .addMemOperand(*MI.memoperands_begin()); + break; + case XCore::STWFI: + NewOpcode = (isU6) ? XCore::STWSP_ru6 : XCore::STWSP_lru6; + BuildMI(MBB, II, dl, TII.get(NewOpcode)) + .addReg(Reg, getKillRegState(MI.getOperand(0).isKill())) + .addImm(Offset) + .addMemOperand(*MI.memoperands_begin()); + break; + case XCore::LDAWFI: + NewOpcode = (isU6) ? XCore::LDAWSP_ru6 : XCore::LDAWSP_lru6; + BuildMI(MBB, II, dl, TII.get(NewOpcode), Reg) + .addImm(Offset); + break; + default: + llvm_unreachable("Unexpected Opcode"); + } +} + +static void InsertSPConstInst(MachineBasicBlock::iterator II, + const XCoreInstrInfo &TII, + unsigned Reg, int Offset, RegScavenger *RS ) { + assert(RS && "requiresRegisterScavenging failed"); + MachineInstr &MI = *II; + MachineBasicBlock &MBB = *MI.getParent(); + DebugLoc dl = MI.getDebugLoc(); + unsigned OpCode = MI.getOpcode(); + + unsigned ScratchBase; + if (OpCode==XCore::STWFI) { + ScratchBase = RS->scavengeRegister(&XCore::GRRegsRegClass, II, 0); + RS->setUsed(ScratchBase); + } else + ScratchBase = Reg; + BuildMI(MBB, II, dl, TII.get(XCore::LDAWSP_ru6), ScratchBase).addImm(0); + unsigned ScratchOffset = RS->scavengeRegister(&XCore::GRRegsRegClass, II, 0); + RS->setUsed(ScratchOffset); + TII.loadImmediate(MBB, II, ScratchOffset, Offset); + + switch (OpCode) { + case XCore::LDWFI: + BuildMI(MBB, II, dl, TII.get(XCore::LDW_3r), Reg) + .addReg(ScratchBase, RegState::Kill) + .addReg(ScratchOffset, RegState::Kill) + .addMemOperand(*MI.memoperands_begin()); + break; + case XCore::STWFI: + BuildMI(MBB, II, dl, TII.get(XCore::STW_l3r)) + .addReg(Reg, getKillRegState(MI.getOperand(0).isKill())) + .addReg(ScratchBase, RegState::Kill) + .addReg(ScratchOffset, RegState::Kill) + .addMemOperand(*MI.memoperands_begin()); + break; + case XCore::LDAWFI: + BuildMI(MBB, II, dl, TII.get(XCore::LDAWF_l3r), Reg) + .addReg(ScratchBase, RegState::Kill) + .addReg(ScratchOffset, RegState::Kill); + break; + default: + llvm_unreachable("Unexpected Opcode"); + } +} + bool XCoreRegisterInfo::needsFrameMoves(const MachineFunction &MF) { return MF.getMMI().hasDebugInfo() || MF.getFunction()->needsUnwindTableEntry(); @@ -61,11 +207,21 @@ bool XCoreRegisterInfo::needsFrameMoves(const MachineFunction &MF) { const uint16_t* XCoreRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { + // The callee saved registers LR & FP are explicitly handled during + // emitPrologue & emitEpilogue and related functions. static const uint16_t CalleeSavedRegs[] = { XCore::R4, XCore::R5, XCore::R6, XCore::R7, - XCore::R8, XCore::R9, XCore::R10, XCore::LR, + XCore::R8, XCore::R9, XCore::R10, + 0 + }; + static const uint16_t CalleeSavedRegsFP[] = { + XCore::R4, XCore::R5, XCore::R6, XCore::R7, + XCore::R8, XCore::R9, 0 }; + const TargetFrameLowering *TFI = MF->getTarget().getFrameLowering(); + if (TFI->hasFP(*MF)) + return CalleeSavedRegsFP; return CalleeSavedRegs; } @@ -85,15 +241,12 @@ BitVector XCoreRegisterInfo::getReservedRegs(const MachineFunction &MF) const { bool XCoreRegisterInfo::requiresRegisterScavenging(const MachineFunction &MF) const { - const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); - - // TODO can we estimate stack size? - return TFI->hasFP(MF); + return true; } bool XCoreRegisterInfo::trackLivenessAfterRegAlloc(const MachineFunction &MF) const { - return requiresRegisterScavenging(MF); + return true; } bool @@ -107,12 +260,13 @@ XCoreRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, RegScavenger *RS) const { assert(SPAdj == 0 && "Unexpected"); MachineInstr &MI = *II; - DebugLoc dl = MI.getDebugLoc(); MachineOperand &FrameOp = MI.getOperand(FIOperandNum); int FrameIndex = FrameOp.getIndex(); MachineFunction &MF = *MI.getParent()->getParent(); - const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + const XCoreInstrInfo &TII = + *static_cast<const XCoreInstrInfo*>(MF.getTarget().getInstrInfo()); + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex); int StackSize = MF.getFrameInfo()->getStackSize(); @@ -143,116 +297,28 @@ XCoreRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, MI.getOperand(FIOperandNum + 1).ChangeToImmediate(0); assert(Offset%4 == 0 && "Misaligned stack offset"); - DEBUG(errs() << "Offset : " << Offset << "\n" << "<--------->\n"); - Offset/=4; - bool FP = TFI->hasFP(MF); - unsigned Reg = MI.getOperand(0).getReg(); - bool isKill = MI.getOpcode() == XCore::STWFI && MI.getOperand(0).isKill(); - assert(XCore::GRRegsRegClass.contains(Reg) && "Unexpected register operand"); - - MachineBasicBlock &MBB = *MI.getParent(); - - if (FP) { - bool isUs = isImmUs(Offset); - - if (!isUs) { - if (!RS) - report_fatal_error("eliminateFrameIndex Frame size too big: " + - Twine(Offset)); - unsigned ScratchReg = RS->scavengeRegister(&XCore::GRRegsRegClass, II, - SPAdj); - loadConstant(MBB, II, ScratchReg, Offset, dl); - switch (MI.getOpcode()) { - case XCore::LDWFI: - BuildMI(MBB, II, dl, TII.get(XCore::LDW_3r), Reg) - .addReg(FrameReg) - .addReg(ScratchReg, RegState::Kill); - break; - case XCore::STWFI: - BuildMI(MBB, II, dl, TII.get(XCore::STW_l3r)) - .addReg(Reg, getKillRegState(isKill)) - .addReg(FrameReg) - .addReg(ScratchReg, RegState::Kill); - break; - case XCore::LDAWFI: - BuildMI(MBB, II, dl, TII.get(XCore::LDAWF_l3r), Reg) - .addReg(FrameReg) - .addReg(ScratchReg, RegState::Kill); - break; - default: - llvm_unreachable("Unexpected Opcode"); - } - } else { - switch (MI.getOpcode()) { - case XCore::LDWFI: - BuildMI(MBB, II, dl, TII.get(XCore::LDW_2rus), Reg) - .addReg(FrameReg) - .addImm(Offset); - break; - case XCore::STWFI: - BuildMI(MBB, II, dl, TII.get(XCore::STW_2rus)) - .addReg(Reg, getKillRegState(isKill)) - .addReg(FrameReg) - .addImm(Offset); - break; - case XCore::LDAWFI: - BuildMI(MBB, II, dl, TII.get(XCore::LDAWF_l2rus), Reg) - .addReg(FrameReg) - .addImm(Offset); - break; - default: - llvm_unreachable("Unexpected Opcode"); - } - } + + if (TFI->hasFP(MF)) { + if (isImmUs(Offset)) + InsertFPImmInst(II, TII, Reg, FrameReg, Offset); + else + InsertFPConstInst(II, TII, Reg, FrameReg, Offset, RS); } else { - bool isU6 = isImmU6(Offset); - if (!isU6 && !isImmU16(Offset)) - report_fatal_error("eliminateFrameIndex Frame size too big: " + - Twine(Offset)); - - switch (MI.getOpcode()) { - int NewOpcode; - case XCore::LDWFI: - NewOpcode = (isU6) ? XCore::LDWSP_ru6 : XCore::LDWSP_lru6; - BuildMI(MBB, II, dl, TII.get(NewOpcode), Reg) - .addImm(Offset); - break; - case XCore::STWFI: - NewOpcode = (isU6) ? XCore::STWSP_ru6 : XCore::STWSP_lru6; - BuildMI(MBB, II, dl, TII.get(NewOpcode)) - .addReg(Reg, getKillRegState(isKill)) - .addImm(Offset); - break; - case XCore::LDAWFI: - NewOpcode = (isU6) ? XCore::LDAWSP_ru6 : XCore::LDAWSP_lru6; - BuildMI(MBB, II, dl, TII.get(NewOpcode), Reg) - .addImm(Offset); - break; - default: - llvm_unreachable("Unexpected Opcode"); - } + if (isImmU16(Offset)) + InsertSPImmInst(II, TII, Reg, Offset); + else + InsertSPConstInst(II, TII, Reg, Offset, RS); } // Erase old instruction. + MachineBasicBlock &MBB = *MI.getParent(); MBB.erase(II); } -void XCoreRegisterInfo:: -loadConstant(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, - unsigned DstReg, int64_t Value, DebugLoc dl) const { - // TODO use mkmsk if possible. - if (!isImmU16(Value)) { - // TODO use constant pool. - report_fatal_error("loadConstant value too big " + Twine(Value)); - } - int Opcode = isImmU6(Value) ? XCore::LDC_ru6 : XCore::LDC_lru6; - const TargetInstrInfo &TII = *MBB.getParent()->getTarget().getInstrInfo(); - BuildMI(MBB, I, dl, TII.get(Opcode), DstReg).addImm(Value); -} unsigned XCoreRegisterInfo::getFrameRegister(const MachineFunction &MF) const { const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); diff --git a/lib/Target/XCore/XCoreRegisterInfo.h b/lib/Target/XCore/XCoreRegisterInfo.h index 2370c62..36ba7b4 100644 --- a/lib/Target/XCore/XCoreRegisterInfo.h +++ b/lib/Target/XCore/XCoreRegisterInfo.h @@ -24,19 +24,6 @@ namespace llvm { class TargetInstrInfo; struct XCoreRegisterInfo : public XCoreGenRegisterInfo { -private: - void loadConstant(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, - unsigned DstReg, int64_t Value, DebugLoc dl) const; - - void storeToStack(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, - unsigned SrcReg, int Offset, DebugLoc dl) const; - - void loadFromStack(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, - unsigned DstReg, int Offset, DebugLoc dl) const; - public: XCoreRegisterInfo(); diff --git a/lib/Target/XCore/XCoreSelectionDAGInfo.cpp b/lib/Target/XCore/XCoreSelectionDAGInfo.cpp index 44aeb60..68ede6a 100644 --- a/lib/Target/XCore/XCoreSelectionDAGInfo.cpp +++ b/lib/Target/XCore/XCoreSelectionDAGInfo.cpp @@ -21,3 +21,36 @@ XCoreSelectionDAGInfo::XCoreSelectionDAGInfo(const XCoreTargetMachine &TM) XCoreSelectionDAGInfo::~XCoreSelectionDAGInfo() { } + +SDValue XCoreSelectionDAGInfo:: +EmitTargetCodeForMemcpy(SelectionDAG &DAG, SDLoc dl, SDValue Chain, + SDValue Dst, SDValue Src, SDValue Size, unsigned Align, + bool isVolatile, bool AlwaysInline, + MachinePointerInfo DstPtrInfo, + MachinePointerInfo SrcPtrInfo) const +{ + unsigned SizeBitWidth = Size.getValueType().getSizeInBits(); + // Call __memcpy_4 if the src, dst and size are all 4 byte aligned. + if (!AlwaysInline && (Align & 3) == 0 && + DAG.MaskedValueIsZero(Size, APInt(SizeBitWidth, 3))) { + const TargetLowering &TLI = *DAG.getTarget().getTargetLowering(); + TargetLowering::ArgListTy Args; + TargetLowering::ArgListEntry Entry; + Entry.Ty = TLI.getDataLayout()->getIntPtrType(*DAG.getContext()); + Entry.Node = Dst; Args.push_back(Entry); + Entry.Node = Src; Args.push_back(Entry); + Entry.Node = Size; Args.push_back(Entry); + + TargetLowering::CallLoweringInfo + CLI(Chain, Type::getVoidTy(*DAG.getContext()), false, false, false, false, + 0, TLI.getLibcallCallingConv(RTLIB::MEMCPY), /*isTailCall=*/false, + /*doesNotRet=*/false, /*isReturnValueUsed=*/false, + DAG.getExternalSymbol("__memcpy_4", TLI.getPointerTy()), Args, DAG, dl); + std::pair<SDValue,SDValue> CallResult = + TLI.LowerCallTo(CLI); + return CallResult.second; + } + + // Otherwise have the target-independent code call memcpy. + return SDValue(); +} diff --git a/lib/Target/XCore/XCoreSelectionDAGInfo.h b/lib/Target/XCore/XCoreSelectionDAGInfo.h index 0386968..31704f3 100644 --- a/lib/Target/XCore/XCoreSelectionDAGInfo.h +++ b/lib/Target/XCore/XCoreSelectionDAGInfo.h @@ -24,6 +24,15 @@ class XCoreSelectionDAGInfo : public TargetSelectionDAGInfo { public: explicit XCoreSelectionDAGInfo(const XCoreTargetMachine &TM); ~XCoreSelectionDAGInfo(); + + virtual SDValue + EmitTargetCodeForMemcpy(SelectionDAG &DAG, SDLoc dl, + SDValue Chain, + SDValue Op1, SDValue Op2, + SDValue Op3, unsigned Align, bool isVolatile, + bool AlwaysInline, + MachinePointerInfo DstPtrInfo, + MachinePointerInfo SrcPtrInfo) const; }; } diff --git a/lib/Target/XCore/XCoreTargetMachine.cpp b/lib/Target/XCore/XCoreTargetMachine.cpp index 9ae0b86..781a87b 100644 --- a/lib/Target/XCore/XCoreTargetMachine.cpp +++ b/lib/Target/XCore/XCoreTargetMachine.cpp @@ -27,8 +27,7 @@ XCoreTargetMachine::XCoreTargetMachine(const Target &T, StringRef TT, CodeGenOpt::Level OL) : LLVMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL), Subtarget(TT, CPU, FS), - DL("e-p:32:32:32-a0:0:32-f32:32:32-f64:32:32-i1:8:32-i8:8:32-" - "i16:16:32-i32:32:32-i64:32:32-n32"), + DL("e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:32-f64:32-a:0:32-n32"), InstrInfo(), FrameLowering(Subtarget), TLInfo(*this), @@ -49,6 +48,7 @@ public: virtual bool addPreISel(); virtual bool addInstSelector(); + virtual bool addPreEmitPass(); }; } // namespace @@ -66,6 +66,11 @@ bool XCorePassConfig::addInstSelector() { return false; } +bool XCorePassConfig::addPreEmitPass() { + addPass(createXCoreFrameToArgsOffsetEliminationPass()); + return false; +} + // Force static initialization. extern "C" void LLVMInitializeXCoreTarget() { RegisterTargetMachine<XCoreTargetMachine> X(TheXCoreTarget); diff --git a/lib/Target/XCore/XCoreTargetObjectFile.cpp b/lib/Target/XCore/XCoreTargetObjectFile.cpp index 88e3bfd..ab0f7ad 100644 --- a/lib/Target/XCore/XCoreTargetObjectFile.cpp +++ b/lib/Target/XCore/XCoreTargetObjectFile.cpp @@ -9,27 +9,58 @@ #include "XCoreTargetObjectFile.h" #include "XCoreSubtarget.h" +#include "llvm/IR/DataLayout.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/Support/ELF.h" #include "llvm/Target/TargetMachine.h" + using namespace llvm; void XCoreTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM){ TargetLoweringObjectFileELF::Initialize(Ctx, TM); + BSSSection = + Ctx.getELFSection(".dp.bss", ELF::SHT_NOBITS, + ELF::SHF_ALLOC | ELF::SHF_WRITE | + ELF::XCORE_SHF_DP_SECTION, + SectionKind::getBSS()); + BSSSectionLarge = + Ctx.getELFSection(".dp.bss.large", ELF::SHT_NOBITS, + ELF::SHF_ALLOC | ELF::SHF_WRITE | + ELF::XCORE_SHF_DP_SECTION, + SectionKind::getBSS()); DataSection = - Ctx.getELFSection(".dp.data", ELF::SHT_PROGBITS, + Ctx.getELFSection(".dp.data", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_WRITE | ELF::XCORE_SHF_DP_SECTION, SectionKind::getDataRel()); - BSSSection = - Ctx.getELFSection(".dp.bss", ELF::SHT_NOBITS, + DataSectionLarge = + Ctx.getELFSection(".dp.data.large", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_WRITE | ELF::XCORE_SHF_DP_SECTION, - SectionKind::getBSS()); - + SectionKind::getDataRel()); + DataRelROSection = + Ctx.getELFSection(".dp.rodata", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_WRITE | + ELF::XCORE_SHF_DP_SECTION, + SectionKind::getReadOnlyWithRel()); + DataRelROSectionLarge = + Ctx.getELFSection(".dp.rodata.large", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_WRITE | + ELF::XCORE_SHF_DP_SECTION, + SectionKind::getReadOnlyWithRel()); + ReadOnlySection = + Ctx.getELFSection(".cp.rodata", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::XCORE_SHF_CP_SECTION, + SectionKind::getReadOnlyWithRel()); + ReadOnlySectionLarge = + Ctx.getELFSection(".cp.rodata.large", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::XCORE_SHF_CP_SECTION, + SectionKind::getReadOnlyWithRel()); MergeableConst4Section = Ctx.getELFSection(".cp.rodata.cst4", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_MERGE | @@ -45,16 +76,103 @@ void XCoreTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM){ ELF::SHF_ALLOC | ELF::SHF_MERGE | ELF::XCORE_SHF_CP_SECTION, SectionKind::getMergeableConst16()); - - // TLS globals are lowered in the backend to arrays indexed by the current - // thread id. After lowering they require no special handling by the linker - // and can be placed in the standard data / bss sections. - TLSDataSection = DataSection; - TLSBSSSection = BSSSection; - - ReadOnlySection = - Ctx.getELFSection(".cp.rodata", ELF::SHT_PROGBITS, - ELF::SHF_ALLOC | + CStringSection = + Ctx.getELFSection(".cp.rodata.string", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_MERGE | ELF::SHF_STRINGS | ELF::XCORE_SHF_CP_SECTION, SectionKind::getReadOnlyWithRel()); + // TextSection - see MObjectFileInfo.cpp + // StaticCtorSection - see MObjectFileInfo.cpp + // StaticDtorSection - see MObjectFileInfo.cpp + } + +static unsigned getXCoreSectionType(SectionKind K) { + if (K.isBSS()) + return ELF::SHT_NOBITS; + return ELF::SHT_PROGBITS; +} + +static unsigned getXCoreSectionFlags(SectionKind K, bool IsCPRel) { + unsigned Flags = 0; + + if (!K.isMetadata()) + Flags |= ELF::SHF_ALLOC; + + if (K.isText()) + Flags |= ELF::SHF_EXECINSTR; + else if (IsCPRel) + Flags |= ELF::XCORE_SHF_CP_SECTION; + else + Flags |= ELF::XCORE_SHF_DP_SECTION; + + if (K.isWriteable()) + Flags |= ELF::SHF_WRITE; + + if (K.isMergeableCString() || K.isMergeableConst4() || + K.isMergeableConst8() || K.isMergeableConst16()) + Flags |= ELF::SHF_MERGE; + + if (K.isMergeableCString()) + Flags |= ELF::SHF_STRINGS; + + return Flags; +} + +const MCSection * +XCoreTargetObjectFile::getExplicitSectionGlobal(const GlobalValue *GV, + SectionKind Kind, Mangler &Mang, + const TargetMachine &TM) const { + StringRef SectionName = GV->getSection(); + // Infer section flags from the section name if we can. + bool IsCPRel = SectionName.startswith(".cp."); + if (IsCPRel && !Kind.isReadOnly()) + report_fatal_error("Using .cp. section for writeable object."); + return getContext().getELFSection(SectionName, getXCoreSectionType(Kind), + getXCoreSectionFlags(Kind, IsCPRel), Kind); +} + +const MCSection *XCoreTargetObjectFile:: +SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, Mangler &Mang, + const TargetMachine &TM) const{ + + bool UseCPRel = GV->isLocalLinkage(GV->getLinkage()); + + if (Kind.isText()) return TextSection; + if (UseCPRel) { + if (Kind.isMergeable1ByteCString()) return CStringSection; + if (Kind.isMergeableConst4()) return MergeableConst4Section; + if (Kind.isMergeableConst8()) return MergeableConst8Section; + if (Kind.isMergeableConst16()) return MergeableConst16Section; + } + Type *ObjType = GV->getType()->getPointerElementType(); + if (TM.getCodeModel() == CodeModel::Small || + !ObjType->isSized() || + TM.getDataLayout()->getTypeAllocSize(ObjType) < CodeModelLargeSize) { + if (Kind.isReadOnly()) return UseCPRel? ReadOnlySection + : DataRelROSection; + if (Kind.isBSS() || Kind.isCommon())return BSSSection; + if (Kind.isDataRel()) return DataSection; + if (Kind.isReadOnlyWithRel()) return DataRelROSection; + } else { + if (Kind.isReadOnly()) return UseCPRel? ReadOnlySectionLarge + : DataRelROSectionLarge; + if (Kind.isBSS() || Kind.isCommon())return BSSSectionLarge; + if (Kind.isDataRel()) return DataSectionLarge; + if (Kind.isReadOnlyWithRel()) return DataRelROSectionLarge; + } + + assert((Kind.isThreadLocal() || Kind.isCommon()) && "Unknown section kind"); + report_fatal_error("Target does not support TLS or Common sections"); +} + +const MCSection *XCoreTargetObjectFile:: +getSectionForConstant(SectionKind Kind) const { + if (Kind.isMergeableConst4()) return MergeableConst4Section; + if (Kind.isMergeableConst8()) return MergeableConst8Section; + if (Kind.isMergeableConst16()) return MergeableConst16Section; + assert((Kind.isReadOnly() || Kind.isReadOnlyWithRel()) && + "Unknown section kind"); + // We assume the size of the object is never greater than CodeModelLargeSize. + // To handle CodeModelLargeSize changes to AsmPrinter would be required. + return ReadOnlySection; } diff --git a/lib/Target/XCore/XCoreTargetObjectFile.h b/lib/Target/XCore/XCoreTargetObjectFile.h index 27875e7..733e6d3 100644 --- a/lib/Target/XCore/XCoreTargetObjectFile.h +++ b/lib/Target/XCore/XCoreTargetObjectFile.h @@ -14,11 +14,27 @@ namespace llvm { +static const unsigned CodeModelLargeSize = 256; + class XCoreTargetObjectFile : public TargetLoweringObjectFileELF { + const MCSection *BSSSectionLarge; + const MCSection *DataSectionLarge; + const MCSection *ReadOnlySectionLarge; + const MCSection *DataRelROSectionLarge; public: void Initialize(MCContext &Ctx, const TargetMachine &TM); - // TODO: Classify globals as xcore wishes. + const MCSection * + getExplicitSectionGlobal(const GlobalValue *GV, + SectionKind Kind, Mangler &Mang, + const TargetMachine &TM) const override; + + const MCSection * + SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, + Mangler &Mang, + const TargetMachine &TM) const override; + + const MCSection *getSectionForConstant(SectionKind Kind) const override; }; } // end namespace llvm diff --git a/lib/Target/XCore/XCoreTargetStreamer.h b/lib/Target/XCore/XCoreTargetStreamer.h new file mode 100644 index 0000000..0a394da --- /dev/null +++ b/lib/Target/XCore/XCoreTargetStreamer.h @@ -0,0 +1,27 @@ +//===-- XCoreTargetStreamer.h - XCore Target Streamer ----------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef XCORETARGETSTREAMER_H +#define XCORETARGETSTREAMER_H + +#include "llvm/MC/MCStreamer.h" + +namespace llvm { +class XCoreTargetStreamer : public MCTargetStreamer { +public: + XCoreTargetStreamer(MCStreamer &S); + virtual ~XCoreTargetStreamer(); + virtual void emitCCTopData(StringRef Name) = 0; + virtual void emitCCTopFunction(StringRef Name) = 0; + virtual void emitCCBottomData(StringRef Name) = 0; + virtual void emitCCBottomFunction(StringRef Name) = 0; +}; +} + +#endif diff --git a/lib/Target/XCore/XCoreTargetTransformInfo.cpp b/lib/Target/XCore/XCoreTargetTransformInfo.cpp index cc165f7..313d18d 100644 --- a/lib/Target/XCore/XCoreTargetTransformInfo.cpp +++ b/lib/Target/XCore/XCoreTargetTransformInfo.cpp @@ -18,8 +18,8 @@ #include "XCore.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Support/Debug.h" -#include "llvm/Target/TargetLowering.h" #include "llvm/Target/CostTable.h" +#include "llvm/Target/TargetLowering.h" using namespace llvm; // Declare the pass initialization routine locally as target-specific passes @@ -31,7 +31,7 @@ void initializeXCoreTTIPass(PassRegistry &); namespace { -class XCoreTTI : public ImmutablePass, public TargetTransformInfo { +class XCoreTTI final : public ImmutablePass, public TargetTransformInfo { public: XCoreTTI() : ImmutablePass(ID) { llvm_unreachable("This pass cannot be directly constructed"); @@ -42,27 +42,23 @@ public: initializeXCoreTTIPass(*PassRegistry::getPassRegistry()); } - virtual void initializePass() { + virtual void initializePass() override { pushTTIStack(this); } - virtual void finalizePass() { - popTTIStack(); - } - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { + virtual void getAnalysisUsage(AnalysisUsage &AU) const override { TargetTransformInfo::getAnalysisUsage(AU); } static char ID; - virtual void *getAdjustedAnalysisPointer(const void *ID) { + virtual void *getAdjustedAnalysisPointer(const void *ID) override { if (ID == &TargetTransformInfo::ID) return (TargetTransformInfo*)this; return this; } - unsigned getNumberOfRegisters(bool Vector) const { + unsigned getNumberOfRegisters(bool Vector) const override { if (Vector) { return 0; } |
