summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Stoklund Olesen <stoklund@2pi.dk>2009-08-02 17:32:10 +0000
committerJakob Stoklund Olesen <stoklund@2pi.dk>2009-08-02 17:32:10 +0000
commitd950941e138455ebcd7a5f55805dcb977892e3e3 (patch)
treef9732e3dd797f8f76f0c886f57f295daeb1f1a92
parent4ea480499c40cd7e28bf35cacda33ccbab2aab07 (diff)
downloadllvm-d950941e138455ebcd7a5f55805dcb977892e3e3.tar.gz
llvm-d950941e138455ebcd7a5f55805dcb977892e3e3.tar.bz2
llvm-d950941e138455ebcd7a5f55805dcb977892e3e3.tar.xz
Analog Devices Blackfin back-end.
Generate code for the Blackfin family of DSPs from Analog Devices: http://www.analog.com/en/embedded-processing-dsp/blackfin/processors/index.html We aim to be compatible with the exsisting GNU toolchain found at: http://blackfin.uclinux.org/gf/project/toolchain The back-end is experimental. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@77897 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/ADT/Triple.h1
-rw-r--r--lib/Support/Triple.cpp3
-rw-r--r--lib/Target/Blackfin/AsmPrinter/BlackfinAsmPrinter.cpp237
-rw-r--r--lib/Target/Blackfin/AsmPrinter/CMakeLists.txt3
-rw-r--r--lib/Target/Blackfin/AsmPrinter/Makefile16
-rw-r--r--lib/Target/Blackfin/Blackfin.h38
-rw-r--r--lib/Target/Blackfin/Blackfin.td52
-rw-r--r--lib/Target/Blackfin/BlackfinCallingConv.td30
-rw-r--r--lib/Target/Blackfin/BlackfinISelDAGToDAG.cpp191
-rw-r--r--lib/Target/Blackfin/BlackfinISelLowering.cpp536
-rw-r--r--lib/Target/Blackfin/BlackfinISelLowering.h61
-rw-r--r--lib/Target/Blackfin/BlackfinInstrFormats.td34
-rw-r--r--lib/Target/Blackfin/BlackfinInstrInfo.cpp280
-rw-r--r--lib/Target/Blackfin/BlackfinInstrInfo.h80
-rw-r--r--lib/Target/Blackfin/BlackfinInstrInfo.td838
-rw-r--r--lib/Target/Blackfin/BlackfinRegisterInfo.cpp462
-rw-r--r--lib/Target/Blackfin/BlackfinRegisterInfo.h114
-rw-r--r--lib/Target/Blackfin/BlackfinRegisterInfo.td380
-rw-r--r--lib/Target/Blackfin/BlackfinSubtarget.cpp26
-rw-r--r--lib/Target/Blackfin/BlackfinSubtarget.h39
-rw-r--r--lib/Target/Blackfin/BlackfinTargetAsmInfo.cpp23
-rw-r--r--lib/Target/Blackfin/BlackfinTargetAsmInfo.h27
-rw-r--r--lib/Target/Blackfin/BlackfinTargetMachine.cpp54
-rw-r--r--lib/Target/Blackfin/BlackfinTargetMachine.h61
-rw-r--r--lib/Target/Blackfin/CMakeLists.txt21
-rw-r--r--lib/Target/Blackfin/Makefile23
-rw-r--r--lib/Target/Blackfin/README.txt122
-rw-r--r--lib/Target/Blackfin/TargetInfo/BlackfinTargetInfo.cpp21
-rw-r--r--lib/Target/Blackfin/TargetInfo/CMakeLists.txt3
-rw-r--r--lib/Target/Blackfin/TargetInfo/Makefile15
-rw-r--r--test/CodeGen/Blackfin/add-overflow.ll18
-rw-r--r--test/CodeGen/Blackfin/add.ll5
-rw-r--r--test/CodeGen/Blackfin/addsub-i128.ll42
-rw-r--r--test/CodeGen/Blackfin/basic-i1.ll51
-rw-r--r--test/CodeGen/Blackfin/basic-i16.ll36
-rw-r--r--test/CodeGen/Blackfin/basic-i32.ll51
-rw-r--r--test/CodeGen/Blackfin/basic-i64.ll51
-rw-r--r--test/CodeGen/Blackfin/basic-i8.ll51
-rw-r--r--test/CodeGen/Blackfin/basictest.ll19
-rw-r--r--test/CodeGen/Blackfin/burg.ll19
-rw-r--r--test/CodeGen/Blackfin/cmp-small-imm.ll9
-rw-r--r--test/CodeGen/Blackfin/cmp64.ll17
-rw-r--r--test/CodeGen/Blackfin/ct32.ll20
-rw-r--r--test/CodeGen/Blackfin/ct64.ll20
-rw-r--r--test/CodeGen/Blackfin/ctlz16.ll18
-rw-r--r--test/CodeGen/Blackfin/ctlz64.ll15
-rw-r--r--test/CodeGen/Blackfin/ctpop16.ll18
-rw-r--r--test/CodeGen/Blackfin/cttz16.ll18
-rw-r--r--test/CodeGen/Blackfin/cycles.ll11
-rw-r--r--test/CodeGen/Blackfin/dg.exp5
-rw-r--r--test/CodeGen/Blackfin/double-cast.ll8
-rw-r--r--test/CodeGen/Blackfin/frameindex.ll10
-rw-r--r--test/CodeGen/Blackfin/i17mem.ll9
-rw-r--r--test/CodeGen/Blackfin/i1mem.ll9
-rw-r--r--test/CodeGen/Blackfin/i1ops.ll10
-rw-r--r--test/CodeGen/Blackfin/i216mem.ll9
-rw-r--r--test/CodeGen/Blackfin/i248mem.ll9
-rw-r--r--test/CodeGen/Blackfin/i256mem.ll9
-rw-r--r--test/CodeGen/Blackfin/i256param.ll7
-rw-r--r--test/CodeGen/Blackfin/i56param.ll8
-rw-r--r--test/CodeGen/Blackfin/i8mem.ll10
-rw-r--r--test/CodeGen/Blackfin/int-setcc.ll80
-rw-r--r--test/CodeGen/Blackfin/invalid-apint.ll15
-rw-r--r--test/CodeGen/Blackfin/jumptable.ll53
-rw-r--r--test/CodeGen/Blackfin/large-switch.ll187
-rw-r--r--test/CodeGen/Blackfin/load-i16.ll13
-rw-r--r--test/CodeGen/Blackfin/logic-i16.ll16
-rw-r--r--test/CodeGen/Blackfin/many-args.ll23
-rw-r--r--test/CodeGen/Blackfin/mulhu.ll106
-rw-r--r--test/CodeGen/Blackfin/printf.ll10
-rw-r--r--test/CodeGen/Blackfin/printf2.ll11
-rw-r--r--test/CodeGen/Blackfin/promote-logic.ll42
-rw-r--r--test/CodeGen/Blackfin/promote-setcc.ll40
-rw-r--r--test/CodeGen/Blackfin/sdiv.ll5
-rw-r--r--test/CodeGen/Blackfin/simple-select.ll11
-rw-r--r--test/CodeGen/Blackfin/switch.ll18
-rw-r--r--test/CodeGen/Blackfin/switch2.ll16
77 files changed, 5029 insertions, 0 deletions
diff --git a/include/llvm/ADT/Triple.h b/include/llvm/ADT/Triple.h
index b6c8193f89..5d584f4fe6 100644
--- a/include/llvm/ADT/Triple.h
+++ b/include/llvm/ADT/Triple.h
@@ -38,6 +38,7 @@ public:
alpha, // alpha
arm, // arm, armv.*
+ bfin, // blackfin
cellspu, // spu, cellspu
mips, // mips, mipsallegrex
mipsel, // mipsel, mipsallegrexel, psp
diff --git a/lib/Support/Triple.cpp b/lib/Support/Triple.cpp
index af372e2da6..391c98656d 100644
--- a/lib/Support/Triple.cpp
+++ b/lib/Support/Triple.cpp
@@ -23,6 +23,7 @@ const char *Triple::getArchTypeName(ArchType Kind) {
case alpha: return "alpha";
case arm: return "arm";
+ case bfin: return "bfin";
case cellspu: return "cellspu";
case mips: return "mips";
case mipsel: return "mipsel";
@@ -107,6 +108,8 @@ void Triple::Parse() const {
Arch = sparc;
else if (ArchName == "s390x")
Arch = systemz;
+ else if (ArchName == "bfin")
+ Arch = bfin;
else
Arch = UnknownArch;
diff --git a/lib/Target/Blackfin/AsmPrinter/BlackfinAsmPrinter.cpp b/lib/Target/Blackfin/AsmPrinter/BlackfinAsmPrinter.cpp
new file mode 100644
index 0000000000..60744ddfff
--- /dev/null
+++ b/lib/Target/Blackfin/AsmPrinter/BlackfinAsmPrinter.cpp
@@ -0,0 +1,237 @@
+//===-- BlackfinAsmPrinter.cpp - Blackfin LLVM assembly writer ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a printer that converts from our internal representation
+// of machine-dependent LLVM code to GAS-format BLACKFIN assembly language.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "asm-printer"
+#include "Blackfin.h"
+#include "BlackfinInstrInfo.h"
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Module.h"
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/DwarfWriter.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineConstantPool.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/Target/TargetAsmInfo.h"
+#include "llvm/Target/TargetData.h"
+#include "llvm/Target/TargetLoweringObjectFile.h"
+#include "llvm/Target/TargetRegistry.h"
+#include "llvm/Support/Mangler.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/FormattedStream.h"
+
+using namespace llvm;
+
+STATISTIC(EmittedInsts, "Number of machine instrs printed");
+
+namespace {
+ class VISIBILITY_HIDDEN BlackfinAsmPrinter : public AsmPrinter {
+ public:
+ BlackfinAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
+ const TargetAsmInfo *TAI, bool V)
+ : AsmPrinter(O, TM, TAI, V) {}
+
+ virtual const char *getPassName() const {
+ return "Blackfin Assembly Printer";
+ }
+
+ void printOperand(const MachineInstr *MI, int opNum);
+ void printMemoryOperand(const MachineInstr *MI, int opNum);
+ bool printInstruction(const MachineInstr *MI); // autogenerated.
+ void emitLinkage(const std::string &n, GlobalValue::LinkageTypes l);
+ bool runOnMachineFunction(MachineFunction &F);
+ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+ unsigned AsmVariant, const char *ExtraCode);
+ bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
+ unsigned AsmVariant, const char *ExtraCode);
+ void PrintGlobalVariable(const GlobalVariable* GVar);
+ };
+} // end of anonymous namespace
+
+#include "BlackfinGenAsmWriter.inc"
+
+extern "C" void LLVMInitializeBlackfinAsmPrinter() {
+ RegisterAsmPrinter<BlackfinAsmPrinter> X(TheBlackfinTarget);
+}
+
+void BlackfinAsmPrinter::emitLinkage(const std::string &name,
+ GlobalValue::LinkageTypes l) {
+ switch (l) {
+ default: llvm_unreachable("Unknown linkage type!");
+ case GlobalValue::InternalLinkage: // Symbols default to internal.
+ case GlobalValue::PrivateLinkage:
+ case GlobalValue::LinkerPrivateLinkage:
+ break;
+ case GlobalValue::ExternalLinkage:
+ O << TAI->getGlobalDirective() << name << "\n";
+ break;
+ case GlobalValue::LinkOnceAnyLinkage:
+ case GlobalValue::LinkOnceODRLinkage:
+ case GlobalValue::WeakAnyLinkage:
+ case GlobalValue::WeakODRLinkage:
+ O << TAI->getGlobalDirective() << name << "\n";
+ O << TAI->getWeakDefDirective() << name << "\n";
+ break;
+ }
+}
+
+void BlackfinAsmPrinter::PrintGlobalVariable(const GlobalVariable* GV) {
+ const TargetData *TD = TM.getTargetData();
+
+ if (!GV->hasInitializer() || EmitSpecialLLVMGlobal(GV))
+ return;
+
+ std::string name = Mang->getMangledName(GV);
+ Constant *C = GV->getInitializer();
+
+ SwitchToSection(getObjFileLowering().SectionForGlobal(GV, Mang, TM));
+ emitLinkage(name, GV->getLinkage());
+ EmitAlignment(TD->getPreferredAlignmentLog(GV), GV);
+ printVisibility(name, GV->getVisibility());
+
+ O << "\t.type " << name << ", STT_OBJECT\n";
+ O << "\t.size " << name << ',' << TD->getTypeAllocSize(C->getType()) << '\n';
+ O << name << ":\n";
+ EmitGlobalConstant(C);
+}
+
+/// runOnMachineFunction - This uses the printInstruction()
+/// method to print assembly for each instruction.
+///
+bool BlackfinAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
+ SetupMachineFunction(MF);
+ EmitConstantPool(MF.getConstantPool());
+ EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
+
+ const Function *F = MF.getFunction();
+ SwitchToSection(getObjFileLowering().SectionForGlobal(F, Mang, TM));
+ EmitAlignment(2, F);
+ emitLinkage(CurrentFnName, F->getLinkage());
+ printVisibility(CurrentFnName, F->getVisibility());
+
+ O << "\t.type\t" << CurrentFnName << ", STT_FUNC\n"
+ << CurrentFnName << ":\n";
+
+ if (DW)
+ DW->BeginFunction(&MF);
+
+ // Print out code for the function.
+ for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
+ I != E; ++I) {
+ // Print a label for the basic block.
+ if (!VerboseAsm && (I->pred_empty() || I->isOnlyReachableByFallthrough())) {
+ // This is an entry block or a block that's only reachable via a
+ // fallthrough edge. In non-VerboseAsm mode, don't print the label.
+ } else {
+ printBasicBlockLabel(I, true, true, VerboseAsm);
+ O << '\n';
+ }
+
+ for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
+ II != E; ++II) {
+ // Print the assembly for the instruction.
+ printInstruction(II);
+ ++EmittedInsts;
+ }
+ }
+
+ O << "\t.size " << CurrentFnName << ", .-" << CurrentFnName << "\n";
+
+ if (DW)
+ DW->EndFunction(&MF);
+
+ return false;
+}
+
+void BlackfinAsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
+ const MachineOperand &MO = MI->getOperand (opNum);
+ const TargetRegisterInfo &RI = *TM.getRegisterInfo();
+ switch (MO.getType()) {
+ case MachineOperand::MO_Register:
+ assert (TargetRegisterInfo::isPhysicalRegister(MO.getReg()) &&
+ "Virtual registers should be already mapped!");
+ O << RI.get(MO.getReg()).AsmName;
+ break;
+
+ case MachineOperand::MO_Immediate:
+ O << MO.getImm();
+ break;
+ case MachineOperand::MO_MachineBasicBlock:
+ printBasicBlockLabel(MO.getMBB(), false, false, false);
+ return;
+ case MachineOperand::MO_GlobalAddress:
+ O << Mang->getMangledName(MO.getGlobal());
+ printOffset(MO.getOffset());
+ break;
+ case MachineOperand::MO_ExternalSymbol:
+ O << Mang->makeNameProper(MO.getSymbolName());
+ break;
+ case MachineOperand::MO_ConstantPoolIndex:
+ O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
+ << MO.getIndex();
+ break;
+ case MachineOperand::MO_JumpTableIndex:
+ O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
+ << '_' << MO.getIndex();
+ break;
+ default:
+ llvm_unreachable("<unknown operand type>");
+ break;
+ }
+}
+
+void BlackfinAsmPrinter::printMemoryOperand(const MachineInstr *MI, int opNum) {
+ printOperand(MI, opNum);
+
+ if (MI->getOperand(opNum+1).isImm() && MI->getOperand(opNum+1).getImm() == 0)
+ return;
+
+ O << " + ";
+ printOperand(MI, opNum+1);
+}
+
+/// PrintAsmOperand - Print out an operand for an inline asm expression.
+///
+bool BlackfinAsmPrinter::PrintAsmOperand(const MachineInstr *MI,
+ unsigned OpNo,
+ unsigned AsmVariant,
+ const char *ExtraCode) {
+ if (ExtraCode && ExtraCode[0]) {
+ if (ExtraCode[1] != 0) return true; // Unknown modifier.
+
+ switch (ExtraCode[0]) {
+ default: return true; // Unknown modifier.
+ case 'r':
+ break;
+ }
+ }
+
+ printOperand(MI, OpNo);
+
+ return false;
+}
+
+bool BlackfinAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
+ unsigned OpNo,
+ unsigned AsmVariant,
+ const char *ExtraCode) {
+ if (ExtraCode && ExtraCode[0])
+ return true; // Unknown modifier
+
+ O << '[';
+ printOperand(MI, OpNo);
+ O << ']';
+
+ return false;
+}
diff --git a/lib/Target/Blackfin/AsmPrinter/CMakeLists.txt b/lib/Target/Blackfin/AsmPrinter/CMakeLists.txt
new file mode 100644
index 0000000000..cd20f0754b
--- /dev/null
+++ b/lib/Target/Blackfin/AsmPrinter/CMakeLists.txt
@@ -0,0 +1,3 @@
+include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. )
+add_llvm_library(LLVMBlackfinAsmPrinter BlackfinAsmPrinter.cpp)
+add_dependencies(LLVMBlackfinAsmPrinter BlackfinCodeGenTable_gen)
diff --git a/lib/Target/Blackfin/AsmPrinter/Makefile b/lib/Target/Blackfin/AsmPrinter/Makefile
new file mode 100644
index 0000000000..a2b0d1d1a1
--- /dev/null
+++ b/lib/Target/Blackfin/AsmPrinter/Makefile
@@ -0,0 +1,16 @@
+##===- lib/Target/Blackfin/Makefile ------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+LEVEL = ../../../..
+LIBRARYNAME = LLVMBlackfinAsmPrinter
+
+# Hack: we need to include 'main' Blackfin target directory to grab private
+# headers
+CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
+
+include $(LEVEL)/Makefile.common
diff --git a/lib/Target/Blackfin/Blackfin.h b/lib/Target/Blackfin/Blackfin.h
new file mode 100644
index 0000000000..ec1fa8689d
--- /dev/null
+++ b/lib/Target/Blackfin/Blackfin.h
@@ -0,0 +1,38 @@
+//=== Blackfin.h - Top-level interface for Blackfin backend -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the entry points for global functions defined in the LLVM
+// Blackfin back-end.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TARGET_BLACKFIN_H
+#define TARGET_BLACKFIN_H
+
+#include "llvm/Target/TargetMachine.h"
+
+namespace llvm {
+
+ class FunctionPass;
+ class BlackfinTargetMachine;
+
+ FunctionPass *createBlackfinISelDag(BlackfinTargetMachine &TM,
+ CodeGenOpt::Level OptLevel);
+ extern Target TheBlackfinTarget;
+
+} // end namespace llvm
+
+// Defines symbolic names for Blackfin registers. This defines a mapping from
+// register name to register number.
+#include "BlackfinGenRegisterNames.inc"
+
+// Defines symbolic names for the Blackfin instructions.
+#include "BlackfinGenInstrNames.inc"
+
+#endif
diff --git a/lib/Target/Blackfin/Blackfin.td b/lib/Target/Blackfin/Blackfin.td
new file mode 100644
index 0000000000..0b73d1f4db
--- /dev/null
+++ b/lib/Target/Blackfin/Blackfin.td
@@ -0,0 +1,52 @@
+//===- Blackfin.td - Describe the Blackfin Target Machine --*- tablegen -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Target-independent interfaces which we are implementing
+//===----------------------------------------------------------------------===//
+
+include "llvm/Target/Target.td"
+
+//===----------------------------------------------------------------------===//
+// Blackfin Subtarget features.
+//===----------------------------------------------------------------------===//
+
+def FeatureSSYNC : SubtargetFeature<"ssync","ssyncWorkaround", "true",
+ "Work around SSYNC bugs">;
+
+//===----------------------------------------------------------------------===//
+// Register File, Calling Conv, Instruction Descriptions
+//===----------------------------------------------------------------------===//
+
+include "BlackfinRegisterInfo.td"
+include "BlackfinCallingConv.td"
+include "BlackfinInstrInfo.td"
+
+def BlackfinInstrInfo : InstrInfo {}
+
+//===----------------------------------------------------------------------===//
+// Blackfin processors supported.
+//===----------------------------------------------------------------------===//
+
+class Proc<string Name, list<SubtargetFeature> Features>
+ : Processor<Name, NoItineraries, Features>;
+
+def : Proc<"generic", [FeatureSSYNC]>;
+
+//===----------------------------------------------------------------------===//
+// Declare the target which we are implementing
+//===----------------------------------------------------------------------===//
+
+def Blackfin : Target {
+ // Pull in Instruction Info:
+ let InstructionSet = BlackfinInstrInfo;
+}
diff --git a/lib/Target/Blackfin/BlackfinCallingConv.td b/lib/Target/Blackfin/BlackfinCallingConv.td
new file mode 100644
index 0000000000..0abc84c3c4
--- /dev/null
+++ b/lib/Target/Blackfin/BlackfinCallingConv.td
@@ -0,0 +1,30 @@
+//===--- BlackfinCallingConv.td - Calling Conventions ------*- tablegen -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This describes the calling conventions for the Blackfin architectures.
+//
+//===----------------------------------------------------------------------===//
+
+// Blackfin C Calling convention.
+def CC_Blackfin : CallingConv<[
+ CCIfType<[i16], CCPromoteToType<i32>>,
+ CCIfSRet<CCAssignToReg<[P0]>>,
+ CCAssignToReg<[R0, R1, R2]>,
+ CCAssignToStack<4, 4>
+]>;
+
+//===----------------------------------------------------------------------===//
+// Return Value Calling Conventions
+//===----------------------------------------------------------------------===//
+
+// Blackfin C return-value convention.
+def RetCC_Blackfin : CallingConv<[
+ CCIfType<[i16], CCPromoteToType<i32>>,
+ CCAssignToReg<[R0, R1]>
+]>;
diff --git a/lib/Target/Blackfin/BlackfinISelDAGToDAG.cpp b/lib/Target/Blackfin/BlackfinISelDAGToDAG.cpp
new file mode 100644
index 0000000000..062b22abe6
--- /dev/null
+++ b/lib/Target/Blackfin/BlackfinISelDAGToDAG.cpp
@@ -0,0 +1,191 @@
+//===- BlackfinISelDAGToDAG.cpp - A dag to dag inst selector for Blackfin -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines an instruction selector for the Blackfin target.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Blackfin.h"
+#include "BlackfinISelLowering.h"
+#include "BlackfinTargetMachine.h"
+#include "BlackfinRegisterInfo.h"
+#include "llvm/Intrinsics.h"
+#include "llvm/CodeGen/SelectionDAGISel.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// Instruction Selector Implementation
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+/// BlackfinDAGToDAGISel - Blackfin specific code to select blackfin machine
+/// instructions for SelectionDAG operations.
+namespace {
+ class BlackfinDAGToDAGISel : public SelectionDAGISel {
+ /// Subtarget - Keep a pointer to the Blackfin Subtarget around so that we
+ /// can make the right decision when generating code for different targets.
+ //const BlackfinSubtarget &Subtarget;
+ public:
+ BlackfinDAGToDAGISel(BlackfinTargetMachine &TM, CodeGenOpt::Level OptLevel)
+ : SelectionDAGISel(TM, OptLevel) {}
+
+ virtual void InstructionSelect();
+
+ virtual const char *getPassName() const {
+ return "Blackfin DAG->DAG Pattern Instruction Selection";
+ }
+
+ // Include the pieces autogenerated from the target description.
+#include "BlackfinGenDAGISel.inc"
+
+ private:
+ SDNode *Select(SDValue Op);
+ bool SelectADDRspii(SDValue Op, SDValue Addr,
+ SDValue &Base, SDValue &Offset);
+
+ // Walk the DAG after instruction selection, fixing register class issues.
+ void FixRegisterClasses(SelectionDAG &DAG);
+
+ const BlackfinInstrInfo &getInstrInfo() {
+ return *static_cast<const BlackfinTargetMachine&>(TM).getInstrInfo();
+ }
+ const BlackfinRegisterInfo *getRegisterInfo() {
+ return static_cast<const BlackfinTargetMachine&>(TM).getRegisterInfo();
+ }
+ };
+} // end anonymous namespace
+
+FunctionPass *llvm::createBlackfinISelDag(BlackfinTargetMachine &TM,
+ CodeGenOpt::Level OptLevel) {
+ return new BlackfinDAGToDAGISel(TM, OptLevel);
+}
+
+/// InstructionSelect - This callback is invoked by
+/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
+void BlackfinDAGToDAGISel::InstructionSelect() {
+ // Select target instructions for the DAG.
+ SelectRoot(*CurDAG);
+ DOUT << "Selected selection DAG before regclass fixup:\n";
+ DEBUG(CurDAG->dump());
+ FixRegisterClasses(*CurDAG);
+}
+
+SDNode *BlackfinDAGToDAGISel::Select(SDValue Op) {
+ SDNode *N = Op.getNode();
+ DebugLoc dl = N->getDebugLoc();
+ if (N->isMachineOpcode())
+ return NULL; // Already selected.
+
+ switch (N->getOpcode()) {
+ default: break;
+ case ISD::FrameIndex: {
+ // Selects to ADDpp FI, 0 which in turn will become ADDimm7 SP, imm or ADDpp
+ // SP, Px
+ int FI = cast<FrameIndexSDNode>(N)->getIndex();
+ SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32);
+ return CurDAG->SelectNodeTo(N, BF::ADDpp, MVT::i32, TFI,
+ CurDAG->getTargetConstant(0, MVT::i32));
+ }
+ }
+
+ return SelectCode(Op);
+}
+
+bool BlackfinDAGToDAGISel::SelectADDRspii(SDValue Op,
+ SDValue Addr,
+ SDValue &Base,
+ SDValue &Offset) {
+ FrameIndexSDNode *FIN = 0;
+ if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
+ Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
+ Offset = CurDAG->getTargetConstant(0, MVT::i32);
+ return true;
+ }
+ if (Addr.getOpcode() == ISD::ADD) {
+ ConstantSDNode *CN = 0;
+ if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) &&
+ (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) &&
+ (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
+ // Constant positive word offset from frame index
+ Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
+ Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
+ return true;
+ }
+ }
+ return false;
+}
+
+static inline bool isCC(const TargetRegisterClass *RC) {
+ return RC == &BF::AnyCCRegClass || BF::AnyCCRegClass.hasSubClass(RC);
+}
+
+static inline bool isDCC(const TargetRegisterClass *RC) {
+ return RC == &BF::DRegClass || BF::DRegClass.hasSubClass(RC) || isCC(RC);
+}
+
+static void UpdateNodeOperand(SelectionDAG &DAG,
+ SDNode *N,
+ unsigned Num,
+ SDValue Val) {
+ SmallVector<SDValue, 8> ops(N->op_begin(), N->op_end());
+ ops[Num] = Val;
+ SDValue New = DAG.UpdateNodeOperands(SDValue(N, 0), ops.data(), ops.size());
+ DAG.ReplaceAllUsesWith(N, New.getNode());
+}
+
+// After instruction selection, insert COPY_TO_REGCLASS nodes to help in
+// choosing the proper register classes.
+void BlackfinDAGToDAGISel::FixRegisterClasses(SelectionDAG &DAG) {
+ const BlackfinInstrInfo &TII = getInstrInfo();
+ const BlackfinRegisterInfo *TRI = getRegisterInfo();
+ DAG.AssignTopologicalOrder();
+ HandleSDNode Dummy(DAG.getRoot());
+
+ for (SelectionDAG::allnodes_iterator NI = DAG.allnodes_begin();
+ NI != DAG.allnodes_end(); ++NI) {
+ if (NI->use_empty() || !NI->isMachineOpcode())
+ continue;
+ const TargetInstrDesc &DefTID = TII.get(NI->getMachineOpcode());
+ for (SDNode::use_iterator UI = NI->use_begin(); !UI.atEnd(); ++UI) {
+ if (!UI->isMachineOpcode())
+ continue;
+
+ if (UI.getUse().getResNo() >= DefTID.getNumDefs())
+ continue;
+ const TargetRegisterClass *DefRC =
+ DefTID.OpInfo[UI.getUse().getResNo()].getRegClass(TRI);
+
+ const TargetInstrDesc &UseTID = TII.get(UI->getMachineOpcode());
+ if (UseTID.getNumDefs()+UI.getOperandNo() >= UseTID.getNumOperands())
+ continue;
+ const TargetRegisterClass *UseRC =
+ UseTID.OpInfo[UseTID.getNumDefs()+UI.getOperandNo()].getRegClass(TRI);
+ if (!DefRC || !UseRC)
+ continue;
+ // We cannot copy CC <-> !(CC/D)
+ if ((isCC(DefRC) && !isDCC(UseRC)) || (isCC(UseRC) && !isDCC(DefRC))) {
+ SDNode *Copy =
+ DAG.getTargetNode(TargetInstrInfo::COPY_TO_REGCLASS,
+ NI->getDebugLoc(),
+ MVT::i32,
+ UI.getUse().get(),
+ DAG.getTargetConstant(BF::DRegClassID, MVT::i32));
+ UpdateNodeOperand(DAG, *UI, UI.getOperandNo(), SDValue(Copy, 0));
+ }
+ }
+ }
+ DAG.setRoot(Dummy.getValue());
+}
+
diff --git a/lib/Target/Blackfin/BlackfinISelLowering.cpp b/lib/Target/Blackfin/BlackfinISelLowering.cpp
new file mode 100644
index 0000000000..a4af0ad9e7
--- /dev/null
+++ b/lib/Target/Blackfin/BlackfinISelLowering.cpp
@@ -0,0 +1,536 @@
+//===- BlackfinISelLowering.cpp - Blackfin DAG Lowering Implementation ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the interfaces that Blackfin uses to lower LLVM code
+// into a selection DAG.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BlackfinISelLowering.h"
+#include "BlackfinTargetMachine.h"
+#include "llvm/Function.h"
+#include "llvm/CodeGen/CallingConvLower.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/PseudoSourceValue.h"
+#include "llvm/CodeGen/SelectionDAG.h"
+#include "llvm/Target/TargetLoweringObjectFile.h"
+#include "llvm/ADT/VectorExtras.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// Calling Convention Implementation
+//===----------------------------------------------------------------------===//
+
+#include "BlackfinGenCallingConv.inc"
+
+//===----------------------------------------------------------------------===//
+// TargetLowering Implementation
+//===----------------------------------------------------------------------===//
+
+BlackfinTargetLowering::BlackfinTargetLowering(TargetMachine &TM)
+ : TargetLowering(TM, new TargetLoweringObjectFileELF()) {
+ setShiftAmountType(MVT::i16);
+ setBooleanContents(ZeroOrOneBooleanContent);
+ setStackPointerRegisterToSaveRestore(BF::SP);
+ setIntDivIsCheap(false);
+
+ // Set up the legal register classes.
+ addRegisterClass(MVT::i32, BF::DRegisterClass);
+ addRegisterClass(MVT::i16, BF::D16RegisterClass);
+
+ computeRegisterProperties();
+
+ // Blackfin doesn't have i1 loads or stores
+ setLoadExtAction(ISD::EXTLOAD, MVT::i1, Promote);
+ setLoadExtAction(ISD::ZEXTLOAD, MVT::i1, Promote);
+ setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote);
+
+ setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
+ setOperationAction(ISD::JumpTable, MVT::i32, Custom);
+
+ setOperationAction(ISD::SELECT_CC, MVT::Other, Expand);
+ setOperationAction(ISD::BR_JT, MVT::Other, Expand);
+ setOperationAction(ISD::BR_CC, MVT::Other, Expand);
+
+ // i16 registers don't do much
+ setOperationAction(ISD::AND, MVT::i16, Promote);
+ setOperationAction(ISD::OR, MVT::i16, Promote);
+ setOperationAction(ISD::XOR, MVT::i16, Promote);
+ setOperationAction(ISD::CTPOP, MVT::i16, Promote);
+ // The expansion of CTLZ/CTTZ uses AND/OR, so we might as well promote
+ // immediately.
+ setOperationAction(ISD::CTLZ, MVT::i16, Promote);
+ setOperationAction(ISD::CTTZ, MVT::i16, Promote);
+ setOperationAction(ISD::SETCC, MVT::i16, Promote);
+
+ // Blackfin has no division
+ setOperationAction(ISD::SDIV, MVT::i16, Expand);
+ setOperationAction(ISD::SDIV, MVT::i32, Expand);
+ setOperationAction(ISD::SDIVREM, MVT::i16, Expand);
+ setOperationAction(ISD::SDIVREM, MVT::i32, Expand);
+ setOperationAction(ISD::SREM, MVT::i16, Expand);
+ setOperationAction(ISD::SREM, MVT::i32, Expand);
+ setOperationAction(ISD::UDIV, MVT::i16, Expand);
+ setOperationAction(ISD::UDIV, MVT::i32, Expand);
+ setOperationAction(ISD::UDIVREM, MVT::i16, Expand);
+ setOperationAction(ISD::UDIVREM, MVT::i32, Expand);
+ setOperationAction(ISD::UREM, MVT::i16, Expand);
+ setOperationAction(ISD::UREM, MVT::i32, Expand);
+
+ setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand);
+ setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand);
+ setOperationAction(ISD::MULHU, MVT::i32, Expand);
+ setOperationAction(ISD::MULHS, MVT::i32, Expand);
+
+ // No carry-in operations.
+ setOperationAction(ISD::ADDE, MVT::i32, Custom);
+ setOperationAction(ISD::SUBE, MVT::i32, Custom);
+
+ // Blackfin has no intrinsics for these particular operations.
+ setOperationAction(ISD::MEMBARRIER, MVT::Other, Expand);
+ setOperationAction(ISD::BSWAP, MVT::i32, Expand);
+
+ setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand);
+ setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);
+ setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand);
+
+ setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
+
+ // i32 has native CTPOP, but not CTLZ/CTTZ
+ setOperationAction(ISD::CTLZ, MVT::i32, Expand);
+ setOperationAction(ISD::CTTZ, MVT::i32, Expand);
+
+ // We don't have line number support yet.
+ setOperationAction(ISD::DBG_STOPPOINT, MVT::Other, Expand);
+ setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand);
+ setOperationAction(ISD::DBG_LABEL, MVT::Other, Expand);
+ setOperationAction(ISD::EH_LABEL, MVT::Other, Expand);
+ setOperationAction(ISD::DECLARE, MVT::Other, Expand);
+
+ // Use the default implementation.
+ setOperationAction(ISD::VACOPY, MVT::Other, Expand);
+ setOperationAction(ISD::VAEND, MVT::Other, Expand);
+ setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
+ setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
+
+ // RET must be custom lowered, to meet ABI requirements
+ setOperationAction(ISD::RET, MVT::Other, Custom);
+}
+
+const char *BlackfinTargetLowering::getTargetNodeName(unsigned Opcode) const {
+ switch (Opcode) {
+ default: return 0;
+ case BFISD::CALL: return "BFISD::CALL";
+ case BFISD::RET_FLAG: return "BFISD::RET_FLAG";
+ case BFISD::Wrapper: return "BFISD::Wrapper";
+ }
+}
+
+MVT BlackfinTargetLowering::getSetCCResultType(MVT VT) const {
+ // SETCC always sets the CC register. Technically that is an i1 register, but
+ // that type is not legal, so we treat it as an i32 register.
+ return MVT::i32;
+}
+
+SDValue BlackfinTargetLowering::LowerGlobalAddress(SDValue Op,
+ SelectionDAG &DAG) {
+ DebugLoc DL = Op.getDebugLoc();
+ GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
+
+ Op = DAG.getTargetGlobalAddress(GV, MVT::i32);
+ return DAG.getNode(BFISD::Wrapper, DL, MVT::i32, Op);
+}
+
+SDValue BlackfinTargetLowering::LowerJumpTable(SDValue Op, SelectionDAG &DAG) {
+ DebugLoc DL = Op.getDebugLoc();
+ int JTI = cast<JumpTableSDNode>(Op)->getIndex();
+
+ Op = DAG.getTargetJumpTable(JTI, MVT::i32);
+ return DAG.getNode(BFISD::Wrapper, DL, MVT::i32, Op);
+}
+
+// FORMAL_ARGUMENTS(CHAIN, CC#, ISVARARG, FLAG0, ..., FLAGn) - This node
+// represents the formal arguments for a function. CC# is a Constant value
+// indicating the calling convention of the function, and ISVARARG is a
+// flag that indicates whether the function is varargs or not. This node
+// has one result value for each incoming argument, plus one for the output
+// chain.
+SDValue BlackfinTargetLowering::LowerFORMAL_ARGUMENTS(SDValue Op,
+ SelectionDAG &DAG) {
+ DebugLoc dl = Op.getDebugLoc();
+ SDValue Root = Op.getOperand(0);
+ unsigned CC = Op.getConstantOperandVal(1);
+ bool isVarArg = Op.getConstantOperandVal(2);
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+
+ SmallVector<CCValAssign, 16> ArgLocs;
+ CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs, *DAG.getContext());
+ CCInfo.AllocateStack(12, 4); // ABI requires 12 bytes stack space
+ CCInfo.AnalyzeFormalArguments(Op.getNode(), CC_Blackfin);
+
+ SmallVector<SDValue, 8> ArgValues;
+ for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
+ CCValAssign &VA = ArgLocs[i];
+
+ if (VA.isRegLoc()) {
+ MVT RegVT = VA.getLocVT();
+ TargetRegisterClass *RC = VA.getLocReg() == BF::P0 ?
+ BF::PRegisterClass : BF::DRegisterClass;
+ assert(RC->contains(VA.getLocReg()));
+ assert(RC->hasType(RegVT));
+
+ unsigned Reg = MF.getRegInfo().createVirtualRegister(RC);
+ MF.getRegInfo().addLiveIn(VA.getLocReg(), Reg);
+ SDValue ArgValue = DAG.getCopyFromReg(Root, dl, Reg, RegVT);
+
+ // If this is an 8 or 16-bit value, it is really passed promoted to 32
+ // bits. Insert an assert[sz]ext to capture this, then truncate to the
+ // right size.
+ if (VA.getLocInfo() == CCValAssign::SExt)
+ ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue,
+ DAG.getValueType(VA.getValVT()));
+ else if (VA.getLocInfo() == CCValAssign::ZExt)
+ ArgValue = DAG.getNode(ISD::AssertZext, dl, RegVT, ArgValue,
+ DAG.getValueType(VA.getValVT()));
+
+ if (VA.getLocInfo() != CCValAssign::Full)
+ ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue);
+
+ ArgValues.push_back(ArgValue);
+ } else {
+ assert(VA.isMemLoc());
+ unsigned ObjSize = VA.getLocVT().getStoreSizeInBits()/8;
+ int FI = MFI->CreateFixedObject(ObjSize, VA.getLocMemOffset());
+ SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
+ ArgValues.push_back(DAG.getLoad(VA.getValVT(), dl, Root, FIN, NULL, 0));
+ }
+ }
+
+ ArgValues.push_back(Root);
+
+ // Return the new list of results.
+ return DAG.getNode(ISD::MERGE_VALUES, dl, Op.getNode()->getVTList(),
+ &ArgValues[0], ArgValues.size()).getValue(Op.getResNo());
+}
+
+SDValue BlackfinTargetLowering::LowerRET(SDValue Op, SelectionDAG &DAG) {
+ // CCValAssign - represent the assignment of the return value to locations.
+ SmallVector<CCValAssign, 16> RVLocs;
+ unsigned CC = DAG.getMachineFunction().getFunction()->getCallingConv();
+ bool isVarArg = DAG.getMachineFunction().getFunction()->isVarArg();
+ DebugLoc dl = Op.getDebugLoc();
+
+ // CCState - Info about the registers and stack slot.
+ CCState CCInfo(CC, isVarArg, DAG.getTarget(), RVLocs, *DAG.getContext());
+
+ // Analize return values of ISD::RET
+ CCInfo.AnalyzeReturn(Op.getNode(), RetCC_Blackfin);
+
+ // If this is the first return lowered for this function, add the regs to the
+ // liveout set for the function.
+ if (DAG.getMachineFunction().getRegInfo().liveout_empty()) {
+ for (unsigned i = 0; i != RVLocs.size(); ++i)
+ DAG.getMachineFunction().getRegInfo().addLiveOut(RVLocs[i].getLocReg());
+ }
+
+ SDValue Chain = Op.getOperand(0);
+ SDValue Flag;
+
+ // Copy the result values into the output registers.
+ for (unsigned i = 0; i != RVLocs.size(); ++i) {
+ CCValAssign &VA = RVLocs[i];
+ assert(VA.isRegLoc() && "Can only return in registers!");
+ SDValue Opi = Op.getOperand(i*2+1);
+
+ // Expand to i32 if necessary
+ switch (VA.getLocInfo()) {
+ default: llvm_unreachable("Unknown loc info!");
+ case CCValAssign::Full: break;
+ case CCValAssign::SExt:
+ Opi = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Opi);
+ break;
+ case CCValAssign::ZExt:
+ Opi = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Opi);
+ break;
+ case CCValAssign::AExt:
+ Opi = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Opi);
+ break;
+ }
+ // ISD::RET => ret chain, (regnum1,val1), ...
+ // So i*2+1 index only the regnums.
+ Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), Opi, SDValue());
+ // Guarantee that all emitted copies are stuck together with flags.
+ Flag = Chain.getValue(1);
+ }
+
+ if (Flag.getNode()) {
+ return DAG.getNode(BFISD::RET_FLAG, dl, MVT::Other, Chain, Flag);
+ } else {
+ return DAG.getNode(BFISD::RET_FLAG, dl, MVT::Other, Chain);
+ }
+}
+
+SDValue BlackfinTargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) {
+ CallSDNode *TheCall = cast<CallSDNode>(Op.getNode());
+ unsigned CallingConv = TheCall->getCallingConv();
+ SDValue Chain = TheCall->getChain();
+ SDValue Callee = TheCall->getCallee();
+ bool isVarArg = TheCall->isVarArg();
+ DebugLoc dl = TheCall->getDebugLoc();
+
+ // Analyze operands of the call, assigning locations to each operand.
+ SmallVector<CCValAssign, 16> ArgLocs;
+ CCState CCInfo(CallingConv, isVarArg, DAG.getTarget(), ArgLocs,
+ *DAG.getContext());
+ CCInfo.AllocateStack(12, 4); // ABI requires 12 bytes stack space
+ CCInfo.AnalyzeCallOperands(TheCall, CC_Blackfin);
+
+ // Get the size of the outgoing arguments stack space requirement.
+ unsigned ArgsSize = CCInfo.getNextStackOffset();
+
+ Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(ArgsSize, true));
+ SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass;
+ SmallVector<SDValue, 8> MemOpChains;
+
+ // Walk the register/memloc assignments, inserting copies/loads.
+ for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
+ CCValAssign &VA = ArgLocs[i];
+
+ // Arguments start after the 5 first operands of ISD::CALL
+ SDValue Arg = TheCall->getArg(i);
+
+ // Promote the value if needed.
+ switch (VA.getLocInfo()) {
+ default: llvm_unreachable("Unknown loc info!");
+ case CCValAssign::Full: break;
+ case CCValAssign::SExt:
+ Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg);
+ break;
+ case CCValAssign::ZExt:
+ Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg);
+ break;
+ case CCValAssign::AExt:
+ Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg);
+ break;
+ }
+
+ // Arguments that can be passed on register must be kept at
+ // RegsToPass vector
+ if (VA.isRegLoc()) {
+ RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
+ } else {
+ assert(VA.isMemLoc());
+ int Offset = VA.getLocMemOffset();
+ assert(Offset%4 == 0);
+ assert(VA.getLocVT()==MVT::i32);
+ SDValue SPN = DAG.getCopyFromReg(Chain, dl, BF::SP, MVT::i32);
+ SDValue OffsetN = DAG.getIntPtrConstant(Offset);
+ OffsetN = DAG.getNode(ISD::ADD, dl, MVT::i32, SPN, OffsetN);
+ MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, OffsetN,
+ PseudoSourceValue::getStack(),
+ Offset));
+ }
+ }
+
+ // Transform all store nodes into one single node because
+ // all store nodes are independent of each other.
+ if (!MemOpChains.empty())
+ Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
+ &MemOpChains[0], MemOpChains.size());
+
+ // Build a sequence of copy-to-reg nodes chained together with token
+ // chain and flag operands which copy the outgoing args into registers.
+ // The InFlag in necessary since all emited instructions must be
+ // stuck together.
+ SDValue InFlag;
+ for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
+ Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first,
+ RegsToPass[i].second, InFlag);
+ InFlag = Chain.getValue(1);
+ }
+
+ // If the callee is a GlobalAddress node (quite common, every direct call is)
+ // turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
+ // Likewise ExternalSymbol -> TargetExternalSymbol.
+ if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
+ Callee = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i32);
+ else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee))
+ Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32);
+
+ std::vector<MVT> NodeTys;
+ NodeTys.push_back(MVT::Other); // Returns a chain
+ NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
+ SDValue Ops[] = { Chain, Callee, InFlag };
+ Chain = DAG.getNode(BFISD::CALL, dl, NodeTys, Ops,
+ InFlag.getNode() ? 3 : 2);
+ InFlag = Chain.getValue(1);
+
+ Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(ArgsSize, true),
+ DAG.getIntPtrConstant(0, true), InFlag);
+ InFlag = Chain.getValue(1);
+
+ // Assign locations to each value returned by this call.
+ SmallVector<CCValAssign, 16> RVLocs;
+ CCState RVInfo(CallingConv, isVarArg, DAG.getTarget(), RVLocs,
+ *DAG.getContext());
+
+ RVInfo.AnalyzeCallResult(TheCall, RetCC_Blackfin);
+ SmallVector<SDValue, 8> ResultVals;
+
+ // Copy all of the result registers out of their specified physreg.
+ for (unsigned i = 0; i != RVLocs.size(); ++i) {
+ CCValAssign &RV = RVLocs[i];
+ unsigned Reg = RV.getLocReg();
+
+ Chain = DAG.getCopyFromReg(Chain, dl, Reg,
+ RVLocs[i].getLocVT(), InFlag);
+ SDValue Val = Chain.getValue(0);
+ InFlag = Chain.getValue(2);
+ Chain = Chain.getValue(1);
+
+ // Callee is responsible for extending any i16 return values.
+ switch (RV.getLocInfo()) {
+ case CCValAssign::SExt:
+ Val = DAG.getNode(ISD::AssertSext, dl, RV.getLocVT(), Val,
+ DAG.getValueType(RV.getValVT()));
+ break;
+ case CCValAssign::ZExt:
+ Val = DAG.getNode(ISD::AssertZext, dl, RV.getLocVT(), Val,
+ DAG.getValueType(RV.getValVT()));
+ break;
+ default:
+ break;
+ }
+
+ // Truncate to valtype
+ if (RV.getLocInfo() != CCValAssign::Full)
+ Val = DAG.getNode(ISD::TRUNCATE, dl, RV.getValVT(), Val);
+ ResultVals.push_back(Val);
+ }
+
+ ResultVals.push_back(Chain);
+
+ // Merge everything together with a MERGE_VALUES node.
+ SDValue merge = DAG.getNode(ISD::MERGE_VALUES, dl,
+ TheCall->getVTList(), &ResultVals[0],
+ ResultVals.size());
+ return merge;
+}
+
+// Expansion of ADDE / SUBE. This is a bit involved since blackfin doesn't have
+// add-with-carry instructions.
+SDValue BlackfinTargetLowering::LowerADDE(SDValue Op, SelectionDAG &DAG) {
+ // Operands: lhs, rhs, carry-in (AC0 flag)
+ // Results: sum, carry-out (AC0 flag)
+ DebugLoc dl = Op.getDebugLoc();
+
+ unsigned Opcode = Op.getOpcode()==ISD::ADDE ? BF::ADD : BF::SUB;
+
+ // zext incoming carry flag in AC0 to 32 bits
+ SDNode* CarryIn = DAG.getTargetNode(BF::MOVE_cc_ac0, dl, MVT::i32,
+ /* flag= */ Op.getOperand(2));
+ CarryIn = DAG.getTargetNode(BF::MOVECC_zext, dl, MVT::i32,
+ SDValue(CarryIn, 0));
+
+ // Add operands, produce sum and carry flag
+ SDNode *Sum = DAG.getTargetNode(Opcode, dl, MVT::i32, MVT::Flag,
+ Op.getOperand(0), Op.getOperand(1));
+
+ // Store intermediate carry from Sum
+ SDNode* Carry1 = DAG.getTargetNode(BF::MOVE_cc_ac0, dl, MVT::i32,
+ /* flag= */ SDValue(Sum, 1));
+
+ // Add incoming carry, again producing an output flag
+ Sum = DAG.getTargetNode(Opcode, dl, MVT::i32, MVT::Flag,
+ SDValue(Sum, 0), SDValue(CarryIn, 0));
+
+ // Update AC0 with the intermediate carry, producing a flag.
+ SDNode *CarryOut = DAG.getTargetNode(BF::OR_ac0_cc, dl, MVT::Flag,
+ SDValue(Carry1, 0));
+
+ // Compose (i32, flag) pair
+ SDValue ops[2] = { SDValue(Sum, 0), SDValue(CarryOut, 0) };
+ return DAG.getMergeValues(ops, 2, dl);
+}
+
+SDValue BlackfinTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) {
+ switch (Op.getOpcode()) {
+ default:
+ Op.getNode()->dump();
+ llvm_unreachable("Should not custom lower this!");
+ case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);
+ case ISD::GlobalTLSAddress:
+ llvm_unreachable("TLS not implemented for Blackfin.");
+ case ISD::JumpTable: return LowerJumpTable(Op, DAG);
+ // Frame & Return address. Currently unimplemented
+ case ISD::FRAMEADDR: return SDValue();
+ case ISD::RETURNADDR: return SDValue();
+ case ISD::FORMAL_ARGUMENTS: return LowerFORMAL_ARGUMENTS(Op, DAG);
+ case ISD::CALL: return LowerCALL(Op, DAG);
+ case ISD::RET: return LowerRET(Op, DAG);
+ case ISD::ADDE:
+ case ISD::SUBE: return LowerADDE(Op, DAG);
+ }
+}
+
+/// getFunctionAlignment - Return the Log2 alignment of this function.
+unsigned BlackfinTargetLowering::getFunctionAlignment(const Function *F) const {
+ return 2;
+}
+
+//===----------------------------------------------------------------------===//
+// Blackfin Inline Assembly Support
+//===----------------------------------------------------------------------===//
+
+/// getConstraintType - Given a constraint letter, return the type of
+/// constraint it is for this target.
+BlackfinTargetLowering::ConstraintType
+BlackfinTargetLowering::getConstraintType(const std::string &Constraint) const {
+ if (Constraint.size() == 1) {
+ switch (Constraint[0]) {
+ default: break;
+ case 'r': return C_RegisterClass;
+ }
+ }
+
+ return TargetLowering::getConstraintType(Constraint);
+}
+
+std::pair<unsigned, const TargetRegisterClass*> BlackfinTargetLowering::
+getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const {
+ if (Constraint.size() == 1) {
+ switch (Constraint[0]) {
+ case 'r':
+ return std::make_pair(0U, BF::DRegisterClass);
+ }
+ }
+
+ return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT);
+}
+
+std::vector<unsigned> BlackfinTargetLowering::
+getRegClassForInlineAsmConstraint(const std::string &Constraint,
+ MVT VT) const {
+ if (Constraint.size() != 1)
+ return std::vector<unsigned>();
+
+ return std::vector<unsigned>();
+}
+
+bool BlackfinTargetLowering::
+isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const {
+ // The Blackfin target isn't yet aware of offsets.
+ return false;
+}
diff --git a/lib/Target/Blackfin/BlackfinISelLowering.h b/lib/Target/Blackfin/BlackfinISelLowering.h
new file mode 100644
index 0000000000..7acbd1a8e5
--- /dev/null
+++ b/lib/Target/Blackfin/BlackfinISelLowering.h
@@ -0,0 +1,61 @@
+//===- BlackfinISelLowering.h - Blackfin DAG Lowering Interface -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the interfaces that Blackfin uses to lower LLVM code into a
+// selection DAG.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BLACKFIN_ISELLOWERING_H
+#define BLACKFIN_ISELLOWERING_H
+
+#include "llvm/Target/TargetLowering.h"
+#include "Blackfin.h"
+
+namespace llvm {
+
+ namespace BFISD {
+ enum {
+ FIRST_NUMBER = ISD::BUILTIN_OP_END,
+ CALL, // A call instruction.
+ RET_FLAG, // Return with a flag operand.
+ Wrapper // Address wrapper
+ };
+ }
+
+ class BlackfinTargetLowering : public TargetLowering {
+ int VarArgsFrameOffset; // Frame offset to start of varargs area.
+ public:
+ BlackfinTargetLowering(TargetMachine &TM);
+ virtual MVT getSetCCResultType(MVT VT) const;
+ virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG);
+
+ int getVarArgsFrameOffset() const { return VarArgsFrameOffset; }
+
+ ConstraintType getConstraintType(const std::string &Constraint) const;
+ std::pair<unsigned, const TargetRegisterClass*>
+ getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const;
+ std::vector<unsigned>
+ getRegClassForInlineAsmConstraint(const std::string &Constraint,
+ MVT VT) const;
+ virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const;
+ const char *getTargetNodeName(unsigned Opcode) const;
+ unsigned getFunctionAlignment(const Function *F) const;
+
+ private:
+ SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG);
+ SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG);
+ SDValue LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG);
+ SDValue LowerRET(SDValue Op, SelectionDAG &DAG);
+ SDValue LowerCALL(SDValue Op, SelectionDAG &DAG);
+ SDValue LowerADDE(SDValue Op, SelectionDAG &DAG);
+ };
+} // end namespace llvm
+
+#endif // BLACKFIN_ISELLOWERING_H
diff --git a/lib/Target/Blackfin/BlackfinInstrFormats.td b/lib/Target/Blackfin/BlackfinInstrFormats.td
new file mode 100644
index 0000000000..d8e6e252e7
--- /dev/null
+++ b/lib/Target/Blackfin/BlackfinInstrFormats.td
@@ -0,0 +1,34 @@
+//===--- BlackfinInstrFormats.td ---------------------------*- tablegen -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Instruction format superclass
+//===----------------------------------------------------------------------===//
+
+class InstBfin<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : Instruction {
+ field bits<32> Inst;
+
+ let Namespace = "BF";
+
+ dag OutOperandList = outs;
+ dag InOperandList = ins;
+ let AsmString = asmstr;
+ let Pattern = pattern;
+}
+
+// Single-word (16-bit) instructions
+class F1<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstBfin<outs, ins, asmstr, pattern> {
+}
+
+// Double-word (32-bit) instructions
+class F2<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstBfin<outs, ins, asmstr, pattern> {
+}
diff --git a/lib/Target/Blackfin/BlackfinInstrInfo.cpp b/lib/Target/Blackfin/BlackfinInstrInfo.cpp
new file mode 100644
index 0000000000..3fd5d4dc0b
--- /dev/null
+++ b/lib/Target/Blackfin/BlackfinInstrInfo.cpp
@@ -0,0 +1,280 @@
+//===- BlackfinInstrInfo.cpp - Blackfin Instruction Information -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the Blackfin implementation of the TargetInstrInfo class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BlackfinInstrInfo.h"
+#include "BlackfinSubtarget.h"
+#include "Blackfin.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "BlackfinGenInstrInfo.inc"
+
+using namespace llvm;
+
+BlackfinInstrInfo::BlackfinInstrInfo(BlackfinSubtarget &ST)
+ : TargetInstrInfoImpl(BlackfinInsts, array_lengthof(BlackfinInsts)),
+ RI(ST, *this),
+ Subtarget(ST) {}
+
+/// Return true if the instruction is a register to register move and
+/// leave the source and dest operands in the passed parameters.
+bool BlackfinInstrInfo::isMoveInstr(const MachineInstr &MI,
+ unsigned &SrcReg,
+ unsigned &DstReg,
+ unsigned &SrcSR,
+ unsigned &DstSR) const {
+ SrcSR = DstSR = 0; // No sub-registers.
+ switch (MI.getOpcode()) {
+ case BF::MOVE:
+ case BF::MOVE_ncccc:
+ case BF::MOVE_ccncc:
+ case BF::MOVECC_zext:
+ case BF::MOVECC_nz:
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
+ return true;
+ case BF::SLL16i:
+ if (MI.getOperand(2).getImm()!=0)
+ return false;
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
+ return true;
+ default:
+ return false;
+ }
+}
+
+/// isLoadFromStackSlot - If the specified machine instruction is a direct
+/// load from a stack slot, return the virtual or physical register number of
+/// the destination along with the FrameIndex of the loaded stack slot. If
+/// not, return 0. This predicate must return 0 if the instruction has
+/// any side effects other than loading from the stack slot.
+unsigned BlackfinInstrInfo::isLoadFromStackSlot(const MachineInstr *MI,
+ int &FrameIndex) const {
+ switch (MI->getOpcode()) {
+ default: break;
+ case BF::LOAD32fi:
+ case BF::LOAD16fi:
+ if (MI->getOperand(1).isFI() &&
+ MI->getOperand(2).isImm() &&
+ MI->getOperand(2).getImm() == 0) {
+ FrameIndex = MI->getOperand(1).getIndex();
+ return MI->getOperand(0).getReg();
+ }
+ break;
+ }
+ return 0;
+}
+
+/// isStoreToStackSlot - If the specified machine instruction is a direct
+/// store to a stack slot, return the virtual or physical register number of
+/// the source reg along with the FrameIndex of the loaded stack slot. If
+/// not, return 0. This predicate must return 0 if the instruction has
+/// any side effects other than storing to the stack slot.
+unsigned BlackfinInstrInfo::isStoreToStackSlot(const MachineInstr *MI,
+ int &FrameIndex) const {
+ switch (MI->getOpcode()) {
+ default: break;
+ case BF::STORE32fi:
+ case BF::STORE16fi:
+ if (MI->getOperand(1).isFI() &&
+ MI->getOperand(2).isImm() &&
+ MI->getOperand(2).getImm() == 0) {
+ FrameIndex = MI->getOperand(1).getIndex();
+ return MI->getOperand(0).getReg();
+ }
+ break;
+ }
+ return 0;
+}
+
+unsigned BlackfinInstrInfo::
+InsertBranch(MachineBasicBlock &MBB,
+ MachineBasicBlock *TBB,
+ MachineBasicBlock *FBB,
+ const SmallVectorImpl<MachineOperand> &Cond) const {
+ // FIXME this should probably have a DebugLoc operand
+ DebugLoc dl = DebugLoc::getUnknownLoc();
+
+ // Shouldn't be a fall through.
+ assert(TBB && "InsertBranch must not be told to insert a fallthrough");
+ assert((Cond.size() == 1 || Cond.size() == 0) &&
+ "Branch conditions have one component!");
+
+ if (Cond.empty()) {
+ // Unconditional branch?
+ assert(!FBB && "Unconditional branch with multiple successors!");
+ BuildMI(&MBB, dl, get(BF::JUMPa)).addMBB(TBB);
+ return 1;
+ }
+
+ // Conditional branch.
+ llvm_unreachable("Implement conditional branches!");
+}
+
+static bool inClass(const TargetRegisterClass &Test,
+ unsigned Reg,
+ const TargetRegisterClass *RC) {
+ if (TargetRegisterInfo::isPhysicalRegister(Reg))
+ return Test.contains(Reg);
+ else
+ return &Test==RC || Test.hasSubClass(RC);
+}
+
+bool BlackfinInstrInfo::copyRegToReg(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ unsigned DestReg,
+ unsigned SrcReg,
+ const TargetRegisterClass *DestRC,
+ const TargetRegisterClass *SrcRC) const {
+ DebugLoc dl = DebugLoc::getUnknownLoc();
+
+ if (inClass(BF::ALLRegClass, DestReg, DestRC) &&
+ inClass(BF::ALLRegClass, SrcReg, SrcRC)) {
+ BuildMI(MBB, I, dl, get(BF::MOVE), DestReg).addReg(SrcReg);
+ return true;
+ }
+
+ if (inClass(BF::D16RegClass, DestReg, DestRC) &&
+ inClass(BF::D16RegClass, SrcReg, SrcRC)) {
+ BuildMI(MBB, I, dl, get(BF::SLL16i), DestReg).addReg(SrcReg).addImm(0);
+ return true;
+ }
+
+ if (inClass(BF::AnyCCRegClass, SrcReg, SrcRC) &&
+ inClass(BF::DRegClass, DestReg, DestRC)) {
+ if (inClass(BF::NotCCRegClass, SrcReg, SrcRC)) {
+ BuildMI(MBB, I, dl, get(BF::MOVENCC_z), DestReg).addReg(SrcReg);
+ BuildMI(MBB, I, dl, get(BF::BITTGL), DestReg).addReg(DestReg).addImm(0);
+ } else {
+ BuildMI(MBB, I, dl, get(BF::MOVECC_zext), DestReg).addReg(SrcReg);
+ }
+ return true;
+ }
+
+ if (inClass(BF::AnyCCRegClass, DestReg, DestRC) &&
+ inClass(BF::DRegClass, SrcReg, SrcRC)) {
+ if (inClass(BF::NotCCRegClass, DestReg, DestRC))
+ BuildMI(MBB, I, dl, get(BF::SETEQri_not), DestReg).addReg(SrcReg);
+ else
+ BuildMI(MBB, I, dl, get(BF::MOVECC_nz), DestReg).addReg(SrcReg);
+ return true;
+ }
+
+ if (inClass(BF::NotCCRegClass, DestReg, DestRC) &&
+ inClass(BF::JustCCRegClass, SrcReg, SrcRC)) {
+ BuildMI(MBB, I, dl, get(BF::MOVE_ncccc), DestReg).addReg(SrcReg);
+ return true;
+ }
+
+ if (inClass(BF::JustCCRegClass, DestReg, DestRC) &&
+ inClass(BF::NotCCRegClass, SrcReg, SrcRC)) {
+ BuildMI(MBB, I, dl, get(BF::MOVE_ccncc), DestReg).addReg(SrcReg);
+ return true;
+ }
+
+ llvm_unreachable((std::string("Bad regclasses for reg-to-reg copy: ")+
+ SrcRC->getName() + " -> " + DestRC->getName()).c_str());
+ return false;
+}
+
+void
+BlackfinInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ unsigned SrcReg,
+ bool isKill,
+ int FI,
+ const TargetRegisterClass *RC) const {
+ DebugLoc DL = I != MBB.end() ?
+ I->getDebugLoc() : DebugLoc::getUnknownLoc();
+
+ if (inClass(BF::DPRegClass, SrcReg, RC)) {
+ BuildMI(MBB, I, DL, get(BF::STORE32fi))
+ .addReg(SrcReg, getKillRegState(isKill))
+ .addFrameIndex(FI)
+ .addImm(0);
+ return;
+ }
+
+ if (inClass(BF::D16RegClass, SrcReg, RC)) {
+ BuildMI(MBB, I, DL, get(BF::STORE16fi))
+ .addReg(SrcReg, getKillRegState(isKill))
+ .addFrameIndex(FI)
+ .addImm(0);
+ return;
+ }
+
+ if (inClass(BF::AnyCCRegClass, SrcReg, RC)) {
+ BuildMI(MBB, I, DL, get(BF::STORE8fi))
+ .addReg(SrcReg, getKillRegState(isKill))
+ .addFrameIndex(FI)
+ .addImm(0);
+ return;
+ }
+
+ llvm_unreachable((std::string("Cannot store regclass to stack slot: ")+
+ RC->getName()).c_str());
+}
+
+void BlackfinInstrInfo::
+storeRegToAddr(MachineFunction &MF,
+ unsigned SrcReg,
+ bool isKill,
+ SmallVectorImpl<MachineOperand> &Addr,
+ const TargetRegisterClass *RC,
+ SmallVectorImpl<MachineInstr*> &NewMIs) const {
+ llvm_unreachable("storeRegToAddr not implemented");
+}
+
+void
+BlackfinInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ unsigned DestReg,
+ int FI,
+ const TargetRegisterClass *RC) const {
+ DebugLoc DL = I != MBB.end() ?
+ I->getDebugLoc() : DebugLoc::getUnknownLoc();
+ if (inClass(BF::DPRegClass, DestReg, RC)) {
+ BuildMI(MBB, I, DL, get(BF::LOAD32fi), DestReg)
+ .addFrameIndex(FI)
+ .addImm(0);
+ return;
+ }
+
+ if (inClass(BF::D16RegClass, DestReg, RC)) {
+ BuildMI(MBB, I, DL, get(BF::LOAD16fi), DestReg)
+ .addFrameIndex(FI)
+ .addImm(0);
+ return;
+ }
+
+ if (inClass(BF::AnyCCRegClass, DestReg, RC)) {
+ BuildMI(MBB, I, DL, get(BF::LOAD8fi), DestReg)
+ .addFrameIndex(FI)
+ .addImm(0);
+ return;
+ }
+
+ llvm_unreachable("Cannot load regclass from stack slot");
+}
+
+void BlackfinInstrInfo::
+loadRegFromAddr(MachineFunction &MF,
+ unsigned DestReg,
+ SmallVectorImpl<MachineOperand> &Addr,
+ const TargetRegisterClass *RC,
+ SmallVectorImpl<MachineInstr*> &NewMIs) const {
+ llvm_unreachable("loadRegFromAddr not implemented");
+}
diff --git a/lib/Target/Blackfin/BlackfinInstrInfo.h b/lib/Target/Blackfin/BlackfinInstrInfo.h
new file mode 100644
index 0000000000..ea3429c101
--- /dev/null
+++ b/lib/Target/Blackfin/BlackfinInstrInfo.h
@@ -0,0 +1,80 @@
+//===- BlackfinInstrInfo.h - Blackfin Instruction Information ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the Blackfin implementation of the TargetInstrInfo class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BLACKFININSTRUCTIONINFO_H
+#define BLACKFININSTRUCTIONINFO_H
+
+#include "llvm/Target/TargetInstrInfo.h"
+#include "BlackfinRegisterInfo.h"
+
+namespace llvm {
+
+ class BlackfinInstrInfo : public TargetInstrInfoImpl {
+ const BlackfinRegisterInfo RI;
+ const BlackfinSubtarget& Subtarget;
+ public:
+ explicit BlackfinInstrInfo(BlackfinSubtarget &ST);
+
+ /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As
+ /// such, whenever a client has an instance of instruction info, it should
+ /// always be able to get register info as well (through this method).
+ virtual const BlackfinRegisterInfo &getRegisterInfo() const { return RI; }
+
+ virtual bool isMoveInstr(const MachineInstr &MI,
+ unsigned &SrcReg, unsigned &DstReg,
+ unsigned &SrcSubIdx, unsigned &DstSubIdx) const;
+
+ virtual unsigned isLoadFromStackSlot(const MachineInstr *MI,
+ int &FrameIndex) const;
+
+ virtual unsigned isStoreToStackSlot(const MachineInstr *MI,
+ int &FrameIndex) const;
+
+ virtual unsigned
+ InsertBranch(MachineBasicBlock &MBB,
+ MachineBasicBlock *TBB,
+ MachineBasicBlock *FBB,
+ const SmallVectorImpl<MachineOperand> &Cond) const;
+
+ virtual bool copyRegToReg(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ unsigned DestReg, unsigned SrcReg,
+ const TargetRegisterClass *DestRC,
+ const TargetRegisterClass *SrcRC) const;
+
+ virtual void storeRegToStackSlot(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ unsigned SrcReg, bool isKill,
+ int FrameIndex,
+ const TargetRegisterClass *RC) const;
+
+ virtual void storeRegToAddr(MachineFunction &MF,
+ unsigned SrcReg, bool isKill,
+ SmallVectorImpl<MachineOperand> &Addr,
+ const TargetRegisterClass *RC,
+ SmallVectorImpl<MachineInstr*> &NewMIs) const;
+
+ virtual void loadRegFromStackSlot(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ unsigned DestReg, int FrameIndex,
+ const TargetRegisterClass *RC) const;
+
+ virtual void loadRegFromAddr(MachineFunction &MF, unsigned DestReg,
+ SmallVectorImpl<MachineOperand> &Addr,
+ const TargetRegisterClass *RC,
+ SmallVectorImpl<MachineInstr*> &NewMIs) const;
+ };
+
+} // end namespace llvm
+
+#endif
diff --git a/lib/Target/Blackfin/BlackfinInstrInfo.td b/lib/Target/Blackfin/BlackfinInstrInfo.td
new file mode 100644
index 0000000000..a6653517c9
--- /dev/null
+++ b/lib/Target/Blackfin/BlackfinInstrInfo.td
@@ -0,0 +1,838 @@
+//===- BlackfinInstrInfo.td - Target Description for Blackfin Target ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file describes the Blackfin instructions in TableGen format.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Instruction format superclass
+//===----------------------------------------------------------------------===//
+
+include "BlackfinInstrFormats.td"
+
+// These are target-independent nodes, but have target-specific formats.
+def SDT_BfinCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>;
+def SDT_BfinCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>,
+ SDTCisVT<1, i32> ]>;
+
+def BfinCallseqStart : SDNode<"ISD::CALLSEQ_START", SDT_BfinCallSeqStart,
+ [SDNPHasChain, SDNPOutFlag]>;
+def BfinCallseqEnd : SDNode<"ISD::CALLSEQ_END", SDT_BfinCallSeqEnd,
+ [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>;
+
+def SDT_BfinCall : SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>;
+def BfinCall : SDNode<"BFISD::CALL", SDT_BfinCall,
+ [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>;
+
+def BfinRet: SDNode<"BFISD::RET_FLAG", SDTNone,
+ [SDNPHasChain, SDNPOptInFlag]>;
+
+def BfinWrapper: SDNode<"BFISD::Wrapper", SDTIntUnaryOp>;
+
+//===----------------------------------------------------------------------===//
+// Transformations
+//===----------------------------------------------------------------------===//
+
+def trailingZeros_xform : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant(N->getAPIntValue().countTrailingZeros(),
+ MVT::i32);
+}]>;
+
+def trailingOnes_xform : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant(N->getAPIntValue().countTrailingOnes(),
+ MVT::i32);
+}]>;
+
+def LO16 : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant((unsigned short)N->getZExtValue(), MVT::i16);
+}]>;
+
+def HI16 : SDNodeXForm<imm, [{
+ // Transformation function: shift the immediate value down into the low bits.
+ return CurDAG->getTargetConstant((unsigned)N->getZExtValue() >> 16, MVT::i16);
+}]>;
+
+//===----------------------------------------------------------------------===//
+// Immediates
+//===----------------------------------------------------------------------===//
+
+def imm3 : PatLeaf<(imm), [{return isImm<3>(N->getSExtValue());}]>;
+def uimm3 : PatLeaf<(imm), [{return isUimm<3>(N->getZExtValue());}]>;
+def uimm4 : PatLeaf<(imm), [{return isUimm<4>(N->getZExtValue());}]>;
+def uimm5 : PatLeaf<(imm), [{return isUimm<5>(N->getZExtValue());}]>;
+
+def uimm5m2 : PatLeaf<(imm), [{
+ uint64_t value = N->getZExtValue();
+ return value % 2 == 0 && isUimm<5>(value);
+}]>;
+
+def uimm6m4 : PatLeaf<(imm), [{
+ uint64_t value = N->getZExtValue();
+ return value % 4 == 0 && isUimm<6>(value);
+}]>;
+
+def imm7 : PatLeaf<(imm), [{return isImm<7>(N->getSExtValue());}]>;
+def imm16 : PatLeaf<(imm), [{return isImm<16>(N->getSExtValue());}]>;
+def uimm16 : PatLeaf<(imm), [{return isUimm<16>(N->getZExtValue());}]>;
+
+def ximm16 : PatLeaf<(imm), [{
+ int64_t value = N->getSExtValue();
+ return value < (1<<16) && value >= -(1<<15);
+}]>;
+
+def imm17m2 : PatLeaf<(imm), [{
+ int64_t value = N->getSExtValue();
+ return value % 2 == 0 && isImm<17>(value);
+}]>;
+
+def imm18m4 : PatLeaf<(imm), [{
+ int64_t value = N->getSExtValue();
+ return value % 4 == 0 && isImm<18>(value);
+}]>;
+
+// 32-bit bitmask transformed to a bit number
+def uimm5mask : Operand<i32>, PatLeaf<(imm), [{
+ return isPowerOf2_32(N->getZExtValue());
+}], trailingZeros_xform>;
+
+// 32-bit inverse bitmask transformed to a bit number
+def uimm5imask : Operand<i32>, PatLeaf<(imm), [{
+ return isPowerOf2_32(~N->getZExtValue());
+}], trailingOnes_xform>;
+
+//===----------------------------------------------------------------------===//
+// Operands
+//===----------------------------------------------------------------------===//
+
+def calltarget : Operand<iPTR>;
+
+def brtarget : Operand<OtherVT>;
+
+// Addressing modes
+def ADDRspii : ComplexPattern<i32, 2, "SelectADDRspii", [add, frameindex], []>;
+
+// Address operands
+def MEMii : Operand<i32> {
+ let PrintMethod = "printMemoryOperand";
+ let MIOperandInfo = (ops i32imm, i32imm);
+}
+
+//===----------------------------------------------------------------------===//
+// Instructions
+//===----------------------------------------------------------------------===//
+
+// Pseudo instructions.
+class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstBfin<outs, ins, asmstr, pattern>;
+
+let Defs = [SP], Uses = [SP] in {
+def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt),
+ "${:comment}ADJCALLSTACKDOWN $amt",
+ [(BfinCallseqStart timm:$amt)]>;
+def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2),
+ "${:comment}ADJCALLSTACKUP $amt1 $amt2",
+ [(BfinCallseqEnd timm:$amt1, timm:$amt2)]>;
+}
+
+//===----------------------------------------------------------------------===//
+// Table C-9. Program Flow Control Instructions
+//===----------------------------------------------------------------------===//
+
+let isBranch = 1, isTerminator = 1 in {
+
+let isIndirectBranch = 1 in
+def JUMPp : F1<(outs), (ins P:$target),
+ "JUMP ($target);",
+ [(brind P:$target)]>;
+
+// TODO JUMP (PC-P)
+
+// NOTE: assembler chooses between JUMP.S and JUMP.L
+def JUMPa : F1<(outs), (ins brtarget:$target),
+ "jump $target;",
+ [(br bb:$target)]>;
+
+def JUMPcc : F1<(outs), (ins AnyCC:$cc, brtarget:$target),
+ "if $cc jump $target;",
+ [(brcond AnyCC:$cc, bb:$target)]>;
+}
+
+let isCall = 1,
+ Defs = [R0, R1, R2, R3, P0, P1, P2, LB0, LB1, LC0, LC1, RETS, ASTAT] in {
+def CALLa: F1<(outs), (ins calltarget:$func, variable_ops),
+ "call $func;", []>;
+def CALLp: F1<(outs), (ins P:$func, variable_ops),
+ "call ($func);", [(BfinCall P:$func)]>;
+}
+
+let isReturn = 1,
+ isTerminator = 1,
+ Uses = [RETS] in
+def RTS: F1<(outs), (ins), "rts;", [(BfinRet)]>;
+
+//===----------------------------------------------------------------------===//
+// Table C-10. Load / Store Instructions
+//===----------------------------------------------------------------------===//
+
+// Immediate constant loads
+
+// sext immediate, i32 D/P regs
+def LOADimm7: F1<(outs DP:$dst), (ins i32imm:$src),
+ "$dst = $src (x);",
+ [(set DP:$dst, imm7:$src)]>;
+
+// zext immediate, i32 reg groups 0-3
+def LOADuimm16: F2<(outs GR:$dst), (ins i32imm:$src),
+ "$dst = $src (z);",
+ [(set GR:$dst, uimm16:$src)]>;
+
+// sext immediate, i32 reg groups 0-3
+def LOADimm16: F2<(outs GR:$dst), (ins i32imm:$src),
+ "$dst = $src (x);",
+ [(set GR:$dst, imm16:$src)]>;
+
+// Pseudo-instruction for loading a general 32-bit constant.
+def LOAD32imm: Pseudo<(outs GR:$dst), (ins i32imm:$src),
+ "$dst.h = ($src >> 16); $dst.l = ($src & 0xffff);",
+ [(set GR:$dst, imm:$src)]>;
+
+def LOAD32sym: Pseudo<(outs GR:$dst), (ins i32imm:$src),
+ "$dst.h = $src; $dst.l = $src;", []>;
+
+
+// 16-bit immediate, i16 reg groups 0-3
+def LOAD16i: F2<(outs GR16:$dst), (ins i16imm:$src),
+ "$dst = $src;", []>;
+
+def : Pat<(BfinWrapper (i32 tglobaladdr:$addr)),
+ (LOAD32sym tglobaladdr:$addr)>;
+
+def : Pat<(BfinWrapper (i32 tjumptable:$addr)),
+ (LOAD32sym tjumptable:$addr)>;
+
+// We cannot copy from GR16 to D16, and codegen wants to insert copies if we
+// emit GR16 instructions. As a hack, we use this fake instruction instead.
+def LOAD16i_d16: F2<(outs D16:$dst), (ins i16imm:$src),
+ "$dst = $src;",
+ [(set D16:$dst, ximm16:$src)]>;
+
+// Memory loads with patterns
+
+def LOAD32p: F1<(outs DP:$dst), (ins P:$ptr),
+ "$dst = [$ptr];",
+ [(set DP:$dst, (load P:$ptr))]>;
+
+// Pseudo-instruction for loading a stack slot
+def LOAD32fi: Pseudo<(outs DP:$dst), (ins MEMii:$mem),
+ "${:comment}FI $dst = [$mem];",
+ [(set DP:$dst, (load ADDRspii:$mem))]>;
+
+// Note: Expands to multiple insns
+def LOAD16fi: Pseudo<(outs D16:$dst), (ins MEMii:$mem),
+ "${:comment}FI $dst = [$mem];",
+ [(set D16:$dst, (load ADDRspii:$mem))]>;
+
+// Pseudo-instruction for loading a stack slot, used for AnyCC regs.
+// Replaced with Load D + CC=D
+def LOAD8fi: Pseudo<(outs AnyCC:$dst), (ins MEMii:$mem),
+ "${:comment}FI $dst = B[$mem];",
+ [(set AnyCC:$dst, (load ADDRspii:$mem))]>;
+
+def LOAD32p_uimm6m4: F1<(outs DP:$dst), (ins P:$ptr, i32imm:$off),
+ "$dst = [$ptr + $off];",
+ [(set DP:$dst, (load (add P:$ptr, uimm6m4:$off)))]>;
+
+def LOAD32p_imm18m4: F2<(outs DP:$dst), (ins P:$ptr, i32imm:$off),
+ "$dst = [$ptr + $off];",
+ [(set DP:$dst, (load (add P:$ptr, imm18m4:$off)))]>;
+
+def LOAD32p_16z: F1<(outs D:$dst), (ins P:$ptr),
+ "$dst = W[$ptr] (z);",
+ [(set D:$dst, (zextloadi16 P:$ptr))]>;
+
+def : Pat<(i32 (extloadi16 P:$ptr)),(LOAD32p_16z P:$ptr)>;
+
+def LOAD32p_uimm5m2_16z: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off),
+ "$dst = w[$ptr + $off] (z);",
+ [(set D:$dst, (zextloadi16 (add P:$ptr,
+ uimm5m2:$off)))]>;
+
+def : Pat<(i32 (extloadi16 (add P:$ptr, uimm5m2:$off))),
+ (LOAD32p_uimm5m2_16z P:$ptr, imm:$off)>;
+
+def LOAD32p_imm17m2_16z: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off),
+ "$dst = w[$ptr + $off] (z);",
+ [(set D:$dst,
+ (zextloadi16 (add P:$ptr, imm17m2:$off)))]>;
+
+def : Pat<(i32 (extloadi16 (add P:$ptr, imm17m2:$off))),
+ (LOAD32p_imm17m2_16z P:$ptr, imm:$off)>;
+
+def LOAD32p_16s: F1<(outs D:$dst), (ins P:$ptr),
+ "$dst = w[$ptr] (x);",
+ [(set D:$dst, (sextloadi16 P:$ptr))]>;
+
+def LOAD32p_uimm5m2_16s: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off),
+ "$dst = w[$ptr + $off] (x);",
+ [(set D:$dst,
+ (sextloadi16 (add P:$ptr, uimm5m2:$off)))]>;
+
+def LOAD32p_imm17m2_16s: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off),
+ "$dst = w[$ptr + $off] (x);",
+ [(set D:$dst,
+ (sextloadi16 (add P:$ptr, imm17m2:$off)))]>;
+
+def LOAD16pi: F1<(outs D16:$dst), (ins PI:$ptr),
+ "$dst = w[$ptr];",
+ [(set D16:$dst, (load PI:$ptr))]>;
+
+def LOAD32p_8z: F1<(outs D:$dst), (ins P:$ptr),
+ "$dst = B[$ptr] (z);",
+ [(set D:$dst, (zextloadi8 P:$ptr))]>;
+
+def : Pat<(i32 (extloadi8 P:$ptr)), (LOAD32p_8z P:$ptr)>;
+def : Pat<(i16 (extloadi8 P:$ptr)),
+ (EXTRACT_SUBREG (LOAD32p_8z P:$ptr), bfin_subreg_lo16)>;
+def : Pat<(i16 (zextloadi8 P:$ptr)),
+ (EXTRACT_SUBREG (LOAD32p_8z P:$ptr), bfin_subreg_lo16)>;
+
+def LOAD32p_imm16_8z: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off),
+ "$dst = b[$ptr + $off] (z);",
+ [(set D:$dst, (zextloadi8 (add P:$ptr, imm16:$off)))]>;
+
+def : Pat<(i32 (extloadi8 (add P:$ptr, imm16:$off))),
+ (LOAD32p_imm16_8z P:$ptr, imm:$off)>;
+def : Pat<(i16 (extloadi8 (add P:$ptr, imm16:$off))),
+ (EXTRACT_SUBREG (LOAD32p_imm16_8z P:$ptr, imm:$off),
+ bfin_subreg_lo16)>;
+def : Pat<(i16 (zextloadi8 (add P:$ptr, imm16:$off))),
+ (EXTRACT_SUBREG (LOAD32p_imm16_8z P:$ptr, imm:$off),
+ bfin_subreg_lo16)>;
+
+def LOAD32p_8s: F1<(outs D:$dst), (ins P:$ptr),
+ "$dst = b[$ptr] (x);",
+ [(set D:$dst, (sextloadi8 P:$ptr))]>;
+
+def : Pat<(i16 (sextloadi8 P:$ptr)),
+ (EXTRACT_SUBREG (LOAD32p_8s P:$ptr), bfin_subreg_lo16)>;
+
+def LOAD32p_imm16_8s: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off),
+ "$dst = b[$ptr + $off] (x);",
+ [(set D:$dst, (sextloadi8 (add P:$ptr, imm16:$off)))]>;
+
+def : Pat<(i16 (sextloadi8 (add P:$ptr, imm16:$off))),
+ (EXTRACT_SUBREG (LOAD32p_imm16_8s P:$ptr, imm:$off),
+ bfin_subreg_lo16)>;
+// Memory loads without patterns
+
+let mayLoad = 1 in {
+
+multiclass LOAD_incdec<RegisterClass drc, RegisterClass prc,
+ string mem="", string suf=";"> {
+ def _inc : F1<(outs drc:$dst, prc:$ptr_wb), (ins prc:$ptr),
+ !strconcat(!subst("M", mem, "$dst = M[$ptr++]"), suf), []>;
+ def _dec : F1<(outs drc:$dst, prc:$ptr_wb), (ins prc:$ptr),
+ !strconcat(!subst("M", mem, "$dst = M[$ptr--]"), suf), []>;
+}
+multiclass LOAD_incdecpost<RegisterClass drc, RegisterClass prc,
+ string mem="", string suf=";">
+ : LOAD_incdec<drc, prc, mem, suf> {
+ def _post : F1<(outs drc:$dst, prc:$ptr_wb), (ins prc:$ptr, prc:$off),
+ !strconcat(!subst("M", mem, "$dst = M[$ptr++$off]"), suf), []>;
+}
+
+defm LOAD32p: LOAD_incdec<DP, P>;
+defm LOAD32i: LOAD_incdec<D, I>;
+defm LOAD8z32p: LOAD_incdec<D, P, "b", " (z);">;
+defm LOAD8s32p: LOAD_incdec<D, P, "b", " (x);">;
+defm LOADhi: LOAD_incdec<D16, I, "w">;
+defm LOAD16z32p: LOAD_incdecpost<D, P, "w", " (z);">;
+defm LOAD16s32p: LOAD_incdecpost<D, P, "w", " (x);">;
+
+def LOAD32p_post: F1<(outs D:$dst, P:$ptr_wb), (ins P:$ptr, P:$off),
+ "$dst = [$ptr ++ $off];", []>;
+
+// Note: $fp MUST be FP
+def LOAD32fp_nimm7m4: F1<(outs DP:$dst), (ins P:$fp, i32imm:$off),
+ "$dst = [$fp - $off];", []>;
+
+def LOAD32i: F1<(outs D:$dst), (ins I:$ptr),
+ "$dst = [$ptr];", []>;
+def LOAD32i_post: F1<(outs D:$dst, I:$ptr_wb), (ins I:$ptr, M:$off),
+ "$dst = [$ptr ++ $off];", []>;
+
+
+
+def LOADhp_post: F1<(outs D16:$dst, P:$ptr_wb), (ins P:$ptr, P:$off),
+ "$dst = w[$ptr ++ $off];", []>;
+
+
+}
+
+// Memory stores with patterns
+def STORE32p: F1<(outs), (ins DP:$val, P:$ptr),
+ "[$ptr] = $val;",
+ [(store DP:$val, P:$ptr)]>;
+
+// Pseudo-instructions for storing to a stack slot
+def STORE32fi: Pseudo<(outs), (ins DP:$val, MEMii:$mem),
+ "${:comment}FI [$mem] = $val;",
+ [(store DP:$val, ADDRspii:$mem)]>;
+
+// Note: This stack-storing pseudo-instruction is expanded to multiple insns
+def STORE16fi: Pseudo<(outs), (ins D16:$val, MEMii:$mem),
+ "${:comment}FI [$mem] = $val;",
+ [(store D16:$val, ADDRspii:$mem)]>;
+
+// Pseudo-instructions for storing AnyCC register to a stack slot.
+// Replaced with D=CC + STORE byte
+def STORE8fi: Pseudo<(outs), (ins AnyCC:$val, MEMii:$mem),
+ "${:comment}FI b[$mem] = $val;",
+ [(store AnyCC:$val, ADDRspii:$mem)]>;
+
+def STORE32p_uimm6m4: F1<(outs), (ins DP:$val, P:$ptr, i32imm:$off),
+ "[$ptr + $off] = $val;",
+ [(store DP:$val, (add P:$ptr, uimm6m4:$off))]>;
+
+def STORE32p_imm18m4: F1<(outs), (ins DP:$val, P:$ptr, i32imm:$off),
+ "[$ptr + $off] = $val;",
+ [(store DP:$val, (add P:$ptr, imm18m4:$off))]>;
+
+def STORE16pi: F1<(outs), (ins D16:$val, PI:$ptr),
+ "w[$ptr] = $val;",
+ [(store D16:$val, PI:$ptr)]>;
+
+def STORE8p: F1<(outs), (ins D:$val, P:$ptr),
+ "b[$ptr] = $val;",
+ [(truncstorei8 D:$val, P:$ptr)]>;
+
+def STORE8p_imm16: F1<(outs), (ins D:$val, P:$ptr, i32imm:$off),
+ "b[$ptr + $off] = $val;",
+ [(truncstorei8 D:$val, (add P:$ptr, imm16:$off))]>;
+
+let Constraints = "$ptr = $ptr_wb" in {
+
+multiclass STORE_incdec<RegisterClass drc, RegisterClass prc,
+ int off=4, string pre=""> {
+ def _inc : F1<(outs prc:$ptr_wb), (ins drc:$val, prc:$ptr),
+ !strconcat(pre, "[$ptr++] = $val;"),
+ [(set prc:$ptr_wb, (post_store drc:$val, prc:$ptr, off))]>;
+ def _dec : F1<(outs prc:$ptr_wb), (ins drc:$val, prc:$ptr),
+ !strconcat(pre, "[$ptr--] = $val;"),
+ [(set prc:$ptr_wb, (post_store drc:$val, prc:$ptr,
+ (ineg off)))]>;
+}
+
+defm STORE32p: STORE_incdec<DP, P>;
+defm STORE16i: STORE_incdec<D16, I, 2, "w">;
+defm STORE8p: STORE_incdec<D, P, 1, "b">;
+
+def STORE32p_post: F1<(outs P:$ptr_wb), (ins D:$val, P:$ptr, P:$off),
+ "[$ptr ++ $off] = $val;",
+ [(set P:$ptr_wb, (post_store D:$val, P:$ptr, P:$off))]>;
+
+def STORE16p_post: F1<(outs P:$ptr_wb), (ins D16:$val, P:$ptr, P:$off),
+ "w[$ptr ++ $off] = $val;",
+ [(set P:$ptr_wb, (post_store D16:$val, P:$ptr, P:$off))]>;
+}
+
+// Memory stores without patterns
+
+let mayStore = 1 in {
+
+// Note: only works for $fp == FP
+def STORE32fp_nimm7m4: F1<(outs), (ins DP:$val, P:$fp, i32imm:$off),
+ "[$fp - $off] = $val;", []>;
+
+def STORE32i: F1<(outs), (ins D:$val, I:$ptr),
+ "[$ptr] = $val;", []>;
+
+def STORE32i_inc: F1<(outs I:$ptr_wb), (ins D:$val, I:$ptr),
+ "[$ptr++] = $val;", []>;
+
+def STORE32i_dec: F1<(outs I:$ptr_wb), (ins D:$val, I:$ptr),
+ "[$ptr--] = $val;", []>;
+
+def STORE32i_post: F1<(outs I:$ptr_wb), (ins D:$val, I:$ptr, M:$off),
+ "[$ptr ++ $off] = $val;", []>;
+}
+
+def : Pat<(truncstorei16 D:$val, PI:$ptr),
+ (STORE16pi (EXTRACT_SUBREG (COPY_TO_REGCLASS D:$val, D),
+ bfin_subreg_lo16), PI:$ptr)>;
+
+def : Pat<(truncstorei16 (srl D:$val, (i16 16)), PI:$ptr),
+ (STORE16pi (EXTRACT_SUBREG (COPY_TO_REGCLASS D:$val, D),
+ bfin_subreg_hi16), PI:$ptr)>;
+
+def : Pat<(truncstorei8 D16L:$val, P:$ptr),
+ (STORE8p (INSERT_SUBREG (i32 (IMPLICIT_DEF)),
+ (COPY_TO_REGCLASS D16L:$val, D16L),
+ bfin_subreg_lo16),
+ P:$ptr)>;
+
+//===----------------------------------------------------------------------===//
+// Table C-11. Move Instructions.
+//===----------------------------------------------------------------------===//
+
+def MOVE: F1<(outs ALL:$dst), (ins ALL:$src),
+ "$dst = $src;",
+ []>;
+
+let isTwoAddress = 1 in
+def MOVEcc: F1<(outs DP:$dst), (ins DP:$src1, DP:$src2, AnyCC:$cc),
+ "if $cc $dst = $src2;",
+ [(set DP:$dst, (select AnyCC:$cc, DP:$src2, DP:$src1))]>;
+
+let Defs = [AZ, AN, AC0, V] in {
+def MOVEzext: F1<(outs D:$dst), (ins D16L:$src),
+ "$dst = $src (z);",
+ [(set D:$dst, (zext D16L:$src))]>;
+
+def MOVEsext: F1<(outs D:$dst), (ins D16L:$src),
+ "$dst = $src (x);",
+ [(set D:$dst, (sext D16L:$src))]>;
+
+def MOVEzext8: F1<(outs D:$dst), (ins D:$src),
+ "$dst = $src.b (z);",
+ [(set D:$dst, (and D:$src, 0xff))]>;
+
+def MOVEsext8: F1<(outs D:$dst), (ins D:$src),
+ "$dst = $src.b (x);",
+ [(set D:$dst, (sext_inreg D:$src, i8))]>;
+
+}
+
+def : Pat<(sext_inreg D16L:$src, i8),
+ (EXTRACT_SUBREG (MOVEsext8
+ (INSERT_SUBREG (i32 (IMPLICIT_DEF)),
+ D16L:$src,
+ bfin_subreg_lo16)),
+ bfin_subreg_lo16)>;
+
+def : Pat<(sext_inreg D:$src, i16),
+ (MOVEsext (EXTRACT_SUBREG D:$src, bfin_subreg_lo16))>;
+
+def : Pat<(and D:$src, 0xffff),
+ (MOVEzext (EXTRACT_SUBREG D:$src, bfin_subreg_lo16))>;
+
+def : Pat<(i32 (anyext D16L:$src)),
+ (INSERT_SUBREG (i32 (IMPLICIT_DEF)),
+ (COPY_TO_REGCLASS D16L:$src, D16L),
+ bfin_subreg_lo16)>;
+
+// TODO Dreg = Dreg_byte (X/Z)
+
+// TODO Accumulator moves
+
+//===----------------------------------------------------------------------===//
+// Table C-12. Stack Control Instructions
+//===----------------------------------------------------------------------===//
+
+let Uses = [SP], Defs = [SP] in {
+def PUSH: F1<(outs), (ins ALL:$src),
+ "[--sp] = $src;", []> { let mayStore = 1; }
+
+// NOTE: POP does not work for DP regs, use LOAD instead
+def POP: F1<(outs ALL:$dst), (ins),
+ "$dst = [sp++];", []> { let mayLoad = 1; }
+}
+
+// TODO: push/pop multiple
+
+def LINK: F2<(outs), (ins i32imm:$amount),
+ "link $amount;", []>;
+
+def UNLINK: F2<(outs), (ins),
+ "unlink;", []>;
+
+//===----------------------------------------------------------------------===//
+// Table C-13. Control Code Bit Management Instructions
+//===----------------------------------------------------------------------===//
+
+multiclass SETCC<PatFrag opnode, PatFrag invnode, string cond, string suf=";"> {
+ def dd : F1<(outs JustCC:$cc), (ins D:$a, D:$b),
+ !strconcat(!subst("XX", cond, "cc = $a XX $b"), suf),
+ [(set JustCC:$cc, (opnode D:$a, D:$b))]>;
+
+ def ri : F1<(outs JustCC:$cc), (ins DP:$a, i32imm:$b),
+ !strconcat(!subst("XX", cond, "cc = $a XX $b"), suf),
+ [(set JustCC:$cc, (opnode DP:$a, imm3:$b))]>;
+
+ def pp : F1<(outs JustCC:$cc), (ins P:$a, P:$b),
+ !strconcat(!subst("XX", cond, "cc = $a XX $b"), suf),
+ []>;
+
+ def ri_not : F1<(outs NotCC:$cc), (ins DP:$a, i32imm:$b),
+ !strconcat(!subst("XX", cond, "cc = $a XX $b"), suf),
+ [(set NotCC:$cc, (invnode DP:$a, imm3:$b))]>;
+}
+
+defm SETEQ : SETCC<seteq, setne, "==">;
+defm SETLT : SETCC<setlt, setge, "<">;
+defm SETLE : SETCC<setle, setgt, "<=">;
+defm SETULT : SETCC<setult, setuge, "<", " (iu);">;
+defm SETULE : SETCC<setule, setugt, "<=", " (iu);">;
+
+def SETNEdd : F1<(outs NotCC:$cc), (ins D:$a, D:$b),
+ "cc = $a == $b;",
+ [(set NotCC:$cc, (setne D:$a, D:$b))]>;
+
+def : Pat<(setgt D:$a, D:$b), (SETLTdd D:$b, D:$a)>;
+def : Pat<(setge D:$a, D:$b), (SETLEdd D:$b, D:$a)>;
+def : Pat<(setugt D:$a, D:$b), (SETULTdd D:$b, D:$a)>;
+def : Pat<(setuge D:$a, D:$b), (SETULEdd D:$b, D:$a)>;
+
+// TODO: compare pointer for P-P comparisons
+// TODO: compare accumulator
+
+let Defs = [AC0] in
+def OR_ac0_cc : F1<(outs), (ins JustCC:$cc),
+ "ac0 \\|= cc;", []>;
+
+let Uses = [AC0] in
+def MOVE_cc_ac0 : F1<(outs JustCC:$cc), (ins),
+ "cc = ac0;", []>;
+
+def MOVE_ccncc : F1<(outs JustCC:$cc), (ins NotCC:$sb),
+ "cc = !cc;", []>;
+
+def MOVE_ncccc : F1<(outs NotCC:$cc), (ins JustCC:$sb),
+ "cc = !cc;", []>;
+
+def MOVECC_zext : F1<(outs D:$dst), (ins JustCC:$cc),
+ "$dst = $cc;",
+ [(set D:$dst, (zext JustCC:$cc))]>;
+
+def MOVENCC_z : F1<(outs D:$dst), (ins NotCC:$cc),
+ "$dst = cc;", []>;
+
+def MOVECC_nz : F1<(outs AnyCC:$cc), (ins D:$src),
+ "cc = $src;",
+ [(set AnyCC:$cc, (setne D:$src, 0))]>;
+
+//===----------------------------------------------------------------------===//
+// Table C-14. Logical Operations Instructions
+//===----------------------------------------------------------------------===//
+
+def AND: F1<(outs D:$dst), (ins D:$src1, D:$src2),
+ "$dst = $src1 & $src2;",
+ [(set D:$dst, (and D:$src1, D:$src2))]>;
+
+def NOT: F1<(outs D:$dst), (ins D:$src),
+ "$dst = ~$src;",
+ [(set D:$dst, (not D:$src))]>;
+
+def OR: F1<(outs D:$dst), (ins D:$src1, D:$src2),
+ "$dst = $src1 \\| $src2;",
+ [(set D:$dst, (or D:$src1, D:$src2))]>;
+
+def XOR: F1<(outs D:$dst), (ins D:$src1, D:$src2),
+ "$dst = $src1 ^ $src2;",
+ [(set D:$dst, (xor D:$src1, D:$src2))]>;
+
+// missing: BXOR, BXORSHIFT
+
+//===----------------------------------------------------------------------===//
+// Table C-15. Bit Operations Instructions
+//===----------------------------------------------------------------------===//
+
+let isTwoAddress = 1 in {
+def BITCLR: F1<(outs D:$dst), (ins D:$src1, uimm5imask:$src2),
+ "bitclr($dst, $src2);",
+ [(set D:$dst, (and D:$src1, uimm5imask:$src2))]>;
+
+def BITSET: F1<(outs D:$dst), (ins D:$src1, uimm5mask:$src2),
+ "bitset($dst, $src2);",
+ [(set D:$dst, (or D:$src1, uimm5mask:$src2))]>;
+
+def BITTGL: F1<(outs D:$dst), (ins D:$src1, uimm5mask:$src2),
+ "bittgl($dst, $src2);",
+ [(set D:$dst, (xor D:$src1, uimm5mask:$src2))]>;
+}
+
+def BITTST: F1<(outs JustCC:$cc), (ins D:$src1, uimm5mask:$src2),
+ "cc = bittst($src1, $src2);",
+ [(set JustCC:$cc, (setne (and D:$src1, uimm5mask:$src2),
+ (i32 0)))]>;
+
+def NBITTST: F1<(outs JustCC:$cc), (ins D:$src1, uimm5mask:$src2),
+ "cc = !bittst($src1, $src2);",
+ [(set JustCC:$cc, (seteq (and D:$src1, uimm5mask:$src2),
+ (i32 0)))]>;
+
+// TODO: DEPOSIT, EXTRACT, BITMUX
+
+def ONES: F2<(outs D16L:$dst), (ins D:$src),
+ "$dst = ones $src;",
+ [(set D16L:$dst, (trunc (ctpop D:$src)))]>;
+
+def : Pat<(ctpop D:$src), (MOVEzext (ONES D:$src))>;
+
+//===----------------------------------------------------------------------===//
+// Table C-16. Shift / Rotate Instructions
+//===----------------------------------------------------------------------===//
+
+multiclass SHIFT32<SDNode opnode, string ops> {
+ def i : F1<(outs D:$dst), (ins D:$src, i16imm:$amount),
+ !subst("XX", ops, "$dst XX= $amount;"),
+ [(set D:$dst, (opnode D:$src, (i16 uimm5:$amount)))]>;
+ def r : F1<(outs D:$dst), (ins D:$src, D:$amount),
+ !subst("XX", ops, "$dst XX= $amount;"),
+ [(set D:$dst, (opnode D:$src, D:$amount))]>;
+}
+
+let Defs = [AZ, AN, V, VS],
+ isTwoAddress = 1 in {
+defm SRA : SHIFT32<sra, ">>>">;
+defm SRL : SHIFT32<srl, ">>">;
+defm SLL : SHIFT32<shl, "<<">;
+}
+
+// TODO: automatic switching between 2-addr and 3-addr (?)
+
+let Defs = [AZ, AN, V, VS] in {
+def SLLr16: F2<(outs D:$dst), (ins D:$src, D16L:$amount),
+ "$dst = lshift $src by $amount;",
+ [(set D:$dst, (shl D:$src, D16L:$amount))]>;
+
+// Arithmetic left-shift = saturing overflow.
+def SLAr16: F2<(outs D:$dst), (ins D:$src, D16L:$amount),
+ "$dst = ashift $src by $amount;",
+ [(set D:$dst, (sra D:$src, (ineg D16L:$amount)))]>;
+
+def SRA16i: F1<(outs D16:$dst), (ins D16:$src, i16imm:$amount),
+ "$dst = $src >>> $amount;",
+ [(set D16:$dst, (sra D16:$src, (i16 uimm4:$amount)))]>;
+
+def SRL16i: F1<(outs D16:$dst), (ins D16:$src, i16imm:$amount),
+ "$dst = $src >> $amount;",
+ [(set D16:$dst, (srl D16:$src, (i16 uimm4:$amount)))]>;
+
+// Arithmetic left-shift = saturing overflow.
+def SLA16r: F1<(outs D16:$dst), (ins D16:$src, D16L:$amount),
+ "$dst = ashift $src BY $amount;",
+ [(set D16:$dst, (srl D16:$src, (ineg D16L:$amount)))]>;
+
+def SLL16i: F1<(outs D16:$dst), (ins D16:$src, i16imm:$amount),
+ "$dst = $src << $amount;",
+ [(set D16:$dst, (shl D16:$src, (i16 uimm4:$amount)))]>;
+
+def SLL16r: F1<(outs D16:$dst), (ins D16:$src, D16L:$amount),
+ "$dst = lshift $src by $amount;",
+ [(set D16:$dst, (shl D16:$src, D16L:$amount))]>;
+
+}
+
+//===----------------------------------------------------------------------===//
+// Table C-17. Arithmetic Operations Instructions
+//===----------------------------------------------------------------------===//
+
+// TODO: ABS
+
+let Defs = [AZ, AN, AC0, V, VS] in {
+
+def ADD: F1<(outs D:$dst), (ins D:$src1, D:$src2),
+ "$dst = $src1 + $src2;",
+ [(set D:$dst, (add D:$src1, D:$src2))]>;
+
+def ADD16: F2<(outs D16:$dst), (ins D16:$src1, D16:$src2),
+ "$dst = $src1 + $src2;",
+ [(set D16:$dst, (add D16:$src1, D16:$src2))]>;
+
+let isTwoAddress = 1 in
+def ADDimm7: F1<(outs D:$dst), (ins D:$src1, i32imm:$src2),
+ "$dst += $src2;",
+ [(set D:$dst, (add D:$src1, imm7:$src2))]>;
+
+def SUB: F1<(outs D:$dst), (ins D:$src1, D:$src2),
+ "$dst = $src1 - $src2;",
+ [(set D:$dst, (sub D:$src1, D:$src2))]>;
+
+def SUB16: F2<(outs D16:$dst), (ins D16:$src1, D16:$src2),
+ "$dst = $src1 - $src2;",
+ [(set D16:$dst, (sub D16:$src1, D16:$src2))]>;
+
+}
+
+def : Pat<(addc D:$src1, D:$src2), (ADD D:$src1, D:$src2)>;
+def : Pat<(subc D:$src1, D:$src2), (SUB D:$src1, D:$src2)>;
+
+let Defs = [AZ, AN, V, VS] in
+def NEG: F1<(outs D:$dst), (ins D:$src),
+ "$dst = -$src;",
+ [(set D:$dst, (ineg D:$src))]>;
+
+// No pattern, it would confuse isel to have two i32 = i32+i32 patterns
+def ADDpp: F1<(outs P:$dst), (ins P:$src1, P:$src2),
+ "$dst = $src1 + $src2;", []>;
+
+let isTwoAddress = 1 in
+def ADDpp_imm7: F1<(outs P:$dst), (ins P:$src1, i32imm:$src2),
+ "$dst += $src2;", []>;
+
+let Defs = [AZ, AN, V] in
+def ADD_RND20: F2<(outs D16:$dst), (ins D:$src1, D:$src2),
+ "$dst = $src1 + $src2 (rnd20);", []>;
+
+let Defs = [V, VS] in {
+def MUL16: F2<(outs D16:$dst), (ins D16:$src1, D16:$src2),
+ "$dst = $src1 * $src2 (is);",
+ [(set D16:$dst, (mul D16:$src1, D16:$src2))]>;
+
+def MULHS16: F2<(outs D16:$dst), (ins D16:$src1, D16:$src2),
+ "$dst = $src1 * $src2 (ih);",
+ [(set D16:$dst, (mulhs D16:$src1, D16:$src2))]>;
+
+def MULhh32s: F2<(outs D:$dst), (ins D16:$src1, D16:$src2),
+ "$dst = $src1 * $src2 (is);",
+ [(set D:$dst, (mul (sext D16:$src1), (sext D16:$src2)))]>;
+
+def MULhh32u: F2<(outs D:$dst), (ins D16:$src1, D16:$src2),
+ "$dst = $src1 * $src2 (is);",
+ [(set D:$dst, (mul (zext D16:$src1), (zext D16:$src2)))]>;
+}
+
+
+let isTwoAddress = 1 in
+def MUL32: F1<(outs D:$dst), (ins D:$src1, D:$src2),
+ "$dst *= $src2;",
+ [(set D:$dst, (mul D:$src1, D:$src2))]>;
+
+//===----------------------------------------------------------------------===//
+// Table C-18. External Exent Management Instructions
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Table C-19. Cache Control Instructions
+//===----------------------------------------------------------------------===//
+
+// Table C-20. Video Pixel Operations Instructions
+// Table C-21. Vector Operations Instructions
+
+// Patterns
+def : Pat<(BfinCall (i32 tglobaladdr:$dst)),
+ (CALLa tglobaladdr:$dst)>;
+def : Pat<(BfinCall (i32 texternalsym:$dst)),
+ (CALLa texternalsym:$dst)>;
+
+def : Pat<(sext JustCC:$cc),
+ (NEG (MOVECC_zext JustCC:$cc))>;
+def : Pat<(anyext JustCC:$cc),
+ (MOVECC_zext JustCC:$cc)>;
+def : Pat<(i16 (zext JustCC:$cc)),
+ (EXTRACT_SUBREG (MOVECC_zext JustCC:$cc), bfin_subreg_lo16)>;
+def : Pat<(i16 (sext JustCC:$cc)),
+ (EXTRACT_SUBREG (NEG (MOVECC_zext JustCC:$cc)), bfin_subreg_lo16)>;
+def : Pat<(i16 (anyext JustCC:$cc)),
+ (EXTRACT_SUBREG (MOVECC_zext JustCC:$cc), bfin_subreg_lo16)>;
+
+def : Pat<(i16 (trunc D:$src)),
+ (EXTRACT_SUBREG (COPY_TO_REGCLASS D:$src, D), bfin_subreg_lo16)>;
diff --git a/lib/Target/Blackfin/BlackfinRegisterInfo.cpp b/lib/Target/Blackfin/BlackfinRegisterInfo.cpp
new file mode 100644
index 0000000000..619906e37e
--- /dev/null
+++ b/lib/Target/Blackfin/BlackfinRegisterInfo.cpp
@@ -0,0 +1,462 @@
+//===- BlackfinRegisterInfo.cpp - Blackfin Register Information -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the Blackfin implementation of the TargetRegisterInfo
+// class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Blackfin.h"
+#include "BlackfinRegisterInfo.h"
+#include "BlackfinSubtarget.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineLocation.h"
+#include "llvm/CodeGen/RegisterScavenging.h"
+#include "llvm/Target/TargetFrameInfo.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+#include "llvm/Target/TargetInstrInfo.h"
+#include "llvm/Type.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/STLExtras.h"
+using namespace llvm;
+
+BlackfinRegisterInfo::BlackfinRegisterInfo(BlackfinSubtarget &st,
+ const TargetInstrInfo &tii)
+ : BlackfinGenRegisterInfo(BF::ADJCALLSTACKDOWN, BF::ADJCALLSTACKUP),
+ Subtarget(st),
+ TII(tii) {}
+
+const unsigned*
+BlackfinRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
+ using namespace BF;
+ static const unsigned CalleeSavedRegs[] = {
+ FP,
+ R4, R5, R6, R7,
+ P3, P4, P5,
+ 0 };
+ return CalleeSavedRegs;
+}
+
+const TargetRegisterClass* const *BlackfinRegisterInfo::
+getCalleeSavedRegClasses(const MachineFunction *MF) const {
+ using namespace BF;
+ static const TargetRegisterClass * const CalleeSavedRegClasses[] = {
+ &PRegClass,
+ &DRegClass, &DRegClass, &DRegClass, &DRegClass,
+ &PRegClass, &PRegClass, &PRegClass,
+ 0 };
+ return CalleeSavedRegClasses;
+}
+
+BitVector
+BlackfinRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
+ using namespace BF;
+ BitVector Reserved(getNumRegs());
+ Reserved.set(L0);
+ Reserved.set(L1);
+ Reserved.set(L2);
+ Reserved.set(L3);
+ Reserved.set(SP);
+ Reserved.set(RETS);
+ if (hasFP(MF))
+ Reserved.set(FP);
+ return Reserved;
+}
+
+const TargetRegisterClass*
+BlackfinRegisterInfo::getPhysicalRegisterRegClass(unsigned reg, MVT VT) const {
+ assert(isPhysicalRegister(reg) && "reg must be a physical register");
+
+ // Pick the smallest register class of the right type that contains
+ // this physreg.
+ const TargetRegisterClass* BestRC = 0;
+ for (regclass_iterator I = regclass_begin(), E = regclass_end();
+ I != E; ++I) {
+ const TargetRegisterClass* RC = *I;
+ if ((VT == MVT::Other || RC->hasType(VT)) && RC->contains(reg) &&
+ (!BestRC || RC->getNumRegs() < BestRC->getNumRegs()))
+ BestRC = RC;
+ }
+
+ assert(BestRC && "Couldn't find the register class");
+ return BestRC;
+}
+
+// hasFP - Return true if the specified function should have a dedicated frame
+// pointer register. This is true if the function has variable sized allocas or
+// if frame pointer elimination is disabled.
+bool BlackfinRegisterInfo::hasFP(const MachineFunction &MF) const {
+ const MachineFrameInfo *MFI = MF.getFrameInfo();
+ return NoFramePointerElim || MFI->hasCalls() || MFI->hasVarSizedObjects();
+}
+
+bool BlackfinRegisterInfo::
+requiresRegisterScavenging(const MachineFunction &MF) const {
+ return true;
+}
+
+// Emit instructions to add delta to D/P register. ScratchReg must be of the
+// same class as Reg (P).
+void BlackfinRegisterInfo::adjustRegister(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ DebugLoc DL,
+ unsigned Reg,
+ unsigned ScratchReg,
+ int delta) const {
+ if (!delta)
+ return;
+ if (isImm<7>(delta)) {
+ BuildMI(MBB, I, DL, TII.get(BF::ADDpp_imm7), Reg)
+ .addReg(Reg) // No kill on two-addr operand
+ .addImm(delta);
+ return;
+ }
+
+ // We must load delta into ScratchReg and add that.
+ loadConstant(MBB, I, DL, ScratchReg, delta);
+ if (BF::PRegClass.contains(Reg)) {
+ assert (BF::PRegClass.contains(ScratchReg));
+ BuildMI(MBB, I, DL, TII.get(BF::ADDpp), Reg)
+ .addReg(Reg, RegState::Kill)
+ .addReg(ScratchReg, RegState::Kill);
+ } else {
+ assert (BF::DRegClass.contains(Reg));
+ assert (BF::DRegClass.contains(ScratchReg));
+ BuildMI(MBB, I, DL, TII.get(BF::ADD), Reg)
+ .addReg(Reg, RegState::Kill)
+ .addReg(ScratchReg, RegState::Kill);
+ }
+}
+
+// Emit instructions to load a constant into D/P register
+void BlackfinRegisterInfo::loadConstant(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ DebugLoc DL,
+ unsigned Reg,
+ int value) const {
+ if (isImm<7>(value)) {
+ BuildMI(MBB, I, DL, TII.get(BF::LOADimm7), Reg).addImm(value);
+ return;
+ }
+
+ if (isUimm<16>(value)) {
+ BuildMI(MBB, I, DL, TII.get(BF::LOADuimm16), Reg).addImm(value);
+ return;
+ }
+
+ if (isImm<16>(value)) {
+ BuildMI(MBB, I, DL, TII.get(BF::LOADimm16), Reg).addImm(value);
+ return;
+ }
+
+ // We must split into halves
+ BuildMI(MBB, I, DL,
+ TII.get(BF::LOAD16i), getSubReg(Reg, bfin_subreg_hi16))
+ .addImm((value >> 16) & 0xffff)
+ .addReg(Reg, RegState::ImplicitDefine);
+ BuildMI(MBB, I, DL,
+ TII.get(BF::LOAD16i), getSubReg(Reg, bfin_subreg_lo16))
+ .addImm(value & 0xffff)
+ .addReg(Reg, RegState::ImplicitKill)
+ .addReg(Reg, RegState::ImplicitDefine);
+}
+
+void BlackfinRegisterInfo::
+eliminateCallFramePseudoInstr(MachineFunction &MF,
+ MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I) const {
+ if (!hasReservedCallFrame(MF)) {
+ int64_t Amount = I->getOperand(0).getImm();
+ if (Amount != 0) {
+ assert(Amount%4 == 0);
+ if (I->getOpcode() == BF::ADJCALLSTACKDOWN) {
+ adjustRegister(MBB, I, I->getDebugLoc(), BF::SP, BF::P1, -Amount);
+ } else {
+ assert(I->getOpcode() == BF::ADJCALLSTACKUP);
+ adjustRegister(MBB, I, I->getDebugLoc(), BF::SP, BF::P1, Amount);
+ }
+ }
+ }
+ MBB.erase(I);
+}
+
+/// findScratchRegister - Find a 'free' register. Try for a call-clobbered
+/// register first and then a spilled callee-saved register if that fails.
+static unsigned findScratchRegister(MachineBasicBlock::iterator II,
+ RegScavenger *RS,
+ const TargetRegisterClass *RC,
+ int SPAdj) {
+ assert(RS && "Register scavenging must be on");
+ unsigned Reg = RS->FindUnusedReg(RC, true);
+ if (Reg == 0)
+ Reg = RS->scavengeRegister(RC, II, SPAdj);
+ return Reg;
+}
+
+void BlackfinRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
+ int SPAdj,
+ RegScavenger *RS) const {
+ unsigned i;
+ MachineInstr &MI = *II;
+ MachineBasicBlock &MBB = *MI.getParent();
+ MachineFunction &MF = *MBB.getParent();
+ DebugLoc DL = MI.getDebugLoc();
+
+ for (i=0; !MI.getOperand(i).isFI(); i++) {
+ assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!");
+ }
+ int FrameIndex = MI.getOperand(i).getIndex();
+ assert(i+1 < MI.getNumOperands() && MI.getOperand(i+1).isImm());
+ int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex)
+ + MI.getOperand(i+1).getImm();
+ unsigned BaseReg = BF::FP;
+ if (hasFP(MF)) {
+ assert(SPAdj==0);
+ } else {
+ BaseReg = BF::SP;
+ Offset += MF.getFrameInfo()->getStackSize() + SPAdj;
+ }
+
+ bool isStore = false;
+
+ switch (MI.getOpcode()) {
+ case BF::STORE32fi:
+ isStore = true;
+ case BF::LOAD32fi: {
+ assert(Offset%4 == 0 && "Badly aligned i32 stack access");
+ assert(i==1);
+ MI.getOperand(i).ChangeToRegister(BaseReg, false);
+ MI.getOperand(i+1).setImm(Offset);
+ if (isUimm<6>(Offset)) {
+ MI.setDesc(TII.get(isStore
+ ? BF::STORE32p_uimm6m4
+ : BF::LOAD32p_uimm6m4));
+ return;
+ }
+ if (BaseReg == BF::FP && isUimm<7>(-Offset)) {
+ MI.setDesc(TII.get(isStore
+ ? BF::STORE32fp_nimm7m4
+ : BF::LOAD32fp_nimm7m4));
+ MI.getOperand(i+1).setImm(-Offset);
+ return;
+ }
+ if (isImm<18>(Offset)) {
+ MI.setDesc(TII.get(isStore
+ ? BF::STORE32p_imm18m4
+ : BF::LOAD32p_imm18m4));
+ return;
+ }
+ // Use RegScavenger to calculate proper offset...
+ MI.dump();
+ llvm_unreachable("Stack frame offset too big");
+ break;
+ }
+ case BF::ADDpp: {
+ assert(MI.getOperand(0).isReg());
+ unsigned DestReg = MI.getOperand(0).getReg();
+ // We need to produce a stack offset in a P register. We emit:
+ // P0 = offset;
+ // P0 = BR + P0;
+ assert(i==1);
+ loadConstant(MBB, II, DL, DestReg, Offset);
+ MI.getOperand(1).ChangeToRegister(DestReg, false, false, true);
+ MI.getOperand(2).ChangeToRegister(BaseReg, false);
+ break;
+ }
+ case BF::STORE16fi:
+ isStore = true;
+ case BF::LOAD16fi: {
+ assert(Offset%2 == 0 && "Badly aligned i16 stack access");
+ assert(i==1);
+ // We need a P register to use as an address
+ unsigned ScratchReg = findScratchRegister(II, RS, &BF::PRegClass, SPAdj);
+ assert(ScratchReg);
+ loadConstant(MBB, II, DL, ScratchReg, Offset);
+ BuildMI(MBB, II, DL, TII.get(BF::ADDpp), ScratchReg)
+ .addReg(ScratchReg, RegState::Kill)
+ .addReg(BaseReg);
+ MI.setDesc(TII.get(isStore ? BF::STORE16pi : BF::LOAD16pi));
+ MI.getOperand(1).ChangeToRegister(ScratchReg, false, false, true);
+ MI.RemoveOperand(2);
+ break;
+ }
+ case BF::STORE8fi: {
+ // This is an AnyCC spill, we need a scratch register.
+ assert(i==1);
+ MachineOperand SpillReg = MI.getOperand(0);
+ unsigned ScratchReg = findScratchRegister(II, RS, &BF::DRegClass, SPAdj);
+ assert(ScratchReg);
+ if (SpillReg.getReg()==BF::NCC) {
+ BuildMI(MBB, II, DL, TII.get(BF::MOVENCC_z), ScratchReg)
+ .addOperand(SpillReg);
+ BuildMI(MBB, II, DL, TII.get(BF::BITTGL), ScratchReg)
+ .addReg(ScratchReg).addImm(0);
+ } else {
+ BuildMI(MBB, II, DL, TII.get(BF::MOVECC_zext), ScratchReg)
+ .addOperand(SpillReg);
+ }
+ // STORE D
+ MI.setDesc(TII.get(BF::STORE8p_imm16));
+ MI.getOperand(0).ChangeToRegister(ScratchReg, false, false, true);
+ MI.getOperand(i).ChangeToRegister(BaseReg, false);
+ MI.getOperand(i+1).setImm(Offset);
+ break;
+ }
+ case BF::LOAD8fi: {
+ // This is an restore, we need a scratch register.
+ assert(i==1);
+ MachineOperand SpillReg = MI.getOperand(0);
+ unsigned ScratchReg = findScratchRegister(II, RS, &BF::DRegClass, SPAdj);
+ assert(ScratchReg);
+ MI.setDesc(TII.get(BF::LOAD32p_imm16_8z));
+ MI.getOperand(0).ChangeToRegister(ScratchReg, true);
+ MI.getOperand(i).ChangeToRegister(BaseReg, false);
+ MI.getOperand(i+1).setImm(Offset);
+ ++II;
+ if (SpillReg.getReg()==BF::CC) {
+ // CC = D
+ BuildMI(MBB, II, DL, TII.get(BF::MOVECC_nz), BF::CC)
+ .addReg(ScratchReg, RegState::Kill);
+ } else {
+ // Restore NCC (CC = D==0)
+ BuildMI(MBB, II, DL, TII.get(BF::SETEQri_not), BF::NCC)
+ .addReg(ScratchReg, RegState::Kill)
+ .addImm(0);
+ }
+ break;
+ }
+ default:
+ llvm_unreachable("Cannot eliminate frame index");
+ break;
+ }
+}
+
+void BlackfinRegisterInfo::
+processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
+ RegScavenger *RS) const {
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+ const TargetRegisterClass *RC = BF::DPRegisterClass;
+ if (requiresRegisterScavenging(MF)) {
+ // Reserve a slot close to SP or frame pointer.
+ RS->setScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(),
+ RC->getAlignment()));
+ }
+}
+
+void BlackfinRegisterInfo::
+processFunctionBeforeFrameFinalized(MachineFunction &MF) const {
+}
+
+// Emit a prologue that sets up a stack frame.
+// On function entry, R0-R2 and P0 may hold arguments.
+// R3, P1, and P2 may be used as scratch registers
+void BlackfinRegisterInfo::emitPrologue(MachineFunction &MF) const {
+ MachineBasicBlock &MBB = MF.front(); // Prolog goes in entry BB
+ MachineBasicBlock::iterator MBBI = MBB.begin();
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+ DebugLoc dl = (MBBI != MBB.end()
+ ? MBBI->getDebugLoc()
+ : DebugLoc::getUnknownLoc());
+
+ int FrameSize = MFI->getStackSize();
+ if (FrameSize%4) {
+ FrameSize = (FrameSize+3) & ~3;
+ MFI->setStackSize(FrameSize);
+ }
+
+ if (!hasFP(MF)) {
+ // So far we only support FP elimination on leaf functions
+ assert(!MFI->hasCalls());
+ adjustRegister(MBB, MBBI, dl, BF::SP, BF::P1, -FrameSize);
+ return;
+ }
+
+ // emit a LINK instruction
+ if (FrameSize <= 0x3ffff) {
+ BuildMI(MBB, MBBI, dl, TII.get(BF::LINK)).addImm(FrameSize);
+ return;
+ }
+
+ // Frame is too big, do a manual LINK:
+ // [--SP] = RETS;
+ // [--SP] = FP;
+ // FP = SP;
+ // P1 = -FrameSize;
+ // SP = SP + P1;
+ BuildMI(MBB, MBBI, dl, TII.get(BF::PUSH))
+ .addReg(BF::RETS, RegState::Kill);
+ BuildMI(MBB, MBBI, dl, TII.get(BF::PUSH))
+ .addReg(BF::FP, RegState::Kill);
+ BuildMI(MBB, MBBI, dl, TII.get(BF::MOVE), BF::FP)
+ .addReg(BF::SP);
+ loadConstant(MBB, MBBI, dl, BF::P1, -FrameSize);
+ BuildMI(MBB, MBBI, dl, TII.get(BF::ADDpp), BF::SP)
+ .addReg(BF::SP, RegState::Kill)
+ .addReg(BF::P1, RegState::Kill);
+
+}
+
+void BlackfinRegisterInfo::emitEpilogue(MachineFunction &MF,
+ MachineBasicBlock &MBB) const {
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+ MachineBasicBlock::iterator MBBI = prior(MBB.end());
+ DebugLoc dl = MBBI->getDebugLoc();
+
+ int FrameSize = MFI->getStackSize();
+ assert(FrameSize%4 == 0 && "Misaligned frame size");
+
+ if (!hasFP(MF)) {
+ // So far we only support FP elimination on leaf functions
+ assert(!MFI->hasCalls());
+ adjustRegister(MBB, MBBI, dl, BF::SP, BF::P1, FrameSize);
+ return;
+ }
+
+ // emit an UNLINK instruction
+ BuildMI(MBB, MBBI, dl, TII.get(BF::UNLINK));
+}
+
+unsigned BlackfinRegisterInfo::getRARegister() const {
+ return BF::RETS;
+}
+
+unsigned BlackfinRegisterInfo::getFrameRegister(MachineFunction &MF) const {
+ return hasFP(MF) ? BF::FP : BF::SP;
+}
+
+int
+BlackfinRegisterInfo::getFrameIndexOffset(MachineFunction &MF, int FI) const {
+ const TargetFrameInfo &TFI = *MF.getTarget().getFrameInfo();
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+ return MFI->getObjectOffset(FI) + MFI->getStackSize() -
+ TFI.getOffsetOfLocalArea() + MFI->getOffsetAdjustment();
+}
+
+unsigned BlackfinRegisterInfo::getEHExceptionRegister() const {
+ llvm_unreachable("What is the exception register");
+ return 0;
+}
+
+unsigned BlackfinRegisterInfo::getEHHandlerRegister() const {
+ llvm_unreachable("What is the exception handler register");
+ return 0;
+}
+
+int BlackfinRegisterInfo::getDwarfRegNum(unsigned RegNum, bool isEH) const {
+ llvm_unreachable("What is the dwarf register number");
+ return -1;
+}
+
+#include "BlackfinGenRegisterInfo.inc"
+
diff --git a/lib/Target/Blackfin/BlackfinRegisterInfo.h b/lib/Target/Blackfin/BlackfinRegisterInfo.h
new file mode 100644
index 0000000000..8af65a3ef8
--- /dev/null
+++ b/lib/Target/Blackfin/BlackfinRegisterInfo.h
@@ -0,0 +1,114 @@
+//===- BlackfinRegisterInfo.h - Blackfin Register Information ..-*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the Blackfin implementation of the TargetRegisterInfo
+// class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BLACKFINREGISTERINFO_H
+#define BLACKFINREGISTERINFO_H
+
+#include "llvm/Target/TargetRegisterInfo.h"
+#include "BlackfinGenRegisterInfo.h.inc"
+
+namespace llvm {
+
+ class BlackfinSubtarget;
+ class TargetInstrInfo;
+ class Type;
+
+ template<unsigned N>
+ static inline bool isImm(int x) {
+ return x >= -(1<<(N-1)) && x < (1<<(N-1));
+ }
+
+ template<unsigned N>
+ static inline bool isUimm(unsigned x) {
+ return x < (1<<N);
+ }
+
+ // Subregister indices, keep in sync with BlackfinRegisterInfo.td
+ enum BfinSubregIdx {
+ bfin_subreg_lo16 = 1,
+ bfin_subreg_hi16 = 2,
+ bfin_subreg_lo32 = 3
+ };
+
+ struct BlackfinRegisterInfo : public BlackfinGenRegisterInfo {
+ BlackfinSubtarget &Subtarget;
+ const TargetInstrInfo &TII;
+
+ BlackfinRegisterInfo(BlackfinSubtarget &st, const TargetInstrInfo &tii);
+
+ /// Code Generation virtual methods...
+ const unsigned *getCalleeSavedRegs(const MachineFunction *MF = 0) const;
+
+ const TargetRegisterClass* const*
+ getCalleeSavedRegClasses(const MachineFunction *MF = 0) const;
+
+ BitVector getReservedRegs(const MachineFunction &MF) const;
+
+ // getSubReg implemented by tablegen
+
+ const TargetRegisterClass *getPointerRegClass(unsigned Kind = 0) const {
+ return &BF::PRegClass;
+ }
+
+ const TargetRegisterClass *getPhysicalRegisterRegClass(unsigned reg,
+ MVT VT) const;
+
+ bool hasFP(const MachineFunction &MF) const;
+
+ // bool hasReservedCallFrame(MachineFunction &MF) const;
+
+ bool requiresRegisterScavenging(const MachineFunction &MF) const;
+
+ void eliminateCallFramePseudoInstr(MachineFunction &MF,
+ MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I) const;
+
+ void eliminateFrameIndex(MachineBasicBlock::iterator II,
+ int SPAdj, RegScavenger *RS = NULL) const;
+
+ void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
+ RegScavenger *RS) const;
+
+ void processFunctionBeforeFrameFinalized(MachineFunction &MF) const;
+
+ void emitPrologue(MachineFunction &MF) const;
+ void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const;
+
+ unsigned getFrameRegister(MachineFunction &MF) const;
+ int getFrameIndexOffset(MachineFunction &MF, int FI) const;
+ unsigned getRARegister() const;
+
+ // Exception handling queries.
+ unsigned getEHExceptionRegister() const;
+ unsigned getEHHandlerRegister() const;
+
+ int getDwarfRegNum(unsigned RegNum, bool isEH) const;
+
+ // Utility functions
+ void adjustRegister(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ DebugLoc DL,
+ unsigned Reg,
+ unsigned ScratchReg,
+ int delta) const;
+ void loadConstant(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ DebugLoc DL,
+ unsigned Reg,
+ int value) const;
+ };
+
+} // end namespace llvm
+
+#endif
diff --git a/lib/Target/Blackfin/BlackfinRegisterInfo.td b/lib/Target/Blackfin/BlackfinRegisterInfo.td
new file mode 100644
index 0000000000..2b06fe3496
--- /dev/null
+++ b/lib/Target/Blackfin/BlackfinRegisterInfo.td
@@ -0,0 +1,380 @@
+//===- BlackfinRegisterInfo.td - Blackfin Register defs ----*- tablegen -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Declarations that describe the Blackfin register file
+//===----------------------------------------------------------------------===//
+
+// Registers are identified with 3-bit group and 3-bit ID numbers.
+
+class BlackfinReg<string n> : Register<n> {
+ field bits<3> Group;
+ field bits<3> Num;
+ let Namespace = "BF";
+}
+
+// Rc - 1-bit registers
+class Rc<bits<5> bitno, string n> : BlackfinReg<n> {
+ field bits<5> BitNum = bitno;
+}
+
+// Rs - 16-bit integer registers
+class Rs<bits<3> group, bits<3> num, bits<1> hi, string n> : BlackfinReg<n> {
+ let Group = group;
+ let Num = num;
+ field bits<1> High = hi;
+}
+
+// Ri - 32-bit integer registers with subregs
+class Ri<bits<3> group, bits<3> num, string n> : BlackfinReg<n> {
+ let Group = group;
+ let Num = num;
+}
+
+// Ra 40-bit accumulator registers
+class Ra<bits<3> num, string n, list<Register> subs> : BlackfinReg<n> {
+ let SubRegs = subs;
+ let Group = 4;
+ let Num = num;
+}
+
+// Ywo halves of 32-bit register
+multiclass Rss<bits<3> group, bits<3> num, string n> {
+ def H : Rs<group, num, 1, !strconcat(n, ".h")>;
+ def L : Rs<group, num, 0, !strconcat(n, ".l")>;
+}
+
+// Rii - 32-bit integer registers with subregs
+class Rii<bits<3> group, bits<3> num, string n, list<Register> subs>
+ : BlackfinReg<n> {
+ let SubRegs = subs;
+ let Group = group;
+ let Num = num;
+}
+
+// Status bits are all part of ASTAT
+def AZ : Rc<0, "az">;
+def AN : Rc<1, "an">;
+def CC : Rc<5, "cc">, DwarfRegNum<[34]>;
+def NCC : Rc<5, "!cc"> { let Aliases = [CC]; }
+def AQ : Rc<6, "aq">;
+def AC0 : Rc<12, "ac0">;
+def AC1 : Rc<13, "ac1">;
+def AV0 : Rc<16, "av0">;
+def AV0S : Rc<17, "av0s">;
+def AV1 : Rc<18, "av1">;
+def AV1S : Rc<19, "av1s">;
+def V : Rc<24, "v">;
+def VS : Rc<25, "vs">;
+// Skipped non-status bits: AC0_COPY, V_COPY, RND_MOD
+
+// Group 0: Integer registers
+defm R0 : Rss<0, 0, "r0">;
+def R0 : Rii<0, 0, "r0", [R0H, R0L]>, DwarfRegNum<[0]>;
+defm R1 : Rss<0, 1, "r1">;
+def R1 : Rii<0, 1, "r1", [R1H, R1L]>, DwarfRegNum<[1]>;
+defm R2 : Rss<0, 2, "r2">;
+def R2 : Rii<0, 2, "r2", [R2H, R2L]>, DwarfRegNum<[2]>;
+defm R3 : Rss<0, 3, "r3">;
+def R3 : Rii<0, 3, "r3", [R3H, R3L]>, DwarfRegNum<[3]>;
+defm R4 : Rss<0, 4, "r4">;
+def R4 : Rii<0, 4, "r4", [R4H, R4L]>, DwarfRegNum<[4]>;
+defm R5 : Rss<0, 5, "r5">;
+def R5 : Rii<0, 5, "r5", [R5H, R5L]>, DwarfRegNum<[5]>;
+defm R6 : Rss<0, 6, "r6">;
+def R6 : Rii<0, 6, "r6", [R6H, R6L]>, DwarfRegNum<[6]>;
+defm R7 : Rss<0, 7, "r7">;
+def R7 : Rii<0, 7, "r7", [R7H, R7L]>, DwarfRegNum<[7]>;
+
+// Group 1: Pointer registers
+defm P0 : Rss<1, 0, "p0">;
+def P0 : Rii<1, 0, "p0", [P0H, P0L]>, DwarfRegNum<[8]>;
+defm P1 : Rss<1, 1, "p1">;
+def P1 : Rii<1, 1, "p1", [P1H, P1L]>, DwarfRegNum<[9]>;
+defm P2 : Rss<1, 2, "p2">;
+def P2 : Rii<1, 2, "p2", [P2H, P2L]>, DwarfRegNum<[10]>;
+defm P3 : Rss<1, 3, "p3">;
+def P3 : Rii<1, 3, "p3", [P3H, P3L]>, DwarfRegNum<[11]>;
+defm P4 : Rss<1, 4, "p4">;
+def P4 : Rii<1, 4, "p4", [P4H, P4L]>, DwarfRegNum<[12]>;
+defm P5 : Rss<1, 5, "p5">;
+def P5 : Rii<1, 5, "p5", [P5H, P5L]>, DwarfRegNum<[13]>;
+defm SP : Rss<1, 6, "sp">;
+def SP : Rii<1, 6, "sp", [SPH, SPL]>, DwarfRegNum<[14]>;
+defm FP : Rss<1, 7, "fp">;
+def FP : Rii<1, 7, "fp", [FPH, FPL]>, DwarfRegNum<[15]>;
+
+// Group 2: Index registers
+defm I0 : Rss<2, 0, "i0">;
+def I0 : Rii<2, 0, "i0", [I0H, I0L]>, DwarfRegNum<[16]>;
+defm I1 : Rss<2, 1, "i1">;
+def I1 : Rii<2, 1, "i1", [I1H, I1L]>, DwarfRegNum<[17]>;
+defm I2 : Rss<2, 2, "i2">;
+def I2 : Rii<2, 2, "i2", [I2H, I2L]>, DwarfRegNum<[18]>;
+defm I3 : Rss<2, 3, "i3">;
+def I3 : Rii<2, 3, "i3", [I3H, I3L]>, DwarfRegNum<[19]>;
+defm M0 : Rss<2, 4, "m0">;
+def M0 : Rii<2, 4, "m0", [M0H, M0L]>, DwarfRegNum<[20]>;
+defm M1 : Rss<2, 5, "m1">;
+def M1 : Rii<2, 5, "m1", [M1H, M1L]>, DwarfRegNum<[21]>;
+defm M2 : Rss<2, 6, "m2">;
+def M2 : Rii<2, 6, "m2", [M2H, M2L]>, DwarfRegNum<[22]>;
+defm M3 : Rss<2, 7, "m3">;
+def M3 : Rii<2, 7, "m3", [M3H, M3L]>, DwarfRegNum<[23]>;
+
+// Group 3: Cyclic indexing registers
+defm B0 : Rss<3, 0, "b0">;
+def B0 : Rii<3, 0, "b0", [B0H, B0L]>, DwarfRegNum<[24]>;
+defm B1 : Rss<3, 1, "b1">;
+def B1 : Rii<3, 1, "b1", [B1H, B1L]>, DwarfRegNum<[25]>;
+defm B2 : Rss<3, 2, "b2">;
+def B2 : Rii<3, 2, "b2", [B2H, B2L]>, DwarfRegNum<[26]>;
+defm B3 : Rss<3, 3, "b3">;
+def B3 : Rii<3, 3, "b3", [B3H, B3L]>, DwarfRegNum<[27]>;
+defm L0 : Rss<3, 4, "l0">;
+def L0 : Rii<3, 4, "l0", [L0H, L0L]>, DwarfRegNum<[28]>;
+defm L1 : Rss<3, 5, "l1">;
+def L1 : Rii<3, 5, "l1", [L1H, L1L]>, DwarfRegNum<[29]>;
+defm L2 : Rss<3, 6, "l2">;
+def L2 : Rii<3, 6, "l2", [L2H, L2L]>, DwarfRegNum<[30]>;
+defm L3 : Rss<3, 7, "l3">;
+def L3 : Rii<3, 7, "l3", [L3H, L3L]>, DwarfRegNum<[31]>;
+
+// Accumulators
+def A0X : Ri <4, 0, "a0.x">;
+defm A0 : Rss<4, 1, "a0">;
+def A0W : Rii<4, 1, "a0.w", [A0H, A0L]>, DwarfRegNum<[32]>;
+def A0 : Ra <0, "a0", [A0X, A0W]>;
+
+def A1X : Ri <4, 2, "a1.x">;
+defm A1 : Rss<4, 3, "a1">;
+def A1W : Rii<4, 3, "a1.w", [A1H, A1L]>, DwarfRegNum<[33]>;
+def A1 : Ra <2, "a1", [A1X, A1W]>;
+
+def RETS : Ri<4, 7, "rets">, DwarfRegNum<[35]>;
+def RETI : Ri<7, 3, "reti">, DwarfRegNum<[36]>;
+def RETX : Ri<7, 4, "retx">, DwarfRegNum<[37]>;
+def RETN : Ri<7, 5, "retn">, DwarfRegNum<[38]>;
+def RETE : Ri<7, 6, "rete">, DwarfRegNum<[39]>;
+
+def ASTAT : Ri<4, 6, "astat">, DwarfRegNum<[40]> {
+ let SubRegs = [AZ, AN, CC, NCC, AQ, AC0, AC1, AV0, AV0S, AV1, AV1S, V, VS];
+}
+
+def SEQSTAT : Ri<7, 1, "seqstat">, DwarfRegNum<[41]>;
+def USP : Ri<7, 0, "usp">, DwarfRegNum<[42]>;
+def EMUDAT : Ri<7, 7, "emudat">, DwarfRegNum<[43]>;
+def SYSCFG : Ri<7, 2, "syscfg">;
+def CYCLES : Ri<6, 6, "cycles">;
+def CYCLES2 : Ri<6, 7, "cycles2">;
+
+// Hardware loops
+def LT0 : Ri<6, 1, "lt0">, DwarfRegNum<[44]>;
+def LT1 : Ri<6, 4, "lt1">, DwarfRegNum<[45]>;
+def LC0 : Ri<6, 0, "lc0">, DwarfRegNum<[46]>;
+def LC1 : Ri<6, 3, "lc1">, DwarfRegNum<[47]>;
+def LB0 : Ri<6, 2, "lb0">, DwarfRegNum<[48]>;
+def LB1 : Ri<6, 5, "lb1">, DwarfRegNum<[49]>;
+
+// Subregs are:
+// 1: .L
+// 2: .H
+// 3: .W (32 low bits of 40-bit accu)
+// Keep in sync with enum in BlackfinRegisterInfo.h
+def bfin_subreg_lo16 : PatLeaf<(i32 1)>;
+def bfin_subreg_hi16 : PatLeaf<(i32 2)>;
+def bfin_subreg_32bit : PatLeaf<(i32 3)>;
+
+def : SubRegSet<1,
+ [R0, R1, R2, R3, R4, R5, R6, R7,
+ P0, P1, P2, P3, P4, P5, SP, FP,
+ I0, I1, I2, I3, M0, M1, M2, M3,
+ B0, B1, B2, B3, L0, L1, L2, L3],
+ [R0L, R1L, R2L, R3L, R4L, R5L, R6L, R7L,
+ P0L, P1L, P2L, P3L, P4L, P5L, SPL, FPL,
+ I0L, I1L, I2L, I3L, M0L, M1L, M2L, M3L,
+ B0L, B1L, B2L, B3L, L0L, L1L, L2L, L3L]>;
+
+def : SubRegSet<2,
+ [R0, R1, R2, R3, R4, R5, R6, R7,
+ P0, P1, P2, P3, P4, P5, SP, FP,
+ I0, I1, I2, I3, M0, M1, M2, M3,
+ B0, B1, B2, B3, L0, L1, L2, L3],
+ [R0H, R1H, R2H, R3H, R4H, R5H, R6H, R7H,
+ P0H, P1H, P2H, P3H, P4H, P5H, SPH, FPH,
+ I0H, I1H, I2H, I3H, M0H, M1H, M2H, M3H,
+ B0H, B1H, B2H, B3H, L0H, L1H, L2H, L3H]>;
+
+def : SubRegSet<1, [A0, A0W, A1, A1W], [A0L, A0L, A1L, A1L]>;
+def : SubRegSet<2, [A0, A0W, A1, A1W], [A0H, A0H, A1H, A1H]>;
+
+// Register classes.
+def D16 : RegisterClass<"BF", [i16], 16,
+ [R0H, R0L, R1H, R1L, R2H, R2L, R3H, R3L,
+ R4H, R4L, R5H, R5L, R6H, R6L, R7H, R7L]>;
+
+def D16L : RegisterClass<"BF", [i16], 16,
+ [R0L, R1L, R2L, R3L, R4L, R5L, R6L, R7L]>;
+
+def D16H : RegisterClass<"BF", [i16], 16,
+ [R0H, R1H, R2H, R3H, R4H, R5H, R6H, R7H]>;
+
+def P16 : RegisterClass<"BF", [i16], 16,
+ [P0H, P0L, P1H, P1L, P2H, P2L, P3H, P3L,
+ P4H, P4L, P5H, P5L, SPH, SPL, FPH, FPL]>;
+
+def P16L : RegisterClass<"BF", [i16], 16,
+ [P0L, P1L, P2L, P3L, P4L, P5L, SPL, FPL]>;
+
+def P16H : RegisterClass<"BF", [i16], 16,
+ [P0H, P1H, P2H, P3H, P4H, P5H, SPH, FPH]>;
+
+def DP16 : RegisterClass<"BF", [i16], 16,
+ [R0H, R0L, R1H, R1L, R2H, R2L, R3H, R3L,
+ R4H, R4L, R5H, R5L, R6H, R6L, R7H, R7L,
+ P0H, P0L, P1H, P1L, P2H, P2L, P3H, P3L,
+ P4H, P4L, P5H, P5L, SPH, SPL, FPH, FPL]>;
+
+def DP16L : RegisterClass<"BF", [i16], 16,
+ [R0L, R1L, R2L, R3L, R4L, R5L, R6L, R7L,
+ P0L, P1L, P2L, P3L, P4L, P5L, SPL, FPL]>;
+
+def DP16H : RegisterClass<"BF", [i16], 16,
+ [R0H, R1H, R2H, R3H, R4H, R5H, R6H, R7H,
+ P0H, P1H, P2H, P3H, P4H, P5H, SPH, FPH]>;
+
+def GR16 : RegisterClass<"BF", [i16], 16,
+ [R0H, R0L, R1H, R1L, R2H, R2L, R3H, R3L,
+ R4H, R4L, R5H, R5L, R6H, R6L, R7H, R7L,
+ P0H, P0L, P1H, P1L, P2H, P2L, P3H, P3L,
+ P4H, P4L, P5H, P5L, SPH, SPL, FPH, FPL,
+ I0H, I0L, I1H, I1L, I2H, I2L, I3H, I3L,
+ M0H, M0L, M1H, M1L, M2H, M2L, M3H, M3L,
+ B0H, B0L, B1H, B1L, B2H, B2L, B3H, B3L,
+ L0H, L0L, L1H, L1L, L2H, L2L, L3H, L3L]>;
+
+def D : RegisterClass<"BF", [i32], 32, [R0, R1, R2, R3, R4, R5, R6, R7]> {
+ let SubRegClassList = [D16L, D16H];
+}
+
+def P : RegisterClass<"BF", [i32], 32, [P0, P1, P2, P3, P4, P5, FP, SP]> {
+ let SubRegClassList = [P16L, P16H];
+ let MethodProtos = [{
+ iterator allocation_order_end(const MachineFunction &MF) const;
+ }];
+ let MethodBodies = [{
+ PClass::iterator
+ PClass::allocation_order_end(const MachineFunction &MF) const {
+ const TargetMachine &TM = MF.getTarget();
+ const TargetRegisterInfo *RI = TM.getRegisterInfo();
+ return allocation_order_begin(MF)
+ + (RI->hasFP(MF) ? 7 : 6);
+ }
+ }];
+}
+
+def I : RegisterClass<"BF", [i32], 32, [I0, I1, I2, I3]>;
+def M : RegisterClass<"BF", [i32], 32, [M0, M1, M2, M3]>;
+
+def DP : RegisterClass<"BF", [i32], 32,
+ [R0, R1, R2, R3, R4, R5, R6, R7,
+ P0, P1, P2, P3, P4, P5, FP, SP]> {
+ let SubRegClassList = [DP16L, DP16H];
+ let MethodProtos = [{
+ iterator allocation_order_end(const MachineFunction &MF) const;
+ }];
+ let MethodBodies = [{
+ DPClass::iterator
+ DPClass::allocation_order_end(const MachineFunction &MF) const {
+ const TargetMachine &TM = MF.getTarget();
+ const TargetRegisterInfo *RI = TM.getRegisterInfo();
+ return allocation_order_begin(MF)
+ + (RI->hasFP(MF) ? 15 : 14);
+ }
+ }];
+}
+
+def GR : RegisterClass<"BF", [i32], 32,
+ [R0, R1, R2, R3, R4, R5, R6, R7,
+ P0, P1, P2, P3, P4, P5,
+ I0, I1, I2, I3, M0, M1, M2, M3,
+ B0, B1, B2, B3, L0, L1, L2, L3,
+ FP, SP]> {
+ let MethodProtos = [{
+ iterator allocation_order_end(const MachineFunction &MF) const;
+ }];
+ let MethodBodies = [{
+ GRClass::iterator
+ GRClass::allocation_order_end(const MachineFunction &MF) const {
+ const TargetMachine &TM = MF.getTarget();
+ const TargetRegisterInfo *RI = TM.getRegisterInfo();
+ return allocation_order_begin(MF)
+ + (RI->hasFP(MF) ? 31 : 30);
+ }
+ }];
+}
+
+def ALL : RegisterClass<"BF", [i32], 32,
+ [R0, R1, R2, R3, R4, R5, R6, R7,
+ P0, P1, P2, P3, P4, P5,
+ I0, I1, I2, I3, M0, M1, M2, M3,
+ B0, B1, B2, B3, L0, L1, L2, L3,
+ FP, SP,
+ A0X, A0W, A1X, A1W, ASTAT, RETS,
+ LC0, LT0, LB0, LC1, LT1, LB1, CYCLES, CYCLES2,
+ USP, SEQSTAT, SYSCFG, RETI, RETX, RETN, RETE, EMUDAT]> {
+ let MethodProtos = [{
+ iterator allocation_order_end(const MachineFunction &MF) const;
+ }];
+ let MethodBodies = [{
+ ALLClass::iterator
+ ALLClass::allocation_order_end(const MachineFunction &MF) const {
+ const TargetMachine &TM = MF.getTarget();
+ const TargetRegisterInfo *RI = TM.getRegisterInfo();
+ return allocation_order_begin(MF)
+ + (RI->hasFP(MF) ? 31 : 30);
+ }
+ }];
+}
+
+def PI : RegisterClass<"BF", [i32], 32,
+ [P0, P1, P2, P3, P4, P5, I0, I1, I2, I3, FP, SP]> {
+ let MethodProtos = [{
+ iterator allocation_order_end(const MachineFunction &MF) const;
+ }];
+ let MethodBodies = [{
+ PIClass::iterator
+ PIClass::allocation_order_end(const MachineFunction &MF) const {
+ const TargetMachine &TM = MF.getTarget();
+ const TargetRegisterInfo *RI = TM.getRegisterInfo();
+ return allocation_order_begin(MF)
+ + (RI->hasFP(MF) ? 11 : 10);
+ }
+ }];
+}
+
+// We are going to pretend that CC and !CC are 32-bit registers, even though
+// they only can hold 1 bit.
+let CopyCost = -1, Size = 8 in {
+def JustCC : RegisterClass<"BF", [i32], 8, [CC]>;
+def NotCC : RegisterClass<"BF", [i32], 8, [NCC]>;
+def AnyCC : RegisterClass<"BF", [i32], 8, [CC, NCC]> {
+ let MethodProtos = [{
+ iterator allocation_order_end(const MachineFunction &MF) const;
+ }];
+ let MethodBodies = [{
+ AnyCCClass::iterator
+ AnyCCClass::allocation_order_end(const MachineFunction &MF) const {
+ return allocation_order_begin(MF)+1;
+ }
+ }];
+}
+def StatBit : RegisterClass<"BF", [i1], 8,
+ [AZ, AN, CC, AQ, AC0, AC1, AV0, AV0S, AV1, AV1S, V, VS]>;
+}
diff --git a/lib/Target/Blackfin/BlackfinSubtarget.cpp b/lib/Target/Blackfin/BlackfinSubtarget.cpp
new file mode 100644
index 0000000000..cf14b105aa
--- /dev/null
+++ b/lib/Target/Blackfin/BlackfinSubtarget.cpp
@@ -0,0 +1,26 @@
+//===- BlackfinSubtarget.cpp - BLACKFIN Subtarget Information -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the blackfin specific subclass of TargetSubtarget.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BlackfinSubtarget.h"
+#include "BlackfinGenSubtarget.inc"
+
+using namespace llvm;
+
+BlackfinSubtarget::BlackfinSubtarget(const TargetMachine &TM,
+ const Module &M,
+ const std::string &FS) {
+ std::string CPU = "generic";
+
+ // Parse features string.
+ ParseSubtargetFeatures(FS, CPU);
+}
diff --git a/lib/Target/Blackfin/BlackfinSubtarget.h b/lib/Target/Blackfin/BlackfinSubtarget.h
new file mode 100644
index 0000000000..31df9c0fee
--- /dev/null
+++ b/lib/Target/Blackfin/BlackfinSubtarget.h
@@ -0,0 +1,39 @@
+//===- BlackfinSubtarget.h - Define Subtarget for the Blackfin -*- C++ -*-====//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the BLACKFIN specific subclass of TargetSubtarget.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BLACKFIN_SUBTARGET_H
+#define BLACKFIN_SUBTARGET_H
+
+#include "llvm/Target/TargetSubtarget.h"
+#include <string>
+
+namespace llvm {
+
+ class TargetMachine;
+ class Module;
+
+ class BlackfinSubtarget : public TargetSubtarget {
+ bool ssyncWorkaround;
+ public:
+ BlackfinSubtarget(const TargetMachine &TM, const Module &M,
+ const std::string &FS);
+
+ /// ParseSubtargetFeatures - Parses features string setting specified
+ /// subtarget options. Definition of function is auto generated by tblgen.
+ std::string ParseSubtargetFeatures(const std::string &FS,
+ const std::string &CPU);
+ };
+
+} // end namespace llvm
+
+#endif
diff --git a/lib/Target/Blackfin/BlackfinTargetAsmInfo.cpp b/lib/Target/Blackfin/BlackfinTargetAsmInfo.cpp
new file mode 100644
index 0000000000..8dcb44be50
--- /dev/null
+++ b/lib/Target/Blackfin/BlackfinTargetAsmInfo.cpp
@@ -0,0 +1,23 @@
+//===-- BlackfinTargetAsmInfo.cpp - Blackfin asm properties -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the declarations of the BlackfinTargetAsmInfo properties.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BlackfinTargetAsmInfo.h"
+
+using namespace llvm;
+
+BlackfinTargetAsmInfo::BlackfinTargetAsmInfo() {
+ GlobalPrefix = "_";
+ CommentString = "//";
+ InlineAsmStart = "// APP";
+ InlineAsmEnd = "// NO_APP";
+}
diff --git a/lib/Target/Blackfin/BlackfinTargetAsmInfo.h b/lib/Target/Blackfin/BlackfinTargetAsmInfo.h
new file mode 100644
index 0000000000..fa4cd7c373
--- /dev/null
+++ b/lib/Target/Blackfin/BlackfinTargetAsmInfo.h
@@ -0,0 +1,27 @@
+//===-- BlackfinTargetAsmInfo.h - Blackfin asm properties -----*- C++ -*--====//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the declaration of the BlackfinTargetAsmInfo class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BLACKFINTARGETASMINFO_H
+#define BLACKFINTARGETASMINFO_H
+
+#include "llvm/Target/TargetAsmInfo.h"
+
+namespace llvm {
+
+ struct BlackfinTargetAsmInfo : public TargetAsmInfo {
+ explicit BlackfinTargetAsmInfo();
+ };
+
+} // namespace llvm
+
+#endif
diff --git a/lib/Target/Blackfin/BlackfinTargetMachine.cpp b/lib/Target/Blackfin/BlackfinTargetMachine.cpp
new file mode 100644
index 0000000000..059916b200
--- /dev/null
+++ b/lib/Target/Blackfin/BlackfinTargetMachine.cpp
@@ -0,0 +1,54 @@
+//===-- BlackfinTargetMachine.cpp - Define TargetMachine for Blackfin -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//===----------------------------------------------------------------------===//
+
+#include "BlackfinTargetMachine.h"
+#include "Blackfin.h"
+#include "BlackfinTargetAsmInfo.h"
+#include "llvm/Module.h"
+#include "llvm/PassManager.h"
+#include "llvm/Target/TargetRegistry.h"
+
+using namespace llvm;
+
+extern "C" void LLVMInitializeBlackfinTarget() {
+ RegisterTargetMachine<BlackfinTargetMachine> X(TheBlackfinTarget);
+}
+
+const TargetAsmInfo* BlackfinTargetMachine::createTargetAsmInfo() const {
+ return new BlackfinTargetAsmInfo();
+}
+
+BlackfinTargetMachine::BlackfinTargetMachine(const Target &T,
+ const Module &M,
+ const std::string &FS)
+ : LLVMTargetMachine(T),
+ DataLayout("e-p:32:32-i64:32-f64:32"),
+ Subtarget(*this, M, FS),
+ TLInfo(*this),
+ InstrInfo(Subtarget),
+ FrameInfo(TargetFrameInfo::StackGrowsDown, 4, 0) {
+}
+
+unsigned BlackfinTargetMachine::getModuleMatchQuality(const Module &M) {
+ std::string TT = M.getTargetTriple();
+ if (TT.size() >= 5 && std::string(TT.begin(), TT.begin()+5) == "bfin-")
+ return 20;
+
+ // Otherwise we don't match.
+ return 0;
+}
+
+bool BlackfinTargetMachine::addInstSelector(PassManagerBase &PM,
+ CodeGenOpt::Level OptLevel) {
+ PM.add(createBlackfinISelDag(*this, OptLevel));
+ return false;
+}
diff --git a/lib/Target/Blackfin/BlackfinTargetMachine.h b/lib/Target/Blackfin/BlackfinTargetMachine.h
new file mode 100644
index 0000000000..0538c9a1a5
--- /dev/null
+++ b/lib/Target/Blackfin/BlackfinTargetMachine.h
@@ -0,0 +1,61 @@
+//===-- BlackfinTargetMachine.h - TargetMachine for Blackfin ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the Blackfin specific subclass of TargetMachine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BLACKFINTARGETMACHINE_H
+#define BLACKFINTARGETMACHINE_H
+
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetData.h"
+#include "llvm/Target/TargetFrameInfo.h"
+#include "BlackfinInstrInfo.h"
+#include "BlackfinSubtarget.h"
+#include "BlackfinISelLowering.h"
+
+namespace llvm {
+
+ class Module;
+
+ class BlackfinTargetMachine : public LLVMTargetMachine {
+ const TargetData DataLayout;
+ BlackfinSubtarget Subtarget;
+ BlackfinTargetLowering TLInfo;
+ BlackfinInstrInfo InstrInfo;
+ TargetFrameInfo FrameInfo;
+
+ protected:
+ virtual const TargetAsmInfo *createTargetAsmInfo() const;
+
+ public:
+ BlackfinTargetMachine(const Target &T, const Module &M,
+ const std::string &FS);
+
+ virtual const BlackfinInstrInfo *getInstrInfo() const { return &InstrInfo; }
+ virtual const TargetFrameInfo *getFrameInfo() const { return &FrameInfo; }
+ virtual const BlackfinSubtarget *getSubtargetImpl() const {
+ return &Subtarget;
+ }
+ virtual const BlackfinRegisterInfo *getRegisterInfo() const {
+ return &InstrInfo.getRegisterInfo();
+ }
+ virtual BlackfinTargetLowering* getTargetLowering() const {
+ return const_cast<BlackfinTargetLowering*>(&TLInfo);
+ }
+ virtual const TargetData *getTargetData() const { return &DataLayout; }
+ static unsigned getModuleMatchQuality(const Module &M);
+ virtual bool addInstSelector(PassManagerBase &PM,
+ CodeGenOpt::Level OptLevel);
+ };
+
+} // end namespace llvm
+
+#endif
diff --git a/lib/Target/Blackfin/CMakeLists.txt b/lib/Target/Blackfin/CMakeLists.txt
new file mode 100644
index 0000000000..8163fc260c
--- /dev/null
+++ b/lib/Target/Blackfin/CMakeLists.txt
@@ -0,0 +1,21 @@
+set(LLVM_TARGET_DEFINITIONS Blackfin.td)
+
+tablegen(BlackfinGenRegisterInfo.h.inc -gen-register-desc-header)
+tablegen(BlackfinGenRegisterNames.inc -gen-register-enums)
+tablegen(BlackfinGenRegisterInfo.inc -gen-register-desc)
+tablegen(BlackfinGenInstrNames.inc -gen-instr-enums)
+tablegen(BlackfinGenInstrInfo.inc -gen-instr-desc)
+tablegen(BlackfinGenAsmWriter.inc -gen-asm-writer)
+tablegen(BlackfinGenDAGISel.inc -gen-dag-isel)
+tablegen(BlackfinGenSubtarget.inc -gen-subtarget)
+tablegen(BlackfinGenCallingConv.inc -gen-callingconv)
+
+add_llvm_target(BlackfinCodeGen
+ BlackfinInstrInfo.cpp
+ BlackfinISelDAGToDAG.cpp
+ BlackfinISelLowering.cpp
+ BlackfinRegisterInfo.cpp
+ BlackfinSubtarget.cpp
+ BlackfinTargetAsmInfo.cpp
+ BlackfinTargetMachine.cpp
+ )
diff --git a/lib/Target/Blackfin/Makefile b/lib/Target/Blackfin/Makefile
new file mode 100644
index 0000000000..c0c1bce793
--- /dev/null
+++ b/lib/Target/Blackfin/Makefile
@@ -0,0 +1,23 @@
+##===- lib/Target/Blackfin/Makefile ------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+LEVEL = ../../..
+LIBRARYNAME = LLVMBlackfinCodeGen
+TARGET = Blackfin
+
+# Make sure that tblgen is run, first thing.
+BUILT_SOURCES = BlackfinGenRegisterInfo.h.inc BlackfinGenRegisterNames.inc \
+ BlackfinGenRegisterInfo.inc BlackfinGenInstrNames.inc \
+ BlackfinGenInstrInfo.inc BlackfinGenAsmWriter.inc \
+ BlackfinGenDAGISel.inc BlackfinGenSubtarget.inc \
+ BlackfinGenCallingConv.inc
+
+DIRS = AsmPrinter TargetInfo
+
+include $(LEVEL)/Makefile.common
+
diff --git a/lib/Target/Blackfin/README.txt b/lib/Target/Blackfin/README.txt
new file mode 100644
index 0000000000..4631c12f7e
--- /dev/null
+++ b/lib/Target/Blackfin/README.txt
@@ -0,0 +1,122 @@
+//===-- README.txt - Notes for Blackfin Target ------------------*- org -*-===//
+
+* Condition codes
+** DONE Problem with asymmetric SETCC operations
+The instruction
+
+ CC = R0 < 2
+
+is not symmetric - there is no R0 > 2 instruction. On the other hand, IF CC
+JUMP can take both CC and !CC as a condition. We cannot pattern-match (brcond
+(not cc), target), the DAG optimizer removes that kind of thing.
+
+This is handled by creating a pseudo-register NCC that aliases CC. Register
+classes JustCC and NotCC are used to control the inversion of CC.
+
+** DONE CC as an i32 register
+The AnyCC register class pretends to hold i32 values. It can only represent the
+values 0 and 1, but we can copy to and from the D class. This hack makes it
+possible to represent the setcc instruction without having i1 as a legal type.
+
+In most cases, the CC register is set by a "CC = .." or BITTST instruction, and
+then used in a conditional branch or move. The code generator thinks it is
+moving 32 bits, but the value stays in CC. In other cases, the result of a
+comparison is actually used as am i32 number, and CC will be copied to a D
+register.
+
+* Stack frames
+** TODO Use Push/Pop instructions
+We should use the push/pop instructions when saving callee-saved
+registers. The are smaller, and we may even use push multiple instructions.
+
+** TODO requiresRegisterScavenging
+We need more intelligence in determining when the scavenger is needed. We
+should keep track of:
+- Spilling D16 registers
+- Spilling AnyCC registers
+
+* Assembler
+** TODO Implement PrintGlobalVariable
+** TODO Remove LOAD32sym
+It's a hack combining two instructions by concatenation.
+
+* Inline Assembly
+** TODO Support all register classes
+* DAG combiner
+** Create test case for each Illegal SETCC case
+The DAG combiner may someimes produce illegal i16 SETCC instructions.
+
+*** TODO SETCC (ctlz x), 5) == const
+*** TODO SETCC (and load, const) == const
+*** DONE SETCC (zext x) == const
+*** TODO SETCC (sext x) == const
+
+* Instruction selection
+** TODO Better imediate constants
+Like ARM, build constants as small imm + shift.
+
+** TODO Implement cycle counter
+We have CYCLES and CYCLES2 registers, but the readcyclecounter intrinsic wants
+to return i64, and the code generator doesn't know how to legalize that.
+
+** TODO Instruction alternatives
+Some instructions come in different variants for example:
+
+ D = D + D
+ P = P + P
+
+Cross combinations are not allowed:
+
+ P = D + D (bad)
+
+Similarly for the subreg pseudo-instructions:
+
+ D16L = EXTRACT_SUBREG D16, bfin_subreg_lo16
+ P16L = EXTRACT_SUBREG P16, bfin_subreg_lo16
+
+We want to take advantage of the alternative instructions. This could be done by
+changing the DAG after instruction selection.
+
+
+** Multipatterns for load/store
+We should try to identify multipatterns for load and store instructions. The
+available instruction matrix is a bit irregular.
+
+Loads:
+
+| Addr | D | P | D 16z | D 16s | D16 | D 8z | D 8s |
+|------------+---+---+-------+-------+-----+------+------|
+| P | * | * | * | * | * | * | * |
+| P++ | * | * | * | * | | * | * |
+| P-- | * | * | * | * | | * | * |
+| P+uimm5m2 | | | * | * | | | |
+| P+uimm6m4 | * | * | | | | | |
+| P+imm16 | | | | | | * | * |
+| P+imm17m2 | | | * | * | | | |
+| P+imm18m4 | * | * | | | | | |
+| P++P | * | | * | * | * | | |
+| FP-uimm7m4 | * | * | | | | | |
+| I | * | | | | * | | |
+| I++ | * | | | | * | | |
+| I-- | * | | | | * | | |
+| I++M | * | | | | | | |
+
+Stores:
+
+| Addr | D | P | D16H | D16L | D 8 |
+|------------+---+---+------+------+-----|
+| P | * | * | * | * | * |
+| P++ | * | * | | * | * |
+| P-- | * | * | | * | * |
+| P+uimm5m2 | | | | * | |
+| P+uimm6m4 | * | * | | | |
+| P+imm16 | | | | | * |
+| P+imm17m2 | | | | * | |
+| P+imm18m4 | * | * | | | |
+| P++P | * | | * | * | |
+| FP-uimm7m4 | * | * | | | |
+| I | * | | * | * | |
+| I++ | * | | * | * | |
+| I-- | * | | * | * | |
+| I++M | * | | | | |
+
diff --git a/lib/Target/Blackfin/TargetInfo/BlackfinTargetInfo.cpp b/lib/Target/Blackfin/TargetInfo/BlackfinTargetInfo.cpp
new file mode 100644
index 0000000000..402e0afde8
--- /dev/null
+++ b/lib/Target/Blackfin/TargetInfo/BlackfinTargetInfo.cpp
@@ -0,0 +1,21 @@
+//===-- BlackfinTargetInfo.cpp - Blackfin Target Implementation -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Blackfin.h"
+#include "llvm/Module.h"
+#include "llvm/Target/TargetRegistry.h"
+
+using namespace llvm;
+
+Target llvm::TheBlackfinTarget;
+
+extern "C" void LLVMInitializeBlackfinTargetInfo() {
+ RegisterTarget<Triple::bfin> X(TheBlackfinTarget, "bfin",
+ "Analog Devices Blackfin [experimental]");
+}
diff --git a/lib/Target/Blackfin/TargetInfo/CMakeLists.txt b/lib/Target/Blackfin/TargetInfo/CMakeLists.txt
new file mode 100644
index 0000000000..4584eeba55
--- /dev/null
+++ b/lib/Target/Blackfin/TargetInfo/CMakeLists.txt
@@ -0,0 +1,3 @@
+include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. )
+add_llvm_library(LLVMBlackfinInfo BlackfinTargetInfo.cpp)
+add_dependencies(LLVMBlackfinInfo BlackfinCodeGenTable_gen)
diff --git a/lib/Target/Blackfin/TargetInfo/Makefile b/lib/Target/Blackfin/TargetInfo/Makefile
new file mode 100644
index 0000000000..c49cfbe690
--- /dev/null
+++ b/lib/Target/Blackfin/TargetInfo/Makefile
@@ -0,0 +1,15 @@
+##===- lib/Target/Blackfin/TargetInfo/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+LEVEL = ../../../..
+LIBRARYNAME = LLVMBlackfinInfo
+
+# Hack: we need to include 'main' target directory to grab private headers
+CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
+
+include $(LEVEL)/Makefile.common
diff --git a/test/CodeGen/Blackfin/add-overflow.ll b/test/CodeGen/Blackfin/add-overflow.ll
new file mode 100644
index 0000000000..de80783ac6
--- /dev/null
+++ b/test/CodeGen/Blackfin/add-overflow.ll
@@ -0,0 +1,18 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t
+
+ type { i24, i1 } ; type %0
+
+define i1 @func2(i24 zeroext %v1, i24 zeroext %v2) nounwind {
+entry:
+ %t = call %0 @llvm.uadd.with.overflow.i24(i24 %v1, i24 %v2) ; <%0> [#uses=1]
+ %obit = extractvalue %0 %t, 1 ; <i1> [#uses=1]
+ br i1 %obit, label %carry, label %normal
+
+normal: ; preds = %entry
+ ret i1 true
+
+carry: ; preds = %entry
+ ret i1 false
+}
+
+declare %0 @llvm.uadd.with.overflow.i24(i24, i24) nounwind
diff --git a/test/CodeGen/Blackfin/add.ll b/test/CodeGen/Blackfin/add.ll
new file mode 100644
index 0000000000..267f309257
--- /dev/null
+++ b/test/CodeGen/Blackfin/add.ll
@@ -0,0 +1,5 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
+define i32 @add(i32 %A, i32 %B) {
+ %R = add i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R
+}
diff --git a/test/CodeGen/Blackfin/addsub-i128.ll b/test/CodeGen/Blackfin/addsub-i128.ll
new file mode 100644
index 0000000000..8dd04d808a
--- /dev/null
+++ b/test/CodeGen/Blackfin/addsub-i128.ll
@@ -0,0 +1,42 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
+; XFAIL: *
+; Assertion failed: (isUsed(Reg) && "Using an undefined register!"),
+; function forward, file RegisterScavenging.cpp, line 182.
+
+define void @test_add(i64 %AL, i64 %AH, i64 %BL, i64 %BH, i64* %RL, i64* %RH) {
+entry:
+ %tmp1 = zext i64 %AL to i128 ; <i128> [#uses=1]
+ %tmp23 = zext i64 %AH to i128 ; <i128> [#uses=1]
+ %tmp4 = shl i128 %tmp23, 64 ; <i128> [#uses=1]
+ %tmp5 = or i128 %tmp4, %tmp1 ; <i128> [#uses=1]
+ %tmp67 = zext i64 %BL to i128 ; <i128> [#uses=1]
+ %tmp89 = zext i64 %BH to i128 ; <i128> [#uses=1]
+ %tmp11 = shl i128 %tmp89, 64 ; <i128> [#uses=1]
+ %tmp12 = or i128 %tmp11, %tmp67 ; <i128> [#uses=1]
+ %tmp15 = add i128 %tmp12, %tmp5 ; <i128> [#uses=2]
+ %tmp1617 = trunc i128 %tmp15 to i64 ; <i64> [#uses=1]
+ store i64 %tmp1617, i64* %RL
+ %tmp21 = lshr i128 %tmp15, 64 ; <i128> [#uses=1]
+ %tmp2122 = trunc i128 %tmp21 to i64 ; <i64> [#uses=1]
+ store i64 %tmp2122, i64* %RH
+ ret void
+}
+
+define void @test_sub(i64 %AL, i64 %AH, i64 %BL, i64 %BH, i64* %RL, i64* %RH) {
+entry:
+ %tmp1 = zext i64 %AL to i128 ; <i128> [#uses=1]
+ %tmp23 = zext i64 %AH to i128 ; <i128> [#uses=1]
+ %tmp4 = shl i128 %tmp23, 64 ; <i128> [#uses=1]
+ %tmp5 = or i128 %tmp4, %tmp1 ; <i128> [#uses=1]
+ %tmp67 = zext i64 %BL to i128 ; <i128> [#uses=1]
+ %tmp89 = zext i64 %BH to i128 ; <i128> [#uses=1]
+ %tmp11 = shl i128 %tmp89, 64 ; <i128> [#uses=1]
+ %tmp12 = or i128 %tmp11, %tmp67 ; <i128> [#uses=1]
+ %tmp15 = sub i128 %tmp5, %tmp12 ; <i128> [#uses=2]
+ %tmp1617 = trunc i128 %tmp15 to i64 ; <i64> [#uses=1]
+ store i64 %tmp1617, i64* %RL
+ %tmp21 = lshr i128 %tmp15, 64 ; <i128> [#uses=1]
+ %tmp2122 = trunc i128 %tmp21 to i64 ; <i64> [#uses=1]
+ store i64 %tmp2122, i64* %RH
+ ret void
+}
diff --git a/test/CodeGen/Blackfin/basic-i1.ll b/test/CodeGen/Blackfin/basic-i1.ll
new file mode 100644
index 0000000000..1c0c72aaea
--- /dev/null
+++ b/test/CodeGen/Blackfin/basic-i1.ll
@@ -0,0 +1,51 @@
+; RUN: llvm-as < %s | llc -march=bfin > %t
+
+define i1 @add(i1 %A, i1 %B) {
+ %R = add i1 %A, %B ; <i1> [#uses=1]
+ ret i1 %R
+}
+
+define i1 @sub(i1 %A, i1 %B) {
+ %R = sub i1 %A, %B ; <i1> [#uses=1]
+ ret i1 %R
+}
+
+define i1 @mul(i1 %A, i1 %B) {
+ %R = mul i1 %A, %B ; <i1> [#uses=1]
+ ret i1 %R
+}
+
+define i1 @sdiv(i1 %A, i1 %B) {
+ %R = sdiv i1 %A, %B ; <i1> [#uses=1]
+ ret i1 %R
+}
+
+define i1 @udiv(i1 %A, i1 %B) {
+ %R = udiv i1 %A, %B ; <i1> [#uses=1]
+ ret i1 %R
+}
+
+define i1 @srem(i1 %A, i1 %B) {
+ %R = srem i1 %A, %B ; <i1> [#uses=1]
+ ret i1 %R
+}
+
+define i1 @urem(i1 %A, i1 %B) {
+ %R = urem i1 %A, %B ; <i1> [#uses=1]
+ ret i1 %R
+}
+
+define i1 @and(i1 %A, i1 %B) {
+ %R = and i1 %A, %B ; <i1> [#uses=1]
+ ret i1 %R
+}
+
+define i1 @or(i1 %A, i1 %B) {
+ %R = or i1 %A, %B ; <i1> [#uses=1]
+ ret i1 %R
+}
+
+define i1 @xor(i1 %A, i1 %B) {
+ %R = xor i1 %A, %B ; <i1> [#uses=1]
+ ret i1 %R
+}
diff --git a/test/CodeGen/Blackfin/basic-i16.ll b/test/CodeGen/Blackfin/basic-i16.ll
new file mode 100644
index 0000000000..d8506319ef
--- /dev/null
+++ b/test/CodeGen/Blackfin/basic-i16.ll
@@ -0,0 +1,36 @@
+; RUN: llvm-as < %s | llc -march=bfin
+
+define i16 @add(i16 %A, i16 %B) {
+ %R = add i16 %A, %B ; <i16> [#uses=1]
+ ret i16 %R
+}
+
+define i16 @sub(i16 %A, i16 %B) {
+ %R = sub i16 %A, %B ; <i16> [#uses=1]
+ ret i16 %R
+}
+
+define i16 @mul(i16 %A, i16 %B) {
+ %R = mul i16 %A, %B ; <i16> [#uses=1]
+ ret i16 %R
+}
+
+define i16 @sdiv(i16 %A, i16 %B) {
+ %R = sdiv i16 %A, %B ; <i16> [#uses=1]
+ ret i16 %R
+}
+
+define i16 @udiv(i16 %A, i16 %B) {
+ %R = udiv i16 %A, %B ; <i16> [#uses=1]
+ ret i16 %R
+}
+
+define i16 @srem(i16 %A, i16 %B) {
+ %R = srem i16 %A, %B ; <i16> [#uses=1]
+ ret i16 %R
+}
+
+define i16 @urem(i16 %A, i16 %B) {
+ %R = urem i16 %A, %B ; <i16> [#uses=1]
+ ret i16 %R
+}
diff --git a/test/CodeGen/Blackfin/basic-i32.ll b/test/CodeGen/Blackfin/basic-i32.ll
new file mode 100644
index 0000000000..3a9377c504
--- /dev/null
+++ b/test/CodeGen/Blackfin/basic-i32.ll
@@ -0,0 +1,51 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
+
+define i32 @add(i32 %A, i32 %B) {
+ %R = add i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R
+}
+
+define i32 @sub(i32 %A, i32 %B) {
+ %R = sub i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R
+}
+
+define i32 @mul(i32 %A, i32 %B) {
+ %R = mul i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R
+}
+
+define i32 @sdiv(i32 %A, i32 %B) {
+ %R = sdiv i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R
+}
+
+define i32 @udiv(i32 %A, i32 %B) {
+ %R = udiv i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R
+}
+
+define i32 @srem(i32 %A, i32 %B) {
+ %R = srem i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R
+}
+
+define i32 @urem(i32 %A, i32 %B) {
+ %R = urem i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R
+}
+
+define i32 @and(i32 %A, i32 %B) {
+ %R = and i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R
+}
+
+define i32 @or(i32 %A, i32 %B) {
+ %R = or i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R
+}
+
+define i32 @xor(i32 %A, i32 %B) {
+ %R = xor i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R
+}
diff --git a/test/CodeGen/Blackfin/basic-i64.ll b/test/CodeGen/Blackfin/basic-i64.ll
new file mode 100644
index 0000000000..32dfc1ca65
--- /dev/null
+++ b/test/CodeGen/Blackfin/basic-i64.ll
@@ -0,0 +1,51 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
+
+define i64 @add(i64 %A, i64 %B) {
+ %R = add i64 %A, %B ; <i64> [#uses=1]
+ ret i64 %R
+}
+
+define i64 @sub(i64 %A, i64 %B) {
+ %R = sub i64 %A, %B ; <i64> [#uses=1]
+ ret i64 %R
+}
+
+define i64 @mul(i64 %A, i64 %B) {
+ %R = mul i64 %A, %B ; <i64> [#uses=1]
+ ret i64 %R
+}
+
+define i64 @sdiv(i64 %A, i64 %B) {
+ %R = sdiv i64 %A, %B ; <i64> [#uses=1]
+ ret i64 %R
+}
+
+define i64 @udiv(i64 %A, i64 %B) {
+ %R = udiv i64 %A, %B ; <i64> [#uses=1]
+ ret i64 %R
+}
+
+define i64 @srem(i64 %A, i64 %B) {
+ %R = srem i64 %A, %B ; <i64> [#uses=1]
+ ret i64 %R
+}
+
+define i64 @urem(i64 %A, i64 %B) {
+ %R = urem i64 %A, %B ; <i64> [#uses=1]
+ ret i64 %R
+}
+
+define i64 @and(i64 %A, i64 %B) {
+ %R = and i64 %A, %B ; <i64> [#uses=1]
+ ret i64 %R
+}
+
+define i64 @or(i64 %A, i64 %B) {
+ %R = or i64 %A, %B ; <i64> [#uses=1]
+ ret i64 %R
+}
+
+define i64 @xor(i64 %A, i64 %B) {
+ %R = xor i64 %A, %B ; <i64> [#uses=1]
+ ret i64 %R
+}
diff --git a/test/CodeGen/Blackfin/basic-i8.ll b/test/CodeGen/Blackfin/basic-i8.ll
new file mode 100644
index 0000000000..7338d46124
--- /dev/null
+++ b/test/CodeGen/Blackfin/basic-i8.ll
@@ -0,0 +1,51 @@
+; RUN: llvm-as < %s | llc -march=bfin
+
+define i8 @add(i8 %A, i8 %B) {
+ %R = add i8 %A, %B ; <i8> [#uses=1]
+ ret i8 %R
+}
+
+define i8 @sub(i8 %A, i8 %B) {
+ %R = sub i8 %A, %B ; <i8> [#uses=1]
+ ret i8 %R
+}
+
+define i8 @mul(i8 %A, i8 %B) {
+ %R = mul i8 %A, %B ; <i8> [#uses=1]
+ ret i8 %R
+}
+
+define i8 @sdiv(i8 %A, i8 %B) {
+ %R = sdiv i8 %A, %B ; <i8> [#uses=1]
+ ret i8 %R
+}
+
+define i8 @udiv(i8 %A, i8 %B) {
+ %R = udiv i8 %A, %B ; <i8> [#uses=1]
+ ret i8 %R
+}
+
+define i8 @srem(i8 %A, i8 %B) {
+ %R = srem i8 %A, %B ; <i8> [#uses=1]
+ ret i8 %R
+}
+
+define i8 @urem(i8 %A, i8 %B) {
+ %R = urem i8 %A, %B ; <i8> [#uses=1]
+ ret i8 %R
+}
+
+define i8 @and(i8 %A, i8 %B) {
+ %R = and i8 %A, %B ; <i8> [#uses=1]
+ ret i8 %R
+}
+
+define i8 @or(i8 %A, i8 %B) {
+ %R = or i8 %A, %B ; <i8> [#uses=1]
+ ret i8 %R
+}
+
+define i8 @xor(i8 %A, i8 %B) {
+ %R = xor i8 %A, %B ; <i8> [#uses=1]
+ ret i8 %R
+}
diff --git a/test/CodeGen/Blackfin/basictest.ll b/test/CodeGen/Blackfin/basictest.ll
new file mode 100644
index 0000000000..09a389da4c
--- /dev/null
+++ b/test/CodeGen/Blackfin/basictest.ll
@@ -0,0 +1,19 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
+
+define void @void(i32, i32) {
+ add i32 0, 0 ; <i32>:3 [#uses=2]
+ sub i32 0, 4 ; <i32>:4 [#uses=2]
+ br label %5
+
+; <label>:5 ; preds = %5, %2
+ add i32 %0, %1 ; <i32>:6 [#uses=2]
+ sub i32 %6, %4 ; <i32>:7 [#uses=1]
+ icmp sle i32 %7, %3 ; <i1>:8 [#uses=1]
+ br i1 %8, label %9, label %5
+
+; <label>:9 ; preds = %5
+ add i32 %0, %1 ; <i32>:10 [#uses=0]
+ sub i32 %6, %4 ; <i32>:11 [#uses=1]
+ icmp sle i32 %11, %3 ; <i1>:12 [#uses=0]
+ ret void
+}
diff --git a/test/CodeGen/Blackfin/burg.ll b/test/CodeGen/Blackfin/burg.ll
new file mode 100644
index 0000000000..fb5f74bddb
--- /dev/null
+++ b/test/CodeGen/Blackfin/burg.ll
@@ -0,0 +1,19 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t
+
+ %IntList = type %struct.intlist*
+ %ReadFn = type i32 ()*
+ %YYSTYPE = type { %IntList }
+ %struct.intlist = type { i32, %IntList }
+@yyval = external global %YYSTYPE ; <%YYSTYPE*> [#uses=1]
+
+define i32 @yyparse() {
+bb0:
+ %reg254 = load i16* null ; <i16> [#uses=1]
+ %reg254-idxcast = sext i16 %reg254 to i64 ; <i64> [#uses=1]
+ %reg254-idxcast-scale = mul i64 %reg254-idxcast, -1 ; <i64> [#uses=1]
+ %reg254-idxcast-scale-offset = add i64 %reg254-idxcast-scale, 1 ; <i64> [#uses=1]
+ %reg261.idx1 = getelementptr %YYSTYPE* null, i64 %reg254-idxcast-scale-offset, i32 0 ; <%IntList*> [#uses=1]
+ %reg261 = load %IntList* %reg261.idx1 ; <%IntList> [#uses=1]
+ store %IntList %reg261, %IntList* getelementptr (%YYSTYPE* @yyval, i64 0, i32 0)
+ unreachable
+}
diff --git a/test/CodeGen/Blackfin/cmp-small-imm.ll b/test/CodeGen/Blackfin/cmp-small-imm.ll
new file mode 100644
index 0000000000..7d87cb07f3
--- /dev/null
+++ b/test/CodeGen/Blackfin/cmp-small-imm.ll
@@ -0,0 +1,9 @@
+; RUN: llvm-as < %s | llc -march=bfin > %t
+; XFAIL: *
+; Assertion failed: (isUsed(Reg) && "Using an undefined register!")
+; function forward, file RegisterScavenging.cpp, line 259.
+
+define i1 @cmp3(i32 %A) {
+ %R = icmp uge i32 %A, 2
+ ret i1 %R
+}
diff --git a/test/CodeGen/Blackfin/cmp64.ll b/test/CodeGen/Blackfin/cmp64.ll
new file mode 100644
index 0000000000..c5c5f7e8ac
--- /dev/null
+++ b/test/CodeGen/Blackfin/cmp64.ll
@@ -0,0 +1,17 @@
+; RUN: llvm-as < %s | llc -march=bfin
+
+; This test tries to use a JustCC register as a data operand for MOVEcc. It
+; calls copyRegToReg(JustCC -> DP), failing because JustCC can only be copied to
+; D. The proper solution would be to restrict the virtual register to D only.
+
+define i32 @main() {
+entry:
+ br label %loopentry
+
+loopentry:
+ %done = icmp sle i64 undef, 5
+ br i1 %done, label %loopentry, label %exit.1
+
+exit.1:
+ ret i32 0
+}
diff --git a/test/CodeGen/Blackfin/ct32.ll b/test/CodeGen/Blackfin/ct32.ll
new file mode 100644
index 0000000000..ab5b12fbd4
--- /dev/null
+++ b/test/CodeGen/Blackfin/ct32.ll
@@ -0,0 +1,20 @@
+; RUN: llvm-as < %s | llc -march=bfin
+
+declare i32 @llvm.ctlz.i32(i32)
+declare i32 @llvm.cttz.i32(i32)
+declare i32 @llvm.ctpop.i32(i32)
+
+define i32 @ctlztest(i32 %B) {
+ %b = call i32 @llvm.ctlz.i32( i32 %B )
+ ret i32 %b;
+}
+
+define i32 @cttztest(i32 %B) {
+ %b = call i32 @llvm.cttz.i32( i32 %B )
+ ret i32 %b;
+}
+
+define i32 @ctpoptest(i32 %B) {
+ %b = call i32 @llvm.ctpop.i32( i32 %B )
+ ret i32 %b;
+}
diff --git a/test/CodeGen/Blackfin/ct64.ll b/test/CodeGen/Blackfin/ct64.ll
new file mode 100644
index 0000000000..43cde5e323
--- /dev/null
+++ b/test/CodeGen/Blackfin/ct64.ll
@@ -0,0 +1,20 @@
+; RUN: llvm-as < %s | llc -march=bfin
+
+declare i64 @llvm.ctlz.i64(i64)
+declare i64 @llvm.cttz.i64(i64)
+declare i64 @llvm.ctpop.i64(i64)
+
+define i64 @ctlztest(i64 %B) {
+ %b = call i64 @llvm.ctlz.i64( i64 %B )
+ ret i64 %b;
+}
+
+define i64 @cttztest(i64 %B) {
+ %b = call i64 @llvm.cttz.i64( i64 %B )
+ ret i64 %b;
+}
+
+define i64 @ctpoptest(i64 %B) {
+ %b = call i64 @llvm.ctpop.i64( i64 %B )
+ ret i64 %b;
+}
diff --git a/test/CodeGen/Blackfin/ctlz16.ll b/test/CodeGen/Blackfin/ctlz16.ll
new file mode 100644
index 0000000000..039ffbd57c
--- /dev/null
+++ b/test/CodeGen/Blackfin/ctlz16.ll
@@ -0,0 +1,18 @@
+; RUN: llvm-as < %s | llc -march=bfin
+
+declare i16 @llvm.ctlz.i16(i16)
+
+define i16 @ctlztest(i16 %B) {
+ %b = call i16 @llvm.ctlz.i16( i16 %B ) ; <i16> [#uses=1]
+ ret i16 %b;
+}
+define i16 @ctlztest_z(i16 zeroext %B) {
+ %b = call i16 @llvm.ctlz.i16( i16 %B ) ; <i16> [#uses=1]
+ ret i16 %b;
+}
+
+define i16 @ctlztest_s(i16 signext %B) {
+ %b = call i16 @llvm.ctlz.i16( i16 %B ) ; <i16> [#uses=1]
+ ret i16 %b;
+}
+
diff --git a/test/CodeGen/Blackfin/ctlz64.ll b/test/CodeGen/Blackfin/ctlz64.ll
new file mode 100644
index 0000000000..276b1d5927
--- /dev/null
+++ b/test/CodeGen/Blackfin/ctlz64.ll
@@ -0,0 +1,15 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t
+
+@.str = external constant [14 x i8] ; <[14 x i8]*> [#uses=1]
+
+define i32 @main(i64 %arg) nounwind {
+entry:
+ %tmp47 = tail call i64 @llvm.cttz.i64(i64 %arg) ; <i64> [#uses=1]
+ %tmp48 = trunc i64 %tmp47 to i32 ; <i32> [#uses=1]
+ %tmp40 = tail call i32 (i8*, ...)* @printf(i8* noalias getelementptr ([14 x i8]* @.str, i32 0, i32 0), i64 %arg, i32 0, i32 %tmp48, i32 0) nounwind ; <i32> [#uses=0]
+ ret i32 0
+}
+
+declare i32 @printf(i8* noalias, ...) nounwind
+
+declare i64 @llvm.cttz.i64(i64) nounwind readnone
diff --git a/test/CodeGen/Blackfin/ctpop16.ll b/test/CodeGen/Blackfin/ctpop16.ll
new file mode 100644
index 0000000000..cb06aa24fd
--- /dev/null
+++ b/test/CodeGen/Blackfin/ctpop16.ll
@@ -0,0 +1,18 @@
+; RUN: llvm-as < %s | llc -march=bfin
+
+declare i16 @llvm.ctpop.i16(i16)
+
+define i16 @ctpoptest(i16 %B) {
+ %b = call i16 @llvm.ctpop.i16( i16 %B ) ; <i16> [#uses=1]
+ ret i16 %b;
+}
+define i16 @ctpoptest_z(i16 zeroext %B) {
+ %b = call i16 @llvm.ctpop.i16( i16 %B ) ; <i16> [#uses=1]
+ ret i16 %b;
+}
+
+define i16 @ctpoptest_s(i16 signext %B) {
+ %b = call i16 @llvm.ctpop.i16( i16 %B ) ; <i16> [#uses=1]
+ ret i16 %b;
+}
+
diff --git a/test/CodeGen/Blackfin/cttz16.ll b/test/CodeGen/Blackfin/cttz16.ll
new file mode 100644
index 0000000000..a76cd36b75
--- /dev/null
+++ b/test/CodeGen/Blackfin/cttz16.ll
@@ -0,0 +1,18 @@
+; RUN: llvm-as < %s | llc -march=bfin
+
+declare i16 @llvm.cttz.i16(i16)
+
+define i16 @cttztest(i16 %B) {
+ %b = call i16 @llvm.cttz.i16( i16 %B ) ; <i16> [#uses=1]
+ ret i16 %b;
+}
+define i16 @cttztest_z(i16 zeroext %B) {
+ %b = call i16 @llvm.cttz.i16( i16 %B ) ; <i16> [#uses=1]
+ ret i16 %b;
+}
+
+define i16 @cttztest_s(i16 signext %B) {
+ %b = call i16 @llvm.cttz.i16( i16 %B ) ; <i16> [#uses=1]
+ ret i16 %b;
+}
+
diff --git a/test/CodeGen/Blackfin/cycles.ll b/test/CodeGen/Blackfin/cycles.ll
new file mode 100644
index 0000000000..042cb57ffc
--- /dev/null
+++ b/test/CodeGen/Blackfin/cycles.ll
@@ -0,0 +1,11 @@
+; RUN: llvm-as < %s | llc -march=bfin | grep cycles
+; XFAIL: *
+; ExpandIntegerResult #0: 0x181a60c: i64,ch = ReadCycleCounter 0x1104b08
+; Do not know how to expand the result of this operator!
+
+declare i64 @llvm.readcyclecounter()
+
+define i64 @foo() {
+ %tmp.1 = call i64 @llvm.readcyclecounter()
+ ret i64 %tmp.1
+}
diff --git a/test/CodeGen/Blackfin/dg.exp b/test/CodeGen/Blackfin/dg.exp
new file mode 100644
index 0000000000..5fdbe5feb0
--- /dev/null
+++ b/test/CodeGen/Blackfin/dg.exp
@@ -0,0 +1,5 @@
+load_lib llvm.exp
+
+if { [llvm_supports_target Blackfin] } {
+ RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,c,cpp}]]
+}
diff --git a/test/CodeGen/Blackfin/double-cast.ll b/test/CodeGen/Blackfin/double-cast.ll
new file mode 100644
index 0000000000..774615fea9
--- /dev/null
+++ b/test/CodeGen/Blackfin/double-cast.ll
@@ -0,0 +1,8 @@
+; RUN: llvm-as < %s | llc -march=bfin
+
+declare i32 @printf(i8*, ...)
+
+define i32 @main() {
+ %1 = call i32 (i8*, ...)* @printf(i8* undef, double undef)
+ ret i32 0
+}
diff --git a/test/CodeGen/Blackfin/frameindex.ll b/test/CodeGen/Blackfin/frameindex.ll
new file mode 100644
index 0000000000..34ca3eb328
--- /dev/null
+++ b/test/CodeGen/Blackfin/frameindex.ll
@@ -0,0 +1,10 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
+
+declare i32 @SIM(i8*, i8*, i32, i32, i32, [256 x i32]*, i32, i32, i32)
+
+define void @foo() {
+bb0:
+ %V = alloca [256 x i32], i32 256 ; <[256 x i32]*> [#uses=1]
+ %0 = call i32 @SIM(i8* null, i8* null, i32 0, i32 0, i32 0, [256 x i32]* %V, i32 0, i32 0, i32 2) ; <i32> [#uses=0]
+ ret void
+}
diff --git a/test/CodeGen/Blackfin/i17mem.ll b/test/CodeGen/Blackfin/i17mem.ll
new file mode 100644
index 0000000000..6a3b394a34
--- /dev/null
+++ b/test/CodeGen/Blackfin/i17mem.ll
@@ -0,0 +1,9 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
+@i17_l = external global i17 ; <i17*> [#uses=1]
+@i17_s = external global i17 ; <i17*> [#uses=1]
+
+define void @i17_ls() nounwind {
+ %tmp = load i17* @i17_l ; <i17> [#uses=1]
+ store i17 %tmp, i17* @i17_s
+ ret void
+}
diff --git a/test/CodeGen/Blackfin/i1mem.ll b/test/CodeGen/Blackfin/i1mem.ll
new file mode 100644
index 0000000000..97bc035885
--- /dev/null
+++ b/test/CodeGen/Blackfin/i1mem.ll
@@ -0,0 +1,9 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
+@i1_l = external global i1 ; <i1*> [#uses=1]
+@i1_s = external global i1 ; <i1*> [#uses=1]
+
+define void @i1_ls() nounwind {
+ %tmp = load i1* @i1_l ; <i1> [#uses=1]
+ store i1 %tmp, i1* @i1_s
+ ret void
+}
diff --git a/test/CodeGen/Blackfin/i1ops.ll b/test/CodeGen/Blackfin/i1ops.ll
new file mode 100644
index 0000000000..0bbd198e78
--- /dev/null
+++ b/test/CodeGen/Blackfin/i1ops.ll
@@ -0,0 +1,10 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
+
+define i32 @adj(i32 %d.1, i32 %ct.1) {
+entry:
+ %tmp.22.not = trunc i32 %ct.1 to i1 ; <i1> [#uses=1]
+ %tmp.221 = xor i1 %tmp.22.not, true ; <i1> [#uses=1]
+ %tmp.26 = or i1 false, %tmp.221 ; <i1> [#uses=1]
+ %tmp.27 = zext i1 %tmp.26 to i32 ; <i32> [#uses=1]
+ ret i32 %tmp.27
+}
diff --git a/test/CodeGen/Blackfin/i216mem.ll b/test/CodeGen/Blackfin/i216mem.ll
new file mode 100644
index 0000000000..085dc154a8
--- /dev/null
+++ b/test/CodeGen/Blackfin/i216mem.ll
@@ -0,0 +1,9 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
+@i216_l = external global i216 ; <i216*> [#uses=1]
+@i216_s = external global i216 ; <i216*> [#uses=1]
+
+define void @i216_ls() nounwind {
+ %tmp = load i216* @i216_l ; <i216> [#uses=1]
+ store i216 %tmp, i216* @i216_s
+ ret void
+}
diff --git a/test/CodeGen/Blackfin/i248mem.ll b/test/CodeGen/Blackfin/i248mem.ll
new file mode 100644
index 0000000000..7dde2a111c
--- /dev/null
+++ b/test/CodeGen/Blackfin/i248mem.ll
@@ -0,0 +1,9 @@
+; RUN: llvm-as < %s | llc -march=bfin
+@i248_l = external global i248 ; <i248*> [#uses=1]
+@i248_s = external global i248 ; <i248*> [#uses=1]
+
+define void @i248_ls() nounwind {
+ %tmp = load i248* @i248_l ; <i248> [#uses=1]
+ store i248 %tmp, i248* @i248_s
+ ret void
+}
diff --git a/test/CodeGen/Blackfin/i256mem.ll b/test/CodeGen/Blackfin/i256mem.ll
new file mode 100644
index 0000000000..6a3b394a34
--- /dev/null
+++ b/test/CodeGen/Blackfin/i256mem.ll
@@ -0,0 +1,9 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
+@i17_l = external global i17 ; <i17*> [#uses=1]
+@i17_s = external global i17 ; <i17*> [#uses=1]
+
+define void @i17_ls() nounwind {
+ %tmp = load i17* @i17_l ; <i17> [#uses=1]
+ store i17 %tmp, i17* @i17_s
+ ret void
+}
diff --git a/test/CodeGen/Blackfin/i256param.ll b/test/CodeGen/Blackfin/i256param.ll
new file mode 100644
index 0000000000..85a74fa5ee
--- /dev/null
+++ b/test/CodeGen/Blackfin/i256param.ll
@@ -0,0 +1,7 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
+@i256_s = external global i256 ; <i256*> [#uses=1]
+
+define void @i256_ls(i256 %x) nounwind {
+ store i256 %x, i256* @i256_s
+ ret void
+}
diff --git a/test/CodeGen/Blackfin/i56param.ll b/test/CodeGen/Blackfin/i56param.ll
new file mode 100644
index 0000000000..a03c182e32
--- /dev/null
+++ b/test/CodeGen/Blackfin/i56param.ll
@@ -0,0 +1,8 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
+@i56_l = external global i56 ; <i56*> [#uses=1]
+@i56_s = external global i56 ; <i56*> [#uses=1]
+
+define void @i56_ls(i56 %x) nounwind {
+ store i56 %x, i56* @i56_s
+ ret void
+}
diff --git a/test/CodeGen/Blackfin/i8mem.ll b/test/CodeGen/Blackfin/i8mem.ll
new file mode 100644
index 0000000000..967a86f36e
--- /dev/null
+++ b/test/CodeGen/Blackfin/i8mem.ll
@@ -0,0 +1,10 @@
+; RUN: llvm-as < %s | llc -march=bfin
+
+@i8_l = external global i8 ; <i8*> [#uses=1]
+@i8_s = external global i8 ; <i8*> [#uses=1]
+
+define void @i8_ls() nounwind {
+ %tmp = load i8* @i8_l ; <i8> [#uses=1]
+ store i8 %tmp, i8* @i8_s
+ ret void
+}
diff --git a/test/CodeGen/Blackfin/int-setcc.ll b/test/CodeGen/Blackfin/int-setcc.ll
new file mode 100644
index 0000000000..e1f822b0a3
--- /dev/null
+++ b/test/CodeGen/Blackfin/int-setcc.ll
@@ -0,0 +1,80 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t
+
+define fastcc void @Evaluate() {
+entry:
+ br i1 false, label %cond_false186, label %cond_true
+
+cond_true: ; preds = %entry
+ ret void
+
+cond_false186: ; preds = %entry
+ br i1 false, label %cond_true293, label %bb203
+
+bb203: ; preds = %cond_false186
+ ret void
+
+cond_true293: ; preds = %cond_false186
+ br i1 false, label %cond_true298, label %cond_next317
+
+cond_true298: ; preds = %cond_true293
+ br i1 false, label %cond_next518, label %cond_true397.preheader
+
+cond_next317: ; preds = %cond_true293
+ ret void
+
+cond_true397.preheader: ; preds = %cond_true298
+ ret void
+
+cond_next518: ; preds = %cond_true298
+ br i1 false, label %bb1069, label %cond_true522
+
+cond_true522: ; preds = %cond_next518
+ ret void
+
+bb1069: ; preds = %cond_next518
+ br i1 false, label %cond_next1131, label %bb1096
+
+bb1096: ; preds = %bb1069
+ ret void
+
+cond_next1131: ; preds = %bb1069
+ br i1 false, label %cond_next1207, label %cond_true1150
+
+cond_true1150: ; preds = %cond_next1131
+ ret void
+
+cond_next1207: ; preds = %cond_next1131
+ br i1 false, label %cond_next1219, label %cond_true1211
+
+cond_true1211: ; preds = %cond_next1207
+ ret void
+
+cond_next1219: ; preds = %cond_next1207
+ br i1 false, label %cond_true1223, label %cond_next1283
+
+cond_true1223: ; preds = %cond_next1219
+ br i1 false, label %cond_true1254, label %cond_true1264
+
+cond_true1254: ; preds = %cond_true1223
+ br i1 false, label %bb1567, label %cond_true1369.preheader
+
+cond_true1264: ; preds = %cond_true1223
+ ret void
+
+cond_next1283: ; preds = %cond_next1219
+ ret void
+
+cond_true1369.preheader: ; preds = %cond_true1254
+ ret void
+
+bb1567: ; preds = %cond_true1254
+ %tmp1605 = load i8* null ; <i8> [#uses=1]
+ %tmp1606 = icmp eq i8 %tmp1605, 0 ; <i1> [#uses=1]
+ br i1 %tmp1606, label %cond_next1637, label %cond_true1607
+
+cond_true1607: ; preds = %bb1567
+ ret void
+
+cond_next1637: ; preds = %bb1567
+ ret void
+}
diff --git a/test/CodeGen/Blackfin/invalid-apint.ll b/test/CodeGen/Blackfin/invalid-apint.ll
new file mode 100644
index 0000000000..bc3bbb38c6
--- /dev/null
+++ b/test/CodeGen/Blackfin/invalid-apint.ll
@@ -0,0 +1,15 @@
+; RUN: llvm-as < %s | llc -march=bfin
+
+; Assertion failed: (width < BitWidth && "Invalid APInt Truncate request"),
+; function trunc, file APInt.cpp, line 956.
+
+@str2 = external global [29 x i8]
+
+define void @printArgsNoRet(i32 %a1, float %a2, i8 %a3, double %a4, i8* %a5, i32 %a6, float %a7, i8 %a8, double %a9, i8* %a10, i32 %a11, float %a12, i8 %a13, double %a14, i8* %a15) {
+entry:
+ %tmp17 = sext i8 %a13 to i32
+ %tmp23 = call i32 (i8*, ...)* @printf(i8* getelementptr ([29 x i8]* @str2, i32 0, i64 0), i32 %a11, double 0.000000e+00, i32 %tmp17, double %a14, i32 0)
+ ret void
+}
+
+declare i32 @printf(i8*, ...)
diff --git a/test/CodeGen/Blackfin/jumptable.ll b/test/CodeGen/Blackfin/jumptable.ll
new file mode 100644
index 0000000000..62b5831405
--- /dev/null
+++ b/test/CodeGen/Blackfin/jumptable.ll
@@ -0,0 +1,53 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs | FileCheck %s
+
+; CHECK: .section .rodata
+; CHECK: JTI1_0:
+; CHECK: .long .BB1_1
+
+define i32 @oper(i32 %op, i32 %A, i32 %B) {
+entry:
+ switch i32 %op, label %bbx [
+ i32 1 , label %bb1
+ i32 2 , label %bb2
+ i32 3 , label %bb3
+ i32 4 , label %bb4
+ i32 5 , label %bb5
+ i32 6 , label %bb6
+ i32 7 , label %bb7
+ i32 8 , label %bb8
+ i32 9 , label %bb9
+ i32 10, label %bb10
+ ]
+bb1:
+ %R1 = add i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R1
+bb2:
+ %R2 = sub i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R2
+bb3:
+ %R3 = mul i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R3
+bb4:
+ %R4 = sdiv i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R4
+bb5:
+ %R5 = udiv i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R5
+bb6:
+ %R6 = srem i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R6
+bb7:
+ %R7 = urem i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R7
+bb8:
+ %R8 = and i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R8
+bb9:
+ %R9 = or i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R9
+bb10:
+ %R10 = xor i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R10
+bbx:
+ ret i32 0
+}
diff --git a/test/CodeGen/Blackfin/large-switch.ll b/test/CodeGen/Blackfin/large-switch.ll
new file mode 100644
index 0000000000..42aa4cd9fa
--- /dev/null
+++ b/test/CodeGen/Blackfin/large-switch.ll
@@ -0,0 +1,187 @@
+; RUN: llvm-as < %s | llc -march=bfin
+
+; The switch expansion uses a dynamic shl, and it produces a jumptable
+
+define void @athlon_fp_unit_ready_cost() {
+entry:
+ switch i32 0, label %UnifiedReturnBlock [
+ i32 -1, label %bb2063
+ i32 19, label %bb2035
+ i32 20, label %bb2035
+ i32 21, label %bb2035
+ i32 23, label %bb2035
+ i32 24, label %bb2035
+ i32 27, label %bb2035
+ i32 32, label %bb2035
+ i32 33, label %bb1994
+ i32 35, label %bb2035
+ i32 36, label %bb1994
+ i32 90, label %bb1948
+ i32 94, label %bb1948
+ i32 95, label %bb1948
+ i32 133, label %bb1419
+ i32 135, label %bb1238
+ i32 136, label %bb1238
+ i32 137, label %bb1238
+ i32 138, label %bb1238
+ i32 139, label %bb1201
+ i32 140, label %bb1201
+ i32 141, label %bb1154
+ i32 142, label %bb1126
+ i32 144, label %bb1201
+ i32 145, label %bb1126
+ i32 146, label %bb1201
+ i32 147, label %bb1126
+ i32 148, label %bb1201
+ i32 149, label %bb1126
+ i32 150, label %bb1201
+ i32 151, label %bb1126
+ i32 152, label %bb1096
+ i32 153, label %bb1096
+ i32 154, label %bb1096
+ i32 157, label %bb1096
+ i32 158, label %bb1096
+ i32 159, label %bb1096
+ i32 162, label %bb1096
+ i32 163, label %bb1096
+ i32 164, label %bb1096
+ i32 167, label %bb1201
+ i32 168, label %bb1201
+ i32 170, label %bb1201
+ i32 171, label %bb1201
+ i32 173, label %bb1201
+ i32 174, label %bb1201
+ i32 176, label %bb1201
+ i32 177, label %bb1201
+ i32 179, label %bb993
+ i32 180, label %bb993
+ i32 181, label %bb993
+ i32 182, label %bb993
+ i32 183, label %bb993
+ i32 184, label %bb993
+ i32 365, label %bb1126
+ i32 366, label %bb1126
+ i32 367, label %bb1126
+ i32 368, label %bb1126
+ i32 369, label %bb1126
+ i32 370, label %bb1126
+ i32 371, label %bb1126
+ i32 372, label %bb1126
+ i32 373, label %bb1126
+ i32 384, label %bb1126
+ i32 385, label %bb1126
+ i32 386, label %bb1126
+ i32 387, label %bb1126
+ i32 388, label %bb1126
+ i32 389, label %bb1126
+ i32 390, label %bb1126
+ i32 391, label %bb1126
+ i32 392, label %bb1126
+ i32 525, label %bb919
+ i32 526, label %bb839
+ i32 528, label %bb919
+ i32 529, label %bb839
+ i32 532, label %cond_next6.i97
+ i32 533, label %cond_next6.i81
+ i32 534, label %bb495
+ i32 536, label %cond_next6.i81
+ i32 537, label %cond_next6.i81
+ i32 538, label %bb396
+ i32 539, label %bb288
+ i32 541, label %bb396
+ i32 542, label %bb396
+ i32 543, label %bb396
+ i32 544, label %bb396
+ i32 545, label %bb189
+ i32 546, label %cond_next6.i
+ i32 547, label %bb189
+ i32 548, label %cond_next6.i
+ i32 549, label %bb189
+ i32 550, label %cond_next6.i
+ i32 551, label %bb189
+ i32 552, label %cond_next6.i
+ i32 553, label %bb189
+ i32 554, label %cond_next6.i
+ i32 555, label %bb189
+ i32 556, label %cond_next6.i
+ i32 557, label %bb189
+ i32 558, label %cond_next6.i
+ i32 618, label %bb40
+ i32 619, label %bb18
+ i32 620, label %bb40
+ i32 621, label %bb10
+ i32 622, label %bb10
+ ]
+
+bb10:
+ ret void
+
+bb18:
+ ret void
+
+bb40:
+ ret void
+
+cond_next6.i:
+ ret void
+
+bb189:
+ ret void
+
+bb288:
+ ret void
+
+bb396:
+ ret void
+
+bb495:
+ ret void
+
+cond_next6.i81:
+ ret void
+
+cond_next6.i97:
+ ret void
+
+bb839:
+ ret void
+
+bb919:
+ ret void
+
+bb993:
+ ret void
+
+bb1096:
+ ret void
+
+bb1126:
+ ret void
+
+bb1154:
+ ret void
+
+bb1201:
+ ret void
+
+bb1238:
+ ret void
+
+bb1419:
+ ret void
+
+bb1948:
+ ret void
+
+bb1994:
+ ret void
+
+bb2035:
+ ret void
+
+bb2063:
+ ret void
+
+UnifiedReturnBlock:
+ ret void
+}
diff --git a/test/CodeGen/Blackfin/load-i16.ll b/test/CodeGen/Blackfin/load-i16.ll
new file mode 100644
index 0000000000..853b662179
--- /dev/null
+++ b/test/CodeGen/Blackfin/load-i16.ll
@@ -0,0 +1,13 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
+
+; This somewhat contrived function heavily exercises register classes
+; It can trick -join-cross-class-copies into making illegal joins
+
+define void @f(i16** nocapture %p) nounwind readonly {
+entry:
+ %tmp1 = load i16** %p ; <i16*> [#uses=1]
+ %tmp2 = load i16* %tmp1 ; <i16> [#uses=1]
+ %ptr = getelementptr i16* %tmp1, i16 %tmp2
+ store i16 %tmp2, i16* %ptr
+ ret void
+}
diff --git a/test/CodeGen/Blackfin/logic-i16.ll b/test/CodeGen/Blackfin/logic-i16.ll
new file mode 100644
index 0000000000..fba0afbfa4
--- /dev/null
+++ b/test/CodeGen/Blackfin/logic-i16.ll
@@ -0,0 +1,16 @@
+; RUN: llvm-as < %s | llc -march=bfin
+
+define i16 @and(i16 %A, i16 %B) {
+ %R = and i16 %A, %B ; <i16> [#uses=1]
+ ret i16 %R
+}
+
+define i16 @or(i16 %A, i16 %B) {
+ %R = or i16 %A, %B ; <i16> [#uses=1]
+ ret i16 %R
+}
+
+define i16 @xor(i16 %A, i16 %B) {
+ %R = xor i16 %A, %B ; <i16> [#uses=1]
+ ret i16 %R
+}
diff --git a/test/CodeGen/Blackfin/many-args.ll b/test/CodeGen/Blackfin/many-args.ll
new file mode 100644
index 0000000000..3160d6c544
--- /dev/null
+++ b/test/CodeGen/Blackfin/many-args.ll
@@ -0,0 +1,23 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
+
+ type { i32, float, float, float, float, float, float, float, float, float, float } ; type %0
+ %struct..s_segment_inf = type { float, i32, i16, i16, float, float, i32, float, float }
+
+define i32 @main(i32 %argc.1, i8** %argv.1) {
+entry:
+ %tmp.218 = load float* null ; <float> [#uses=1]
+ %tmp.219 = getelementptr %0* null, i64 0, i32 6 ; <float*> [#uses=1]
+ %tmp.220 = load float* %tmp.219 ; <float> [#uses=1]
+ %tmp.221 = getelementptr %0* null, i64 0, i32 7 ; <float*> [#uses=1]
+ %tmp.222 = load float* %tmp.221 ; <float> [#uses=1]
+ %tmp.223 = getelementptr %0* null, i64 0, i32 8 ; <float*> [#uses=1]
+ %tmp.224 = load float* %tmp.223 ; <float> [#uses=1]
+ %tmp.225 = getelementptr %0* null, i64 0, i32 9 ; <float*> [#uses=1]
+ %tmp.226 = load float* %tmp.225 ; <float> [#uses=1]
+ %tmp.227 = getelementptr %0* null, i64 0, i32 10 ; <float*> [#uses=1]
+ %tmp.228 = load float* %tmp.227 ; <float> [#uses=1]
+ call void @place_and_route(i32 0, i32 0, float 0.000000e+00, i32 0, i32 0, i8* null, i32 0, i32 0, i8* null, i8* null, i8* null, i8* null, i32 0, i32 0, i32 0, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, i32 0, i32 0, i32 0, i32 0, i32 0, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, i32 0, i32 0, i16 0, i16 0, i16 0, float 0.000000e+00, float 0.000000e+00, %struct..s_segment_inf* null, i32 0, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float %tmp.218, float %tmp.220, float %tmp.222, float %tmp.224, float %tmp.226, float %tmp.228)
+ ret i32 0
+}
+
+declare void @place_and_route(i32, i32, float, i32, i32, i8*, i32, i32, i8*, i8*, i8*, i8*, i32, i32, i32, float, float, float, float, float, float, float, float, float, i32, i32, i32, i32, i32, float, float, float, i32, i32, i16, i16, i16, float, float, %struct..s_segment_inf*, i32, float, float, float, float, float, float, float, float, float, float)
diff --git a/test/CodeGen/Blackfin/mulhu.ll b/test/CodeGen/Blackfin/mulhu.ll
new file mode 100644
index 0000000000..91be4502d7
--- /dev/null
+++ b/test/CodeGen/Blackfin/mulhu.ll
@@ -0,0 +1,106 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t
+
+ %struct.CUMULATIVE_ARGS = type { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }
+ %struct.VEC_edge = type { i32, i32, [1 x %struct.edge_def*] }
+ %struct._obstack_chunk = type { i8*, %struct._obstack_chunk*, [4 x i8] }
+ %struct.basic_block_def = type { %struct.rtx_def*, %struct.rtx_def*, %struct.tree_node*, %struct.VEC_edge*, %struct.VEC_edge*, %struct.bitmap_head_def*, %struct.bitmap_head_def*, i8*, %struct.loop*, [2 x %struct.et_node*], %struct.basic_block_def*, %struct.basic_block_def*, %struct.reorder_block_def*, %struct.bb_ann_d*, i64, i32, i32, i32, i32 }
+ %struct.bb_ann_d = type { %struct.tree_node*, i8, %struct.edge_prediction* }
+ %struct.bitmap_element_def = type { %struct.bitmap_element_def*, %struct.bitmap_element_def*, i32, [4 x i32] }
+ %struct.bitmap_head_def = type { %struct.bitmap_element_def*, %struct.bitmap_element_def*, i32, %struct.bitmap_obstack* }
+ %struct.bitmap_obstack = type { %struct.bitmap_element_def*, %struct.bitmap_head_def*, %struct.obstack }
+ %struct.cost_pair = type { %struct.iv_cand*, i32, %struct.bitmap_head_def* }
+ %struct.dataflow_d = type { %struct.varray_head_tag*, [2 x %struct.tree_node*] }
+ %struct.def_operand_ptr = type { %struct.tree_node** }
+ %struct.def_optype_d = type { i32, [1 x %struct.def_operand_ptr] }
+ %struct.edge_def = type { %struct.basic_block_def*, %struct.basic_block_def*, %struct.edge_def_insns, i8*, %struct.location_t*, i32, i32, i64, i32 }
+ %struct.edge_def_insns = type { %struct.rtx_def* }
+ %struct.edge_prediction = type { %struct.edge_prediction*, %struct.edge_def*, i32, i32 }
+ %struct.eh_status = type opaque
+ %struct.emit_status = type { i32, i32, %struct.rtx_def*, %struct.rtx_def*, %struct.sequence_stack*, i32, %struct.location_t, i32, i8*, %struct.rtx_def** }
+ %struct.et_node = type opaque
+ %struct.expr_status = type { i32, i32, i32, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def* }
+ %struct.function = type { %struct.eh_status*, %struct.expr_status*, %struct.emit_status*, %struct.varasm_status*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.function*, i32, i32, i32, i32, %struct.rtx_def*, %struct.CUMULATIVE_ARGS, %struct.rtx_def*, %struct.rtx_def*, %struct.initial_value_struct*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, i8, i32, i64, %struct.tree_node*, %struct.tree_node*, %struct.rtx_def*, %struct.varray_head_tag*, %struct.temp_slot*, i32, %struct.var_refs_queue*, i32, i32, %struct.rtvec_def*, %struct.tree_node*, i32, i32, i32, %struct.machine_function*, i32, i32, i1, i1, %struct.language_function*, %struct.rtx_def*, i32, i32, i32, i32, %struct.location_t, %struct.varray_head_tag*, %struct.tree_node*, i8, i8, i8 }
+ %struct.htab = type { i32 (i8*)*, i32 (i8*, i8*)*, void (i8*)*, i8**, i32, i32, i32, i32, i32, i8* (i32, i32)*, void (i8*)*, i8*, i8* (i8*, i32, i32)*, void (i8*, i8*)*, i32 }
+ %struct.initial_value_struct = type opaque
+ %struct.iv = type { %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, i1, i1, i32 }
+ %struct.iv_cand = type { i32, i1, i32, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.iv*, i32 }
+ %struct.iv_use = type { i32, i32, %struct.iv*, %struct.tree_node*, %struct.tree_node**, %struct.bitmap_head_def*, i32, %struct.cost_pair*, %struct.iv_cand* }
+ %struct.ivopts_data = type { %struct.loop*, %struct.htab*, i32, %struct.version_info*, %struct.bitmap_head_def*, i32, %struct.varray_head_tag*, %struct.varray_head_tag*, %struct.bitmap_head_def*, i1 }
+ %struct.lang_decl = type opaque
+ %struct.language_function = type opaque
+ %struct.location_t = type { i8*, i32 }
+ %struct.loop = type { i32, %struct.basic_block_def*, %struct.basic_block_def*, %struct.basic_block_def*, %struct.lpt_decision, i32, i32, %struct.edge_def**, i32, %struct.basic_block_def*, %struct.basic_block_def*, i32, %struct.edge_def**, i32, %struct.edge_def**, i32, %struct.simple_bitmap_def*, i32, %struct.loop**, i32, %struct.loop*, %struct.loop*, %struct.loop*, %struct.loop*, i32, i8*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, i32, %struct.tree_node*, %struct.tree_node*, %struct.nb_iter_bound*, %struct.edge_def*, i1 }
+ %struct.lpt_decision = type { i32, i32 }
+ %struct.machine_function = type { %struct.stack_local_entry*, i8*, %struct.rtx_def*, i32, i32, i32, i32, i32 }
+ %struct.nb_iter_bound = type { %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.nb_iter_bound* }
+ %struct.obstack = type { i32, %struct._obstack_chunk*, i8*, i8*, i8*, i32, i32, %struct._obstack_chunk* (i8*, i32)*, void (i8*, %struct._obstack_chunk*)*, i8*, i8 }
+ %struct.reorder_block_def = type { %struct.rtx_def*, %struct.rtx_def*, %struct.basic_block_def*, %struct.basic_block_def*, %struct.basic_block_def*, i32, i32, i32 }
+ %struct.rtvec_def = type { i32, [1 x %struct.rtx_def*] }
+ %struct.rtx_def = type { i16, i8, i8, %struct.u }
+ %struct.sequence_stack = type { %struct.rtx_def*, %struct.rtx_def*, %struct.sequence_stack* }
+ %struct.simple_bitmap_def = type { i32, i32, i32, [1 x i64] }
+ %struct.stack_local_entry = type opaque
+ %struct.stmt_ann_d = type { %struct.tree_ann_common_d, i8, %struct.basic_block_def*, %struct.stmt_operands_d, %struct.dataflow_d*, %struct.bitmap_head_def*, i32 }
+ %struct.stmt_operands_d = type { %struct.def_optype_d*, %struct.def_optype_d*, %struct.v_may_def_optype_d*, %struct.vuse_optype_d*, %struct.v_may_def_optype_d* }
+ %struct.temp_slot = type opaque
+ %struct.tree_ann_common_d = type { i32, i8*, %struct.tree_node* }
+ %struct.tree_ann_d = type { %struct.stmt_ann_d }
+ %struct.tree_common = type { %struct.tree_node*, %struct.tree_node*, %struct.tree_ann_d*, i8, i8, i8, i8, i8 }
+ %struct.tree_decl = type { %struct.tree_common, %struct.location_t, i32, %struct.tree_node*, i8, i8, i8, i8, i8, i8, i8, i32, %struct.tree_decl_u1, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.rtx_def*, i32, %struct.tree_decl_u2, %struct.tree_node*, %struct.tree_node*, i64, %struct.lang_decl* }
+ %struct.tree_decl_u1 = type { i64 }
+ %struct.tree_decl_u2 = type { %struct.function* }
+ %struct.tree_node = type { %struct.tree_decl }
+ %struct.u = type { [1 x i64] }
+ %struct.v_def_use_operand_type_t = type { %struct.tree_node*, %struct.tree_node* }
+ %struct.v_may_def_optype_d = type { i32, [1 x %struct.v_def_use_operand_type_t] }
+ %struct.var_refs_queue = type { %struct.rtx_def*, i32, i32, %struct.var_refs_queue* }
+ %struct.varasm_status = type opaque
+ %struct.varray_head_tag = type { i32, i32, i32, i8*, %struct.u }
+ %struct.version_info = type { %struct.tree_node*, %struct.iv*, i1, i32, i1 }
+ %struct.vuse_optype_d = type { i32, [1 x %struct.tree_node*] }
+
+define i1 @determine_use_iv_cost(%struct.ivopts_data* %data, %struct.iv_use* %use, %struct.iv_cand* %cand) {
+entry:
+ switch i32 0, label %bb91 [
+ i32 0, label %bb
+ i32 1, label %bb6
+ i32 3, label %cond_next135
+ ]
+
+bb: ; preds = %entry
+ ret i1 false
+
+bb6: ; preds = %entry
+ br i1 false, label %bb87, label %cond_next27
+
+cond_next27: ; preds = %bb6
+ br i1 false, label %cond_true30, label %cond_next55
+
+cond_true30: ; preds = %cond_next27
+ br i1 false, label %cond_next41, label %cond_true35
+
+cond_true35: ; preds = %cond_true30
+ ret i1 false
+
+cond_next41: ; preds = %cond_true30
+ %tmp44 = call i32 @force_var_cost(%struct.ivopts_data* %data, %struct.tree_node* null, %struct.bitmap_head_def** null) ; <i32> [#uses=1]
+ %tmp46 = udiv i32 %tmp44, 5 ; <i32> [#uses=1]
+ call void @set_use_iv_cost(%struct.ivopts_data* %data, %struct.iv_use* %use, %struct.iv_cand* %cand, i32 %tmp46, %struct.bitmap_head_def* null)
+ br label %bb87
+
+cond_next55: ; preds = %cond_next27
+ ret i1 false
+
+bb87: ; preds = %cond_next41, %bb6
+ ret i1 false
+
+bb91: ; preds = %entry
+ ret i1 false
+
+cond_next135: ; preds = %entry
+ ret i1 false
+}
+
+declare void @set_use_iv_cost(%struct.ivopts_data*, %struct.iv_use*, %struct.iv_cand*, i32, %struct.bitmap_head_def*)
+
+declare i32 @force_var_cost(%struct.ivopts_data*, %struct.tree_node*, %struct.bitmap_head_def**)
diff --git a/test/CodeGen/Blackfin/printf.ll b/test/CodeGen/Blackfin/printf.ll
new file mode 100644
index 0000000000..d66d1efe24
--- /dev/null
+++ b/test/CodeGen/Blackfin/printf.ll
@@ -0,0 +1,10 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
+@.str_1 = external constant [42 x i8] ; <[42 x i8]*> [#uses=1]
+
+declare i32 @printf(i8*, ...)
+
+define i32 @main(i32 %argc.1, i8** %argv.1) {
+entry:
+ %tmp.16 = call i32 (i8*, ...)* @printf(i8* getelementptr ([42 x i8]* @.str_1, i64 0, i64 0), i32 0, i32 0, i64 0, i64 0)
+ ret i32 0
+}
diff --git a/test/CodeGen/Blackfin/printf2.ll b/test/CodeGen/Blackfin/printf2.ll
new file mode 100644
index 0000000000..6f402d547e
--- /dev/null
+++ b/test/CodeGen/Blackfin/printf2.ll
@@ -0,0 +1,11 @@
+; RUN: llvm-as < %s | llc -march=bfin
+; XFAIL: *
+; Assertion failed: (isUsed(Reg) && "Using an undefined register!"),
+; function forward, file RegisterScavenging.cpp, line 182.
+
+declare i32 @printf(i8*, ...)
+
+define i32 @main() {
+ %1 = call i32 (i8*, ...)* @printf(i8* undef, i1 undef)
+ ret i32 0
+}
diff --git a/test/CodeGen/Blackfin/promote-logic.ll b/test/CodeGen/Blackfin/promote-logic.ll
new file mode 100644
index 0000000000..ba2caefe66
--- /dev/null
+++ b/test/CodeGen/Blackfin/promote-logic.ll
@@ -0,0 +1,42 @@
+; RUN: llvm-as < %s | llc -march=bfin > %t
+; XFAIL: *
+
+; DAG combiner can produce an illegal i16 OR operation after LegalizeOps.
+
+define void @mng_display_bgr565() {
+entry:
+ br i1 false, label %bb.preheader, label %return
+
+bb.preheader:
+ br i1 false, label %cond_true48, label %cond_next80
+
+cond_true48:
+ %tmp = load i8* null
+ %tmp51 = zext i8 %tmp to i16
+ %tmp99 = load i8* null
+ %tmp54 = bitcast i8 %tmp99 to i8
+ %tmp54.upgrd.1 = zext i8 %tmp54 to i32
+ %tmp55 = lshr i32 %tmp54.upgrd.1, 3
+ %tmp55.upgrd.2 = trunc i32 %tmp55 to i16
+ %tmp52 = shl i16 %tmp51, 5
+ %tmp56 = and i16 %tmp55.upgrd.2, 28
+ %tmp57 = or i16 %tmp56, %tmp52
+ %tmp60 = zext i16 %tmp57 to i32
+ %tmp62 = xor i32 0, 65535
+ %tmp63 = mul i32 %tmp60, %tmp62
+ %tmp65 = add i32 0, %tmp63
+ %tmp69 = add i32 0, %tmp65
+ %tmp70 = lshr i32 %tmp69, 16
+ %tmp70.upgrd.3 = trunc i32 %tmp70 to i16
+ %tmp75 = lshr i16 %tmp70.upgrd.3, 8
+ %tmp75.upgrd.4 = trunc i16 %tmp75 to i8
+ %tmp76 = lshr i8 %tmp75.upgrd.4, 5
+ store i8 %tmp76, i8* null
+ ret void
+
+cond_next80:
+ ret void
+
+return:
+ ret void
+}
diff --git a/test/CodeGen/Blackfin/promote-setcc.ll b/test/CodeGen/Blackfin/promote-setcc.ll
new file mode 100644
index 0000000000..b686c54271
--- /dev/null
+++ b/test/CodeGen/Blackfin/promote-setcc.ll
@@ -0,0 +1,40 @@
+; RUN: llvm-as < %s | llc -march=bfin > %t
+; XFAIL: *
+; Assertion failed: (isUsed(Reg) && "Using an undefined register!"),
+; function forward, file RegisterScavenging.cpp, line 259.
+
+; The DAG combiner may sometimes create illegal i16 SETCC operations when run
+; after LegalizeOps. Try to tease out all the optimizations in
+; TargetLowering::SimplifySetCC.
+
+@x = external global i16
+@y = external global i16
+
+declare i16 @llvm.ctlz.i16(i16)
+
+; Case (srl (ctlz x), 5) == const
+; Note: ctlz is promoted, so this test does not catch the DAG combiner
+define i1 @srl_ctlz_const() {
+ %x = load i16* @x
+ %c = call i16 @llvm.ctlz.i16(i16 %x)
+ %s = lshr i16 %c, 4
+ %r = icmp eq i16 %s, 1
+ ret i1 %r
+}
+
+; Case (zext x) == const
+define i1 @zext_const() {
+ %x = load i16* @x
+ %r = icmp ugt i16 %x, 1
+ ret i1 %r
+}
+
+; Case (sext x) == const
+define i1 @sext_const() {
+ %x = load i16* @x
+ %y = add i16 %x, 1
+ %x2 = sext i16 %y to i32
+ %r = icmp ne i32 %x2, -1
+ ret i1 %r
+}
+
diff --git a/test/CodeGen/Blackfin/sdiv.ll b/test/CodeGen/Blackfin/sdiv.ll
new file mode 100644
index 0000000000..e03f4ff512
--- /dev/null
+++ b/test/CodeGen/Blackfin/sdiv.ll
@@ -0,0 +1,5 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
+define i32 @sdiv(i32 %A, i32 %B) {
+ %R = sdiv i32 %A, %B ; <i32> [#uses=1]
+ ret i32 %R
+}
diff --git a/test/CodeGen/Blackfin/simple-select.ll b/test/CodeGen/Blackfin/simple-select.ll
new file mode 100644
index 0000000000..286db7c2e3
--- /dev/null
+++ b/test/CodeGen/Blackfin/simple-select.ll
@@ -0,0 +1,11 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t
+
+declare i1 @foo()
+
+define i32 @test(i32* %A, i32* %B) {
+ %a = load i32* %A
+ %b = load i32* %B
+ %cond = call i1 @foo()
+ %c = select i1 %cond, i32 %a, i32 %b
+ ret i32 %c
+}
diff --git a/test/CodeGen/Blackfin/switch.ll b/test/CodeGen/Blackfin/switch.ll
new file mode 100644
index 0000000000..738fff7c7a
--- /dev/null
+++ b/test/CodeGen/Blackfin/switch.ll
@@ -0,0 +1,18 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t
+
+define i32 @foo(i32 %A, i32 %B, i32 %C) {
+entry:
+ switch i32 %A, label %out [
+ i32 1, label %bb
+ i32 0, label %bb13
+ ]
+
+bb: ; preds = %entry
+ ret i32 1
+
+bb13: ; preds = %entry
+ ret i32 1
+
+out: ; preds = %entry
+ ret i32 0
+}
diff --git a/test/CodeGen/Blackfin/switch2.ll b/test/CodeGen/Blackfin/switch2.ll
new file mode 100644
index 0000000000..f0fe1a7c90
--- /dev/null
+++ b/test/CodeGen/Blackfin/switch2.ll
@@ -0,0 +1,16 @@
+; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t
+
+define i8* @FindChar(i8* %CurPtr) {
+entry:
+ br label %bb
+
+bb: ; preds = %bb, %entry
+ %tmp = load i8* null ; <i8> [#uses=1]
+ switch i8 %tmp, label %bb [
+ i8 0, label %bb7
+ i8 120, label %bb7
+ ]
+
+bb7: ; preds = %bb, %bb
+ ret i8* null
+}