aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Target/XCore
diff options
context:
space:
mode:
authorStephen Hines <srhines@google.com>2014-04-23 16:57:46 -0700
committerStephen Hines <srhines@google.com>2014-04-24 15:53:16 -0700
commit36b56886974eae4f9c5ebc96befd3e7bfe5de338 (patch)
treee6cfb69fbbd937f450eeb83bfb83b9da3b01275a /lib/Target/XCore
parent69a8640022b04415ae9fac62f8ab090601d8f889 (diff)
downloadexternal_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')
-rw-r--r--lib/Target/XCore/CMakeLists.txt3
-rw-r--r--lib/Target/XCore/Disassembler/CMakeLists.txt2
-rw-r--r--lib/Target/XCore/InstPrinter/CMakeLists.txt4
-rw-r--r--lib/Target/XCore/LLVMBuild.txt2
-rw-r--r--lib/Target/XCore/MCTargetDesc/CMakeLists.txt5
-rw-r--r--lib/Target/XCore/MCTargetDesc/LLVMBuild.txt2
-rw-r--r--lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.cpp3
-rw-r--r--lib/Target/XCore/MCTargetDesc/XCoreMCTargetDesc.cpp58
-rw-r--r--lib/Target/XCore/TargetInfo/CMakeLists.txt4
-rw-r--r--lib/Target/XCore/TargetInfo/LLVMBuild.txt2
-rw-r--r--lib/Target/XCore/XCore.h1
-rw-r--r--lib/Target/XCore/XCore.td6
-rw-r--r--lib/Target/XCore/XCoreAsmPrinter.cpp77
-rw-r--r--lib/Target/XCore/XCoreCallingConv.td6
-rw-r--r--lib/Target/XCore/XCoreFrameLowering.cpp543
-rw-r--r--lib/Target/XCore/XCoreFrameLowering.h3
-rw-r--r--lib/Target/XCore/XCoreFrameToArgsOffsetElim.cpp62
-rw-r--r--lib/Target/XCore/XCoreISelDAGToDAG.cpp27
-rw-r--r--lib/Target/XCore/XCoreISelLowering.cpp424
-rw-r--r--lib/Target/XCore/XCoreISelLowering.h20
-rw-r--r--lib/Target/XCore/XCoreInstrInfo.cpp54
-rw-r--r--lib/Target/XCore/XCoreInstrInfo.h6
-rw-r--r--lib/Target/XCore/XCoreInstrInfo.td45
-rw-r--r--lib/Target/XCore/XCoreLowerThreadLocal.cpp23
-rw-r--r--lib/Target/XCore/XCoreMCInstLower.cpp2
-rw-r--r--lib/Target/XCore/XCoreMachineFunctionInfo.cpp58
-rw-r--r--lib/Target/XCore/XCoreMachineFunctionInfo.h79
-rw-r--r--lib/Target/XCore/XCoreRegisterInfo.cpp282
-rw-r--r--lib/Target/XCore/XCoreRegisterInfo.h13
-rw-r--r--lib/Target/XCore/XCoreSelectionDAGInfo.cpp33
-rw-r--r--lib/Target/XCore/XCoreSelectionDAGInfo.h9
-rw-r--r--lib/Target/XCore/XCoreTargetMachine.cpp9
-rw-r--r--lib/Target/XCore/XCoreTargetObjectFile.cpp148
-rw-r--r--lib/Target/XCore/XCoreTargetObjectFile.h18
-rw-r--r--lib/Target/XCore/XCoreTargetStreamer.h27
-rw-r--r--lib/Target/XCore/XCoreTargetTransformInfo.cpp16
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;
}