aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Osborne <richard@xmos.com>2008-11-07 10:59:00 +0000
committerRichard Osborne <richard@xmos.com>2008-11-07 10:59:00 +0000
commitb25baef26f03b9909b65dd5f762b38f93000445d (patch)
treef03bc8e40b55feab99b0f32e4428d215fa45f988
parent4df60f5491ff35c8a48c2cf14e18a33c9793b3bb (diff)
Add XCore backend.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@58838 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--autoconf/configure.ac6
-rwxr-xr-xconfigure55
-rw-r--r--lib/Target/XCore/CMakeLists.txt23
-rw-r--r--lib/Target/XCore/README.txt8
-rw-r--r--lib/Target/XCore/XCore.h38
-rw-r--r--lib/Target/XCore/XCore.td62
-rw-r--r--lib/Target/XCore/XCoreAsmPrinter.cpp459
-rw-r--r--lib/Target/XCore/XCoreCallingConv.td33
-rw-r--r--lib/Target/XCore/XCoreFrameInfo.cpp27
-rw-r--r--lib/Target/XCore/XCoreFrameInfo.h34
-rw-r--r--lib/Target/XCore/XCoreISelDAGToDAG.cpp228
-rw-r--r--lib/Target/XCore/XCoreISelLowering.cpp919
-rw-r--r--lib/Target/XCore/XCoreISelLowering.h119
-rw-r--r--lib/Target/XCore/XCoreInstrFormats.td120
-rw-r--r--lib/Target/XCore/XCoreInstrInfo.cpp506
-rw-r--r--lib/Target/XCore/XCoreInstrInfo.h107
-rw-r--r--lib/Target/XCore/XCoreInstrInfo.td980
-rw-r--r--lib/Target/XCore/XCoreMachineFunctionInfo.h69
-rw-r--r--lib/Target/XCore/XCoreRegisterInfo.cpp596
-rw-r--r--lib/Target/XCore/XCoreRegisterInfo.h94
-rw-r--r--lib/Target/XCore/XCoreRegisterInfo.td91
-rw-r--r--lib/Target/XCore/XCoreSubtarget.cpp28
-rw-r--r--lib/Target/XCore/XCoreSubtarget.h45
-rw-r--r--lib/Target/XCore/XCoreTargetAsmInfo.cpp201
-rw-r--r--lib/Target/XCore/XCoreTargetAsmInfo.h45
-rw-r--r--lib/Target/XCore/XCoreTargetMachine.cpp60
-rw-r--r--lib/Target/XCore/XCoreTargetMachine.h62
27 files changed, 4989 insertions, 26 deletions
diff --git a/autoconf/configure.ac b/autoconf/configure.ac
index f2c7714a2a..2054548979 100644
--- a/autoconf/configure.ac
+++ b/autoconf/configure.ac
@@ -225,6 +225,7 @@ AC_CACHE_CHECK([target architecture],[llvm_cv_target_arch],
arm-*) llvm_cv_target_arch="ARM" ;;
mips-*) llvm_cv_target_arch="Mips" ;;
pic16-*) llvm_cv_target_arch="PIC16" ;;
+ xcore-*) llvm_cv_target_arch="XCore" ;;
*) llvm_cv_target_arch="Unknown" ;;
esac])
@@ -332,6 +333,7 @@ else
ARM) AC_SUBST(TARGET_HAS_JIT,0) ;;
Mips) AC_SUBST(TARGET_HAS_JIT,0) ;;
PIC16) AC_SUBST(TARGET_HAS_JIT,0) ;;
+ XCore) AC_SUBST(TARGET_HAS_JIT,0) ;;
*) AC_SUBST(TARGET_HAS_JIT,0) ;;
esac
fi
@@ -381,7 +383,7 @@ AC_ARG_ENABLE([targets],AS_HELP_STRING([--enable-targets],
[Build specific host targets: all,host-only,{target-name} (default=all)]),,
enableval=all)
case "$enableval" in
- all) TARGETS_TO_BUILD="X86 Sparc PowerPC Alpha IA64 ARM Mips CellSPU PIC16 CBackend MSIL CppBackend" ;;
+ all) TARGETS_TO_BUILD="X86 Sparc PowerPC Alpha IA64 ARM Mips CellSPU PIC16 XCore CBackend MSIL CppBackend" ;;
host-only)
case "$llvm_cv_target_arch" in
x86) TARGETS_TO_BUILD="X86" ;;
@@ -394,6 +396,7 @@ case "$enableval" in
Mips) TARGETS_TO_BUILD="Mips" ;;
CellSPU|SPU) TARGETS_TO_BUILD="CellSPU" ;;
PIC16) TARGETS_TO_BUILD="PIC16" ;;
+ XCore) TARGETS_TO_BUILD="XCore" ;;
*) AC_MSG_ERROR([Can not set target to build]) ;;
esac
;;
@@ -409,6 +412,7 @@ case "$enableval" in
mips) TARGETS_TO_BUILD="Mips $TARGETS_TO_BUILD" ;;
spu) TARGETS_TO_BUILD="CellSPU $TARGETS_TO_BUILD" ;;
pic16) TARGETS_TO_BUILD="PIC16 $TARGETS_TO_BUILD" ;;
+ xcore) TARGETS_TO_BUILD="XCore $TARGETS_TO_BUILD" ;;
cbe) TARGETS_TO_BUILD="CBackend $TARGETS_TO_BUILD" ;;
msil) TARGETS_TO_BUILD="MSIL $TARGETS_TO_BUILD" ;;
cpp) TARGETS_TO_BUILD="CppBackend $TARGETS_TO_BUILD" ;;
diff --git a/configure b/configure
index 154e0931d2..f4faa67132 100755
--- a/configure
+++ b/configure
@@ -2389,6 +2389,7 @@ else
arm-*) llvm_cv_target_arch="ARM" ;;
mips-*) llvm_cv_target_arch="Mips" ;;
pic16-*) llvm_cv_target_arch="PIC16" ;;
+ xcore-*) llvm_cv_target_arch="XCore" ;;
*) llvm_cv_target_arch="Unknown" ;;
esac
fi
@@ -4811,6 +4812,8 @@ else
;;
PIC16) TARGET_HAS_JIT=0
;;
+ XCore) TARGET_HAS_JIT=0
+ ;;
*) TARGET_HAS_JIT=0
;;
esac
@@ -4892,7 +4895,7 @@ else
fi
case "$enableval" in
- all) TARGETS_TO_BUILD="X86 Sparc PowerPC Alpha IA64 ARM Mips CellSPU PIC16 CBackend MSIL CppBackend" ;;
+ all) TARGETS_TO_BUILD="X86 Sparc PowerPC Alpha IA64 ARM Mips CellSPU PIC16 XCore CBackend MSIL CppBackend" ;;
host-only)
case "$llvm_cv_target_arch" in
x86) TARGETS_TO_BUILD="X86" ;;
@@ -4905,6 +4908,7 @@ case "$enableval" in
Mips) TARGETS_TO_BUILD="Mips" ;;
CellSPU|SPU) TARGETS_TO_BUILD="CellSPU" ;;
PIC16) TARGETS_TO_BUILD="PIC16" ;;
+ XCore) TARGETS_TO_BUILD="XCore" ;;
*) { { echo "$as_me:$LINENO: error: Can not set target to build" >&5
echo "$as_me: error: Can not set target to build" >&2;}
{ (exit 1); exit 1; }; } ;;
@@ -4922,6 +4926,7 @@ echo "$as_me: error: Can not set target to build" >&2;}
mips) TARGETS_TO_BUILD="Mips $TARGETS_TO_BUILD" ;;
spu) TARGETS_TO_BUILD="CellSPU $TARGETS_TO_BUILD" ;;
pic16) TARGETS_TO_BUILD="PIC16 $TARGETS_TO_BUILD" ;;
+ xcore) TARGETS_TO_BUILD="XCore $TARGETS_TO_BUILD" ;;
cbe) TARGETS_TO_BUILD="CBackend $TARGETS_TO_BUILD" ;;
msil) TARGETS_TO_BUILD="MSIL $TARGETS_TO_BUILD" ;;
cpp) TARGETS_TO_BUILD="CppBackend $TARGETS_TO_BUILD" ;;
@@ -10827,7 +10832,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 10830 "configure"
+#line 10835 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -12971,7 +12976,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 12974 "configure"' > conftest.$ac_ext
+ echo '#line 12979 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -14689,11 +14694,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:14692: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:14697: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:14696: \$? = $ac_status" >&5
+ echo "$as_me:14701: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -14957,11 +14962,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:14960: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:14965: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:14964: \$? = $ac_status" >&5
+ echo "$as_me:14969: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -15061,11 +15066,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:15064: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:15069: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:15068: \$? = $ac_status" >&5
+ echo "$as_me:15073: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -17513,7 +17518,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 17516 "configure"
+#line 17521 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -17613,7 +17618,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 17616 "configure"
+#line 17621 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -19981,11 +19986,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:19984: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:19989: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:19988: \$? = $ac_status" >&5
+ echo "$as_me:19993: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -20085,11 +20090,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:20088: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:20093: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:20092: \$? = $ac_status" >&5
+ echo "$as_me:20097: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -21655,11 +21660,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:21658: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:21663: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:21662: \$? = $ac_status" >&5
+ echo "$as_me:21667: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -21759,11 +21764,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:21762: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:21767: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:21766: \$? = $ac_status" >&5
+ echo "$as_me:21771: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -23994,11 +23999,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:23997: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:24002: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:24001: \$? = $ac_status" >&5
+ echo "$as_me:24006: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -24262,11 +24267,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:24265: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:24270: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:24269: \$? = $ac_status" >&5
+ echo "$as_me:24274: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -24366,11 +24371,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:24369: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:24374: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:24373: \$? = $ac_status" >&5
+ echo "$as_me:24378: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
diff --git a/lib/Target/XCore/CMakeLists.txt b/lib/Target/XCore/CMakeLists.txt
new file mode 100644
index 0000000000..a7aba14a7a
--- /dev/null
+++ b/lib/Target/XCore/CMakeLists.txt
@@ -0,0 +1,23 @@
+set(LLVM_TARGET_DEFINITIONS XCore.td)
+
+tablegen(XCoreGenRegisterInfo.h.inc -gen-register-desc-header)
+tablegen(XCoreGenRegisterNames.inc -gen-register-enums)
+tablegen(XCoreGenRegisterInfo.inc -gen-register-desc)
+tablegen(XCoreGenInstrNames.inc -gen-instr-enums)
+tablegen(XCoreGenInstrInfo.inc -gen-instr-desc)
+tablegen(XCoreGenAsmWriter.inc -gen-asm-writer)
+tablegen(XCoreGenDAGISel.inc -gen-dag-isel)
+tablegen(XCoreGenCallingConv.inc -gen-callingconv)
+tablegen(XCoreGenSubtarget.inc -gen-subtarget)
+
+add_llvm_target(XCore
+ XCoreAsmPrinter.cpp
+ XCoreFrameInfo.cpp
+ XCoreInstrInfo.cpp
+ XCoreISelDAGToDAG.cpp
+ XCoreISelLowering.cpp
+ XCoreRegisterInfo.cpp
+ XCoreSubtarget.cpp
+ XCoreTargetAsmInfo.cpp
+ XCoreTargetMachine.cpp
+ )
diff --git a/lib/Target/XCore/README.txt b/lib/Target/XCore/README.txt
new file mode 100644
index 0000000000..deaeb0f2a9
--- /dev/null
+++ b/lib/Target/XCore/README.txt
@@ -0,0 +1,8 @@
+To-do
+-----
+
+* Instruction encodings
+* Tailcalls
+* Investigate loop alignment
+* Add builtins
+* Make better use of lmul / macc
diff --git a/lib/Target/XCore/XCore.h b/lib/Target/XCore/XCore.h
new file mode 100644
index 0000000000..347ac47ac3
--- /dev/null
+++ b/lib/Target/XCore/XCore.h
@@ -0,0 +1,38 @@
+//===-- XCore.h - Top-level interface for XCore representation --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the entry points for global functions defined in the LLVM
+// XCore back-end.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TARGET_XCORE_H
+#define TARGET_XCORE_H
+
+namespace llvm {
+ class FunctionPass;
+ class TargetMachine;
+ class XCoreTargetMachine;
+ class raw_ostream;
+
+ FunctionPass *createXCoreISelDag(XCoreTargetMachine &TM);
+ FunctionPass *createXCoreCodePrinterPass(raw_ostream &OS,
+ XCoreTargetMachine &TM);
+} // end namespace llvm;
+
+// Defines symbolic names for XCore registers. This defines a mapping from
+// register name to register number.
+//
+#include "XCoreGenRegisterNames.inc"
+
+// Defines symbolic names for the XCore instructions.
+//
+#include "XCoreGenInstrNames.inc"
+
+#endif
diff --git a/lib/Target/XCore/XCore.td b/lib/Target/XCore/XCore.td
new file mode 100644
index 0000000000..39c4226b61
--- /dev/null
+++ b/lib/Target/XCore/XCore.td
@@ -0,0 +1,62 @@
+//===- XCore.td - Describe the XCore 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 "../Target.td"
+
+//===----------------------------------------------------------------------===//
+// Descriptions
+//===----------------------------------------------------------------------===//
+
+include "XCoreRegisterInfo.td"
+include "XCoreInstrInfo.td"
+include "XCoreCallingConv.td"
+
+def XCoreInstrInfo : InstrInfo {
+ let TSFlagsFields = [];
+ let TSFlagsShifts = [];
+}
+
+//===----------------------------------------------------------------------===//
+// XCore Subtarget features.
+//===----------------------------------------------------------------------===//
+
+def FeatureXS1A
+ : SubtargetFeature<"xs1a", "IsXS1A", "true",
+ "Enable XS1A instructions">;
+
+def FeatureXS1B
+ : SubtargetFeature<"xs1b", "IsXS1B", "true",
+ "Enable XS1B instructions">;
+
+//===----------------------------------------------------------------------===//
+// XCore processors supported.
+//===----------------------------------------------------------------------===//
+
+class Proc<string Name, list<SubtargetFeature> Features>
+ : Processor<Name, NoItineraries, Features>;
+
+def : Proc<"generic", [FeatureXS1A]>;
+def : Proc<"xs1a-generic", [FeatureXS1A]>;
+def : Proc<"xs1b-generic", [FeatureXS1B]>;
+
+//===----------------------------------------------------------------------===//
+// Declare the target which we are implementing
+//===----------------------------------------------------------------------===//
+
+def XCore : Target {
+ // Pull in Instruction Info:
+ let InstructionSet = XCoreInstrInfo;
+}
diff --git a/lib/Target/XCore/XCoreAsmPrinter.cpp b/lib/Target/XCore/XCoreAsmPrinter.cpp
new file mode 100644
index 0000000000..519b38bdfa
--- /dev/null
+++ b/lib/Target/XCore/XCoreAsmPrinter.cpp
@@ -0,0 +1,459 @@
+//===-- XCoreAsmPrinter.cpp - XCore 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 the XAS-format XCore assembly language.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "asm-printer"
+#include "XCore.h"
+#include "XCoreInstrInfo.h"
+#include "XCoreSubtarget.h"
+#include "XCoreTargetMachine.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/MachineModuleInfo.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/Support/Mangler.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cctype>
+using namespace llvm;
+
+STATISTIC(EmittedInsts, "Number of machine instrs printed");
+
+static cl::opt<std::string> FileDirective("xcore-file-directive", cl::Optional,
+ cl::desc("Output a file directive into the assembly file"),
+ cl::Hidden,
+ cl::value_desc("filename"),
+ cl::init(""));
+
+static cl::opt<unsigned> MaxThreads("xcore-max-threads", cl::Optional,
+ cl::desc("Maximum number of threads (for emulation thread-local storage)"),
+ cl::Hidden,
+ cl::value_desc("number"),
+ cl::init(8));
+
+namespace {
+ struct VISIBILITY_HIDDEN XCoreAsmPrinter : public AsmPrinter {
+ XCoreAsmPrinter(raw_ostream &O, XCoreTargetMachine &TM,
+ const TargetAsmInfo *T)
+ : AsmPrinter(O, TM, T), DW(O, this, T),
+ Subtarget(*TM.getSubtargetImpl()) { }
+
+ DwarfWriter DW;
+ const XCoreSubtarget &Subtarget;
+
+ virtual const char *getPassName() const {
+ return "XCore Assembly Printer";
+ }
+
+ void printMemOperand(const MachineInstr *MI, int opNum);
+ void printOperand(const MachineInstr *MI, int opNum);
+ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+ unsigned AsmVariant, const char *ExtraCode);
+
+ void emitFileDirective(const std::string &filename);
+ void emitGlobalDirective(const std::string &name);
+ void emitExternDirective(const std::string &name);
+
+ void emitArrayBound(const std::string &name, const GlobalVariable *GV);
+ void emitGlobal(const GlobalVariable *GV);
+
+ void emitFunctionStart(MachineFunction &MF);
+ void emitFunctionEnd(MachineFunction &MF);
+
+ bool printInstruction(const MachineInstr *MI); // autogenerated.
+ void printMachineInstruction(const MachineInstr *MI);
+ bool runOnMachineFunction(MachineFunction &F);
+ bool doInitialization(Module &M);
+ bool doFinalization(Module &M);
+
+ void getAnalysisUsage(AnalysisUsage &AU) const {
+ AsmPrinter::getAnalysisUsage(AU);
+ AU.setPreservesAll();
+ AU.addRequired<MachineModuleInfo>();
+ }
+ };
+} // end of anonymous namespace
+
+#include "XCoreGenAsmWriter.inc"
+
+/// createXCoreCodePrinterPass - Returns a pass that prints the XCore
+/// assembly code for a MachineFunction to the given output stream,
+/// using the given target machine description. This should work
+/// regardless of whether the function is in SSA form.
+///
+FunctionPass *llvm::createXCoreCodePrinterPass(raw_ostream &o,
+ XCoreTargetMachine &tm) {
+ return new XCoreAsmPrinter(o, tm, tm.getTargetAsmInfo());
+}
+
+// PrintEscapedString - Print each character of the specified string, escaping
+// it if it is not printable or if it is an escape char.
+static void PrintEscapedString(const std::string &Str, raw_ostream &Out) {
+ for (unsigned i = 0, e = Str.size(); i != e; ++i) {
+ unsigned char C = Str[i];
+ if (isprint(C) && C != '"' && C != '\\') {
+ Out << C;
+ } else {
+ Out << '\\'
+ << (char) ((C/16 < 10) ? ( C/16 +'0') : ( C/16 -10+'A'))
+ << (char)(((C&15) < 10) ? ((C&15)+'0') : ((C&15)-10+'A'));
+ }
+ }
+}
+
+void XCoreAsmPrinter::
+emitFileDirective(const std::string &name)
+{
+ O << "\t.file\t\"";
+ PrintEscapedString(name, O);
+ O << "\"\n";
+}
+
+void XCoreAsmPrinter::
+emitGlobalDirective(const std::string &name)
+{
+ O << TAI->getGlobalDirective() << name;
+ O << "\n";
+}
+
+void XCoreAsmPrinter::
+emitExternDirective(const std::string &name)
+{
+ O << "\t.extern\t" << name;
+ O << '\n';
+}
+
+void XCoreAsmPrinter::
+emitArrayBound(const std::string &name, const GlobalVariable *GV)
+{
+ assert((GV->hasExternalLinkage() ||
+ GV->hasWeakLinkage()) ||
+ GV->hasLinkOnceLinkage() && "Unexpected linkage");
+ if (const ArrayType *ATy = dyn_cast<ArrayType>(
+ cast<PointerType>(GV->getType())->getElementType()))
+ {
+ O << TAI->getGlobalDirective() << name << ".globound" << "\n";
+ O << TAI->getSetDirective() << name << ".globound" << ","
+ << ATy->getNumElements() << "\n";
+ if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) {
+ // TODO Use COMDAT groups for LinkOnceLinkage
+ O << TAI->getWeakDefDirective() << name << ".globound" << "\n";
+ }
+ }
+}
+
+void XCoreAsmPrinter::
+emitGlobal(const GlobalVariable *GV)
+{
+ const TargetData *TD = TM.getTargetData();
+
+ if (GV->hasInitializer()) {
+ // Check to see if this is a special global used by LLVM, if so, emit it.
+ if (EmitSpecialLLVMGlobal(GV))
+ return;
+
+ SwitchToSection(TAI->SectionForGlobal(GV));
+
+ std::string name = Mang->getValueName(GV);
+ Constant *C = GV->getInitializer();
+ unsigned Align = (unsigned)TD->getPreferredTypeAlignmentShift(C->getType());
+
+ // Mark the start of the global
+ O << "\t.cc_top " << name << ".data," << name << "\n";
+
+ switch (GV->getLinkage()) {
+ case GlobalValue::AppendingLinkage:
+ cerr << "AppendingLinkage is not supported by this target!\n";
+ abort();
+ case GlobalValue::LinkOnceLinkage:
+ case GlobalValue::WeakLinkage:
+ case GlobalValue::ExternalLinkage:
+ emitArrayBound(name, GV);
+ emitGlobalDirective(name);
+ // TODO Use COMDAT groups for LinkOnceLinkage
+ if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) {
+ O << TAI->getWeakDefDirective() << name << "\n";
+ }
+ // FALL THROUGH
+ case GlobalValue::InternalLinkage:
+ break;
+ case GlobalValue::GhostLinkage:
+ cerr << "Should not have any unmaterialized functions!\n";
+ abort();
+ case GlobalValue::DLLImportLinkage:
+ cerr << "DLLImport linkage is not supported by this target!\n";
+ abort();
+ case GlobalValue::DLLExportLinkage:
+ cerr << "DLLExport linkage is not supported by this target!\n";
+ abort();
+ default:
+ assert(0 && "Unknown linkage type!");
+ }
+
+ EmitAlignment(Align, GV, 2);
+
+ unsigned Size = TD->getABITypeSize(C->getType());
+ if (GV->isThreadLocal()) {
+ Size *= MaxThreads;
+ }
+ if (TAI->hasDotTypeDotSizeDirective()) {
+ O << "\t.type " << name << ",@object\n";
+ O << "\t.size " << name << "," << Size << "\n";
+ }
+ O << name << ":\n";
+
+ EmitGlobalConstant(C);
+ if (GV->isThreadLocal()) {
+ for (unsigned i = 1; i < MaxThreads; ++i) {
+ EmitGlobalConstant(C);
+ }
+ }
+ if (Size < 4) {
+ // The ABI requires that unsigned scalar types smaller than 32 bits
+ // are are padded to 32 bits.
+ EmitZeros(4 - Size);
+ }
+
+ // Mark the end of the global
+ O << "\t.cc_bottom " << name << ".data\n";
+ } else {
+ if (GV->hasExternalWeakLinkage())
+ ExtWeakSymbols.insert(GV);
+ }
+}
+
+/// Emit the directives on the start of functions
+void XCoreAsmPrinter::
+emitFunctionStart(MachineFunction &MF)
+{
+ // Print out the label for the function.
+ const Function *F = MF.getFunction();
+
+ SwitchToSection(TAI->SectionForGlobal(F));
+
+ // Mark the start of the function
+ O << "\t.cc_top " << CurrentFnName << ".function," << CurrentFnName << "\n";
+
+ switch (F->getLinkage()) {
+ default: assert(0 && "Unknown linkage type!");
+ case Function::InternalLinkage: // Symbols default to internal.
+ break;
+ case Function::ExternalLinkage:
+ emitGlobalDirective(CurrentFnName);
+ break;
+ case Function::LinkOnceLinkage:
+ case Function::WeakLinkage:
+ // TODO Use COMDAT groups for LinkOnceLinkage
+ O << TAI->getGlobalDirective() << CurrentFnName << "\n";
+ O << TAI->getWeakDefDirective() << CurrentFnName << "\n";
+ break;
+ }
+ // (1 << 1) byte aligned
+ EmitAlignment(1, F, 1);
+ if (TAI->hasDotTypeDotSizeDirective()) {
+ O << "\t.type " << CurrentFnName << ",@function\n";
+ }
+ O << CurrentFnName << ":\n";
+}
+
+/// Emit the directives on the end of functions
+void XCoreAsmPrinter::
+emitFunctionEnd(MachineFunction &MF)
+{
+ // Mark the end of the function
+ O << "\t.cc_bottom " << CurrentFnName << ".function\n";
+}
+
+/// runOnMachineFunction - This uses the printMachineInstruction()
+/// method to print assembly for each instruction.
+///
+bool XCoreAsmPrinter::runOnMachineFunction(MachineFunction &MF)
+{
+ SetupMachineFunction(MF);
+
+ // Print out constants referenced by the function
+ EmitConstantPool(MF.getConstantPool());
+
+ // Print out jump tables referenced by the function
+ EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
+
+ // What's my mangled name?
+ CurrentFnName = Mang->getValueName(MF.getFunction());
+
+ // Emit the function start directives
+ emitFunctionStart(MF);
+
+ // Emit pre-function debug information.
+ 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 (I != MF.begin()) {
+ printBasicBlockLabel(I, true , true);
+ O << '\n';
+ }
+
+ for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
+ II != E; ++II) {
+ // Print the assembly for the instruction.
+ O << "\t";
+ printMachineInstruction(II);
+ }
+
+ // Each Basic Block is separated by a newline
+ O << '\n';
+ }
+
+ // Emit function end directives
+ emitFunctionEnd(MF);
+
+ // Emit post-function debug information.
+ DW.EndFunction(&MF);
+
+ // We didn't modify anything.
+ return false;
+}
+
+void XCoreAsmPrinter::printMemOperand(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);
+}
+
+void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
+ const MachineOperand &MO = MI->getOperand(opNum);
+ switch (MO.getType()) {
+ case MachineOperand::MO_Register:
+ if (TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
+ O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
+ else
+ assert(0 && "not