Add separate patch files for all the customizations we have currently

applied to our copy of llvm/clang.  These can be applied in alphabetical
order to a pristine llvm/clang 3.4 release source tree, to result in the
same version used in FreeBSD.

This is intended to clearly document all the changes until now, which
mostly consist of cherry pickings from the respective upstream trunks,
plus a number of hand-written FreeBSD-specific ones.  Hopefully those
can eventually be cleaned up and sent upstream too.

MFC after:	1 week
X-MFC-With:	r263313
This commit is contained in:
Dimitry Andric 2014-03-18 22:07:45 +00:00
parent 4f11a684ff
commit a1f8ad145e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=263320
100 changed files with 16346 additions and 0 deletions

View File

@ -0,0 +1,16 @@
This is a set of individual patches, which contain all the customizations to
llvm/clang currently in the FreeBSD base system. These can be applied in
alphabetical order to a pristine llvm/clang 3.4 release source tree, for example
by doing:
svn co https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_34/final llvm-3.4-final
svn co https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_34/final llvm-3.4-final/tools/clang
cd llvm-3.4-final
for p in /usr/src/contrib/llvm/patches/patch-*.diff; do
patch -p0 -f -F0 -E -i $p -s || break
done
A number of these consist of hand-written modifications, specifically for
FreeBSD, while most others are cherry pickings off the llvm and clang trunks.
When a new version of llvm/clang is eventually imported, those latter ones will
largely disappear.

View File

@ -0,0 +1,39 @@
This patch adjusts clang's default include paths to add FreeBSD-specific
directories.
Introduced here: http://svn.freebsd.org/changeset/base/208961
Index: tools/clang/lib/Frontend/InitHeaderSearch.cpp
===================================================================
--- tools/clang/lib/Frontend/InitHeaderSearch.cpp
+++ tools/clang/lib/Frontend/InitHeaderSearch.cpp
@@ -14,6 +14,7 @@
#include "clang/Frontend/Utils.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/Version.h"
#include "clang/Config/config.h" // C_INCLUDE_DIRS
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
@@ -333,6 +334,9 @@ void InitHeaderSearch::AddDefaultCIncludePaths(con
#endif
}
break;
+ case llvm::Triple::FreeBSD:
+ AddPath("/usr/include/clang/" CLANG_VERSION_STRING, System, false);
+ break;
default:
break;
@@ -423,11 +427,6 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple
else
AddPath("/usr/include/c++/4.4", CXXSystem, false);
break;
- case llvm::Triple::FreeBSD:
- // FreeBSD 8.0
- // FreeBSD 7.3
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", "", "", "", triple);
- break;
case llvm::Triple::OpenBSD: {
std::string t = triple.getTriple();
if (t.substr(0, 6) == "x86_64")

View File

@ -0,0 +1,214 @@
This patch adds support for the FreeBSD-specific -fformat-extension option,
which enables additional printf modifiers for the kernel.
Introduced here: http://svn.freebsd.org/changeset/base/208987
Index: tools/clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- tools/clang/lib/Frontend/CompilerInvocation.cpp
+++ tools/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1319,6 +1319,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgLi
Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
Opts.ShortEnums = Args.hasArg(OPT_fshort_enums);
Opts.Freestanding = Args.hasArg(OPT_ffreestanding);
+ Opts.FormatExtensions = Args.hasArg(OPT_fformat_extensions);
Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
Opts.NoMathBuiltin = Args.hasArg(OPT_fno_math_builtin);
Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
Index: tools/clang/lib/Analysis/FormatString.cpp
===================================================================
--- tools/clang/lib/Analysis/FormatString.cpp
+++ tools/clang/lib/Analysis/FormatString.cpp
@@ -548,6 +548,11 @@ const char *ConversionSpecifier::toString() const
// Objective-C specific specifiers.
case ObjCObjArg: return "@";
+ // FreeBSD specific specifiers.
+ case FreeBSDbArg: return "b";
+ case FreeBSDDArg: return "D";
+ case FreeBSDrArg: return "r";
+
// GlibC specific specifiers.
case PrintErrno: return "m";
}
@@ -626,6 +631,7 @@ bool FormatSpecifier::hasValidLengthModifier(const
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
case ConversionSpecifier::nArg:
+ case ConversionSpecifier::FreeBSDrArg:
return true;
default:
return false;
@@ -654,6 +660,7 @@ bool FormatSpecifier::hasValidLengthModifier(const
case ConversionSpecifier::nArg:
case ConversionSpecifier::cArg:
case ConversionSpecifier::sArg:
+ case ConversionSpecifier::FreeBSDrArg:
case ConversionSpecifier::ScanListArg:
return true;
default:
@@ -774,6 +781,9 @@ bool FormatSpecifier::hasStandardConversionSpecifi
case ConversionSpecifier::SArg:
return LangOpt.ObjC1 || LangOpt.ObjC2;
case ConversionSpecifier::InvalidSpecifier:
+ case ConversionSpecifier::FreeBSDbArg:
+ case ConversionSpecifier::FreeBSDDArg:
+ case ConversionSpecifier::FreeBSDrArg:
case ConversionSpecifier::PrintErrno:
case ConversionSpecifier::DArg:
case ConversionSpecifier::OArg:
Index: tools/clang/lib/Analysis/PrintfFormatString.cpp
===================================================================
--- tools/clang/lib/Analysis/PrintfFormatString.cpp
+++ tools/clang/lib/Analysis/PrintfFormatString.cpp
@@ -198,10 +198,25 @@ static PrintfSpecifierResult ParsePrintfSpecifier(
case '@': k = ConversionSpecifier::ObjCObjArg; break;
// Glibc specific.
case 'm': k = ConversionSpecifier::PrintErrno; break;
+ // FreeBSD format extensions
+ case 'b':
+ if (LO.FormatExtensions)
+ k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
+ break;
+ case 'r':
+ if (LO.FormatExtensions)
+ k = ConversionSpecifier::FreeBSDrArg;
+ break;
+ case 'y':
+ if (LO.FormatExtensions)
+ k = ConversionSpecifier::iArg;
+ break;
// Apple-specific
case 'D':
if (Target.getTriple().isOSDarwin())
k = ConversionSpecifier::DArg;
+ else if (LO.FormatExtensions)
+ k = ConversionSpecifier::FreeBSDDArg; // u_char * followed by char *
break;
case 'O':
if (Target.getTriple().isOSDarwin())
@@ -216,6 +231,10 @@ static PrintfSpecifierResult ParsePrintfSpecifier(
FS.setConversionSpecifier(CS);
if (CS.consumesDataArgument() && !FS.usesPositionalArg())
FS.setArgIndex(argIndex++);
+ // FreeBSD extension
+ if (k == ConversionSpecifier::FreeBSDbArg ||
+ k == ConversionSpecifier::FreeBSDDArg)
+ argIndex++;
if (k == ConversionSpecifier::InvalidSpecifier) {
// Assume the conversion takes one argument.
@@ -618,6 +637,7 @@ bool PrintfSpecifier::hasValidPlusPrefix() const {
case ConversionSpecifier::GArg:
case ConversionSpecifier::aArg:
case ConversionSpecifier::AArg:
+ case ConversionSpecifier::FreeBSDrArg:
return true;
default:
@@ -643,6 +663,7 @@ bool PrintfSpecifier::hasValidAlternativeForm() co
case ConversionSpecifier::FArg:
case ConversionSpecifier::gArg:
case ConversionSpecifier::GArg:
+ case ConversionSpecifier::FreeBSDrArg:
return true;
default:
Index: tools/clang/lib/Sema/SemaChecking.cpp
===================================================================
--- tools/clang/lib/Sema/SemaChecking.cpp
+++ tools/clang/lib/Sema/SemaChecking.cpp
@@ -2980,6 +2980,40 @@ CheckPrintfHandler::HandlePrintfSpecifier(const an
CoveredArgs.set(argIndex);
}
+ // FreeBSD extensions
+ if (CS.getKind() == ConversionSpecifier::FreeBSDbArg ||
+ CS.getKind() == ConversionSpecifier::FreeBSDDArg) {
+ // claim the second argument
+ CoveredArgs.set(argIndex + 1);
+
+ // Now type check the data expression that matches the
+ // format specifier.
+ const Expr *Ex = getDataArg(argIndex);
+ const analyze_printf::ArgType &AT =
+ (CS.getKind() == ConversionSpecifier::FreeBSDbArg) ?
+ ArgType(S.Context.IntTy) : ArgType::CStrTy;
+ if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType()))
+ S.Diag(getLocationOfByte(CS.getStart()),
+ diag::warn_printf_conversion_argument_type_mismatch)
+ << AT.getRepresentativeType(S.Context) << Ex->getType()
+ << getSpecifierRange(startSpecifier, specifierLen)
+ << Ex->getSourceRange();
+
+ // Now type check the data expression that matches the
+ // format specifier.
+ Ex = getDataArg(argIndex + 1);
+ const analyze_printf::ArgType &AT2 = ArgType::CStrTy;
+ if (AT2.isValid() && !AT2.matchesType(S.Context, Ex->getType()))
+ S.Diag(getLocationOfByte(CS.getStart()),
+ diag::warn_printf_conversion_argument_type_mismatch)
+ << AT2.getRepresentativeType(S.Context) << Ex->getType()
+ << getSpecifierRange(startSpecifier, specifierLen)
+ << Ex->getSourceRange();
+
+ return true;
+ }
+ // END OF FREEBSD EXTENSIONS
+
// Check for using an Objective-C specific conversion specifier
// in a non-ObjC literal.
if (!ObjCContext && CS.isObjCArg()) {
Index: tools/clang/lib/Driver/Tools.cpp
===================================================================
--- tools/clang/lib/Driver/Tools.cpp
+++ tools/clang/lib/Driver/Tools.cpp
@@ -2991,6 +2991,7 @@ void Clang::ConstructJob(Compilation &C, const Job
// Forward -f (flag) options which we can pass directly.
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
+ Args.AddLastArg(CmdArgs, options::OPT_fformat_extensions);
Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info);
Args.AddLastArg(CmdArgs, options::OPT_fno_limit_debug_info);
Index: tools/clang/include/clang/Basic/LangOptions.def
===================================================================
--- tools/clang/include/clang/Basic/LangOptions.def
+++ tools/clang/include/clang/Basic/LangOptions.def
@@ -84,6 +84,7 @@ LANGOPT(TraditionalCPP , 1, 0, "traditional CPP
LANGOPT(RTTI , 1, 1, "run-time type information")
LANGOPT(MSBitfields , 1, 0, "Microsoft-compatible structure layout")
LANGOPT(Freestanding, 1, 0, "freestanding implementation")
+LANGOPT(FormatExtensions , 1, 0, "FreeBSD format extensions")
LANGOPT(NoBuiltin , 1, 0, "disable builtin functions")
LANGOPT(NoMathBuiltin , 1, 0, "disable math builtin functions")
Index: tools/clang/include/clang/Analysis/Analyses/FormatString.h
===================================================================
--- tools/clang/include/clang/Analysis/Analyses/FormatString.h
+++ tools/clang/include/clang/Analysis/Analyses/FormatString.h
@@ -158,6 +158,11 @@ class ConversionSpecifier {
ObjCObjArg, // '@'
ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg,
+ // FreeBSD specific specifiers
+ FreeBSDbArg,
+ FreeBSDDArg,
+ FreeBSDrArg,
+
// GlibC specific specifiers.
PrintErrno, // 'm'
Index: tools/clang/include/clang/Driver/Options.td
===================================================================
--- tools/clang/include/clang/Driver/Options.td
+++ tools/clang/include/clang/Driver/Options.td
@@ -530,6 +530,8 @@ def fno_rewrite_includes : Flag<["-"], "fno-rewrit
def ffreestanding : Flag<["-"], "ffreestanding">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Assert that the compilation takes place in a freestanding environment">;
+def fformat_extensions: Flag<["-"], "fformat-extensions">, Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Enable FreeBSD kernel specific format string extensions">;
def fgnu_keywords : Flag<["-"], "fgnu-keywords">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Allow GNU-extension keywords regardless of language standard">;
def fgnu89_inline : Flag<["-"], "fgnu89-inline">, Group<f_Group>, Flags<[CC1Option]>,

View File

@ -0,0 +1,22 @@
This patch adds a FreeBSD-specific suffix to clang's version string. This is
usually of the form "(yyyyddmm)", representing the date when the compiler was
last updated.
Introduced here: http://svn.freebsd.org/changeset/base/209107
Index: tools/clang/lib/Basic/Version.cpp
===================================================================
--- tools/clang/lib/Basic/Version.cpp
+++ tools/clang/lib/Basic/Version.cpp
@@ -124,8 +124,10 @@ std::string getClangFullVersion() {
OS << "clang version " CLANG_VERSION_STRING " "
<< getClangFullRepositoryVersion();
+#ifdef CLANG_VENDOR_SUFFIX
+ OS << CLANG_VENDOR_SUFFIX;
+#elif defined(CLANG_VENDOR)
// If vendor supplied, include the base LLVM version as well.
-#ifdef CLANG_VENDOR
OS << " (based on LLVM " << PACKAGE_VERSION << ")";
#endif

View File

@ -0,0 +1,18 @@
This patch makes "clang -print-multi-os-directory" print "." on amd64, which is
required by certain ports.
Introduced here: http://svn.freebsd.org/changeset/base/213492
Index: tools/clang/lib/Driver/Driver.cpp
===================================================================
--- tools/clang/lib/Driver/Driver.cpp
+++ tools/clang/lib/Driver/Driver.cpp
@@ -780,7 +780,7 @@ bool Driver::HandleImmediateArgs(const Compilation
break;
case llvm::Triple::x86_64:
- llvm::outs() << "x86_64" << "\n";
+ llvm::outs() << "." << "\n";
break;
case llvm::Triple::ppc64:

View File

@ -0,0 +1,26 @@
This patch ensures the target triple that is passed during the compiler build is
respected, instead of mangling it.
Introduced here: http://svn.freebsd.org/changeset/base/221503
Index: lib/Support/Unix/Host.inc
===================================================================
--- lib/Support/Unix/Host.inc
+++ lib/Support/Unix/Host.inc
@@ -26,6 +26,11 @@
using namespace llvm;
+#ifdef __FreeBSD__
+std::string sys::getDefaultTargetTriple() {
+ return LLVM_DEFAULT_TARGET_TRIPLE;
+}
+#else // __FreeBSD__
static std::string getOSVersion() {
struct utsname info;
@@ -61,3 +66,4 @@ std::string sys::getDefaultTargetTriple() {
return Triple;
}
+#endif // __FreeBSD__

View File

@ -0,0 +1,19 @@
This patch ensures __clear_cache is not called on arm. In earlier versions of
clang, this special builtin was emitted as a function call, leading to link
errors.
Introduced here: http://svn.freebsd.org/changeset/base/243830
Index: lib/Support/Unix/Memory.inc
===================================================================
--- lib/Support/Unix/Memory.inc
+++ lib/Support/Unix/Memory.inc
@@ -332,7 +332,7 @@ void Memory::InvalidateInstructionCache(const void
for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize)
asm volatile("icbi 0, %0" : : "r"(Line));
asm volatile("isync");
-# elif (defined(__arm__) || defined(__aarch64__)) && defined(__GNUC__)
+# elif (defined(__arm__) || defined(__aarch64__)) && defined(__GNUC__) && !defined(__FreeBSD__)
// FIXME: Can we safely always call this for __GNUC__ everywhere?
const char *Start = static_cast<const char *>(Addr);
const char *End = Start + Len;

View File

@ -0,0 +1,79 @@
This patch applies a workaround for an ARM EABI issue, where clang would
sometimes incorrectly align the stack in a leaf function that uses TLS.
Introduced here: http://svn.freebsd.org/changeset/base/252503
Index: test/CodeGen/Thumb2/large-stack.ll
===================================================================
--- test/CodeGen/Thumb2/large-stack.ll
+++ test/CodeGen/Thumb2/large-stack.ll
@@ -13,7 +13,7 @@ define void @test1() {
define void @test2() {
; DARWIN-LABEL: test2:
; DARWIN: sub.w sp, sp, #4160
-; DARWIN: sub sp, #8
+; DARWIN: sub sp, #12
; LINUX-LABEL: test2:
; LINUX: sub.w sp, sp, #4160
; LINUX: sub sp, #8
Index: test/CodeGen/ARM/2009-10-30.ll
===================================================================
--- test/CodeGen/ARM/2009-10-30.ll
+++ test/CodeGen/ARM/2009-10-30.ll
@@ -4,9 +4,10 @@
define void @f(i32 %a1, i32 %a2, i32 %a3, i32 %a4, i32 %a5, ...) {
entry:
-;CHECK: sub sp, sp, #4
-;CHECK: add r{{[0-9]+}}, sp, #8
-;CHECK: str r{{[0-9]+}}, [sp], #4
+;CHECK: sub sp, sp, #8
+;CHECK: add r{{[0-9]+}}, sp, #12
+;CHECK: str r{{[0-9]+}}, [sp, #4]
+;CHECK: add sp, sp, #8
;CHECK: bx lr
%ap = alloca i8*, align 4
%ap1 = bitcast i8** %ap to i8*
Index: test/CodeGen/ARM/vargs_align.ll
===================================================================
--- test/CodeGen/ARM/vargs_align.ll
+++ test/CodeGen/ARM/vargs_align.ll
@@ -15,8 +15,8 @@ entry:
return: ; preds = %entry
%retval2 = load i32* %retval ; <i32> [#uses=1]
ret i32 %retval2
-; EABI: add sp, sp, #12
; EABI: add sp, sp, #16
+; EABI: add sp, sp, #16
+; OABI: add sp, sp, #16
; OABI: add sp, sp, #12
-; OABI: add sp, sp, #12
}
Index: test/CodeGen/ARM/prefetch-thumb.ll
===================================================================
--- test/CodeGen/ARM/prefetch-thumb.ll
+++ test/CodeGen/ARM/prefetch-thumb.ll
@@ -10,8 +10,8 @@ entry:
;ARM: pld [sp, #50]
;THUMB2: t6:
-;THUMB2: pld [sp]
-;THUMB2: pld [sp, #50]
+;THUMB2: pld [sp, #4]
+;THUMB2: pld [sp, #54]
%red = alloca [100 x i8], align 1
%0 = getelementptr inbounds [100 x i8]* %red, i32 0, i32 0
Index: lib/Target/ARM/ARMFrameLowering.h
===================================================================
--- lib/Target/ARM/ARMFrameLowering.h
+++ lib/Target/ARM/ARMFrameLowering.h
@@ -27,7 +27,7 @@ class ARMFrameLowering : public TargetFrameLowerin
public:
explicit ARMFrameLowering(const ARMSubtarget &sti)
- : TargetFrameLowering(StackGrowsDown, sti.getStackAlignment(), 0, 4),
+ : TargetFrameLowering(StackGrowsDown, sti.getStackAlignment(), 0, 8),
STI(sti) {
}

View File

@ -0,0 +1,25 @@
This patch adds "CC" and "clang-CC" to the list of program name aliases which
invoke the C++ compiler.
Introduced here: http://svn.freebsd.org/changeset/base/257109
Index: tools/clang/tools/driver/driver.cpp
===================================================================
--- tools/clang/tools/driver/driver.cpp
+++ tools/clang/tools/driver/driver.cpp
@@ -215,6 +215,7 @@ static void ParseProgName(SmallVectorImpl<const ch
} suffixes [] = {
{ "clang", 0 },
{ "clang++", "--driver-mode=g++" },
+ { "clang-CC", "--driver-mode=g++" },
{ "clang-c++", "--driver-mode=g++" },
{ "clang-cc", 0 },
{ "clang-cpp", "--driver-mode=cpp" },
@@ -221,6 +222,7 @@ static void ParseProgName(SmallVectorImpl<const ch
{ "clang-g++", "--driver-mode=g++" },
{ "clang-gcc", 0 },
{ "clang-cl", "--driver-mode=cl" },
+ { "CC", "--driver-mode=g++" },
{ "cc", 0 },
{ "cpp", "--driver-mode=cpp" },
{ "cl" , "--driver-mode=cl" },

View File

@ -0,0 +1,63 @@
This patch eliminates the unnecessary search for various gcc installation
directories during each startup of clang.
Introduced here: http://svn.freebsd.org/changeset/base/259053
Index: tools/clang/lib/Driver/ToolChains.cpp
===================================================================
--- tools/clang/lib/Driver/ToolChains.cpp
+++ tools/clang/lib/Driver/ToolChains.cpp
@@ -1014,7 +1014,7 @@ static StringRef getGCCToolchainDir(const ArgList
return GCC_INSTALL_PREFIX;
}
-/// \brief Construct a GCCInstallationDetector from the driver.
+/// \brief Initialize a GCCInstallationDetector from the driver.
///
/// This performs all of the autodetection and sets up the various paths.
/// Once constructed, a GCCInstallationDetector is essentially immutable.
@@ -1023,9 +1023,9 @@ static StringRef getGCCToolchainDir(const ArgList
/// should instead pull the target out of the driver. This is currently
/// necessary because the driver doesn't store the final version of the target
/// triple.
-Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
- const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args)
- : IsValid(false), D(D) {
+void
+Generic_GCC::GCCInstallationDetector::init(
+ const llvm::Triple &TargetTriple, const ArgList &Args) {
llvm::Triple BiarchVariantTriple =
TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant()
: TargetTriple.get32BitArchVariant();
@@ -1565,7 +1565,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLib
Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple& Triple,
const ArgList &Args)
- : ToolChain(D, Triple, Args), GCCInstallation(getDriver(), Triple, Args) {
+ : ToolChain(D, Triple, Args), GCCInstallation(getDriver()) {
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
@@ -2361,6 +2361,7 @@ static StringRef getMultilibDir(const llvm::Triple
Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
: Generic_ELF(D, Triple, Args) {
+ GCCInstallation.init(Triple, Args);
llvm::Triple::ArchType Arch = Triple.getArch();
std::string SysRoot = computeSysRoot();
Index: tools/clang/lib/Driver/ToolChains.h
===================================================================
--- tools/clang/lib/Driver/ToolChains.h
+++ tools/clang/lib/Driver/ToolChains.h
@@ -92,8 +92,8 @@ class LLVM_LIBRARY_VISIBILITY Generic_GCC : public
std::set<std::string> CandidateGCCInstallPaths;
public:
- GCCInstallationDetector(const Driver &D, const llvm::Triple &TargetTriple,
- const llvm::opt::ArgList &Args);
+ GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {}
+ void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args);
/// \brief Check whether we detected a valid GCC install.
bool isValid() const { return IsValid; }

View File

@ -0,0 +1,16 @@
This patch adds the alias bit_FXSAVE for bit_FXSR to cpuid.h.
Introduced here: http://svn.freebsd.org/changeset/base/259498
Index: tools/clang/lib/Headers/cpuid.h
===================================================================
--- tools/clang/lib/Headers/cpuid.h
+++ tools/clang/lib/Headers/cpuid.h
@@ -79,6 +79,7 @@
#define bit_ACPI 0x00400000
#define bit_MMX 0x00800000
#define bit_FXSR 0x01000000
+#define bit_FXSAVE bit_FXSR /* for gcc compat */
#define bit_SSE 0x02000000
#define bit_SSE2 0x04000000
#define bit_SS 0x08000000

View File

@ -0,0 +1,63 @@
Pull in r200899 from upstream clang trunk (by Serge Pavlov):
Allow transformation of VariableArray to ConstantArray.
In the following code:
struct A { static const int sz; };
template<class T> void f() { T arr[A::sz]; }
the array 'arr' is represented as a variable size array in the template.
If 'A::sz' gets value below in the translation unit, the array in
instantiation can turn into constant size array.
This change fixes PR18633.
Differential Revision: http://llvm-reviews.chandlerc.com/D2688
Introduced here: http://svn.freebsd.org/changeset/base/261680
Index: tools/clang/test/SemaCXX/c99-variable-length-array.cpp
===================================================================
--- tools/clang/test/SemaCXX/c99-variable-length-array.cpp
+++ tools/clang/test/SemaCXX/c99-variable-length-array.cpp
@@ -140,3 +140,24 @@ namespace PR11744 {
}
int test = f<int>(0); // expected-note {{instantiation of}}
}
+
+namespace pr18633 {
+ struct A1 {
+ static const int sz;
+ static const int sz2;
+ };
+ const int A1::sz2 = 11;
+ template<typename T>
+ void func () {
+ int arr[A1::sz]; // expected-warning{{variable length arrays are a C99 feature}}
+ }
+ template<typename T>
+ void func2 () {
+ int arr[A1::sz2];
+ }
+ const int A1::sz = 12;
+ void func2() {
+ func<int>();
+ func2<int>();
+ }
+}
Index: tools/clang/lib/Sema/TreeTransform.h
===================================================================
--- tools/clang/lib/Sema/TreeTransform.h
+++ tools/clang/lib/Sema/TreeTransform.h
@@ -3966,7 +3966,9 @@ TreeTransform<Derived>::TransformVariableArrayType
return QualType();
}
- VariableArrayTypeLoc NewTL = TLB.push<VariableArrayTypeLoc>(Result);
+ // We might have constant size array now, but fortunately it has the same
+ // location layout.
+ ArrayTypeLoc NewTL = TLB.push<ArrayTypeLoc>(Result);
NewTL.setLBracketLoc(TL.getLBracketLoc());
NewTL.setRBracketLoc(TL.getRBracketLoc());
NewTL.setSizeExpr(Size);

View File

@ -0,0 +1,540 @@
Pull in r195391 from upstream llvm trunk (by Eric Christopher):
In Dwarf 3 (and Dwarf 2) attributes whose value are offsets into a
section use the form DW_FORM_data4 whilst in Dwarf 4 and later they
use the form DW_FORM_sec_offset.
This patch updates the places where such attributes are generated to
use the appropriate form depending on the Dwarf version. The DIE entries
affected have the following tags:
DW_AT_stmt_list, DW_AT_ranges, DW_AT_location, DW_AT_GNU_pubnames,
DW_AT_GNU_pubtypes, DW_AT_GNU_addr_base, DW_AT_GNU_ranges_base
It also adds a hidden command line option "--dwarf-version=<uint>"
to llc which allows the version of Dwarf to be generated to override
what is specified in the metadata; this makes it possible to update
existing tests to check the debugging information generated for both
Dwarf 4 (the default) and Dwarf 3 using the same metadata.
Patch (slightly modified) by Keith Walker!
Introduced here: http://svn.freebsd.org/changeset/base/261991
Index: lib/CodeGen/AsmPrinter/DIE.cpp
===================================================================
--- lib/CodeGen/AsmPrinter/DIE.cpp
+++ lib/CodeGen/AsmPrinter/DIE.cpp
@@ -338,6 +338,7 @@ void DIEDelta::EmitValue(AsmPrinter *AP, dwarf::Fo
///
unsigned DIEDelta::SizeOf(AsmPrinter *AP, dwarf::Form Form) const {
if (Form == dwarf::DW_FORM_data4) return 4;
+ if (Form == dwarf::DW_FORM_sec_offset) return 4;
if (Form == dwarf::DW_FORM_strp) return 4;
return AP->getDataLayout().getPointerSize();
}
Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp
===================================================================
--- lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -105,6 +105,11 @@ DwarfPubSections("generate-dwarf-pub-sections", cl
clEnumVal(Disable, "Disabled"), clEnumValEnd),
cl::init(Default));
+static cl::opt<unsigned>
+DwarfVersionNumber("dwarf-version", cl::Hidden,
+ cl::desc("Generate DWARF for dwarf version."),
+ cl::init(0));
+
static const char *const DWARFGroupName = "DWARF Emission";
static const char *const DbgTimerName = "DWARF Debug Writer";
@@ -215,7 +220,9 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M)
else
HasDwarfPubSections = DwarfPubSections == Enable;
- DwarfVersion = getDwarfVersionFromModule(MMI->getModule());
+ DwarfVersion = DwarfVersionNumber
+ ? DwarfVersionNumber
+ : getDwarfVersionFromModule(MMI->getModule());
{
NamedRegionTimer T(DbgTimerName, DWARFGroupName, TimePassesIsEnabled);
@@ -470,9 +477,9 @@ DIE *DwarfDebug::constructLexicalScopeDIE(CompileU
// .debug_range section has not been laid out yet. Emit offset in
// .debug_range as a uint, size 4, for now. emitDIE will handle
// DW_AT_ranges appropriately.
- TheCU->addUInt(ScopeDIE, dwarf::DW_AT_ranges, dwarf::DW_FORM_data4,
- DebugRangeSymbols.size()
- * Asm->getDataLayout().getPointerSize());
+ TheCU->addSectionOffset(ScopeDIE, dwarf::DW_AT_ranges,
+ DebugRangeSymbols.size() *
+ Asm->getDataLayout().getPointerSize());
for (SmallVectorImpl<InsnRange>::const_iterator RI = Ranges.begin(),
RE = Ranges.end(); RI != RE; ++RI) {
DebugRangeSymbols.push_back(getLabelBeforeInsn(RI->first));
@@ -525,9 +532,9 @@ DIE *DwarfDebug::constructInlinedScopeDIE(CompileU
// .debug_range section has not been laid out yet. Emit offset in
// .debug_range as a uint, size 4, for now. emitDIE will handle
// DW_AT_ranges appropriately.
- TheCU->addUInt(ScopeDIE, dwarf::DW_AT_ranges, dwarf::DW_FORM_data4,
- DebugRangeSymbols.size()
- * Asm->getDataLayout().getPointerSize());
+ TheCU->addSectionOffset(ScopeDIE, dwarf::DW_AT_ranges,
+ DebugRangeSymbols.size() *
+ Asm->getDataLayout().getPointerSize());
for (SmallVectorImpl<InsnRange>::const_iterator RI = Ranges.begin(),
RE = Ranges.end(); RI != RE; ++RI) {
DebugRangeSymbols.push_back(getLabelBeforeInsn(RI->first));
@@ -758,14 +765,15 @@ CompileUnit *DwarfDebug::constructCompileUnit(DICo
// The line table entries are not always emitted in assembly, so it
// is not okay to use line_table_start here.
if (Asm->MAI->doesDwarfUseRelocationsAcrossSections())
- NewCU->addLabel(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_sec_offset,
- UseTheFirstCU ? Asm->GetTempSymbol("section_line")
- : LineTableStartSym);
+ NewCU->addSectionLabel(
+ Die, dwarf::DW_AT_stmt_list,
+ UseTheFirstCU ? Asm->GetTempSymbol("section_line")
+ : LineTableStartSym);
else if (UseTheFirstCU)
- NewCU->addUInt(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_data4, 0);
+ NewCU->addSectionOffset(Die, dwarf::DW_AT_stmt_list, 0);
else
- NewCU->addDelta(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_data4,
- LineTableStartSym, DwarfLineSectionSym);
+ NewCU->addSectionDelta(Die, dwarf::DW_AT_stmt_list,
+ LineTableStartSym, DwarfLineSectionSym);
// If we're using split dwarf the compilation dir is going to be in the
// skeleton CU and so we don't need to duplicate it here.
@@ -776,26 +784,24 @@ CompileUnit *DwarfDebug::constructCompileUnit(DICo
// emit it here if we don't have a skeleton CU for split dwarf.
if (GenerateGnuPubSections) {
if (Asm->MAI->doesDwarfUseRelocationsAcrossSections())
- NewCU->addLabel(Die, dwarf::DW_AT_GNU_pubnames,
- dwarf::DW_FORM_sec_offset,
- Asm->GetTempSymbol("gnu_pubnames",
- NewCU->getUniqueID()));
+ NewCU->addSectionLabel(
+ Die, dwarf::DW_AT_GNU_pubnames,
+ Asm->GetTempSymbol("gnu_pubnames", NewCU->getUniqueID()));
else
- NewCU->addDelta(Die, dwarf::DW_AT_GNU_pubnames, dwarf::DW_FORM_data4,
- Asm->GetTempSymbol("gnu_pubnames",
- NewCU->getUniqueID()),
- DwarfGnuPubNamesSectionSym);
+ NewCU->addSectionDelta(
+ Die, dwarf::DW_AT_GNU_pubnames,
+ Asm->GetTempSymbol("gnu_pubnames", NewCU->getUniqueID()),
+ DwarfGnuPubNamesSectionSym);
if (Asm->MAI->doesDwarfUseRelocationsAcrossSections())
- NewCU->addLabel(Die, dwarf::DW_AT_GNU_pubtypes,
- dwarf::DW_FORM_sec_offset,
- Asm->GetTempSymbol("gnu_pubtypes",
- NewCU->getUniqueID()));
+ NewCU->addSectionLabel(
+ Die, dwarf::DW_AT_GNU_pubtypes,
+ Asm->GetTempSymbol("gnu_pubtypes", NewCU->getUniqueID()));
else
- NewCU->addDelta(Die, dwarf::DW_AT_GNU_pubtypes, dwarf::DW_FORM_data4,
- Asm->GetTempSymbol("gnu_pubtypes",
- NewCU->getUniqueID()),
- DwarfGnuPubTypesSectionSym);
+ NewCU->addSectionDelta(
+ Die, dwarf::DW_AT_GNU_pubtypes,
+ Asm->GetTempSymbol("gnu_pubtypes", NewCU->getUniqueID()),
+ DwarfGnuPubTypesSectionSym);
}
}
@@ -2956,11 +2962,10 @@ CompileUnit *DwarfDebug::constructSkeletonCU(const
// Relocate to the beginning of the addr_base section, else 0 for the
// beginning of the one for this compile unit.
if (Asm->MAI->doesDwarfUseRelocationsAcrossSections())
- NewCU->addLabel(Die, dwarf::DW_AT_GNU_addr_base, dwarf::DW_FORM_sec_offset,
- DwarfAddrSectionSym);
+ NewCU->addSectionLabel(Die, dwarf::DW_AT_GNU_addr_base,
+ DwarfAddrSectionSym);
else
- NewCU->addUInt(Die, dwarf::DW_AT_GNU_addr_base,
- dwarf::DW_FORM_sec_offset, 0);
+ NewCU->addSectionOffset(Die, dwarf::DW_AT_GNU_addr_base, 0);
// 2.17.1 requires that we use DW_AT_low_pc for a single entry point
// into an entity. We're using 0, or a NULL label for this.
@@ -2970,10 +2975,10 @@ CompileUnit *DwarfDebug::constructSkeletonCU(const
// compile unit in debug_line section.
// FIXME: Should handle multiple compile units.
if (Asm->MAI->doesDwarfUseRelocationsAcrossSections())
- NewCU->addLabel(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_sec_offset,
- DwarfLineSectionSym);
+ NewCU->addSectionLabel(Die, dwarf::DW_AT_stmt_list,
+ DwarfLineSectionSym);
else
- NewCU->addUInt(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_sec_offset, 0);
+ NewCU->addSectionOffset(Die, dwarf::DW_AT_stmt_list, 0);
if (!CompilationDir.empty())
NewCU->addLocalString(Die, dwarf::DW_AT_comp_dir, CompilationDir);
@@ -2981,27 +2986,31 @@ CompileUnit *DwarfDebug::constructSkeletonCU(const
// Flags to let the linker know we have emitted new style pubnames.
if (GenerateGnuPubSections) {
if (Asm->MAI->doesDwarfUseRelocationsAcrossSections())
- NewCU->addLabel(Die, dwarf::DW_AT_GNU_pubnames, dwarf::DW_FORM_sec_offset,
- Asm->GetTempSymbol("gnu_pubnames", NewCU->getUniqueID()));
+ NewCU->addSectionLabel(
+ Die, dwarf::DW_AT_GNU_pubnames,
+ Asm->GetTempSymbol("gnu_pubnames", NewCU->getUniqueID()));
else
- NewCU->addDelta(Die, dwarf::DW_AT_GNU_pubnames, dwarf::DW_FORM_data4,
- Asm->GetTempSymbol("gnu_pubnames", NewCU->getUniqueID()),
- DwarfGnuPubNamesSectionSym);
+ NewCU->addSectionDelta(
+ Die, dwarf::DW_AT_GNU_pubnames,
+ Asm->GetTempSymbol("gnu_pubnames", NewCU->getUniqueID()),
+ DwarfGnuPubNamesSectionSym);
if (Asm->MAI->doesDwarfUseRelocationsAcrossSections())
- NewCU->addLabel(Die, dwarf::DW_AT_GNU_pubtypes, dwarf::DW_FORM_sec_offset,
- Asm->GetTempSymbol("gnu_pubtypes", NewCU->getUniqueID()));
+ NewCU->addSectionLabel(
+ Die, dwarf::DW_AT_GNU_pubtypes,
+ Asm->GetTempSymbol("gnu_pubtypes", NewCU->getUniqueID()));
else
- NewCU->addDelta(Die, dwarf::DW_AT_GNU_pubtypes, dwarf::DW_FORM_data4,
- Asm->GetTempSymbol("gnu_pubtypes", NewCU->getUniqueID()),
- DwarfGnuPubTypesSectionSym);
+ NewCU->addSectionDelta(
+ Die, dwarf::DW_AT_GNU_pubtypes,
+ Asm->GetTempSymbol("gnu_pubtypes", NewCU->getUniqueID()),
+ DwarfGnuPubTypesSectionSym);
}
// Flag if we've emitted any ranges and their location for the compile unit.
if (DebugRangeSymbols.size()) {
if (Asm->MAI->doesDwarfUseRelocationsAcrossSections())
- NewCU->addLabel(Die, dwarf::DW_AT_GNU_ranges_base,
- dwarf::DW_FORM_sec_offset, DwarfDebugRangeSectionSym);
+ NewCU->addSectionLabel(Die, dwarf::DW_AT_GNU_ranges_base,
+ DwarfDebugRangeSectionSym);
else
NewCU->addUInt(Die, dwarf::DW_AT_GNU_ranges_base, dwarf::DW_FORM_data4,
0);
Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
===================================================================
--- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -227,6 +227,26 @@ void CompileUnit::addLabel(DIEBlock *Die, dwarf::F
addLabel(Die, (dwarf::Attribute)0, Form, Label);
}
+/// addSectionLabel - Add a Dwarf section label attribute data and value.
+///
+void CompileUnit::addSectionLabel(DIE *Die, dwarf::Attribute Attribute,
+ const MCSymbol *Label) {
+ if (DD->getDwarfVersion() >= 4)
+ addLabel(Die, Attribute, dwarf::DW_FORM_sec_offset, Label);
+ else
+ addLabel(Die, Attribute, dwarf::DW_FORM_data4, Label);
+}
+
+/// addSectionOffset - Add an offset into a section attribute data and value.
+///
+void CompileUnit::addSectionOffset(DIE *Die, dwarf::Attribute Attribute,
+ uint64_t Integer) {
+ if (DD->getDwarfVersion() >= 4)
+ addUInt(Die, Attribute, dwarf::DW_FORM_sec_offset, Integer);
+ else
+ addUInt(Die, Attribute, dwarf::DW_FORM_data4, Integer);
+}
+
/// addLabelAddress - Add a dwarf label attribute data and value using
/// DW_FORM_addr or DW_FORM_GNU_addr_index.
///
@@ -264,13 +284,15 @@ void CompileUnit::addOpAddress(DIEBlock *Die, cons
}
}
-/// addDelta - Add a label delta attribute data and value.
+/// addSectionDelta - Add a section label delta attribute data and value.
///
-void CompileUnit::addDelta(DIE *Die, dwarf::Attribute Attribute,
- dwarf::Form Form, const MCSymbol *Hi,
- const MCSymbol *Lo) {
+void CompileUnit::addSectionDelta(DIE *Die, dwarf::Attribute Attribute,
+ const MCSymbol *Hi, const MCSymbol *Lo) {
DIEValue *Value = new (DIEValueAllocator) DIEDelta(Hi, Lo);
- Die->addValue(Attribute, Form, Value);
+ if (DD->getDwarfVersion() >= 4)
+ Die->addValue(Attribute, dwarf::DW_FORM_sec_offset, Value);
+ else
+ Die->addValue(Attribute, dwarf::DW_FORM_data4, Value);
}
/// addDIEEntry - Add a DIE attribute data and value.
@@ -1768,10 +1790,8 @@ DIE *CompileUnit::constructVariableDIE(DbgVariable
unsigned Offset = DV.getDotDebugLocOffset();
if (Offset != ~0U) {
- addLabel(VariableDie, dwarf::DW_AT_location,
- DD->getDwarfVersion() >= 4 ? dwarf::DW_FORM_sec_offset
- : dwarf::DW_FORM_data4,
- Asm->GetTempSymbol("debug_loc", Offset));
+ addSectionLabel(VariableDie, dwarf::DW_AT_location,
+ Asm->GetTempSymbol("debug_loc", Offset));
DV.setDIE(VariableDie);
return VariableDie;
}
Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
===================================================================
--- lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
+++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
@@ -209,6 +209,14 @@ class CompileUnit {
void addLabel(DIEBlock *Die, dwarf::Form Form, const MCSymbol *Label);
+ /// addSectionLabel - Add a Dwarf section label attribute data and value.
+ ///
+ void addSectionLabel(DIE *Die, dwarf::Attribute Attribute, const MCSymbol *Label);
+
+ /// addSectionOffset - Add an offset into a section attribute data and value.
+ ///
+ void addSectionOffset(DIE *Die, dwarf::Attribute Attribute, uint64_t Integer);
+
/// addLabelAddress - Add a dwarf label attribute data and value using
/// either DW_FORM_addr or DW_FORM_GNU_addr_index.
///
@@ -219,10 +227,9 @@ class CompileUnit {
///
void addOpAddress(DIEBlock *Die, const MCSymbol *Label);
- /// addDelta - Add a label delta attribute data and value.
- ///
- void addDelta(DIE *Die, dwarf::Attribute Attribute, dwarf::Form Form, const MCSymbol *Hi,
- const MCSymbol *Lo);
+ /// addSectionDelta - Add a label delta attribute data and value.
+ void addSectionDelta(DIE *Die, dwarf::Attribute Attribute, const MCSymbol *Hi,
+ const MCSymbol *Lo);
/// addDIEEntry - Add a DIE attribute data and value.
///
Index: test/DebugInfo/X86/gnu-public-names.ll
===================================================================
--- test/DebugInfo/X86/gnu-public-names.ll
+++ test/DebugInfo/X86/gnu-public-names.ll
@@ -1,5 +1,6 @@
; RUN: llc -mtriple=x86_64-pc-linux-gnu -generate-gnu-dwarf-pub-sections < %s | FileCheck -check-prefix=ASM %s
; RUN: llc -mtriple=x86_64-pc-linux-gnu -generate-gnu-dwarf-pub-sections -filetype=obj < %s | llvm-dwarfdump - | FileCheck %s
+; RUN: llc -mtriple=x86_64-pc-linux-gnu -generate-gnu-dwarf-pub-sections -filetype=obj -dwarf-version=3 < %s | llvm-dwarfdump - | FileCheck %s -check-prefix=DWARF3
; ModuleID = 'dwarf-public-names.cpp'
;
; Generated from:
@@ -123,6 +124,85 @@
; CHECK-DAG: [[D]] EXTERNAL TYPE "ns::D"
; CHECK-DAG: [[INT]] STATIC TYPE "int"
+; DWARF3: .debug_info contents:
+; DWARF3: DW_AT_GNU_pubnames [DW_FORM_data4] (0x00000000)
+; DWARF3: DW_AT_GNU_pubtypes [DW_FORM_data4] (0x00000000)
+
+; DWARF3: [[C:[0-9a-f]+]]: DW_TAG_structure_type
+; DWARF3-NEXT: DW_AT_name {{.*}} "C"
+
+; DWARF3: [[STATIC_MEM_DECL:[0-9a-f]+]]: DW_TAG_member
+; DWARF3-NEXT: DW_AT_name {{.*}} "static_member_variable"
+
+; DWARF3: [[MEM_FUNC_DECL:[0-9a-f]+]]: DW_TAG_subprogram
+; DWARF3-NEXT: DW_AT_MIPS_linkage_name
+; DWARF3-NEXT: DW_AT_name {{.*}} "member_function"
+
+; DWARF3: [[STATIC_MEM_FUNC_DECL:[0-9a-f]+]]: DW_TAG_subprogram
+; DWARF3-NEXT: DW_AT_MIPS_linkage_name
+; DWARF3-NEXT: DW_AT_name {{.*}} "static_member_function"
+
+; DWARF3: [[INT:[0-9a-f]+]]: DW_TAG_base_type
+; DWARF3-NEXT: DW_AT_name {{.*}} "int"
+
+; DWARF3: [[STATIC_MEM_VAR:[0-9a-f]+]]: DW_TAG_variable
+; DWARF3-NEXT: DW_AT_specification {{.*}}[[STATIC_MEM_DECL]]
+
+; DWARF3: [[GLOB_VAR:[0-9a-f]+]]: DW_TAG_variable
+; DWARF3-NEXT: DW_AT_name {{.*}} "global_variable"
+
+; DWARF3: [[NS:[0-9a-f]+]]: DW_TAG_namespace
+; DWARF3-NEXT: DW_AT_name {{.*}} "ns"
+
+; DWARF3: [[GLOB_NS_VAR_DECL:[0-9a-f]+]]: DW_TAG_variable
+; DWARF3-NEXT: DW_AT_name {{.*}} "global_namespace_variable"
+
+; DWARF3: [[D_VAR_DECL:[0-9a-f]+]]: DW_TAG_variable
+; DWARF3-NEXT: DW_AT_name {{.*}} "d"
+
+; DWARF3: [[D:[0-9a-f]+]]: DW_TAG_structure_type
+; DWARF3-NEXT: DW_AT_name {{.*}} "D"
+
+; DWARF3: [[GLOB_NS_FUNC:[0-9a-f]+]]: DW_TAG_subprogram
+; DWARF3-NEXT: DW_AT_MIPS_linkage_name
+; DWARF3-NEXT: DW_AT_name {{.*}} "global_namespace_function"
+
+; DWARF3: [[GLOB_NS_VAR:[0-9a-f]+]]: DW_TAG_variable
+; DWARF3-NEXT: DW_AT_specification {{.*}}[[GLOB_NS_VAR_DECL]]
+
+; DWARF3: [[D_VAR:[0-9a-f]+]]: DW_TAG_variable
+; DWARF3-NEXT: DW_AT_specification {{.*}}[[D_VAR_DECL]]
+
+; DWARF3: [[MEM_FUNC:[0-9a-f]+]]: DW_TAG_subprogram
+; DWARF3-NEXT: DW_AT_specification {{.*}}[[MEM_FUNC_DECL]]
+
+; DWARF3: [[STATIC_MEM_FUNC:[0-9a-f]+]]: DW_TAG_subprogram
+; DWARF3-NEXT: DW_AT_specification {{.*}}[[STATIC_MEM_FUNC_DECL]]
+
+; DWARF3: [[GLOBAL_FUNC:[0-9a-f]+]]: DW_TAG_subprogram
+; DWARF3-NEXT: DW_AT_MIPS_linkage_name
+; DWARF3-NEXT: DW_AT_name {{.*}} "global_function"
+
+; DWARF3-LABEL: .debug_gnu_pubnames contents:
+; DWARF3-NEXT: length = 0x000000e7 version = 0x0002 unit_offset = 0x00000000 unit_size = 0x0000018b
+; DWARF3-NEXT: Offset Linkage Kind Name
+; DWARF3-DAG: [[GLOBAL_FUNC]] EXTERNAL FUNCTION "global_function"
+; DWARF3-DAG: [[NS]] EXTERNAL TYPE "ns"
+; DWARF3-DAG: [[MEM_FUNC]] EXTERNAL FUNCTION "C::member_function"
+; DWARF3-DAG: [[GLOB_VAR]] EXTERNAL VARIABLE "global_variable"
+; DWARF3-DAG: [[GLOB_NS_VAR]] EXTERNAL VARIABLE "ns::global_namespace_variable"
+; DWARF3-DAG: [[GLOB_NS_FUNC]] EXTERNAL FUNCTION "ns::global_namespace_function"
+; DWARF3-DAG: [[D_VAR]] EXTERNAL VARIABLE "ns::d"
+; DWARF3-DAG: [[STATIC_MEM_VAR]] EXTERNAL VARIABLE "C::static_member_variable"
+; DWARF3-DAG: [[STATIC_MEM_FUNC]] EXTERNAL FUNCTION "C::static_member_function"
+
+
+; DWARF3-LABEL: debug_gnu_pubtypes contents:
+; DWARF3: Offset Linkage Kind Name
+; DWARF3-DAG: [[C]] EXTERNAL TYPE "C"
+; DWARF3-DAG: [[D]] EXTERNAL TYPE "ns::D"
+; DWARF3-DAG: [[INT]] STATIC TYPE "int"
+
%struct.C = type { i8 }
%"struct.ns::D" = type { i32 }
Index: test/DebugInfo/X86/stmt-list-multiple-compile-units.ll
===================================================================
--- test/DebugInfo/X86/stmt-list-multiple-compile-units.ll
+++ test/DebugInfo/X86/stmt-list-multiple-compile-units.ll
@@ -1,5 +1,7 @@
; RUN: llc -O0 %s -mtriple=x86_64-apple-darwin -filetype=obj -o %t
; RUN: llvm-dwarfdump %t | FileCheck %s
+; RUN: llc -O0 %s -mtriple=x86_64-apple-darwin -filetype=obj -o %t -dwarf-version=3
+; RUN: llvm-dwarfdump %t | FileCheck %s -check-prefix=DWARF3
; RUN: llc < %s -O0 -mtriple=x86_64-apple-macosx10.7 | FileCheck %s -check-prefix=ASM
; rdar://13067005
@@ -6,11 +8,11 @@
; CHECK: .debug_info contents:
; CHECK: DW_TAG_compile_unit
; CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000)
-; CHECK: DW_AT_stmt_list [DW_FORM_data4] (0x00000000)
+; CHECK: DW_AT_stmt_list [DW_FORM_sec_offset] (0x00000000)
; CHECK: DW_TAG_compile_unit
; CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000)
-; CHECK: DW_AT_stmt_list [DW_FORM_data4] (0x0000003c)
+; CHECK: DW_AT_stmt_list [DW_FORM_sec_offset] (0x0000003c)
; CHECK: .debug_line contents:
; CHECK-NEXT: Line table prologue:
@@ -21,6 +23,24 @@
; CHECK: file_names[ 1] 0 0x00000000 0x00000000 simple2.c
; CHECK-NOT: file_names
+; DWARF3: .debug_info contents:
+; DWARF3: DW_TAG_compile_unit
+; DWARF3: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000)
+; DWARF3: DW_AT_stmt_list [DW_FORM_data4] (0x00000000)
+
+; DWARF3: DW_TAG_compile_unit
+; DWARF3: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000)
+; DWARF3: DW_AT_stmt_list [DW_FORM_data4] (0x0000003c)
+
+; DWARF3: .debug_line contents:
+; DWARF3-NEXT: Line table prologue:
+; DWARF3-NEXT: total_length: 0x00000038
+; DWARF3: file_names[ 1] 0 0x00000000 0x00000000 simple.c
+; DWARF3: Line table prologue:
+; DWARF3-NEXT: total_length: 0x00000039
+; DWARF3: file_names[ 1] 0 0x00000000 0x00000000 simple2.c
+; DWARF3-NOT: file_names
+
; PR15408
; ASM: L__DWARF__debug_info_begin0:
; ASM: .long 0 ## DW_AT_stmt_list
Index: test/DebugInfo/X86/block-capture.ll
===================================================================
--- test/DebugInfo/X86/block-capture.ll
+++ test/DebugInfo/X86/block-capture.ll
@@ -1,5 +1,7 @@
; RUN: llc -mtriple=x86_64-apple-darwin %s -o %t -filetype=obj
; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s
+; RUN: llc -mtriple=x86_64-apple-darwin %s -o %t -filetype=obj -dwarf-version=3
+; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s -check-prefix=DWARF3
; Checks that we emit debug info for the block variable declare.
; CHECK: DW_TAG_subprogram [3]
@@ -7,6 +9,11 @@
; CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[{{.*}}] = "block")
; CHECK: DW_AT_location [DW_FORM_sec_offset] ({{.*}})
+; DWARF3: DW_TAG_subprogram [3]
+; DWARF3: DW_TAG_variable [5]
+; DWARF3: DW_AT_name [DW_FORM_strp] ( .debug_str[{{.*}}] = "block")
+; DWARF3: DW_AT_location [DW_FORM_data4] ({{.*}})
+
%struct.__block_descriptor = type { i64, i64 }
%struct.__block_literal_generic = type { i8*, i32, i32, i8*, %struct.__block_descriptor* }
Index: test/DebugInfo/X86/op_deref.ll
===================================================================
--- test/DebugInfo/X86/op_deref.ll
+++ test/DebugInfo/X86/op_deref.ll
@@ -1,5 +1,7 @@
; RUN: llc -O0 -mtriple=x86_64-apple-darwin %s -o %t -filetype=obj
; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s -check-prefix=DW-CHECK
+; RUN: llc -O0 -mtriple=x86_64-apple-darwin %s -o %t -filetype=obj -dwarf-version=3
+; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s -check-prefix=DWARF3
; DW-CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000067] = "vla")
; FIXME: The location here needs to be fixed, but llvm-dwarfdump doesn't handle
@@ -6,6 +8,11 @@
; DW_AT_location lists yet.
; DW-CHECK: DW_AT_location [DW_FORM_sec_offset] (0x00000000)
+; DWARF3: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000067] = "vla")
+; FIXME: The location here needs to be fixed, but llvm-dwarfdump doesn't handle
+; DW_AT_location lists yet.
+; DWARF3: DW_AT_location [DW_FORM_data4] (0x00000000)
+
; Unfortunately llvm-dwarfdump can't unparse a list of DW_AT_locations
; right now, so we check the asm output:
; RUN: llc -O0 -mtriple=x86_64-apple-darwin %s -o - -filetype=asm | FileCheck %s -check-prefix=ASM-CHECK
Index: test/DebugInfo/X86/DW_AT_stmt_list_sec_offset.ll
===================================================================
--- test/DebugInfo/X86/DW_AT_stmt_list_sec_offset.ll
+++ test/DebugInfo/X86/DW_AT_stmt_list_sec_offset.ll
@@ -1,7 +1,10 @@
; RUN: llc -mtriple=i686-w64-mingw32 -o %t -filetype=obj %s
; RUN: llvm-dwarfdump -debug-dump=all %t | FileCheck %s
+; RUN: llc -mtriple=i686-w64-mingw32 -o %t -filetype=obj -dwarf-version=3 %s
+; RUN: llvm-dwarfdump -debug-dump=all %t | FileCheck %s -check-prefix=DWARF3
; CHECK: DW_AT_stmt_list [DW_FORM_sec_offset]
+; DWARF3: DW_AT_stmt_list [DW_FORM_data4]
;
; generated from:
; clang -g -S -emit-llvm test.c -o test.ll
@@ -36,6 +39,6 @@ attributes #0 = { nounwind "less-precise-fpmad"="f
!6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !7, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
!7 = metadata !{metadata !8}
!8 = metadata !{i32 786468, null, null, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed]
-!9 = metadata !{i32 2, metadata !"Dwarf Version", i32 3}
+!9 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
!10 = metadata !{i32 3, i32 0, metadata !4, null}
!11 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}

View File

@ -0,0 +1,91 @@
Pull in r198385 from upstream llvm trunk (by David Blaikie):
Reverting r193835 due to weirdness with Go...
Apologies for the noise - we're seeing some Go failures with cgo
interacting with Clang's debug info due to this change.
Introduced here: http://svn.freebsd.org/changeset/base/261991
Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
===================================================================
--- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -1845,9 +1845,6 @@ void CompileUnit::constructMemberDIE(DIE &Buffer,
addSourceLine(MemberDie, DT);
- DIEBlock *MemLocationDie = new (DIEValueAllocator) DIEBlock();
- addUInt(MemLocationDie, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst);
-
if (DT.getTag() == dwarf::DW_TAG_inheritance && DT.isVirtual()) {
// For C++, virtual base classes are not at fixed offset. Use following
@@ -1892,7 +1889,11 @@ void CompileUnit::constructMemberDIE(DIE &Buffer,
} else
// This is not a bitfield.
OffsetInBytes = DT.getOffsetInBits() >> 3;
- addUInt(MemberDie, dwarf::DW_AT_data_member_location, None, OffsetInBytes);
+
+ DIEBlock *MemLocationDie = new (DIEValueAllocator) DIEBlock();
+ addUInt(MemLocationDie, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst);
+ addUInt(MemLocationDie, dwarf::DW_FORM_udata, OffsetInBytes);
+ addBlock(MemberDie, dwarf::DW_AT_data_member_location, MemLocationDie);
}
if (DT.isProtected())
Index: test/DebugInfo/X86/data_member_location.ll
===================================================================
--- test/DebugInfo/X86/data_member_location.ll
+++ test/DebugInfo/X86/data_member_location.ll
@@ -11,11 +11,11 @@
; CHECK: DW_AT_name {{.*}} "c"
; CHECK-NOT: DW_TAG
-; CHECK: DW_AT_data_member_location {{.*}} (0x00)
+; CHECK: DW_AT_data_member_location {{.*}} (<0x02> 23 00 )
; CHECK: DW_AT_name {{.*}} "i"
; CHECK-NOT: DW_TAG
-; CHECK: DW_AT_data_member_location {{.*}} (0x04)
+; CHECK: DW_AT_data_member_location {{.*}} (<0x02> 23 04 )
%struct.foo = type { i8, i32 }
Index: test/DebugInfo/X86/concrete_out_of_line.ll
===================================================================
--- test/DebugInfo/X86/concrete_out_of_line.ll
+++ test/DebugInfo/X86/concrete_out_of_line.ll
@@ -7,7 +7,7 @@
; first check that we have a TAG_subprogram at a given offset and it has
; AT_inline.
-; CHECK: 0x0000011c: DW_TAG_subprogram [17]
+; CHECK: 0x0000011e: DW_TAG_subprogram [17]
; CHECK-NEXT: DW_AT_specification
; CHECK-NEXT: DW_AT_inline
@@ -14,8 +14,8 @@
; and then that a TAG_subprogram refers to it with AT_abstract_origin.
-; CHECK: 0x0000015d: DW_TAG_subprogram [19]
-; CHECK-NEXT: DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x011c => {0x0000011c})
+; CHECK: 0x0000015f: DW_TAG_subprogram [19]
+; CHECK-NEXT: DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x011e => {0x0000011e})
define i32 @_ZN17nsAutoRefCnt7ReleaseEv() {
entry:
Index: test/DebugInfo/X86/generate-odr-hash.ll
===================================================================
--- test/DebugInfo/X86/generate-odr-hash.ll
+++ test/DebugInfo/X86/generate-odr-hash.ll
@@ -1,5 +1,8 @@
; REQUIRES: object-emission
+; Fail while investigating problem with non-block representations of member offsets.
+; XFAIL: *
+
; RUN: llc %s -o %t -filetype=obj -O0 -generate-odr-hash -mtriple=x86_64-unknown-linux-gnu
; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s
;

View File

@ -0,0 +1,105 @@
Pull in r198389 from upstream llvm trunk (by David Blaikie):
Revert "Reverting r193835 due to weirdness with Go..."
The cgo problem was that it wants dwarf2 which doesn't support direct
constant encoding of the location. So let's add support for dwarf2
encoding (using a location expression) of data member locations.
This reverts commit r198385.
Introduced here: http://svn.freebsd.org/changeset/base/261991
Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
===================================================================
--- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -1890,10 +1890,14 @@ void CompileUnit::constructMemberDIE(DIE &Buffer,
// This is not a bitfield.
OffsetInBytes = DT.getOffsetInBits() >> 3;
- DIEBlock *MemLocationDie = new (DIEValueAllocator) DIEBlock();
- addUInt(MemLocationDie, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst);
- addUInt(MemLocationDie, dwarf::DW_FORM_udata, OffsetInBytes);
- addBlock(MemberDie, dwarf::DW_AT_data_member_location, MemLocationDie);
+ if (DD->getDwarfVersion() <= 2) {
+ DIEBlock *MemLocationDie = new (DIEValueAllocator) DIEBlock();
+ addUInt(MemLocationDie, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst);
+ addUInt(MemLocationDie, dwarf::DW_FORM_udata, OffsetInBytes);
+ addBlock(MemberDie, dwarf::DW_AT_data_member_location, MemLocationDie);
+ } else
+ addUInt(MemberDie, dwarf::DW_AT_data_member_location, None,
+ OffsetInBytes);
}
if (DT.isProtected())
Index: test/DebugInfo/X86/data_member_location.ll
===================================================================
--- test/DebugInfo/X86/data_member_location.ll
+++ test/DebugInfo/X86/data_member_location.ll
@@ -1,4 +1,5 @@
; RUN: llc -mtriple=x86_64-linux -O0 -o - -filetype=obj < %s | llvm-dwarfdump -debug-dump=info -| FileCheck %s
+; RUN: llc -mtriple=x86_64-linux -dwarf-version=2 -O0 -o - -filetype=obj < %s | llvm-dwarfdump -debug-dump=info -| FileCheck -check-prefix=DWARF2 %s
; Generated from Clang with the following source:
;
@@ -11,12 +12,20 @@
; CHECK: DW_AT_name {{.*}} "c"
; CHECK-NOT: DW_TAG
-; CHECK: DW_AT_data_member_location {{.*}} (<0x02> 23 00 )
+; CHECK: DW_AT_data_member_location {{.*}} (0x00)
; CHECK: DW_AT_name {{.*}} "i"
; CHECK-NOT: DW_TAG
-; CHECK: DW_AT_data_member_location {{.*}} (<0x02> 23 04 )
+; CHECK: DW_AT_data_member_location {{.*}} (0x04)
+; DWARF2: DW_AT_name {{.*}} "c"
+; DWARF2-NOT: DW_TAG
+; DWARF2: DW_AT_data_member_location {{.*}} (<0x02> 23 00 )
+
+; DWARF2: DW_AT_name {{.*}} "i"
+; DWARF2-NOT: DW_TAG
+; DWARF2: DW_AT_data_member_location {{.*}} (<0x02> 23 04 )
+
%struct.foo = type { i8, i32 }
@f = global %struct.foo zeroinitializer, align 4
Index: test/DebugInfo/X86/concrete_out_of_line.ll
===================================================================
--- test/DebugInfo/X86/concrete_out_of_line.ll
+++ test/DebugInfo/X86/concrete_out_of_line.ll
@@ -7,7 +7,7 @@
; first check that we have a TAG_subprogram at a given offset and it has
; AT_inline.
-; CHECK: 0x0000011e: DW_TAG_subprogram [17]
+; CHECK: 0x0000011c: DW_TAG_subprogram [17]
; CHECK-NEXT: DW_AT_specification
; CHECK-NEXT: DW_AT_inline
@@ -14,8 +14,8 @@
; and then that a TAG_subprogram refers to it with AT_abstract_origin.
-; CHECK: 0x0000015f: DW_TAG_subprogram [19]
-; CHECK-NEXT: DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x011e => {0x0000011e})
+; CHECK: 0x0000015d: DW_TAG_subprogram [19]
+; CHECK-NEXT: DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x011c => {0x0000011c})
define i32 @_ZN17nsAutoRefCnt7ReleaseEv() {
entry:
Index: test/DebugInfo/X86/generate-odr-hash.ll
===================================================================
--- test/DebugInfo/X86/generate-odr-hash.ll
+++ test/DebugInfo/X86/generate-odr-hash.ll
@@ -1,8 +1,5 @@
; REQUIRES: object-emission
-; Fail while investigating problem with non-block representations of member offsets.
-; XFAIL: *
-
; RUN: llc %s -o %t -filetype=obj -O0 -generate-odr-hash -mtriple=x86_64-unknown-linux-gnu
; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s
;

View File

@ -0,0 +1,258 @@
Pull in r198028 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Add MCInstPrinter implementation for SPARC.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/InstPrinter/LLVMBuild.txt
===================================================================
--- lib/Target/Sparc/InstPrinter/LLVMBuild.txt
+++ lib/Target/Sparc/InstPrinter/LLVMBuild.txt
@@ -0,0 +1,23 @@
+;===- ./lib/Target/Sparc/InstPrinter/LLVMBuild.txt -------------*- Conf -*--===;
+;
+; The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+; http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Library
+name = SparcAsmPrinter
+parent = Sparc
+required_libraries = MC Support
+add_to_library_groups = Sparc
Index: lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
===================================================================
--- lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
+++ lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
@@ -0,0 +1,95 @@
+//===-- SparcInstPrinter.cpp - Convert Sparc MCInst to assembly syntax -----==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class prints an Sparc MCInst to a .s file.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "asm-printer"
+#include "SparcInstPrinter.h"
+
+#include "Sparc.h"
+#include "MCTargetDesc/SparcBaseInfo.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+#define GET_INSTRUCTION_NAME
+// Uncomment the following line once we are ready to use MCAsmWriter.
+//#include "SparcGenAsmWriter.inc"
+
+void SparcInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const
+{
+ OS << '%' << StringRef(getRegisterName(RegNo)).lower();
+}
+
+void SparcInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
+ StringRef Annot)
+{
+ printInstruction(MI, O);
+ printAnnotation(O, Annot);
+}
+
+void SparcInstPrinter::printOperand(const MCInst *MI, int opNum,
+ raw_ostream &O)
+{
+ const MCOperand &MO = MI->getOperand (opNum);
+
+ if (MO.isReg()) {
+ printRegName(O, MO.getReg());
+ return ;
+ }
+
+ if (MO.isImm()) {
+ O << (int)MO.getImm();
+ return;
+ }
+
+ assert(MO.isExpr() && "Unknown operand kind in printOperand");
+ MO.getExpr()->print(O);
+}
+
+void SparcInstPrinter::printMemOperand(const MCInst *MI, int opNum,
+ raw_ostream &O, const char *Modifier)
+{
+ printOperand(MI, opNum, O);
+
+ // If this is an ADD operand, emit it like normal operands.
+ if (Modifier && !strcmp(Modifier, "arith")) {
+ O << ", ";
+ printOperand(MI, opNum+1, O);
+ return;
+ }
+ const MCOperand &MO = MI->getOperand(opNum+1);
+
+ if (MO.isReg() && MO.getReg() == SP::G0)
+ return; // don't print "+%g0"
+ if (MO.isImm() && MO.getImm() == 0)
+ return; // don't print "+0"
+
+ O << "+";
+
+ printOperand(MI, opNum+1, O);
+}
+
+void SparcInstPrinter::printCCOperand(const MCInst *MI, int opNum,
+ raw_ostream &O)
+{
+ int CC = (int)MI->getOperand(opNum).getImm();
+ O << SPARCCondCodeToString((SPCC::CondCodes)CC);
+}
+
+bool SparcInstPrinter::printGetPCX(const MCInst *MI, unsigned opNum,
+ raw_ostream &O)
+{
+ assert(0 && "FIXME: Implement SparcInstPrinter::printGetPCX.");
+ return true;
+}
Index: lib/Target/Sparc/InstPrinter/CMakeLists.txt
===================================================================
--- lib/Target/Sparc/InstPrinter/CMakeLists.txt
+++ lib/Target/Sparc/InstPrinter/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_llvm_library(LLVMSparcAsmPrinter
+ SparcInstPrinter.cpp
+ )
Index: lib/Target/Sparc/InstPrinter/Makefile
===================================================================
--- lib/Target/Sparc/InstPrinter/Makefile
+++ lib/Target/Sparc/InstPrinter/Makefile
@@ -0,0 +1,16 @@
+##===- lib/Target/Sparc/InstPrinter/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 = LLVMSparcAsmPrinter
+
+# Hack: we need to include 'main' target directory to grab private headers
+CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
+
+include $(LEVEL)/Makefile.common
Index: lib/Target/Sparc/InstPrinter/SparcInstPrinter.h
===================================================================
--- lib/Target/Sparc/InstPrinter/SparcInstPrinter.h
+++ lib/Target/Sparc/InstPrinter/SparcInstPrinter.h
@@ -0,0 +1,46 @@
+//===-- SparcInstPrinter.h - Convert Sparc MCInst to assembly syntax ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class prints an Sparc MCInst to a .s file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SparcINSTPRINTER_H
+#define SparcINSTPRINTER_H
+
+#include "llvm/MC/MCInstPrinter.h"
+
+namespace llvm {
+
+class MCOperand;
+
+class SparcInstPrinter : public MCInstPrinter {
+public:
+ SparcInstPrinter(const MCAsmInfo &MAI,
+ const MCInstrInfo &MII,
+ const MCRegisterInfo &MRI)
+ : MCInstPrinter(MAI, MII, MRI) {}
+
+ virtual void printRegName(raw_ostream &OS, unsigned RegNo) const;
+ virtual void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot);
+
+ // Autogenerated by tblgen.
+ void printInstruction(const MCInst *MI, raw_ostream &O);
+ static const char *getRegisterName(unsigned RegNo);
+
+ void printOperand(const MCInst *MI, int opNum, raw_ostream &OS);
+ void printMemOperand(const MCInst *MI, int opNum, raw_ostream &OS,
+ const char *Modifier = 0);
+ void printCCOperand(const MCInst *MI, int opNum, raw_ostream &OS);
+ bool printGetPCX(const MCInst *MI, unsigned OpNo, raw_ostream &OS);
+
+};
+} // end namespace llvm
+
+#endif
Index: lib/Target/Sparc/LLVMBuild.txt
===================================================================
--- lib/Target/Sparc/LLVMBuild.txt
+++ lib/Target/Sparc/LLVMBuild.txt
@@ -16,7 +16,7 @@
;===------------------------------------------------------------------------===;
[common]
-subdirectories = MCTargetDesc TargetInfo
+subdirectories = InstPrinter MCTargetDesc TargetInfo
[component_0]
type = TargetGroup
@@ -29,6 +29,6 @@ has_jit = 1
type = Library
name = SparcCodeGen
parent = Sparc
-required_libraries = AsmPrinter CodeGen Core MC SelectionDAG SparcDesc
- SparcInfo Support Target
+required_libraries = AsmPrinter CodeGen Core MC SelectionDAG SparcAsmPrinter
+ SparcDesc SparcInfo Support Target
add_to_library_groups = Sparc
Index: lib/Target/Sparc/CMakeLists.txt
===================================================================
--- lib/Target/Sparc/CMakeLists.txt
+++ lib/Target/Sparc/CMakeLists.txt
@@ -29,3 +29,4 @@ add_dependencies(LLVMSparcCodeGen SparcCommonTable
add_subdirectory(TargetInfo)
add_subdirectory(MCTargetDesc)
+add_subdirectory(InstPrinter)
Index: lib/Target/Sparc/Makefile
===================================================================
--- lib/Target/Sparc/Makefile
+++ lib/Target/Sparc/Makefile
@@ -17,7 +17,7 @@ BUILT_SOURCES = SparcGenRegisterInfo.inc SparcGenI
SparcGenSubtargetInfo.inc SparcGenCallingConv.inc \
SparcGenCodeEmitter.inc
-DIRS = TargetInfo MCTargetDesc
+DIRS = InstPrinter TargetInfo MCTargetDesc
include $(LEVEL)/Makefile.common

View File

@ -0,0 +1,210 @@
Pull in r198029 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Add target specific MCExpr class to handle sparc specific modifiers like %hi, %lo, etc.,
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
@@ -0,0 +1,84 @@
+//===-- SparcMCExpr.cpp - Sparc specific MC expression classes --------===//
+//
+// 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 implementation of the assembly expression modifiers
+// accepted by the Sparc architecture (e.g. "%hi", "%lo", ...).
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "sparcmcexpr"
+#include "SparcMCExpr.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCELF.h"
+#include "llvm/Object/ELF.h"
+
+
+using namespace llvm;
+
+const SparcMCExpr*
+SparcMCExpr::Create(VariantKind Kind, const MCExpr *Expr,
+ MCContext &Ctx) {
+ return new (Ctx) SparcMCExpr(Kind, Expr);
+}
+
+
+void SparcMCExpr::PrintImpl(raw_ostream &OS) const
+{
+ bool closeParen = true;
+ switch (Kind) {
+ case VK_Sparc_None: closeParen = false; break;
+ case VK_Sparc_LO: OS << "%lo("; break;
+ case VK_Sparc_HI: OS << "%hi("; break;
+ case VK_Sparc_H44: OS << "%h44("; break;
+ case VK_Sparc_M44: OS << "%m44("; break;
+ case VK_Sparc_L44: OS << "%l44("; break;
+ case VK_Sparc_HH: OS << "%hh("; break;
+ case VK_Sparc_HM: OS << "%hm("; break;
+ case VK_Sparc_TLS_GD_HI22: OS << "%tgd_hi22("; break;
+ case VK_Sparc_TLS_GD_LO10: OS << "%tgd_lo10("; break;
+ case VK_Sparc_TLS_GD_ADD: OS << "%tgd_add("; break;
+ case VK_Sparc_TLS_GD_CALL: OS << "%tgd_call("; break;
+ case VK_Sparc_TLS_LDM_HI22: OS << "%tldm_hi22("; break;
+ case VK_Sparc_TLS_LDM_LO10: OS << "%tldm_lo10("; break;
+ case VK_Sparc_TLS_LDM_ADD: OS << "%tldm_add("; break;
+ case VK_Sparc_TLS_LDM_CALL: OS << "%tldm_call("; break;
+ case VK_Sparc_TLS_LDO_HIX22: OS << "%tldo_hix22("; break;
+ case VK_Sparc_TLS_LDO_LOX10: OS << "%tldo_lox10("; break;
+ case VK_Sparc_TLS_LDO_ADD: OS << "%tldo_add("; break;
+ case VK_Sparc_TLS_IE_HI22: OS << "%tie_hi22("; break;
+ case VK_Sparc_TLS_IE_LO10: OS << "%tie_lo10("; break;
+ case VK_Sparc_TLS_IE_LD: OS << "%tie_ld("; break;
+ case VK_Sparc_TLS_IE_LDX: OS << "%tie_ldx("; break;
+ case VK_Sparc_TLS_IE_ADD: OS << "%tie_add("; break;
+ case VK_Sparc_TLS_LE_HIX22: OS << "%tle_hix22("; break;
+ case VK_Sparc_TLS_LE_LOX10: OS << "%tle_lox10("; break;
+ }
+
+ const MCExpr *Expr = getSubExpr();
+ Expr->print(OS);
+ if (closeParen)
+ OS << ')';
+}
+
+bool
+SparcMCExpr::EvaluateAsRelocatableImpl(MCValue &Res,
+ const MCAsmLayout *Layout) const {
+ assert(0 && "FIXME: Implement SparcMCExpr::EvaluateAsRelocatableImpl");
+ return getSubExpr()->EvaluateAsRelocatable(Res, *Layout);
+}
+
+
+void SparcMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
+ assert(0 && "FIXME: Implement SparcMCExpr::fixELFSymbolsInTLSFixups");
+}
+
+void SparcMCExpr::AddValueSymbols(MCAssembler *Asm) const {
+ assert(0 && "FIXME: Implement SparcMCExpr::AddValueSymbols");
+}
Index: lib/Target/Sparc/MCTargetDesc/CMakeLists.txt
===================================================================
--- lib/Target/Sparc/MCTargetDesc/CMakeLists.txt
+++ lib/Target/Sparc/MCTargetDesc/CMakeLists.txt
@@ -1,6 +1,7 @@
add_llvm_library(LLVMSparcDesc
SparcMCTargetDesc.cpp
SparcMCAsmInfo.cpp
+ SparcMCExpr.cpp
)
add_dependencies(LLVMSparcDesc SparcCommonTableGen)
Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
+++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
@@ -0,0 +1,98 @@
+//====- SparcMCExpr.h - Sparc specific MC expression classes --*- C++ -*-=====//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file describes Sparc-specific MCExprs, used for modifiers like
+// "%hi" or "%lo" etc.,
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SPARCMCEXPR_H
+#define LLVM_SPARCMCEXPR_H
+
+#include "llvm/MC/MCExpr.h"
+
+namespace llvm {
+
+class SparcMCExpr : public MCTargetExpr {
+public:
+ enum VariantKind {
+ VK_Sparc_None,
+ VK_Sparc_LO,
+ VK_Sparc_HI,
+ VK_Sparc_H44,
+ VK_Sparc_M44,
+ VK_Sparc_L44,
+ VK_Sparc_HH,
+ VK_Sparc_HM,
+ VK_Sparc_TLS_GD_HI22,
+ VK_Sparc_TLS_GD_LO10,
+ VK_Sparc_TLS_GD_ADD,
+ VK_Sparc_TLS_GD_CALL,
+ VK_Sparc_TLS_LDM_HI22,
+ VK_Sparc_TLS_LDM_LO10,
+ VK_Sparc_TLS_LDM_ADD,
+ VK_Sparc_TLS_LDM_CALL,
+ VK_Sparc_TLS_LDO_HIX22,
+ VK_Sparc_TLS_LDO_LOX10,
+ VK_Sparc_TLS_LDO_ADD,
+ VK_Sparc_TLS_IE_HI22,
+ VK_Sparc_TLS_IE_LO10,
+ VK_Sparc_TLS_IE_LD,
+ VK_Sparc_TLS_IE_LDX,
+ VK_Sparc_TLS_IE_ADD,
+ VK_Sparc_TLS_LE_HIX22,
+ VK_Sparc_TLS_LE_LOX10
+ };
+
+private:
+ const VariantKind Kind;
+ const MCExpr *Expr;
+
+ explicit SparcMCExpr(VariantKind _Kind, const MCExpr *_Expr)
+ : Kind(_Kind), Expr(_Expr) {}
+
+public:
+ /// @name Construction
+ /// @{
+
+ static const SparcMCExpr *Create(VariantKind Kind, const MCExpr *Expr,
+ MCContext &Ctx);
+ /// @}
+ /// @name Accessors
+ /// @{
+
+ /// getOpcode - Get the kind of this expression.
+ VariantKind getKind() const { return Kind; }
+
+ /// getSubExpr - Get the child of this expression.
+ const MCExpr *getSubExpr() const { return Expr; }
+
+ /// @}
+ void PrintImpl(raw_ostream &OS) const;
+ bool EvaluateAsRelocatableImpl(MCValue &Res,
+ const MCAsmLayout *Layout) const;
+ void AddValueSymbols(MCAssembler *) const;
+ const MCSection *FindAssociatedSection() const {
+ return getSubExpr()->FindAssociatedSection();
+ }
+
+ void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const;
+
+ static bool classof(const MCExpr *E) {
+ return E->getKind() == MCExpr::Target;
+ }
+
+ static bool classof(const SparcMCExpr *) { return true; }
+
+
+};
+
+} // end namespace llvm.
+
+#endif

View File

@ -0,0 +1,678 @@
Pull in r198030 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Lower and MachineInstr to MC and print assembly using MCInstPrinter.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp
@@ -0,0 +1,40 @@
+//===-- SparcTargetStreamer.cpp - Sparc Target Streamer Methods -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides Sparc specific target streamer methods.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcTargetStreamer.h"
+#include "InstPrinter/SparcInstPrinter.h"
+#include "llvm/Support/FormattedStream.h"
+
+using namespace llvm;
+
+// pin vtable to this file
+void SparcTargetStreamer::anchor() {}
+
+SparcTargetAsmStreamer::SparcTargetAsmStreamer(formatted_raw_ostream &OS)
+ : OS(OS) {}
+
+void SparcTargetAsmStreamer::emitSparcRegisterIgnore(unsigned reg) {
+ OS << "\t.register "
+ << "%" << StringRef(SparcInstPrinter::getRegisterName(reg)).lower()
+ << ", #ignore\n";
+}
+
+void SparcTargetAsmStreamer::emitSparcRegisterScratch(unsigned reg) {
+ OS << "\t.register "
+ << "%" << StringRef(SparcInstPrinter::getRegisterName(reg)).lower()
+ << ", #scratch\n";
+}
+
+MCELFStreamer &SparcTargetELFStreamer::getStreamer() {
+ return static_cast<MCELFStreamer &>(*Streamer);
+}
Index: lib/Target/Sparc/MCTargetDesc/LLVMBuild.txt
===================================================================
--- lib/Target/Sparc/MCTargetDesc/LLVMBuild.txt
+++ lib/Target/Sparc/MCTargetDesc/LLVMBuild.txt
@@ -19,5 +19,5 @@
type = Library
name = SparcDesc
parent = Sparc
-required_libraries = MC SparcInfo Support
+required_libraries = MC SparcAsmPrinter SparcInfo Support
add_to_library_groups = Sparc
Index: lib/Target/Sparc/MCTargetDesc/CMakeLists.txt
===================================================================
--- lib/Target/Sparc/MCTargetDesc/CMakeLists.txt
+++ lib/Target/Sparc/MCTargetDesc/CMakeLists.txt
@@ -2,6 +2,7 @@ add_llvm_library(LLVMSparcDesc
SparcMCTargetDesc.cpp
SparcMCAsmInfo.cpp
SparcMCExpr.cpp
+ SparcTargetStreamer.cpp
)
add_dependencies(LLVMSparcDesc SparcCommonTableGen)
Index: lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
@@ -13,6 +13,8 @@
#include "SparcMCTargetDesc.h"
#include "SparcMCAsmInfo.h"
+#include "SparcTargetStreamer.h"
+#include "InstPrinter/SparcInstPrinter.h"
#include "llvm/MC/MCCodeGenInfo.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
@@ -86,6 +88,28 @@ static MCCodeGenInfo *createSparcV9MCCodeGenInfo(S
X->InitMCCodeGenInfo(RM, CM, OL);
return X;
}
+
+static MCStreamer *
+createMCAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS,
+ bool isVerboseAsm, bool useLoc, bool useCFI,
+ bool useDwarfDirectory, MCInstPrinter *InstPrint,
+ MCCodeEmitter *CE, MCAsmBackend *TAB, bool ShowInst) {
+ SparcTargetAsmStreamer *S = new SparcTargetAsmStreamer(OS);
+
+ return llvm::createAsmStreamer(Ctx, S, OS, isVerboseAsm, useLoc, useCFI,
+ useDwarfDirectory, InstPrint, CE, TAB,
+ ShowInst);
+}
+
+static MCInstPrinter *createSparcMCInstPrinter(const Target &T,
+ unsigned SyntaxVariant,
+ const MCAsmInfo &MAI,
+ const MCInstrInfo &MII,
+ const MCRegisterInfo &MRI,
+ const MCSubtargetInfo &STI) {
+ return new SparcInstPrinter(MAI, MII, MRI);
+}
+
extern "C" void LLVMInitializeSparcTargetMC() {
// Register the MC asm info.
RegisterMCAsmInfo<SparcELFMCAsmInfo> X(TheSparcTarget);
@@ -106,4 +130,15 @@ extern "C" void LLVMInitializeSparcTargetMC() {
// Register the MC subtarget info.
TargetRegistry::RegisterMCSubtargetInfo(TheSparcTarget,
createSparcMCSubtargetInfo);
+
+ TargetRegistry::RegisterAsmStreamer(TheSparcTarget,
+ createMCAsmStreamer);
+ TargetRegistry::RegisterAsmStreamer(TheSparcV9Target,
+ createMCAsmStreamer);
+
+ // Register the MCInstPrinter
+ TargetRegistry::RegisterMCInstPrinter(TheSparcTarget,
+ createSparcMCInstPrinter);
+ TargetRegistry::RegisterMCInstPrinter(TheSparcV9Target,
+ createSparcMCInstPrinter);
}
Index: lib/Target/Sparc/SparcTargetStreamer.h
===================================================================
--- lib/Target/Sparc/SparcTargetStreamer.h
+++ lib/Target/Sparc/SparcTargetStreamer.h
@@ -0,0 +1,47 @@
+//===-- SparcTargetStreamer.h - Sparc Target Streamer ----------*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SPARCTARGETSTREAMER_H
+#define SPARCTARGETSTREAMER_H
+
+#include "llvm/MC/MCELFStreamer.h"
+#include "llvm/MC/MCStreamer.h"
+
+namespace llvm {
+class SparcTargetStreamer : public MCTargetStreamer {
+ virtual void anchor();
+
+public:
+ /// Emit ".register <reg>, #ignore".
+ virtual void emitSparcRegisterIgnore(unsigned reg) = 0;
+ /// Emit ".register <reg>, #scratch".
+ virtual void emitSparcRegisterScratch(unsigned reg) = 0;
+};
+
+// This part is for ascii assembly output
+class SparcTargetAsmStreamer : public SparcTargetStreamer {
+ formatted_raw_ostream &OS;
+
+public:
+ SparcTargetAsmStreamer(formatted_raw_ostream &OS);
+ virtual void emitSparcRegisterIgnore(unsigned reg);
+ virtual void emitSparcRegisterScratch(unsigned reg);
+
+};
+
+// This part is for ELF object output
+class SparcTargetELFStreamer : public SparcTargetStreamer {
+public:
+ MCELFStreamer &getStreamer();
+ virtual void emitSparcRegisterIgnore(unsigned reg) {}
+ virtual void emitSparcRegisterScratch(unsigned reg) {}
+};
+} // end namespace llvm
+
+#endif
Index: lib/Target/Sparc/CMakeLists.txt
===================================================================
--- lib/Target/Sparc/CMakeLists.txt
+++ lib/Target/Sparc/CMakeLists.txt
@@ -23,6 +23,7 @@ add_llvm_target(SparcCodeGen
SparcSelectionDAGInfo.cpp
SparcJITInfo.cpp
SparcCodeEmitter.cpp
+ SparcMCInstLower.cpp
)
add_dependencies(LLVMSparcCodeGen SparcCommonTableGen intrinsics_gen)
Index: lib/Target/Sparc/Sparc.td
===================================================================
--- lib/Target/Sparc/Sparc.td
+++ lib/Target/Sparc/Sparc.td
@@ -65,6 +65,10 @@ def : Proc<"ultrasparc", [FeatureV9, FeatureV
def : Proc<"ultrasparc3", [FeatureV9, FeatureV8Deprecated]>;
def : Proc<"ultrasparc3-vis", [FeatureV9, FeatureV8Deprecated, FeatureVIS]>;
+def SparcAsmWriter : AsmWriter {
+ string AsmWriterClassName = "InstPrinter";
+ bit isMCAsmWriter = 1;
+}
//===----------------------------------------------------------------------===//
// Declare the target which we are implementing
@@ -73,4 +77,6 @@ def : Proc<"ultrasparc3-vis", [FeatureV9, FeatureV
def Sparc : Target {
// Pull in Instruction Info:
let InstructionSet = SparcInstrInfo;
+
+ let AssemblyWriters = [SparcAsmWriter];
}
Index: lib/Target/Sparc/SparcMCInstLower.cpp
===================================================================
--- lib/Target/Sparc/SparcMCInstLower.cpp
+++ lib/Target/Sparc/SparcMCInstLower.cpp
@@ -0,0 +1,141 @@
+//===-- SparcMCInstLower.cpp - Convert Sparc MachineInstr to MCInst -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains code to lower Sparc MachineInstrs to their corresponding
+// MCInst records.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sparc.h"
+#include "MCTargetDesc/SparcBaseInfo.h"
+#include "MCTargetDesc/SparcMCExpr.h"
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/Target/Mangler.h"
+#include "llvm/ADT/SmallString.h"
+
+using namespace llvm;
+
+
+static MCOperand LowerSymbolOperand(const MachineInstr *MI,
+ const MachineOperand &MO,
+ AsmPrinter &AP) {
+
+ SparcMCExpr::VariantKind Kind;
+ const MCSymbol *Symbol = 0;
+
+ unsigned TF = MO.getTargetFlags();
+
+ switch(TF) {
+ default: llvm_unreachable("Unknown target flags on operand");
+ case SPII::MO_NO_FLAG: Kind = SparcMCExpr::VK_Sparc_None; break;
+ case SPII::MO_LO: Kind = SparcMCExpr::VK_Sparc_LO; break;
+ case SPII::MO_HI: Kind = SparcMCExpr::VK_Sparc_HI; break;
+ case SPII::MO_H44: Kind = SparcMCExpr::VK_Sparc_H44; break;
+ case SPII::MO_M44: Kind = SparcMCExpr::VK_Sparc_M44; break;
+ case SPII::MO_L44: Kind = SparcMCExpr::VK_Sparc_L44; break;
+ case SPII::MO_HH: Kind = SparcMCExpr::VK_Sparc_HH; break;
+ case SPII::MO_HM: Kind = SparcMCExpr::VK_Sparc_HM; break;
+ case SPII::MO_TLS_GD_HI22: Kind = SparcMCExpr::VK_Sparc_TLS_GD_HI22; break;
+ case SPII::MO_TLS_GD_LO10: Kind = SparcMCExpr::VK_Sparc_TLS_GD_LO10; break;
+ case SPII::MO_TLS_GD_ADD: Kind = SparcMCExpr::VK_Sparc_TLS_GD_ADD; break;
+ case SPII::MO_TLS_GD_CALL: Kind = SparcMCExpr::VK_Sparc_TLS_GD_CALL; break;
+ case SPII::MO_TLS_LDM_HI22: Kind = SparcMCExpr::VK_Sparc_TLS_LDM_HI22; break;
+ case SPII::MO_TLS_LDM_LO10: Kind = SparcMCExpr::VK_Sparc_TLS_LDM_LO10; break;
+ case SPII::MO_TLS_LDM_ADD: Kind = SparcMCExpr::VK_Sparc_TLS_LDM_ADD; break;
+ case SPII::MO_TLS_LDM_CALL: Kind = SparcMCExpr::VK_Sparc_TLS_LDM_CALL; break;
+ case SPII::MO_TLS_LDO_HIX22:Kind = SparcMCExpr::VK_Sparc_TLS_LDO_HIX22; break;
+ case SPII::MO_TLS_LDO_LOX10:Kind = SparcMCExpr::VK_Sparc_TLS_LDO_LOX10; break;
+ case SPII::MO_TLS_LDO_ADD: Kind = SparcMCExpr::VK_Sparc_TLS_LDO_ADD; break;
+ case SPII::MO_TLS_IE_HI22: Kind = SparcMCExpr::VK_Sparc_TLS_IE_HI22; break;
+ case SPII::MO_TLS_IE_LO10: Kind = SparcMCExpr::VK_Sparc_TLS_IE_LO10; break;
+ case SPII::MO_TLS_IE_LD: Kind = SparcMCExpr::VK_Sparc_TLS_IE_LD; break;
+ case SPII::MO_TLS_IE_LDX: Kind = SparcMCExpr::VK_Sparc_TLS_IE_LDX; break;
+ case SPII::MO_TLS_IE_ADD: Kind = SparcMCExpr::VK_Sparc_TLS_IE_ADD; break;
+ case SPII::MO_TLS_LE_HIX22: Kind = SparcMCExpr::VK_Sparc_TLS_LE_HIX22; break;
+ case SPII::MO_TLS_LE_LOX10: Kind = SparcMCExpr::VK_Sparc_TLS_LE_LOX10; break;
+ }
+
+ switch(MO.getType()) {
+ default: llvm_unreachable("Unknown type in LowerSymbolOperand");
+ case MachineOperand::MO_MachineBasicBlock:
+ Symbol = MO.getMBB()->getSymbol();
+ break;
+
+ case MachineOperand::MO_GlobalAddress:
+ Symbol = AP.getSymbol(MO.getGlobal());
+ break;
+
+ case MachineOperand::MO_BlockAddress:
+ Symbol = AP.GetBlockAddressSymbol(MO.getBlockAddress());
+ break;
+
+ case MachineOperand::MO_ExternalSymbol:
+ Symbol = AP.GetExternalSymbolSymbol(MO.getSymbolName());
+ break;
+
+ case MachineOperand::MO_ConstantPoolIndex:
+ Symbol = AP.GetCPISymbol(MO.getIndex());
+ break;
+ }
+
+ const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Symbol,
+ AP.OutContext);
+ const SparcMCExpr *expr = SparcMCExpr::Create(Kind, MCSym,
+ AP.OutContext);
+ return MCOperand::CreateExpr(expr);
+}
+
+static MCOperand LowerOperand(const MachineInstr *MI,
+ const MachineOperand &MO,
+ AsmPrinter &AP) {
+ switch(MO.getType()) {
+ default: llvm_unreachable("unknown operand type"); break;
+ case MachineOperand::MO_Register:
+ if (MO.isImplicit())
+ break;
+ return MCOperand::CreateReg(MO.getReg());
+
+ case MachineOperand::MO_Immediate:
+ return MCOperand::CreateImm(MO.getImm());
+
+ case MachineOperand::MO_MachineBasicBlock:
+ case MachineOperand::MO_GlobalAddress:
+ case MachineOperand::MO_BlockAddress:
+ case MachineOperand::MO_ExternalSymbol:
+ case MachineOperand::MO_ConstantPoolIndex:
+ return LowerSymbolOperand(MI, MO, AP);
+
+ case MachineOperand::MO_RegisterMask: break;
+
+ }
+ return MCOperand();
+}
+
+void llvm::LowerSparcMachineInstrToMCInst(const MachineInstr *MI,
+ MCInst &OutMI,
+ AsmPrinter &AP)
+{
+
+ OutMI.setOpcode(MI->getOpcode());
+
+ for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
+ const MachineOperand &MO = MI->getOperand(i);
+ MCOperand MCOp = LowerOperand(MI, MO, AP);
+
+ if (MCOp.isValid())
+ OutMI.addOperand(MCOp);
+ }
+}
Index: lib/Target/Sparc/Sparc.h
===================================================================
--- lib/Target/Sparc/Sparc.h
+++ lib/Target/Sparc/Sparc.h
@@ -23,6 +23,9 @@ namespace llvm {
class FunctionPass;
class SparcTargetMachine;
class formatted_raw_ostream;
+ class AsmPrinter;
+ class MCInst;
+ class MachineInstr;
FunctionPass *createSparcISelDag(SparcTargetMachine &TM);
FunctionPass *createSparcDelaySlotFillerPass(TargetMachine &TM);
@@ -29,6 +32,9 @@ namespace llvm {
FunctionPass *createSparcJITCodeEmitterPass(SparcTargetMachine &TM,
JITCodeEmitter &JCE);
+ void LowerSparcMachineInstrToMCInst(const MachineInstr *MI,
+ MCInst &OutMI,
+ AsmPrinter &AP);
} // end namespace llvm;
namespace llvm {
Index: lib/Target/Sparc/SparcAsmPrinter.cpp
===================================================================
--- lib/Target/Sparc/SparcAsmPrinter.cpp
+++ lib/Target/Sparc/SparcAsmPrinter.cpp
@@ -16,12 +16,17 @@
#include "Sparc.h"
#include "SparcInstrInfo.h"
#include "SparcTargetMachine.h"
+#include "SparcTargetStreamer.h"
+#include "InstPrinter/SparcInstPrinter.h"
#include "MCTargetDesc/SparcBaseInfo.h"
+#include "MCTargetDesc/SparcMCExpr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/TargetRegistry.h"
@@ -31,6 +36,9 @@ using namespace llvm;
namespace {
class SparcAsmPrinter : public AsmPrinter {
+ SparcTargetStreamer &getTargetStreamer() {
+ return static_cast<SparcTargetStreamer&>(OutStreamer.getTargetStreamer());
+ }
public:
explicit SparcAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
: AsmPrinter(TM, Streamer) {}
@@ -45,14 +53,11 @@ namespace {
void printCCOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
virtual void EmitFunctionBodyStart();
- virtual void EmitInstruction(const MachineInstr *MI) {
- SmallString<128> Str;
- raw_svector_ostream OS(Str);
- printInstruction(MI, OS);
- OutStreamer.EmitRawText(OS.str());
+ virtual void EmitInstruction(const MachineInstr *MI);
+
+ static const char *getRegisterName(unsigned RegNo) {
+ return SparcInstPrinter::getRegisterName(RegNo);
}
- void printInstruction(const MachineInstr *MI, raw_ostream &OS);// autogen'd.
- static const char *getRegisterName(unsigned RegNo);
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode,
@@ -61,25 +66,139 @@ namespace {
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &O);
- bool printGetPCX(const MachineInstr *MI, unsigned OpNo, raw_ostream &OS);
-
virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB)
const;
- void EmitGlobalRegisterDecl(unsigned reg) {
- SmallString<128> Str;
- raw_svector_ostream OS(Str);
- OS << "\t.register "
- << "%" << StringRef(getRegisterName(reg)).lower()
- << ", "
- << ((reg == SP::G6 || reg == SP::G7)? "#ignore" : "#scratch");
- OutStreamer.EmitRawText(OS.str());
- }
};
} // end of anonymous namespace
-#include "SparcGenAsmWriter.inc"
+static MCOperand createPCXCallOP(MCSymbol *Label,
+ MCContext &OutContext)
+{
+ const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Label,
+ OutContext);
+ const SparcMCExpr *expr = SparcMCExpr::Create(SparcMCExpr::VK_Sparc_None,
+ MCSym, OutContext);
+ return MCOperand::CreateExpr(expr);
+}
+static MCOperand createPCXRelExprOp(SparcMCExpr::VariantKind Kind,
+ MCSymbol *GOTLabel, MCSymbol *StartLabel,
+ MCSymbol *CurLabel,
+ MCContext &OutContext)
+{
+ const MCSymbolRefExpr *GOT = MCSymbolRefExpr::Create(GOTLabel, OutContext);
+ const MCSymbolRefExpr *Start = MCSymbolRefExpr::Create(StartLabel,
+ OutContext);
+ const MCSymbolRefExpr *Cur = MCSymbolRefExpr::Create(CurLabel,
+ OutContext);
+
+ const MCBinaryExpr *Sub = MCBinaryExpr::CreateSub(Cur, Start, OutContext);
+ const MCBinaryExpr *Add = MCBinaryExpr::CreateAdd(GOT, Sub, OutContext);
+ const SparcMCExpr *expr = SparcMCExpr::Create(Kind,
+ Add, OutContext);
+ return MCOperand::CreateExpr(expr);
+}
+
+static void EmitCall(MCStreamer &OutStreamer,
+ MCOperand &Callee)
+{
+ MCInst CallInst;
+ CallInst.setOpcode(SP::CALL);
+ CallInst.addOperand(Callee);
+ OutStreamer.EmitInstruction(CallInst);
+}
+
+static void EmitSETHI(MCStreamer &OutStreamer,
+ MCOperand &Imm, MCOperand &RD)
+{
+ MCInst SETHIInst;
+ SETHIInst.setOpcode(SP::SETHIi);
+ SETHIInst.addOperand(RD);
+ SETHIInst.addOperand(Imm);
+ OutStreamer.EmitInstruction(SETHIInst);
+}
+
+static void EmitOR(MCStreamer &OutStreamer, MCOperand &RS1,
+ MCOperand &Imm, MCOperand &RD)
+{
+ MCInst ORInst;
+ ORInst.setOpcode(SP::ORri);
+ ORInst.addOperand(RD);
+ ORInst.addOperand(RS1);
+ ORInst.addOperand(Imm);
+ OutStreamer.EmitInstruction(ORInst);
+}
+
+void EmitADD(MCStreamer &OutStreamer,
+ MCOperand &RS1, MCOperand &RS2, MCOperand &RD)
+{
+ MCInst ADDInst;
+ ADDInst.setOpcode(SP::ADDrr);
+ ADDInst.addOperand(RD);
+ ADDInst.addOperand(RS1);
+ ADDInst.addOperand(RS2);
+ OutStreamer.EmitInstruction(ADDInst);
+}
+
+static void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,
+ MCStreamer &OutStreamer,
+ MCContext &OutContext)
+{
+ const MachineOperand &MO = MI->getOperand(0);
+ MCSymbol *StartLabel = OutContext.CreateTempSymbol();
+ MCSymbol *EndLabel = OutContext.CreateTempSymbol();
+ MCSymbol *SethiLabel = OutContext.CreateTempSymbol();
+ MCSymbol *GOTLabel =
+ OutContext.GetOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
+
+ assert(MO.getReg() != SP::O7 &&
+ "%o7 is assigned as destination for getpcx!");
+
+ MCOperand MCRegOP = MCOperand::CreateReg(MO.getReg());
+ MCOperand RegO7 = MCOperand::CreateReg(SP::O7);
+
+ // <StartLabel>:
+ // call <EndLabel>
+ // <SethiLabel>:
+ // sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO>
+ // <EndLabel>:
+ // or <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO>
+ // add <MO>, %o7, <MO>
+
+ OutStreamer.EmitLabel(StartLabel);
+ MCOperand Callee = createPCXCallOP(EndLabel, OutContext);
+ EmitCall(OutStreamer, Callee);
+ OutStreamer.EmitLabel(SethiLabel);
+ MCOperand hiImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_HI,
+ GOTLabel, StartLabel, SethiLabel,
+ OutContext);
+ EmitSETHI(OutStreamer, hiImm, MCRegOP);
+ OutStreamer.EmitLabel(EndLabel);
+ MCOperand loImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_LO,
+ GOTLabel, StartLabel, EndLabel,
+ OutContext);
+ EmitOR(OutStreamer, MCRegOP, loImm, MCRegOP);
+ EmitADD(OutStreamer, MCRegOP, RegO7, MCRegOP);
+}
+
+void SparcAsmPrinter::EmitInstruction(const MachineInstr *MI)
+{
+ MCInst TmpInst;
+
+ switch (MI->getOpcode()) {
+ default: break;
+ case TargetOpcode::DBG_VALUE:
+ // FIXME: Debug Value.
+ return;
+ case SP::GETPCX:
+ LowerGETPCXAndEmitMCInsts(MI, OutStreamer, OutContext);
+ return;
+ }
+ LowerSparcMachineInstrToMCInst(MI, TmpInst, *this);
+ OutStreamer.EmitInstruction(TmpInst);
+}
+
void SparcAsmPrinter::EmitFunctionBodyStart() {
if (!TM.getSubtarget<SparcSubtarget>().is64Bit())
return;
@@ -90,7 +209,11 @@ void SparcAsmPrinter::EmitFunctionBodyStart() {
unsigned reg = globalRegs[i];
if (MRI.use_empty(reg))
continue;
- EmitGlobalRegisterDecl(reg);
+
+ if (reg == SP::G6 || reg == SP::G7)
+ getTargetStreamer().emitSparcRegisterIgnore(reg);
+ else
+ getTargetStreamer().emitSparcRegisterScratch(reg);
}
}
@@ -226,46 +349,6 @@ void SparcAsmPrinter::printMemOperand(const Machin
printOperand(MI, opNum+1, O);
}
-bool SparcAsmPrinter::printGetPCX(const MachineInstr *MI, unsigned opNum,
- raw_ostream &O) {
- std::string operand = "";
- const MachineOperand &MO = MI->getOperand(opNum);
- switch (MO.getType()) {
- default: llvm_unreachable("Operand is not a register");
- case MachineOperand::MO_Register:
- assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) &&
- "Operand is not a physical register ");
- assert(MO.getReg() != SP::O7 &&
- "%o7 is assigned as destination for getpcx!");
- operand = "%" + StringRef(getRegisterName(MO.getReg())).lower();
- break;
- }
-
- unsigned mfNum = MI->getParent()->getParent()->getFunctionNumber();
- unsigned bbNum = MI->getParent()->getNumber();
-
- O << '\n' << ".LLGETPCH" << mfNum << '_' << bbNum << ":\n";
- O << "\tcall\t.LLGETPC" << mfNum << '_' << bbNum << '\n' ;
-
- O << "\t sethi\t"
- << "%hi(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << mfNum << '_' << bbNum
- << ")), " << operand << '\n' ;
-
- O << ".LLGETPC" << mfNum << '_' << bbNum << ":\n" ;
- O << "\tor\t" << operand
- << ", %lo(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << mfNum << '_' << bbNum
- << ")), " << operand << '\n';
- O << "\tadd\t" << operand << ", %o7, " << operand << '\n';
-
- return true;
-}
-
-void SparcAsmPrinter::printCCOperand(const MachineInstr *MI, int opNum,
- raw_ostream &O) {
- int CC = (int)MI->getOperand(opNum).getImm();
- O << SPARCCondCodeToString((SPCC::CondCodes)CC);
-}
-
/// PrintAsmOperand - Print out an operand for an inline asm expression.
///
bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
Index: lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
===================================================================
--- lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
+++ lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
@@ -23,8 +23,7 @@
using namespace llvm;
#define GET_INSTRUCTION_NAME
-// Uncomment the following line once we are ready to use MCAsmWriter.
-//#include "SparcGenAsmWriter.inc"
+#include "SparcGenAsmWriter.inc"
void SparcInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const
{
Index: test/CodeGen/SPARC/exception.ll
===================================================================
--- test/CodeGen/SPARC/exception.ll
+++ test/CodeGen/SPARC/exception.ll
@@ -11,7 +11,7 @@
; CHECK-LABEL: main:
; CHECK: .cfi_startproc
-; CHECK: .cfi_def_cfa_register 30
+; CHECK: .cfi_def_cfa_register {{30|%fp}}
; CHECK: .cfi_window_save
; CHECK: .cfi_register 15, 31

View File

@ -0,0 +1,166 @@
Pull in r198145 from upstream llvm trunk (by Venkatraman Govindaraju):
[SparcV9]: Implement lowering of long double (fp128) arguments in Sparc64 ABI.
Also, pass fp128 arguments to varargs through integer registers if necessary.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: test/CodeGen/SPARC/64abi.ll
===================================================================
--- test/CodeGen/SPARC/64abi.ll
+++ test/CodeGen/SPARC/64abi.ll
@@ -411,3 +411,33 @@ entry:
}
declare i32 @use_buf(i32, i8*)
+
+; CHECK-LABEL: test_fp128_args
+; CHECK-DAG: std %f0, [%fp+{{.+}}]
+; CHECK-DAG: std %f2, [%fp+{{.+}}]
+; CHECK-DAG: std %f6, [%fp+{{.+}}]
+; CHECK-DAG: std %f4, [%fp+{{.+}}]
+; CHECK: add %fp, [[Offset:[0-9]+]], %o0
+; CHECK: call _Qp_add
+; CHECK: ldd [%fp+[[Offset]]], %f0
+define fp128 @test_fp128_args(fp128 %a, fp128 %b) {
+entry:
+ %0 = fadd fp128 %a, %b
+ ret fp128 %0
+}
+
+declare i64 @receive_fp128(i64 %a, ...)
+
+; CHECK-LABEL: test_fp128_variable_args
+; CHECK-DAG: std %f4, [%sp+[[Offset0:[0-9]+]]]
+; CHECK-DAG: std %f6, [%sp+[[Offset1:[0-9]+]]]
+; CHECK-DAG: ldx [%sp+[[Offset0]]], %o2
+; CHECK-DAG: ldx [%sp+[[Offset1]]], %o3
+; CHECK: call receive_fp128
+define i64 @test_fp128_variable_args(i64 %a, fp128 %b) {
+entry:
+ %0 = call i64 (i64, ...)* @receive_fp128(i64 %a, fp128 %b)
+ ret i64 %0
+}
+
+
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -80,11 +80,14 @@ static bool CC_Sparc_Assign_f64(unsigned &ValNo, M
static bool CC_Sparc64_Full(unsigned &ValNo, MVT &ValVT,
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
ISD::ArgFlagsTy &ArgFlags, CCState &State) {
- assert((LocVT == MVT::f32 || LocVT.getSizeInBits() == 64) &&
+ assert((LocVT == MVT::f32 || LocVT == MVT::f128
+ || LocVT.getSizeInBits() == 64) &&
"Can't handle non-64 bits locations");
// Stack space is allocated for all arguments starting from [%fp+BIAS+128].
- unsigned Offset = State.AllocateStack(8, 8);
+ unsigned size = (LocVT == MVT::f128) ? 16 : 8;
+ unsigned alignment = (LocVT == MVT::f128) ? 16 : 8;
+ unsigned Offset = State.AllocateStack(size, alignment);
unsigned Reg = 0;
if (LocVT == MVT::i64 && Offset < 6*8)
@@ -96,6 +99,9 @@ static bool CC_Sparc64_Full(unsigned &ValNo, MVT &
else if (LocVT == MVT::f32 && Offset < 16*8)
// Promote floats to %f1, %f3, ...
Reg = SP::F1 + Offset/4;
+ else if (LocVT == MVT::f128 && Offset < 16*8)
+ // Promote long doubles to %q0-%q28. (Which LLVM calls Q0-Q7).
+ Reg = SP::Q0 + Offset/16;
// Promote to register when possible, otherwise use the stack slot.
if (Reg) {
@@ -998,9 +1004,10 @@ static void fixupVariableFloatArgs(SmallVectorImpl
ArrayRef<ISD::OutputArg> Outs) {
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
const CCValAssign &VA = ArgLocs[i];
+ MVT ValTy = VA.getLocVT();
// FIXME: What about f32 arguments? C promotes them to f64 when calling
// varargs functions.
- if (!VA.isRegLoc() || VA.getLocVT() != MVT::f64)
+ if (!VA.isRegLoc() || (ValTy != MVT::f64 && ValTy != MVT::f128))
continue;
// The fixed arguments to a varargs function still go in FP registers.
if (Outs[VA.getValNo()].IsFixed)
@@ -1010,15 +1017,25 @@ static void fixupVariableFloatArgs(SmallVectorImpl
CCValAssign NewVA;
// Determine the offset into the argument array.
- unsigned Offset = 8 * (VA.getLocReg() - SP::D0);
+ unsigned firstReg = (ValTy == MVT::f64) ? SP::D0 : SP::Q0;
+ unsigned argSize = (ValTy == MVT::f64) ? 8 : 16;
+ unsigned Offset = argSize * (VA.getLocReg() - firstReg);
assert(Offset < 16*8 && "Offset out of range, bad register enum?");
if (Offset < 6*8) {
// This argument should go in %i0-%i5.
unsigned IReg = SP::I0 + Offset/8;
- // Full register, just bitconvert into i64.
- NewVA = CCValAssign::getReg(VA.getValNo(), VA.getValVT(),
- IReg, MVT::i64, CCValAssign::BCvt);
+ if (ValTy == MVT::f64)
+ // Full register, just bitconvert into i64.
+ NewVA = CCValAssign::getReg(VA.getValNo(), VA.getValVT(),
+ IReg, MVT::i64, CCValAssign::BCvt);
+ else {
+ assert(ValTy == MVT::f128 && "Unexpected type!");
+ // Full register, just bitconvert into i128 -- We will lower this into
+ // two i64s in LowerCall_64.
+ NewVA = CCValAssign::getCustomReg(VA.getValNo(), VA.getValVT(),
+ IReg, MVT::i128, CCValAssign::BCvt);
+ }
} else {
// This needs to go to memory, we're out of integer registers.
NewVA = CCValAssign::getMem(VA.getValNo(), VA.getValVT(),
@@ -1094,11 +1111,46 @@ SparcTargetLowering::LowerCall_64(TargetLowering::
Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg);
break;
case CCValAssign::BCvt:
- Arg = DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Arg);
+ // fixupVariableFloatArgs() may create bitcasts from f128 to i128. But
+ // SPARC does not support i128 natively. Lower it into two i64, see below.
+ if (!VA.needsCustom() || VA.getValVT() != MVT::f128
+ || VA.getLocVT() != MVT::i128)
+ Arg = DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Arg);
break;
}
if (VA.isRegLoc()) {
+ if (VA.needsCustom() && VA.getValVT() == MVT::f128
+ && VA.getLocVT() == MVT::i128) {
+ // Store and reload into the interger register reg and reg+1.
+ unsigned Offset = 8 * (VA.getLocReg() - SP::I0);
+ unsigned StackOffset = Offset + Subtarget->getStackPointerBias() + 128;
+ SDValue StackPtr = DAG.getRegister(SP::O6, getPointerTy());
+ SDValue HiPtrOff = DAG.getIntPtrConstant(StackOffset);
+ HiPtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(), StackPtr,
+ HiPtrOff);
+ SDValue LoPtrOff = DAG.getIntPtrConstant(StackOffset + 8);
+ LoPtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(), StackPtr,
+ LoPtrOff);
+
+ // Store to %sp+BIAS+128+Offset
+ SDValue Store = DAG.getStore(Chain, DL, Arg, HiPtrOff,
+ MachinePointerInfo(),
+ false, false, 0);
+ // Load into Reg and Reg+1
+ SDValue Hi64 = DAG.getLoad(MVT::i64, DL, Store, HiPtrOff,
+ MachinePointerInfo(),
+ false, false, false, 0);
+ SDValue Lo64 = DAG.getLoad(MVT::i64, DL, Store, LoPtrOff,
+ MachinePointerInfo(),
+ false, false, false, 0);
+ RegsToPass.push_back(std::make_pair(toCallerWindow(VA.getLocReg()),
+ Hi64));
+ RegsToPass.push_back(std::make_pair(toCallerWindow(VA.getLocReg()+1),
+ Lo64));
+ continue;
+ }
+
// The custom bit on an i32 return value indicates that it should be
// passed in the high bits of the register.
if (VA.getValVT() == MVT::i32 && VA.needsCustom()) {

View File

@ -0,0 +1,54 @@
Pull in r198149 from upstream llvm trunk (by Venkatraman Govindaraju):
[SparcV9] For codegen generated library calls that return float, set inreg flag manually in LowerCall().
This makes the sparc backend to generate Sparc64 ABI compliant code.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -1252,6 +1252,12 @@ SparcTargetLowering::LowerCall_64(TargetLowering::
SmallVector<CCValAssign, 16> RVLocs;
CCState RVInfo(CLI.CallConv, CLI.IsVarArg, DAG.getMachineFunction(),
DAG.getTarget(), RVLocs, *DAG.getContext());
+
+ // Set inreg flag manually for codegen generated library calls that
+ // return float.
+ if (CLI.Ins.size() == 1 && CLI.Ins[0].VT == MVT::f32 && CLI.CS == 0)
+ CLI.Ins[0].Flags.setInReg();
+
RVInfo.AnalyzeCallResult(CLI.Ins, CC_Sparc64);
// Copy all of the result registers out of their specified physreg.
Index: test/CodeGen/SPARC/64abi.ll
===================================================================
--- test/CodeGen/SPARC/64abi.ll
+++ test/CodeGen/SPARC/64abi.ll
@@ -440,4 +440,25 @@ entry:
ret i64 %0
}
+; CHECK-LABEL: test_call_libfunc
+; CHECK: st %f1, [%fp+[[Offset0:[0-9]+]]]
+; CHECK: fmovs %f3, %f1
+; CHECK: call cosf
+; CHECK: st %f0, [%fp+[[Offset1:[0-9]+]]]
+; CHECK: ld [%fp+[[Offset0]]], %f1
+; CHECK: call sinf
+; CHECK: ld [%fp+[[Offset1]]], %f1
+; CHECK: fmuls %f1, %f0, %f0
+define inreg float @test_call_libfunc(float %arg0, float %arg1) {
+entry:
+ %0 = tail call inreg float @cosf(float %arg1)
+ %1 = tail call inreg float @sinf(float %arg0)
+ %2 = fmul float %0, %1
+ ret float %2
+}
+
+declare inreg float @cosf(float %arg) readnone nounwind
+declare inreg float @sinf(float %arg) readnone nounwind
+
+

View File

@ -0,0 +1,368 @@
Pull in r198157 from upstream llvm trunk (by Venkatraman Govindaraju):
[SparcV9] Use separate instruction patterns for 64 bit arithmetic instructions instead of reusing 32 bit instruction patterns.
This is done to avoid spilling the result of the 64-bit instructions to a 4-byte slot.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcAsmPrinter.cpp
===================================================================
--- lib/Target/Sparc/SparcAsmPrinter.cpp
+++ lib/Target/Sparc/SparcAsmPrinter.cpp
@@ -227,7 +227,7 @@ void SparcAsmPrinter::printOperand(const MachineIn
if (MI->getOpcode() == SP::CALL)
assert(TF == SPII::MO_NO_FLAG &&
"Cannot handle target flags on call address");
- else if (MI->getOpcode() == SP::SETHIi)
+ else if (MI->getOpcode() == SP::SETHIi || MI->getOpcode() == SP::SETHIXi)
assert((TF == SPII::MO_HI || TF == SPII::MO_H44 || TF == SPII::MO_HH
|| TF == SPII::MO_TLS_GD_HI22
|| TF == SPII::MO_TLS_LDM_HI22
@@ -250,7 +250,7 @@ void SparcAsmPrinter::printOperand(const MachineIn
else if (MI->getOpcode() == SP::TLS_LDXrr)
assert(TF == SPII::MO_TLS_IE_LDX &&
"Cannot handle target flags on ldx for TLS");
- else if (MI->getOpcode() == SP::XORri)
+ else if (MI->getOpcode() == SP::XORri || MI->getOpcode() == SP::XORXri)
assert((TF == SPII::MO_TLS_LDO_LOX10 || TF == SPII::MO_TLS_LE_LOX10) &&
"Cannot handle target flags on xor for TLS");
else
Index: lib/Target/Sparc/SparcInstr64Bit.td
===================================================================
--- lib/Target/Sparc/SparcInstr64Bit.td
+++ lib/Target/Sparc/SparcInstr64Bit.td
@@ -141,32 +141,36 @@ def : Pat<(i64 imm:$val),
let Predicates = [Is64Bit] in {
// Register-register instructions.
+defm ANDX : F3_12<"and", 0b000001, and, I64Regs, i64, i64imm>;
+defm ORX : F3_12<"or", 0b000010, or, I64Regs, i64, i64imm>;
+defm XORX : F3_12<"xor", 0b000011, xor, I64Regs, i64, i64imm>;
-def : Pat<(and i64:$a, i64:$b), (ANDrr $a, $b)>;
-def : Pat<(or i64:$a, i64:$b), (ORrr $a, $b)>;
-def : Pat<(xor i64:$a, i64:$b), (XORrr $a, $b)>;
+def ANDXNrr : F3_1<2, 0b000101,
+ (outs I64Regs:$dst), (ins I64Regs:$b, I64Regs:$c),
+ "andn $b, $c, $dst",
+ [(set i64:$dst, (and i64:$b, (not i64:$c)))]>;
+def ORXNrr : F3_1<2, 0b000110,
+ (outs I64Regs:$dst), (ins I64Regs:$b, I64Regs:$c),
+ "orn $b, $c, $dst",
+ [(set i64:$dst, (or i64:$b, (not i64:$c)))]>;
+def XNORXrr : F3_1<2, 0b000111,
+ (outs I64Regs:$dst), (ins I64Regs:$b, I64Regs:$c),
+ "xnor $b, $c, $dst",
+ [(set i64:$dst, (not (xor i64:$b, i64:$c)))]>;
-def : Pat<(and i64:$a, (not i64:$b)), (ANDNrr $a, $b)>;
-def : Pat<(or i64:$a, (not i64:$b)), (ORNrr $a, $b)>;
-def : Pat<(xor i64:$a, (not i64:$b)), (XNORrr $a, $b)>;
+defm ADDX : F3_12<"add", 0b000000, add, I64Regs, i64, i64imm>;
+defm SUBX : F3_12<"sub", 0b000100, sub, I64Regs, i64, i64imm>;
-def : Pat<(add i64:$a, i64:$b), (ADDrr $a, $b)>;
-def : Pat<(sub i64:$a, i64:$b), (SUBrr $a, $b)>;
-
def : Pat<(SPcmpicc i64:$a, i64:$b), (CMPrr $a, $b)>;
-def : Pat<(tlsadd i64:$a, i64:$b, tglobaltlsaddr:$sym),
- (TLS_ADDrr $a, $b, $sym)>;
+def TLS_ADDXrr : F3_1<2, 0b000000, (outs I64Regs:$rd),
+ (ins I64Regs:$rs1, I64Regs:$rs2, TLSSym:$sym),
+ "add $rs1, $rs2, $rd, $sym",
+ [(set i64:$rd,
+ (tlsadd i64:$rs1, i64:$rs2, tglobaltlsaddr:$sym))]>;
// Register-immediate instructions.
-def : Pat<(and i64:$a, (i64 simm13:$b)), (ANDri $a, (as_i32imm $b))>;
-def : Pat<(or i64:$a, (i64 simm13:$b)), (ORri $a, (as_i32imm $b))>;
-def : Pat<(xor i64:$a, (i64 simm13:$b)), (XORri $a, (as_i32imm $b))>;
-
-def : Pat<(add i64:$a, (i64 simm13:$b)), (ADDri $a, (as_i32imm $b))>;
-def : Pat<(sub i64:$a, (i64 simm13:$b)), (SUBri $a, (as_i32imm $b))>;
-
def : Pat<(SPcmpicc i64:$a, (i64 simm13:$b)), (CMPri $a, (as_i32imm $b))>;
def : Pat<(ctpop i64:$src), (POPCrr $src)>;
@@ -402,3 +406,38 @@ def : Pat<(SPselectfcc (i64 simm11:$t), i64:$f, im
(MOVFCCri (as_i32imm $t), $f, imm:$cond)>;
} // Predicates = [Is64Bit]
+
+
+// 64 bit SETHI
+let Predicates = [Is64Bit] in {
+def SETHIXi : F2_1<0b100,
+ (outs IntRegs:$rd), (ins i64imm:$imm22),
+ "sethi $imm22, $rd",
+ [(set i64:$rd, SETHIimm:$imm22)]>;
+}
+// Global addresses, constant pool entries
+let Predicates = [Is64Bit] in {
+
+def : Pat<(SPhi tglobaladdr:$in), (SETHIi tglobaladdr:$in)>;
+def : Pat<(SPlo tglobaladdr:$in), (ORXri (i64 G0), tglobaladdr:$in)>;
+def : Pat<(SPhi tconstpool:$in), (SETHIi tconstpool:$in)>;
+def : Pat<(SPlo tconstpool:$in), (ORXri (i64 G0), tconstpool:$in)>;
+
+// GlobalTLS addresses
+def : Pat<(SPhi tglobaltlsaddr:$in), (SETHIi tglobaltlsaddr:$in)>;
+def : Pat<(SPlo tglobaltlsaddr:$in), (ORXri (i64 G0), tglobaltlsaddr:$in)>;
+def : Pat<(add (SPhi tglobaltlsaddr:$in1), (SPlo tglobaltlsaddr:$in2)),
+ (ADDXri (SETHIXi tglobaltlsaddr:$in1), (tglobaltlsaddr:$in2))>;
+def : Pat<(xor (SPhi tglobaltlsaddr:$in1), (SPlo tglobaltlsaddr:$in2)),
+ (XORXri (SETHIXi tglobaltlsaddr:$in1), (tglobaltlsaddr:$in2))>;
+
+// Blockaddress
+def : Pat<(SPhi tblockaddress:$in), (SETHIi tblockaddress:$in)>;
+def : Pat<(SPlo tblockaddress:$in), (ORXri (i64 G0), tblockaddress:$in)>;
+
+// Add reg, lo. This is used when taking the addr of a global/constpool entry.
+def : Pat<(add iPTR:$r, (SPlo tglobaladdr:$in)), (ADDXri $r, tglobaladdr:$in)>;
+def : Pat<(add iPTR:$r, (SPlo tconstpool:$in)), (ADDXri $r, tconstpool:$in)>;
+def : Pat<(add iPTR:$r, (SPlo tblockaddress:$in)),
+ (ADDXri $r, tblockaddress:$in)>;
+}
Index: lib/Target/Sparc/SparcInstrInfo.td
===================================================================
--- lib/Target/Sparc/SparcInstrInfo.td
+++ lib/Target/Sparc/SparcInstrInfo.td
@@ -210,15 +210,16 @@ def FCC_O : FCC_VAL<29>; // Ordered
//===----------------------------------------------------------------------===//
/// F3_12 multiclass - Define a normal F3_1/F3_2 pattern in one shot.
-multiclass F3_12<string OpcStr, bits<6> Op3Val, SDNode OpNode> {
+multiclass F3_12<string OpcStr, bits<6> Op3Val, SDNode OpNode,
+ RegisterClass RC, ValueType Ty, Operand immOp> {
def rr : F3_1<2, Op3Val,
- (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
+ (outs RC:$dst), (ins RC:$b, RC:$c),
!strconcat(OpcStr, " $b, $c, $dst"),
- [(set i32:$dst, (OpNode i32:$b, i32:$c))]>;
+ [(set Ty:$dst, (OpNode Ty:$b, Ty:$c))]>;
def ri : F3_2<2, Op3Val,
- (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c),
+ (outs RC:$dst), (ins RC:$b, immOp:$c),
!strconcat(OpcStr, " $b, $c, $dst"),
- [(set i32:$dst, (OpNode i32:$b, (i32 simm13:$c)))]>;
+ [(set Ty:$dst, (OpNode Ty:$b, (Ty simm13:$c)))]>;
}
/// F3_12np multiclass - Define a normal F3_1/F3_2 pattern in one shot, with no
@@ -464,7 +465,7 @@ let rd = 0, imm22 = 0 in
def NOP : F2_1<0b100, (outs), (ins), "nop", []>;
// Section B.11 - Logical Instructions, p. 106
-defm AND : F3_12<"and", 0b000001, and>;
+defm AND : F3_12<"and", 0b000001, and, IntRegs, i32, i32imm>;
def ANDNrr : F3_1<2, 0b000101,
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
@@ -474,7 +475,7 @@ def ANDNri : F3_2<2, 0b000101,
(outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c),
"andn $b, $c, $dst", []>;
-defm OR : F3_12<"or", 0b000010, or>;
+defm OR : F3_12<"or", 0b000010, or, IntRegs, i32, i32imm>;
def ORNrr : F3_1<2, 0b000110,
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
@@ -483,7 +484,7 @@ def ORNrr : F3_1<2, 0b000110,
def ORNri : F3_2<2, 0b000110,
(outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c),
"orn $b, $c, $dst", []>;
-defm XOR : F3_12<"xor", 0b000011, xor>;
+defm XOR : F3_12<"xor", 0b000011, xor, IntRegs, i32, i32imm>;
def XNORrr : F3_1<2, 0b000111,
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
@@ -494,12 +495,12 @@ def XNORri : F3_2<2, 0b000111,
"xnor $b, $c, $dst", []>;
// Section B.12 - Shift Instructions, p. 107
-defm SLL : F3_12<"sll", 0b100101, shl>;
-defm SRL : F3_12<"srl", 0b100110, srl>;
-defm SRA : F3_12<"sra", 0b100111, sra>;
+defm SLL : F3_12<"sll", 0b100101, shl, IntRegs, i32, i32imm>;
+defm SRL : F3_12<"srl", 0b100110, srl, IntRegs, i32, i32imm>;
+defm SRA : F3_12<"sra", 0b100111, sra, IntRegs, i32, i32imm>;
// Section B.13 - Add Instructions, p. 108
-defm ADD : F3_12<"add", 0b000000, add>;
+defm ADD : F3_12<"add", 0b000000, add, IntRegs, i32, i32imm>;
// "LEA" forms of add (patterns to make tblgen happy)
let Predicates = [Is32Bit] in
@@ -509,18 +510,18 @@ let Predicates = [Is32Bit] in
[(set iPTR:$dst, ADDRri:$addr)]>;
let Defs = [ICC] in
- defm ADDCC : F3_12<"addcc", 0b010000, addc>;
+ defm ADDCC : F3_12<"addcc", 0b010000, addc, IntRegs, i32, i32imm>;
let Uses = [ICC], Defs = [ICC] in
- defm ADDX : F3_12<"addxcc", 0b011000, adde>;
+ defm ADDE : F3_12<"addxcc", 0b011000, adde, IntRegs, i32, i32imm>;
// Section B.15 - Subtract Instructions, p. 110
-defm SUB : F3_12 <"sub" , 0b000100, sub>;
+defm SUB : F3_12 <"sub" , 0b000100, sub, IntRegs, i32, i32imm>;
let Uses = [ICC], Defs = [ICC] in
- defm SUBX : F3_12 <"subxcc" , 0b011100, sube>;
+ defm SUBE : F3_12 <"subxcc" , 0b011100, sube, IntRegs, i32, i32imm>;
let Defs = [ICC] in
- defm SUBCC : F3_12 <"subcc", 0b010100, subc>;
+ defm SUBCC : F3_12 <"subcc", 0b010100, subc, IntRegs, i32, i32imm>;
let Defs = [ICC], rd = 0 in {
def CMPrr : F3_1<2, 0b010100,
@@ -542,7 +543,7 @@ let Uses = [ICC], Defs = [ICC] in
// Section B.18 - Multiply Instructions, p. 113
let Defs = [Y] in {
defm UMUL : F3_12np<"umul", 0b001010>;
- defm SMUL : F3_12 <"smul", 0b001011, mul>;
+ defm SMUL : F3_12 <"smul", 0b001011, mul, IntRegs, i32, i32imm>;
}
// Section B.19 - Divide Instructions, p. 115
@@ -987,6 +988,8 @@ def : Pat<(i32 imm:$val),
// Global addresses, constant pool entries
+let Predicates = [Is32Bit] in {
+
def : Pat<(SPhi tglobaladdr:$in), (SETHIi tglobaladdr:$in)>;
def : Pat<(SPlo tglobaladdr:$in), (ORri (i32 G0), tglobaladdr:$in)>;
def : Pat<(SPhi tconstpool:$in), (SETHIi tconstpool:$in)>;
@@ -1009,6 +1012,7 @@ def : Pat<(add iPTR:$r, (SPlo tglobaladdr:$in)), (
def : Pat<(add iPTR:$r, (SPlo tconstpool:$in)), (ADDri $r, tconstpool:$in)>;
def : Pat<(add iPTR:$r, (SPlo tblockaddress:$in)),
(ADDri $r, tblockaddress:$in)>;
+}
// Calls:
def : Pat<(call tglobaladdr:$dst),
Index: test/CodeGen/SPARC/64spill.ll
===================================================================
--- test/CodeGen/SPARC/64spill.ll
+++ test/CodeGen/SPARC/64spill.ll
@@ -0,0 +1,116 @@
+; RUN: llc < %s -march=sparcv9 | FileCheck %s
+
+target datalayout = "E-i64:64-n32:64-S128"
+target triple = "sparc64-sun-sparc"
+
+; CHECK-LABEL: test_and_spill
+; CHECK: and %i0, %i1, [[R:%[gilo][0-7]]]
+; CHECK: stx [[R]], [%fp+{{.+}}]
+; CHECK: ldx [%fp+{{.+}}, %i0
+define i64 @test_and_spill(i64 %a, i64 %b) {
+entry:
+ %r0 = and i64 %a, %b
+ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0)
+ ret i64 %r0
+}
+
+; CHECK-LABEL: test_or_spill
+; CHECK: or %i0, %i1, [[R:%[gilo][0-7]]]
+; CHECK: stx [[R]], [%fp+{{.+}}]
+; CHECK: ldx [%fp+{{.+}}, %i0
+define i64 @test_or_spill(i64 %a, i64 %b) {
+entry:
+ %r0 = or i64 %a, %b
+ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0)
+ ret i64 %r0
+}
+
+; CHECK-LABEL: test_xor_spill
+; CHECK: xor %i0, %i1, [[R:%[gilo][0-7]]]
+; CHECK: stx [[R]], [%fp+{{.+}}]
+; CHECK: ldx [%fp+{{.+}}, %i0
+define i64 @test_xor_spill(i64 %a, i64 %b) {
+entry:
+ %r0 = xor i64 %a, %b
+ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0)
+ ret i64 %r0
+}
+
+
+; CHECK-LABEL: test_add_spill
+; CHECK: add %i0, %i1, [[R:%[gilo][0-7]]]
+; CHECK: stx [[R]], [%fp+{{.+}}]
+; CHECK: ldx [%fp+{{.+}}, %i0
+define i64 @test_add_spill(i64 %a, i64 %b) {
+entry:
+ %r0 = add i64 %a, %b
+ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0)
+ ret i64 %r0
+}
+
+; CHECK-LABEL: test_sub_spill
+; CHECK: sub %i0, %i1, [[R:%[gilo][0-7]]]
+; CHECK: stx [[R]], [%fp+{{.+}}]
+; CHECK: ldx [%fp+{{.+}}, %i0
+define i64 @test_sub_spill(i64 %a, i64 %b) {
+entry:
+ %r0 = sub i64 %a, %b
+ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0)
+ ret i64 %r0
+}
+
+; CHECK-LABEL: test_andi_spill
+; CHECK: and %i0, 1729, [[R:%[gilo][0-7]]]
+; CHECK: stx [[R]], [%fp+{{.+}}]
+; CHECK: ldx [%fp+{{.+}}, %i0
+define i64 @test_andi_spill(i64 %a) {
+entry:
+ %r0 = and i64 %a, 1729
+ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0)
+ ret i64 %r0
+}
+
+; CHECK-LABEL: test_ori_spill
+; CHECK: or %i0, 1729, [[R:%[gilo][0-7]]]
+; CHECK: stx [[R]], [%fp+{{.+}}]
+; CHECK: ldx [%fp+{{.+}}, %i0
+define i64 @test_ori_spill(i64 %a) {
+entry:
+ %r0 = or i64 %a, 1729
+ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0)
+ ret i64 %r0
+}
+
+; CHECK-LABEL: test_xori_spill
+; CHECK: xor %i0, 1729, [[R:%[gilo][0-7]]]
+; CHECK: stx [[R]], [%fp+{{.+}}]
+; CHECK: ldx [%fp+{{.+}}, %i0
+define i64 @test_xori_spill(i64 %a) {
+entry:
+ %r0 = xor i64 %a, 1729
+ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0)
+ ret i64 %r0
+}
+
+; CHECK-LABEL: test_addi_spill
+; CHECK: add %i0, 1729, [[R:%[gilo][0-7]]]
+; CHECK: stx [[R]], [%fp+{{.+}}]
+; CHECK: ldx [%fp+{{.+}}, %i0
+define i64 @test_addi_spill(i64 %a) {
+entry:
+ %r0 = add i64 %a, 1729
+ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0)
+ ret i64 %r0
+}
+
+; CHECK-LABEL: test_subi_spill
+; CHECK: add %i0, -1729, [[R:%[gilo][0-7]]]
+; CHECK: stx [[R]], [%fp+{{.+}}]
+; CHECK: ldx [%fp+{{.+}}, %i0
+define i64 @test_subi_spill(i64 %a) {
+entry:
+ %r0 = sub i64 %a, 1729
+ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0)
+ ret i64 %r0
+}
+

View File

@ -0,0 +1,55 @@
Pull in r198280 from upstream llvm trunk (by Venkatraman Govindaraju):
[SparcV9]: Use SRL instead of SLL to clear top 32-bits in ctpop:i32. SLL does not clear top 32 bit, only SRL does.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcInstrInfo.td
===================================================================
--- lib/Target/Sparc/SparcInstrInfo.td
+++ lib/Target/Sparc/SparcInstrInfo.td
@@ -967,13 +967,13 @@ let Predicates = [HasV9] in {
}
// POPCrr - This does a ctpop of a 64-bit register. As such, we have to clear
-// the top 32-bits before using it. To do this clearing, we use a SLLri X,0.
+// the top 32-bits before using it. To do this clearing, we use a SRLri X,0.
let rs1 = 0 in
def POPCrr : F3_1<2, 0b101110,
(outs IntRegs:$dst), (ins IntRegs:$src),
"popc $src, $dst", []>, Requires<[HasV9]>;
def : Pat<(ctpop i32:$src),
- (POPCrr (SLLri $src, 0))>;
+ (POPCrr (SRLri $src, 0))>;
//===----------------------------------------------------------------------===//
// Non-Instruction Patterns
Index: test/CodeGen/SPARC/ctpop.ll
===================================================================
--- test/CodeGen/SPARC/ctpop.ll
+++ test/CodeGen/SPARC/ctpop.ll
@@ -1,8 +1,22 @@
-; RUN: llc < %s -march=sparc -mattr=-v9 | not grep popc
-; RUN: llc < %s -march=sparc -mattr=+v9 | grep popc
+; RUN: llc < %s -march=sparc -mattr=-v9 | FileCheck %s -check-prefix=V8
+; RUN: llc < %s -march=sparc -mattr=+v9 | FileCheck %s -check-prefix=V9
+; RUN: llc < %s -march=sparcv9 | FileCheck %s -check-prefix=SPARC64
declare i32 @llvm.ctpop.i32(i32)
+; V8-LABEL: test
+; V8-NOT : popc
+
+; V9-LABEL: test
+; V9: srl %o0, 0, %o0
+; V9-NEXT: jmp %o7+8
+; V9-NEXT: popc %o0, %o0
+
+; SPARC64-LABEL: test
+; SPARC64: srl %o0, 0, %o0
+; SPARC64: jmp %o7+8
+; SPARC64: popc %o0, %o0
+
define i32 @test(i32 %X) {
%Y = call i32 @llvm.ctpop.i32( i32 %X ) ; <i32> [#uses=1]
ret i32 %Y

View File

@ -0,0 +1,99 @@
Pull in r198281 from upstream llvm trunk (by Venkatraman Govindaraju):
[SparcV9]: Custom lower UMULO/SMULO so that the arguments are send to __multi3() in correct order.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -1525,6 +1525,9 @@ SparcTargetLowering::SparcTargetLowering(TargetMac
setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand);
setOperationAction(ISD::MULHU, MVT::i64, Expand);
setOperationAction(ISD::MULHS, MVT::i64, Expand);
+
+ setOperationAction(ISD::UMULO, MVT::i64, Custom);
+ setOperationAction(ISD::SMULO, MVT::i64, Custom);
}
// VASTART needs to be custom lowered to use the VarArgsFrameIndex.
@@ -2673,6 +2676,53 @@ static SDValue LowerADDC_ADDE_SUBC_SUBE(SDValue Op
return DAG.getMergeValues(Ops, 2, dl);
}
+// Custom lower UMULO/SMULO for SPARC. This code is similar to ExpandNode()
+// in LegalizeDAG.cpp except the order of arguments to the library function.
+static SDValue LowerUMULO_SMULO(SDValue Op, SelectionDAG &DAG,
+ const SparcTargetLowering &TLI)
+{
+ unsigned opcode = Op.getOpcode();
+ assert((opcode == ISD::UMULO || opcode == ISD::SMULO) && "Invalid Opcode.");
+
+ bool isSigned = (opcode == ISD::SMULO);
+ EVT VT = MVT::i64;
+ EVT WideVT = MVT::i128;
+ SDLoc dl(Op);
+ SDValue LHS = Op.getOperand(0);
+
+ if (LHS.getValueType() != VT)
+ return Op;
+
+ SDValue ShiftAmt = DAG.getConstant(63, VT);
+
+ SDValue RHS = Op.getOperand(1);
+ SDValue HiLHS = DAG.getNode(ISD::SRA, dl, VT, LHS, ShiftAmt);
+ SDValue HiRHS = DAG.getNode(ISD::SRA, dl, MVT::i64, RHS, ShiftAmt);
+ SDValue Args[] = { HiLHS, LHS, HiRHS, RHS };
+
+ SDValue MulResult = TLI.makeLibCall(DAG,
+ RTLIB::MUL_I128, WideVT,
+ Args, 4, isSigned, dl).first;
+ SDValue BottomHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT,
+ MulResult, DAG.getIntPtrConstant(0));
+ SDValue TopHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT,
+ MulResult, DAG.getIntPtrConstant(1));
+ if (isSigned) {
+ SDValue Tmp1 = DAG.getNode(ISD::SRA, dl, VT, BottomHalf, ShiftAmt);
+ TopHalf = DAG.getSetCC(dl, MVT::i32, TopHalf, Tmp1, ISD::SETNE);
+ } else {
+ TopHalf = DAG.getSetCC(dl, MVT::i32, TopHalf, DAG.getConstant(0, VT),
+ ISD::SETNE);
+ }
+ // MulResult is a node with an illegal type. Because such things are not
+ // generally permitted during this phase of legalization, delete the
+ // node. The above EXTRACT_ELEMENT nodes should have been folded.
+ DAG.DeleteNode(MulResult.getNode());
+
+ SDValue Ops[2] = { BottomHalf, TopHalf } ;
+ return DAG.getMergeValues(Ops, 2, dl);
+}
+
SDValue SparcTargetLowering::
LowerOperation(SDValue Op, SelectionDAG &DAG) const {
@@ -2726,6 +2776,8 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) cons
case ISD::ADDE:
case ISD::SUBC:
case ISD::SUBE: return LowerADDC_ADDE_SUBC_SUBE(Op, DAG);
+ case ISD::UMULO:
+ case ISD::SMULO: return LowerUMULO_SMULO(Op, DAG, *this);
}
}
Index: test/CodeGen/SPARC/64cond.ll
===================================================================
--- test/CodeGen/SPARC/64cond.ll
+++ test/CodeGen/SPARC/64cond.ll
@@ -111,6 +111,11 @@ entry:
}
; CHECK-LABEL: setcc_resultty
+; CHECK-DAG: srax %i0, 63, %o0
+; CHECK-DAG: or %g0, %i0, %o1
+; CHECK-DAG: or %g0, 0, %o2
+; CHECK-DAG: or %g0, 32, %o3
+; CHECK-DAG: call __multi3
; CHECK: cmp
; CHECK: movne %xcc, 1, [[R:%[gilo][0-7]]]
; CHECK: or [[R]], %i1, %i0

View File

@ -0,0 +1,231 @@
Pull in r198286 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Handle atomic loads/stores in sparc backend.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcInstrInfo.td
===================================================================
--- lib/Target/Sparc/SparcInstrInfo.td
+++ lib/Target/Sparc/SparcInstrInfo.td
@@ -975,6 +975,33 @@ let rs1 = 0 in
def : Pat<(ctpop i32:$src),
(POPCrr (SRLri $src, 0))>;
+// Atomic swap.
+let hasSideEffects =1, rd = 0, rs1 = 0b01111, rs2 = 0 in
+ def STBAR : F3_1<2, 0b101000, (outs), (ins), "stbar", []>;
+
+let Predicates = [HasV9], hasSideEffects = 1, rd = 0, rs1 = 0b01111 in
+ def MEMBARi : F3_2<2, 0b101000, (outs), (ins i32imm:$simm13),
+ "membar $simm13", []>;
+
+let Constraints = "$val = $rd" in {
+ def SWAPrr : F3_1<3, 0b001111,
+ (outs IntRegs:$rd), (ins IntRegs:$val, MEMrr:$addr),
+ "swap [$addr], $rd",
+ [(set i32:$rd, (atomic_swap_32 ADDRrr:$addr, i32:$val))]>;
+ def SWAPri : F3_2<3, 0b001111,
+ (outs IntRegs:$rd), (ins IntRegs:$val, MEMri:$addr),
+ "swap [$addr], $rd",
+ [(set i32:$rd, (atomic_swap_32 ADDRri:$addr, i32:$val))]>;
+}
+
+let Predicates = [HasV9], Constraints = "$swap = $rd" in
+ def CASrr: F3_1<3, 0b111100,
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2,
+ IntRegs:$swap),
+ "cas [$rs1], $rs2, $rd",
+ [(set i32:$rd,
+ (atomic_cmp_swap iPTR:$rs1, i32:$rs2, i32:$swap))]>;
+
//===----------------------------------------------------------------------===//
// Non-Instruction Patterns
//===----------------------------------------------------------------------===//
@@ -1036,4 +1063,17 @@ def : Pat<(i32 (zextloadi1 ADDRri:$src)), (LDUBri
def : Pat<(store (i32 0), ADDRrr:$dst), (STrr ADDRrr:$dst, (i32 G0))>;
def : Pat<(store (i32 0), ADDRri:$dst), (STri ADDRri:$dst, (i32 G0))>;
+// store bar for all atomic_fence in V8.
+let Predicates = [HasNoV9] in
+ def : Pat<(atomic_fence imm, imm), (STBAR)>;
+
+// atomic_load_32 addr -> load addr
+def : Pat<(i32 (atomic_load ADDRrr:$src)), (LDrr ADDRrr:$src)>;
+def : Pat<(i32 (atomic_load ADDRri:$src)), (LDri ADDRri:$src)>;
+
+// atomic_store_32 val, addr -> store val, addr
+def : Pat<(atomic_store ADDRrr:$dst, i32:$val), (STrr ADDRrr:$dst, $val)>;
+def : Pat<(atomic_store ADDRri:$dst, i32:$val), (STri ADDRri:$dst, $val)>;
+
+
include "SparcInstr64Bit.td"
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -1472,10 +1472,30 @@ SparcTargetLowering::SparcTargetLowering(TargetMac
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Custom);
}
- // FIXME: There are instructions available for ATOMIC_FENCE
- // on SparcV8 and later.
- setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Expand);
+ // ATOMICs.
+ // FIXME: We insert fences for each atomics and generate sub-optimal code
+ // for PSO/TSO. Also, implement other atomicrmw operations.
+ setInsertFencesForAtomic(true);
+
+ setOperationAction(ISD::ATOMIC_SWAP, MVT::i32, Legal);
+ setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i32,
+ (Subtarget->isV9() ? Legal: Expand));
+
+
+ setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Legal);
+
+ // Custom Lower Atomic LOAD/STORE
+ setOperationAction(ISD::ATOMIC_LOAD, MVT::i32, Custom);
+ setOperationAction(ISD::ATOMIC_STORE, MVT::i32, Custom);
+
+ if (Subtarget->is64Bit()) {
+ setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i64, Legal);
+ setOperationAction(ISD::ATOMIC_SWAP, MVT::i64, Expand);
+ setOperationAction(ISD::ATOMIC_LOAD, MVT::i64, Custom);
+ setOperationAction(ISD::ATOMIC_STORE, MVT::i64, Custom);
+ }
+
if (!Subtarget->isV9()) {
// SparcV8 does not have FNEGD and FABSD.
setOperationAction(ISD::FNEG, MVT::f64, Custom);
@@ -2723,6 +2743,16 @@ static SDValue LowerUMULO_SMULO(SDValue Op, Select
return DAG.getMergeValues(Ops, 2, dl);
}
+static SDValue LowerATOMIC_LOAD_STORE(SDValue Op, SelectionDAG &DAG) {
+ // Monotonic load/stores are legal.
+ if (cast<AtomicSDNode>(Op)->getOrdering() <= Monotonic)
+ return Op;
+
+ // Otherwise, expand with a fence.
+ return SDValue();
+}
+
+
SDValue SparcTargetLowering::
LowerOperation(SDValue Op, SelectionDAG &DAG) const {
@@ -2778,6 +2808,8 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) cons
case ISD::SUBE: return LowerADDC_ADDE_SUBC_SUBE(Op, DAG);
case ISD::UMULO:
case ISD::SMULO: return LowerUMULO_SMULO(Op, DAG, *this);
+ case ISD::ATOMIC_LOAD:
+ case ISD::ATOMIC_STORE: return LowerATOMIC_LOAD_STORE(Op, DAG);
}
}
Index: lib/Target/Sparc/SparcInstr64Bit.td
===================================================================
--- lib/Target/Sparc/SparcInstr64Bit.td
+++ lib/Target/Sparc/SparcInstr64Bit.td
@@ -415,6 +415,32 @@ def SETHIXi : F2_1<0b100,
"sethi $imm22, $rd",
[(set i64:$rd, SETHIimm:$imm22)]>;
}
+
+// ATOMICS.
+let Predicates = [Is64Bit], Constraints = "$swap = $rd" in {
+ def CASXrr: F3_1<3, 0b111110,
+ (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2,
+ I64Regs:$swap),
+ "casx [$rs1], $rs2, $rd",
+ [(set i64:$rd,
+ (atomic_cmp_swap i64:$rs1, i64:$rs2, i64:$swap))]>;
+
+} // Predicates = [Is64Bit], Constraints = ...
+
+let Predicates = [Is64Bit] in {
+
+def : Pat<(atomic_fence imm, imm), (MEMBARi 0xf)>;
+
+// atomic_load_64 addr -> load addr
+def : Pat<(i64 (atomic_load ADDRrr:$src)), (LDXrr ADDRrr:$src)>;
+def : Pat<(i64 (atomic_load ADDRri:$src)), (LDXri ADDRri:$src)>;
+
+// atomic_store_64 val, addr -> store val, addr
+def : Pat<(atomic_store ADDRrr:$dst, i64:$val), (STXrr ADDRrr:$dst, $val)>;
+def : Pat<(atomic_store ADDRri:$dst, i64:$val), (STXri ADDRri:$dst, $val)>;
+
+} // Predicates = [Is64Bit]
+
// Global addresses, constant pool entries
let Predicates = [Is64Bit] in {
Index: test/CodeGen/SPARC/atomics.ll
===================================================================
--- test/CodeGen/SPARC/atomics.ll
+++ test/CodeGen/SPARC/atomics.ll
@@ -0,0 +1,63 @@
+; RUN: llc < %s -march=sparcv9 | FileCheck %s
+
+; CHECK-LABEL: test_atomic_i32
+; CHECK: ld [%o0]
+; CHECK: membar
+; CHECK: ld [%o1]
+; CHECK: membar
+; CHECK: membar
+; CHECK: st {{.+}}, [%o2]
+define i32 @test_atomic_i32(i32* %ptr1, i32* %ptr2, i32* %ptr3) {
+entry:
+ %0 = load atomic i32* %ptr1 acquire, align 8
+ %1 = load atomic i32* %ptr2 acquire, align 8
+ %2 = add i32 %0, %1
+ store atomic i32 %2, i32* %ptr3 release, align 8
+ ret i32 %2
+}
+
+; CHECK-LABEL: test_atomic_i64
+; CHECK: ldx [%o0]
+; CHECK: membar
+; CHECK: ldx [%o1]
+; CHECK: membar
+; CHECK: membar
+; CHECK: stx {{.+}}, [%o2]
+define i64 @test_atomic_i64(i64* %ptr1, i64* %ptr2, i64* %ptr3) {
+entry:
+ %0 = load atomic i64* %ptr1 acquire, align 8
+ %1 = load atomic i64* %ptr2 acquire, align 8
+ %2 = add i64 %0, %1
+ store atomic i64 %2, i64* %ptr3 release, align 8
+ ret i64 %2
+}
+
+; CHECK-LABEL: test_cmpxchg_i32
+; CHECK: or %g0, 123, [[R:%[gilo][0-7]]]
+; CHECK: cas [%o1], %o0, [[R]]
+
+define i32 @test_cmpxchg_i32(i32 %a, i32* %ptr) {
+entry:
+ %b = cmpxchg i32* %ptr, i32 %a, i32 123 monotonic
+ ret i32 %b
+}
+
+; CHECK-LABEL: test_cmpxchg_i64
+; CHECK: or %g0, 123, [[R:%[gilo][0-7]]]
+; CHECK: casx [%o1], %o0, [[R]]
+
+define i64 @test_cmpxchg_i64(i64 %a, i64* %ptr) {
+entry:
+ %b = cmpxchg i64* %ptr, i64 %a, i64 123 monotonic
+ ret i64 %b
+}
+
+; CHECK-LABEL: test_swap_i32
+; CHECK: or %g0, 42, [[R:%[gilo][0-7]]]
+; CHECK: swap [%o1], [[R]]
+
+define i32 @test_swap_i32(i32 %a, i32* %ptr) {
+entry:
+ %b = atomicrmw xchg i32* %ptr, i32 42 monotonic
+ ret i32 %b
+}

View File

@ -0,0 +1,213 @@
Pull in r198480 from upstream llvm trunk (by Venkatraman Govindaraju):
[SparcV9]: Implement RETURNADDR and FRAMEADDR lowering in SPARC64.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -2415,7 +2415,8 @@ static SDValue getFLUSHW(SDValue Op, SelectionDAG
return Chain;
}
-static SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) {
+static SDValue getFRAMEADDR(uint64_t depth, SDValue Op, SelectionDAG &DAG,
+ const SparcSubtarget *Subtarget) {
MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
MFI->setFrameAddressIsTaken(true);
@@ -2422,32 +2423,49 @@ static SDValue getFLUSHW(SDValue Op, SelectionDAG
EVT VT = Op.getValueType();
SDLoc dl(Op);
unsigned FrameReg = SP::I6;
+ unsigned stackBias = Subtarget->getStackPointerBias();
- uint64_t depth = Op.getConstantOperandVal(0);
+ SDValue FrameAddr;
- SDValue FrameAddr;
- if (depth == 0)
+ if (depth == 0) {
FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT);
- else {
- // flush first to make sure the windowed registers' values are in stack
- SDValue Chain = getFLUSHW(Op, DAG);
- FrameAddr = DAG.getCopyFromReg(Chain, dl, FrameReg, VT);
+ if (Subtarget->is64Bit())
+ FrameAddr = DAG.getNode(ISD::ADD, dl, VT, FrameAddr,
+ DAG.getIntPtrConstant(stackBias));
+ return FrameAddr;
+ }
- for (uint64_t i = 0; i != depth; ++i) {
- SDValue Ptr = DAG.getNode(ISD::ADD,
- dl, MVT::i32,
- FrameAddr, DAG.getIntPtrConstant(56));
- FrameAddr = DAG.getLoad(MVT::i32, dl,
- Chain,
- Ptr,
- MachinePointerInfo(), false, false, false, 0);
- }
+ // flush first to make sure the windowed registers' values are in stack
+ SDValue Chain = getFLUSHW(Op, DAG);
+ FrameAddr = DAG.getCopyFromReg(Chain, dl, FrameReg, VT);
+
+ unsigned Offset = (Subtarget->is64Bit()) ? (stackBias + 112) : 56;
+
+ while (depth--) {
+ SDValue Ptr = DAG.getNode(ISD::ADD, dl, VT, FrameAddr,
+ DAG.getIntPtrConstant(Offset));
+ FrameAddr = DAG.getLoad(VT, dl, Chain, Ptr, MachinePointerInfo(),
+ false, false, false, 0);
}
+ if (Subtarget->is64Bit())
+ FrameAddr = DAG.getNode(ISD::ADD, dl, VT, FrameAddr,
+ DAG.getIntPtrConstant(stackBias));
return FrameAddr;
}
+
+static SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG,
+ const SparcSubtarget *Subtarget) {
+
+ uint64_t depth = Op.getConstantOperandVal(0);
+
+ return getFRAMEADDR(depth, Op, DAG, Subtarget);
+
+}
+
static SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG,
- const SparcTargetLowering &TLI) {
+ const SparcTargetLowering &TLI,
+ const SparcSubtarget *Subtarget) {
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo *MFI = MF.getFrameInfo();
MFI->setReturnAddressIsTaken(true);
@@ -2461,25 +2479,20 @@ static SDValue LowerRETURNADDR(SDValue Op, Selecti
unsigned RetReg = MF.addLiveIn(SP::I7,
TLI.getRegClassFor(TLI.getPointerTy()));
RetAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, RetReg, VT);
- } else {
- // Need frame address to find return address of the caller.
- MFI->setFrameAddressIsTaken(true);
+ return RetAddr;
+ }
- // flush first to make sure the windowed registers' values are in stack
- SDValue Chain = getFLUSHW(Op, DAG);
- RetAddr = DAG.getCopyFromReg(Chain, dl, SP::I6, VT);
+ // Need frame address to find return address of the caller.
+ SDValue FrameAddr = getFRAMEADDR(depth - 1, Op, DAG, Subtarget);
- for (uint64_t i = 0; i != depth; ++i) {
- SDValue Ptr = DAG.getNode(ISD::ADD,
- dl, MVT::i32,
- RetAddr,
- DAG.getIntPtrConstant((i == depth-1)?60:56));
- RetAddr = DAG.getLoad(MVT::i32, dl,
- Chain,
- Ptr,
- MachinePointerInfo(), false, false, false, 0);
- }
- }
+ unsigned Offset = (Subtarget->is64Bit()) ? 120 : 60;
+ SDValue Ptr = DAG.getNode(ISD::ADD,
+ dl, VT,
+ FrameAddr,
+ DAG.getIntPtrConstant(Offset));
+ RetAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), Ptr,
+ MachinePointerInfo(), false, false, false, 0);
+
return RetAddr;
}
@@ -2763,8 +2776,10 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) cons
switch (Op.getOpcode()) {
default: llvm_unreachable("Should not custom lower this!");
- case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG, *this);
- case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
+ case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG, *this,
+ Subtarget);
+ case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG,
+ Subtarget);
case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG);
case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);
case ISD::BlockAddress: return LowerBlockAddress(Op, DAG);
Index: test/CodeGen/SPARC/2011-01-11-FrameAddr.ll
===================================================================
--- test/CodeGen/SPARC/2011-01-11-FrameAddr.ll
+++ test/CodeGen/SPARC/2011-01-11-FrameAddr.ll
@@ -2,6 +2,7 @@
;RUN: llc -march=sparc -mattr=v9 < %s | FileCheck %s -check-prefix=V9
;RUN: llc -march=sparc -regalloc=basic < %s | FileCheck %s -check-prefix=V8
;RUN: llc -march=sparc -regalloc=basic -mattr=v9 < %s | FileCheck %s -check-prefix=V9
+;RUN: llc -march=sparcv9 < %s | FileCheck %s -check-prefix=SPARC64
define i8* @frameaddr() nounwind readnone {
@@ -15,6 +16,13 @@ entry:
;V9: save %sp, -96, %sp
;V9: jmp %i7+8
;V9: restore %g0, %fp, %o0
+
+;SPARC64-LABEL: frameaddr
+;SPARC64: save %sp, -128, %sp
+;SPARC64: add %fp, 2047, %i0
+;SPARC64: jmp %i7+8
+;SPARC64: restore %g0, %g0, %g0
+
%0 = tail call i8* @llvm.frameaddress(i32 0)
ret i8* %0
}
@@ -32,6 +40,14 @@ entry:
;V9: ld [%fp+56], {{.+}}
;V9: ld [{{.+}}+56], {{.+}}
;V9: ld [{{.+}}+56], {{.+}}
+
+;SPARC64-LABEL: frameaddr2
+;SPARC64: flushw
+;SPARC64: ldx [%fp+2159], %[[R0:[goli][0-7]]]
+;SPARC64: ldx [%[[R0]]+2159], %[[R1:[goli][0-7]]]
+;SPARC64: ldx [%[[R1]]+2159], %[[R2:[goli][0-7]]]
+;SPARC64: add %[[R2]], 2047, {{.+}}
+
%0 = tail call i8* @llvm.frameaddress(i32 3)
ret i8* %0
}
@@ -48,6 +64,9 @@ entry:
;V9-LABEL: retaddr:
;V9: or %g0, %o7, {{.+}}
+;SPARC64-LABEL: retaddr
+;SPARC64: or %g0, %o7, {{.+}}
+
%0 = tail call i8* @llvm.returnaddress(i32 0)
ret i8* %0
}
@@ -66,18 +85,12 @@ entry:
;V9: ld [{{.+}}+56], {{.+}}
;V9: ld [{{.+}}+60], {{.+}}
-;V8LEAF-LABEL: retaddr2:
-;V8LEAF: ta 3
-;V8LEAF: ld [%fp+56], %[[R:[goli][0-7]]]
-;V8LEAF: ld [%[[R]]+56], %[[R1:[goli][0-7]]]
-;V8LEAF: ld [%[[R1]]+60], {{.+}}
+;SPARC64-LABEL: retaddr2
+;SPARC64: flushw
+;SPARC64: ldx [%fp+2159], %[[R0:[goli][0-7]]]
+;SPARC64: ldx [%[[R0]]+2159], %[[R1:[goli][0-7]]]
+;SPARC64: ldx [%[[R1]]+2167], {{.+}}
-;V9LEAF-LABEL: retaddr2:
-;V9LEAF: flushw
-;V9LEAF: ld [%fp+56], %[[R:[goli][0-7]]]
-;V9LEAF: ld [%[[R]]+56], %[[R1:[goli][0-7]]]
-;V9LEAF: ld [%[[R1]]+60], {{.+}}
-
%0 = tail call i8* @llvm.returnaddress(i32 3)
ret i8* %0
}

View File

@ -0,0 +1,844 @@
Pull in r198484 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Add the initial implementation of an asm parser for sparc/sparcv9.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
@@ -123,13 +123,18 @@ extern "C" void LLVMInitializeSparcTargetMC() {
// Register the MC instruction info.
TargetRegistry::RegisterMCInstrInfo(TheSparcTarget, createSparcMCInstrInfo);
+ TargetRegistry::RegisterMCInstrInfo(TheSparcV9Target, createSparcMCInstrInfo);
// Register the MC register info.
TargetRegistry::RegisterMCRegInfo(TheSparcTarget, createSparcMCRegisterInfo);
+ TargetRegistry::RegisterMCRegInfo(TheSparcV9Target,
+ createSparcMCRegisterInfo);
// Register the MC subtarget info.
TargetRegistry::RegisterMCSubtargetInfo(TheSparcTarget,
createSparcMCSubtargetInfo);
+ TargetRegistry::RegisterMCSubtargetInfo(TheSparcV9Target,
+ createSparcMCSubtargetInfo);
TargetRegistry::RegisterAsmStreamer(TheSparcTarget,
createMCAsmStreamer);
Index: lib/Target/Sparc/LLVMBuild.txt
===================================================================
--- lib/Target/Sparc/LLVMBuild.txt
+++ lib/Target/Sparc/LLVMBuild.txt
@@ -16,7 +16,7 @@
;===------------------------------------------------------------------------===;
[common]
-subdirectories = InstPrinter MCTargetDesc TargetInfo
+subdirectories = AsmParser InstPrinter MCTargetDesc TargetInfo
[component_0]
type = TargetGroup
Index: lib/Target/Sparc/SparcInstrInfo.td
===================================================================
--- lib/Target/Sparc/SparcInstrInfo.td
+++ lib/Target/Sparc/SparcInstrInfo.td
@@ -76,13 +76,25 @@ def ADDRrr : ComplexPattern<iPTR, 2, "SelectADDRrr
def ADDRri : ComplexPattern<iPTR, 2, "SelectADDRri", [frameindex], []>;
// Address operands
+def SparcMEMrrAsmOperand : AsmOperandClass {
+ let Name = "MEMrr";
+ let ParserMethod = "parseMEMrrOperand";
+}
+
+def SparcMEMriAsmOperand : AsmOperandClass {
+ let Name = "MEMri";
+ let ParserMethod = "parseMEMriOperand";
+}
+
def MEMrr : Operand<iPTR> {
let PrintMethod = "printMemOperand";
let MIOperandInfo = (ops ptr_rc, ptr_rc);
+ let ParserMatchClass = SparcMEMrrAsmOperand;
}
def MEMri : Operand<iPTR> {
let PrintMethod = "printMemOperand";
let MIOperandInfo = (ops ptr_rc, i32imm);
+ let ParserMatchClass = SparcMEMriAsmOperand;
}
def TLSSym : Operand<iPTR>;
@@ -239,7 +251,10 @@ multiclass F3_12np<string OpcStr, bits<6> Op3Val>
// Pseudo instructions.
class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern>
- : InstSP<outs, ins, asmstr, pattern>;
+ : InstSP<outs, ins, asmstr, pattern> {
+ let isCodeGenOnly = 1;
+ let isPseudo = 1;
+}
// GETPCX for PIC
let Defs = [O7] in {
@@ -503,7 +518,7 @@ defm SRA : F3_12<"sra", 0b100111, sra, IntRegs, i3
defm ADD : F3_12<"add", 0b000000, add, IntRegs, i32, i32imm>;
// "LEA" forms of add (patterns to make tblgen happy)
-let Predicates = [Is32Bit] in
+let Predicates = [Is32Bit], isCodeGenOnly = 1 in
def LEA_ADDri : F3_2<2, 0b000000,
(outs IntRegs:$dst), (ins MEMri:$addr),
"add ${addr:arith}, $dst",
Index: lib/Target/Sparc/CMakeLists.txt
===================================================================
--- lib/Target/Sparc/CMakeLists.txt
+++ lib/Target/Sparc/CMakeLists.txt
@@ -4,6 +4,7 @@ tablegen(LLVM SparcGenRegisterInfo.inc -gen-regist
tablegen(LLVM SparcGenInstrInfo.inc -gen-instr-info)
tablegen(LLVM SparcGenCodeEmitter.inc -gen-emitter)
tablegen(LLVM SparcGenAsmWriter.inc -gen-asm-writer)
+tablegen(LLVM SparcGenAsmMatcher.inc -gen-asm-matcher)
tablegen(LLVM SparcGenDAGISel.inc -gen-dag-isel)
tablegen(LLVM SparcGenSubtargetInfo.inc -gen-subtarget)
tablegen(LLVM SparcGenCallingConv.inc -gen-callingconv)
@@ -31,3 +32,4 @@ add_dependencies(LLVMSparcCodeGen SparcCommonTable
add_subdirectory(TargetInfo)
add_subdirectory(MCTargetDesc)
add_subdirectory(InstPrinter)
+add_subdirectory(AsmParser)
Index: lib/Target/Sparc/Makefile
===================================================================
--- lib/Target/Sparc/Makefile
+++ lib/Target/Sparc/Makefile
@@ -13,11 +13,12 @@ TARGET = Sparc
# Make sure that tblgen is run, first thing.
BUILT_SOURCES = SparcGenRegisterInfo.inc SparcGenInstrInfo.inc \
- SparcGenAsmWriter.inc SparcGenDAGISel.inc \
+ SparcGenAsmWriter.inc SparcGenAsmMatcher.inc \
+ SparcGenDAGISel.inc \
SparcGenSubtargetInfo.inc SparcGenCallingConv.inc \
SparcGenCodeEmitter.inc
-DIRS = InstPrinter TargetInfo MCTargetDesc
+DIRS = InstPrinter AsmParser TargetInfo MCTargetDesc
include $(LEVEL)/Makefile.common
Index: lib/Target/Sparc/Sparc.td
===================================================================
--- lib/Target/Sparc/Sparc.td
+++ lib/Target/Sparc/Sparc.td
@@ -44,6 +44,10 @@ include "SparcInstrInfo.td"
def SparcInstrInfo : InstrInfo;
+def SparcAsmParser : AsmParser {
+ bit ShouldEmitMatchRegisterName = 0;
+}
+
//===----------------------------------------------------------------------===//
// SPARC processors supported.
//===----------------------------------------------------------------------===//
@@ -77,6 +81,7 @@ def SparcAsmWriter : AsmWriter {
def Sparc : Target {
// Pull in Instruction Info:
let InstructionSet = SparcInstrInfo;
+ let AssemblyParsers = [SparcAsmParser];
let AssemblyWriters = [SparcAsmWriter];
}
Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
===================================================================
--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
+++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
@@ -0,0 +1,614 @@
+//===-- SparcAsmParser.cpp - Parse Sparc assembly to MCInst instructions --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/SparcMCTargetDesc.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetAsmParser.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+// The generated AsmMatcher SparcGenAsmMatcher uses "Sparc" as the target
+// namespace. But SPARC backend uses "SP" as its namespace.
+namespace llvm {
+ namespace Sparc {
+ using namespace SP;
+ }
+}
+
+namespace {
+class SparcAsmParser : public MCTargetAsmParser {
+
+ MCSubtargetInfo &STI;
+ MCAsmParser &Parser;
+
+ /// @name Auto-generated Match Functions
+ /// {
+
+#define GET_ASSEMBLER_HEADER
+#include "SparcGenAsmMatcher.inc"
+
+ /// }
+
+ // public interface of the MCTargetAsmParser.
+ bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
+ SmallVectorImpl<MCParsedAsmOperand*> &Operands,
+ MCStreamer &Out, unsigned &ErrorInfo,
+ bool MatchingInlineAsm);
+ bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc);
+ bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
+ SMLoc NameLoc,
+ SmallVectorImpl<MCParsedAsmOperand*> &Operands);
+ bool ParseDirective(AsmToken DirectiveID);
+
+
+ // Custom parse functions for Sparc specific operands.
+ OperandMatchResultTy
+ parseMEMrrOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands);
+ OperandMatchResultTy
+ parseMEMriOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands);
+
+ OperandMatchResultTy
+ parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
+ int ImmOffsetOrReg);
+
+ OperandMatchResultTy
+ parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
+ StringRef Name);
+
+ // returns true if Tok is matched to a register and returns register in RegNo.
+ bool matchRegisterName(const AsmToken &Tok, unsigned &RegNo, bool isDFP,
+ bool isQFP);
+
+public:
+ SparcAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser,
+ const MCInstrInfo &MII)
+ : MCTargetAsmParser(), STI(sti), Parser(parser) {
+ // Initialize the set of available features.
+ setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
+ }
+
+};
+
+ static unsigned IntRegs[32] = {
+ Sparc::G0, Sparc::G1, Sparc::G2, Sparc::G3,
+ Sparc::G4, Sparc::G5, Sparc::G6, Sparc::G7,
+ Sparc::O0, Sparc::O1, Sparc::O2, Sparc::O3,
+ Sparc::O4, Sparc::O5, Sparc::O6, Sparc::O7,
+ Sparc::L0, Sparc::L1, Sparc::L2, Sparc::L3,
+ Sparc::L4, Sparc::L5, Sparc::L6, Sparc::L7,
+ Sparc::I0, Sparc::I1, Sparc::I2, Sparc::I3,
+ Sparc::I4, Sparc::I5, Sparc::I6, Sparc::I7 };
+
+ static unsigned FloatRegs[32] = {
+ Sparc::F0, Sparc::F1, Sparc::F2, Sparc::F3,
+ Sparc::F4, Sparc::F5, Sparc::F6, Sparc::F7,
+ Sparc::F8, Sparc::F9, Sparc::F10, Sparc::F11,
+ Sparc::F12, Sparc::F13, Sparc::F14, Sparc::F15,
+ Sparc::F16, Sparc::F17, Sparc::F18, Sparc::F19,
+ Sparc::F20, Sparc::F21, Sparc::F22, Sparc::F23,
+ Sparc::F24, Sparc::F25, Sparc::F26, Sparc::F27,
+ Sparc::F28, Sparc::F29, Sparc::F30, Sparc::F31 };
+
+ static unsigned DoubleRegs[32] = {
+ Sparc::D0, Sparc::D1, Sparc::D2, Sparc::D3,
+ Sparc::D4, Sparc::D5, Sparc::D6, Sparc::D7,
+ Sparc::D8, Sparc::D7, Sparc::D8, Sparc::D9,
+ Sparc::D12, Sparc::D13, Sparc::D14, Sparc::D15,
+ Sparc::D16, Sparc::D17, Sparc::D18, Sparc::D19,
+ Sparc::D20, Sparc::D21, Sparc::D22, Sparc::D23,
+ Sparc::D24, Sparc::D25, Sparc::D26, Sparc::D27,
+ Sparc::D28, Sparc::D29, Sparc::D30, Sparc::D31 };
+
+ static unsigned QuadFPRegs[32] = {
+ Sparc::Q0, Sparc::Q1, Sparc::Q2, Sparc::Q3,
+ Sparc::Q4, Sparc::Q5, Sparc::Q6, Sparc::Q7,
+ Sparc::Q8, Sparc::Q7, Sparc::Q8, Sparc::Q9,
+ Sparc::Q12, Sparc::Q13, Sparc::Q14, Sparc::Q15 };
+
+
+/// SparcOperand - Instances of this class represent a parsed Sparc machine
+/// instruction.
+class SparcOperand : public MCParsedAsmOperand {
+public:
+ enum RegisterKind {
+ rk_None,
+ rk_IntReg,
+ rk_FloatReg,
+ rk_DoubleReg,
+ rk_QuadReg,
+ rk_CCReg,
+ rk_Y
+ };
+private:
+ enum KindTy {
+ k_Token,
+ k_Register,
+ k_Immediate,
+ k_MemoryReg,
+ k_MemoryImm
+ } Kind;
+
+ SMLoc StartLoc, EndLoc;
+
+ SparcOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
+
+ struct Token {
+ const char *Data;
+ unsigned Length;
+ };
+
+ struct RegOp {
+ unsigned RegNum;
+ RegisterKind Kind;
+ };
+
+ struct ImmOp {
+ const MCExpr *Val;
+ };
+
+ struct MemOp {
+ unsigned Base;
+ unsigned OffsetReg;
+ const MCExpr *Off;
+ };
+
+ union {
+ struct Token Tok;
+ struct RegOp Reg;
+ struct ImmOp Imm;
+ struct MemOp Mem;
+ };
+public:
+ bool isToken() const { return Kind == k_Token; }
+ bool isReg() const { return Kind == k_Register; }
+ bool isImm() const { return Kind == k_Immediate; }
+ bool isMem() const { return isMEMrr() || isMEMri(); }
+ bool isMEMrr() const { return Kind == k_MemoryReg; }
+ bool isMEMri() const { return Kind == k_MemoryImm; }
+
+ StringRef getToken() const {
+ assert(Kind == k_Token && "Invalid access!");
+ return StringRef(Tok.Data, Tok.Length);
+ }
+
+ unsigned getReg() const {
+ assert((Kind == k_Register) && "Invalid access!");
+ return Reg.RegNum;
+ }
+
+ const MCExpr *getImm() const {
+ assert((Kind == k_Immediate) && "Invalid access!");
+ return Imm.Val;
+ }
+
+ unsigned getMemBase() const {
+ assert((Kind == k_MemoryReg || Kind == k_MemoryImm) && "Invalid access!");
+ return Mem.Base;
+ }
+
+ unsigned getMemOffsetReg() const {
+ assert((Kind == k_MemoryReg) && "Invalid access!");
+ return Mem.OffsetReg;
+ }
+
+ const MCExpr *getMemOff() const {
+ assert((Kind == k_MemoryImm) && "Invalid access!");
+ return Mem.Off;
+ }
+
+ /// getStartLoc - Get the location of the first token of this operand.
+ SMLoc getStartLoc() const {
+ return StartLoc;
+ }
+ /// getEndLoc - Get the location of the last token of this operand.
+ SMLoc getEndLoc() const {
+ return EndLoc;
+ }
+
+ virtual void print(raw_ostream &OS) const {
+ switch (Kind) {
+ case k_Token: OS << "Token: " << getToken() << "\n"; break;
+ case k_Register: OS << "Reg: #" << getReg() << "\n"; break;
+ case k_Immediate: OS << "Imm: " << getImm() << "\n"; break;
+ case k_MemoryReg: OS << "Mem: " << getMemBase() << "+"
+ << getMemOffsetReg() << "\n"; break;
+ case k_MemoryImm: assert(getMemOff() != 0);
+ OS << "Mem: " << getMemBase()
+ << "+" << *getMemOff()
+ << "\n"; break;
+ }
+ }
+
+ void addRegOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::CreateReg(getReg()));
+ }
+
+ void addImmOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ const MCExpr *Expr = getImm();
+ addExpr(Inst, Expr);
+ }
+
+ void addExpr(MCInst &Inst, const MCExpr *Expr) const{
+ // Add as immediate when possible. Null MCExpr = 0.
+ if (Expr == 0)
+ Inst.addOperand(MCOperand::CreateImm(0));
+ else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))
+ Inst.addOperand(MCOperand::CreateImm(CE->getValue()));
+ else
+ Inst.addOperand(MCOperand::CreateExpr(Expr));
+ }
+
+ void addMEMrrOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 2 && "Invalid number of operands!");
+
+ Inst.addOperand(MCOperand::CreateReg(getMemBase()));
+
+ assert(getMemOffsetReg() != 0 && "Invalid offset");
+ Inst.addOperand(MCOperand::CreateReg(getMemOffsetReg()));
+ }
+
+ void addMEMriOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 2 && "Invalid number of operands!");
+
+ Inst.addOperand(MCOperand::CreateReg(getMemBase()));
+
+ const MCExpr *Expr = getMemOff();
+ addExpr(Inst, Expr);
+ }
+
+ static SparcOperand *CreateToken(StringRef Str, SMLoc S) {
+ SparcOperand *Op = new SparcOperand(k_Token);
+ Op->Tok.Data = Str.data();
+ Op->Tok.Length = Str.size();
+ Op->StartLoc = S;
+ Op->EndLoc = S;
+ return Op;
+ }
+
+ static SparcOperand *CreateReg(unsigned RegNum,
+ SparcOperand::RegisterKind Kind,
+ SMLoc S, SMLoc E) {
+ SparcOperand *Op = new SparcOperand(k_Register);
+ Op->Reg.RegNum = RegNum;
+ Op->Reg.Kind = Kind;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
+ static SparcOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) {
+ SparcOperand *Op = new SparcOperand(k_Immediate);
+ Op->Imm.Val = Val;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
+
+};
+
+} // end namespace
+
+bool SparcAsmParser::
+MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
+ SmallVectorImpl<MCParsedAsmOperand*> &Operands,
+ MCStreamer &Out, unsigned &ErrorInfo,
+ bool MatchingInlineAsm) {
+ MCInst Inst;
+ SmallVector<MCInst, 8> Instructions;
+ unsigned MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo,
+ MatchingInlineAsm);
+ switch (MatchResult) {
+ default:
+ break;
+
+ case Match_Success: {
+ Inst.setLoc(IDLoc);
+ Out.EmitInstruction(Inst);
+ return false;
+ }
+
+ case Match_MissingFeature:
+ return Error(IDLoc,
+ "instruction requires a CPU feature not currently enabled");
+
+ case Match_InvalidOperand: {
+ SMLoc ErrorLoc = IDLoc;
+ if (ErrorInfo != ~0U) {
+ if (ErrorInfo >= Operands.size())
+ return Error(IDLoc, "too few operands for instruction");
+
+ ErrorLoc = ((SparcOperand*) Operands[ErrorInfo])->getStartLoc();
+ if (ErrorLoc == SMLoc())
+ ErrorLoc = IDLoc;
+ }
+
+ return Error(ErrorLoc, "invalid operand for instruction");
+ }
+ case Match_MnemonicFail:
+ return Error(IDLoc, "invalid instruction");
+ }
+ return true;
+}
+
+bool SparcAsmParser::
+ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc)
+{
+ const AsmToken &Tok = Parser.getTok();
+ StartLoc = Tok.getLoc();
+ EndLoc = Tok.getEndLoc();
+ RegNo = 0;
+ if (getLexer().getKind() != AsmToken::Percent)
+ return false;
+ Parser.Lex();
+ if (matchRegisterName(Tok, RegNo, false, false)) {
+ Parser.Lex();
+ return false;
+ }
+
+ return Error(StartLoc, "invalid register name");
+}
+
+bool SparcAsmParser::
+ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
+ SMLoc NameLoc,
+ SmallVectorImpl<MCParsedAsmOperand*> &Operands)
+{
+ // Check if we have valid mnemonic.
+ if (!mnemonicIsValid(Name, 0)) {
+ Parser.eatToEndOfStatement();
+ return Error(NameLoc, "Unknown instruction");
+ }
+ // First operand in MCInst is instruction mnemonic.
+ Operands.push_back(SparcOperand::CreateToken(Name, NameLoc));
+
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ // Read the first operand.
+ if (parseOperand(Operands, Name) != MatchOperand_Success) {
+ SMLoc Loc = getLexer().getLoc();
+ Parser.eatToEndOfStatement();
+ return Error(Loc, "unexpected token");
+ }
+
+ while (getLexer().is(AsmToken::Comma)) {
+ Parser.Lex(); // Eat the comma.
+ // Parse and remember the operand.
+ if (parseOperand(Operands, Name) != MatchOperand_Success) {
+ SMLoc Loc = getLexer().getLoc();
+ Parser.eatToEndOfStatement();
+ return Error(Loc, "unexpected token");
+ }
+ }
+ }
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ SMLoc Loc = getLexer().getLoc();
+ Parser.eatToEndOfStatement();
+ return Error(Loc, "unexpected token");
+ }
+ Parser.Lex(); // Consume the EndOfStatement.
+ return false;
+}
+
+bool SparcAsmParser::
+ParseDirective(AsmToken DirectiveID)
+{
+ // Ignore all directives for now.
+ Parser.eatToEndOfStatement();
+ return false;
+}
+
+SparcAsmParser::OperandMatchResultTy SparcAsmParser::
+parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
+ int ImmOffsetOrReg)
+{
+ // FIXME: Implement memory operand parsing here.
+ return MatchOperand_NoMatch;
+}
+
+SparcAsmParser::OperandMatchResultTy SparcAsmParser::
+parseMEMrrOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands)
+{
+ return parseMEMOperand(Operands, 2);
+}
+
+SparcAsmParser::OperandMatchResultTy SparcAsmParser::
+parseMEMriOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands)
+{
+ return parseMEMOperand(Operands, 1);
+}
+
+SparcAsmParser::OperandMatchResultTy SparcAsmParser::
+parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
+ StringRef Mnemonic)
+{
+ OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic);
+ if (ResTy == MatchOperand_Success)
+ return ResTy;
+ // If there wasn't a custom match, try the generic matcher below. Otherwise,
+ // there was a match, but an error occurred, in which case, just return that
+ // the operand parsing failed.
+ if (ResTy == MatchOperand_ParseFail)
+ return ResTy;
+
+ SMLoc S = Parser.getTok().getLoc();
+ SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ const MCExpr *EVal;
+ SparcOperand *Op;
+ switch (getLexer().getKind()) {
+ case AsmToken::Percent:
+ Parser.Lex(); // Eat the '%'.
+ unsigned RegNo;
+ if (matchRegisterName(Parser.getTok(), RegNo, false, false)) {
+ Parser.Lex(); // Eat the identifier token.
+ Op = SparcOperand::CreateReg(RegNo, SparcOperand::rk_None, S, E);
+ break;
+ }
+ // FIXME: Handle modifiers like %hi, %lo etc.,
+ return MatchOperand_ParseFail;
+
+ case AsmToken::Minus:
+ case AsmToken::Integer:
+ if (getParser().parseExpression(EVal))
+ return MatchOperand_ParseFail;
+
+ Op = SparcOperand::CreateImm(EVal, S, E);
+ break;
+
+ case AsmToken::Identifier: {
+ StringRef Identifier;
+ if (getParser().parseIdentifier(Identifier))
+ return MatchOperand_ParseFail;
+ SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ MCSymbol *Sym = getContext().GetOrCreateSymbol(Identifier);
+
+ // Otherwise create a symbol reference.
+ const MCExpr *Res = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None,
+ getContext());
+
+ Op = SparcOperand::CreateImm(Res, S, E);
+ break;
+ }
+
+ case AsmToken::LBrac: // handle [
+ return parseMEMOperand(Operands, 0);
+
+ default:
+ return MatchOperand_ParseFail;
+ }
+ // Push the parsed operand into the list of operands
+ Operands.push_back(Op);
+ return MatchOperand_Success;
+}
+
+bool SparcAsmParser::matchRegisterName(const AsmToken &Tok,
+ unsigned &RegNo,
+ bool isDFP,
+ bool isQFP)
+{
+ int64_t intVal = 0;
+ RegNo = 0;
+ if (Tok.is(AsmToken::Identifier)) {
+ StringRef name = Tok.getString();
+
+ // %fp
+ if (name.equals("fp")) {
+ RegNo = Sparc::I6;
+ return true;
+ }
+ // %sp
+ if (name.equals("sp")) {
+ RegNo = Sparc::O6;
+ return true;
+ }
+
+ if (name.equals("y")) {
+ RegNo = Sparc::Y;
+ return true;
+ }
+
+ if (name.equals("icc")) {
+ RegNo = Sparc::ICC;
+ return true;
+ }
+
+ if (name.equals("xcc")) {
+ // FIXME:: check 64bit.
+ RegNo = Sparc::ICC;
+ return true;
+ }
+
+ // %fcc0 - %fcc3
+ if (name.substr(0, 3).equals_lower("fcc")
+ && !name.substr(3).getAsInteger(10, intVal)
+ && intVal < 4) {
+ // FIXME: check 64bit and handle %fcc1 - %fcc3
+ RegNo = Sparc::FCC;
+ return true;
+ }
+
+ // %g0 - %g7
+ if (name.substr(0, 1).equals_lower("g")
+ && !name.substr(1).getAsInteger(10, intVal)
+ && intVal < 8) {
+ RegNo = IntRegs[intVal];
+ return true;
+ }
+ // %o0 - %o7
+ if (name.substr(0, 1).equals_lower("o")
+ && !name.substr(1).getAsInteger(10, intVal)
+ && intVal < 8) {
+ RegNo = IntRegs[8 + intVal];
+ return true;
+ }
+ if (name.substr(0, 1).equals_lower("l")
+ && !name.substr(1).getAsInteger(10, intVal)
+ && intVal < 8) {
+ RegNo = IntRegs[16 + intVal];
+ return true;
+ }
+ if (name.substr(0, 1).equals_lower("i")
+ && !name.substr(1).getAsInteger(10, intVal)
+ && intVal < 8) {
+ RegNo = IntRegs[24 + intVal];
+ return true;
+ }
+ // %f0 - %f31
+ if (name.substr(0, 1).equals_lower("f")
+ && !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 32) {
+ if (isDFP && (intVal%2 == 0)) {
+ RegNo = DoubleRegs[intVal/2];
+ } else if (isQFP && (intVal%4 == 0)) {
+ RegNo = QuadFPRegs[intVal/4];
+ } else {
+ RegNo = FloatRegs[intVal];
+ }
+ return true;
+ }
+ // %f32 - %f62
+ if (name.substr(0, 1).equals_lower("f")
+ && !name.substr(1, 2).getAsInteger(10, intVal)
+ && intVal >= 32 && intVal <= 62 && (intVal % 2 == 0)) {
+ if (isDFP) {
+ RegNo = DoubleRegs[16 + intVal/2];
+ } else if (isQFP && (intVal % 4 == 0)) {
+ RegNo = QuadFPRegs[8 + intVal/4];
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ // %r0 - %r31
+ if (name.substr(0, 1).equals_lower("r")
+ && !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 31) {
+ RegNo = IntRegs[intVal];
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+extern "C" void LLVMInitializeSparcAsmParser() {
+ RegisterMCAsmParser<SparcAsmParser> A(TheSparcTarget);
+ RegisterMCAsmParser<SparcAsmParser> B(TheSparcV9Target);
+}
+
+#define GET_REGISTER_MATCHER
+#define GET_MATCHER_IMPLEMENTATION
+#include "SparcGenAsmMatcher.inc"
Index: lib/Target/Sparc/AsmParser/LLVMBuild.txt
===================================================================
--- lib/Target/Sparc/AsmParser/LLVMBuild.txt
+++ lib/Target/Sparc/AsmParser/LLVMBuild.txt
@@ -0,0 +1,23 @@
+;===- ./lib/Target/Sparc/AsmParser/LLVMBuild.txt ---------------*- Conf -*--===;
+;
+; The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+; http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Library
+name = SparcAsmParser
+parent = Sparc
+required_libraries = MC MCParser Support SparcDesc SparcInfo
+add_to_library_groups = Sparc
Index: lib/Target/Sparc/AsmParser/CMakeLists.txt
===================================================================
--- lib/Target/Sparc/AsmParser/CMakeLists.txt
+++ lib/Target/Sparc/AsmParser/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_llvm_library(LLVMSparcAsmParser
+ SparcAsmParser.cpp
+ )
Index: lib/Target/Sparc/AsmParser/Makefile
===================================================================
--- lib/Target/Sparc/AsmParser/Makefile
+++ lib/Target/Sparc/AsmParser/Makefile
@@ -0,0 +1,15 @@
+##===- lib/Target/Sparc/AsmParser/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 = LLVMSparcAsmParser
+
+# Hack: we need to include 'main' Sparc target directory to grab private headers
+CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
+
+include $(LEVEL)/Makefile.common
Index: lib/Target/Sparc/SparcInstr64Bit.td
===================================================================
--- lib/Target/Sparc/SparcInstr64Bit.td
+++ lib/Target/Sparc/SparcInstr64Bit.td
@@ -176,11 +176,11 @@ def : Pat<(SPcmpicc i64:$a, (i64 simm13:$b)), (CMP
def : Pat<(ctpop i64:$src), (POPCrr $src)>;
// "LEA" form of add
+let isCodeGenOnly = 1 in
def LEAX_ADDri : F3_2<2, 0b000000,
(outs I64Regs:$dst), (ins MEMri:$addr),
"add ${addr:arith}, $dst",
[(set iPTR:$dst, ADDRri:$addr)]>;
-
} // Predicates = [Is64Bit]

View File

@ -0,0 +1,516 @@
Pull in r198533 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Add initial implementation of MC Code emitter for sparc.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcInstrInfo.td
===================================================================
--- lib/Target/Sparc/SparcInstrInfo.td
+++ lib/Target/Sparc/SparcInstrInfo.td
@@ -100,9 +100,14 @@ def MEMri : Operand<iPTR> {
def TLSSym : Operand<iPTR>;
// Branch targets have OtherVT type.
-def brtarget : Operand<OtherVT>;
-def calltarget : Operand<i32>;
+def brtarget : Operand<OtherVT> {
+ let EncoderMethod = "getBranchTargetOpValue";
+}
+def calltarget : Operand<i32> {
+ let EncoderMethod = "getCallTargetOpValue";
+}
+
// Operand for printing out a condition code.
let PrintMethod = "printCCOperand" in
def CCOp : Operand<i32>;
Index: lib/Target/Sparc/MCTargetDesc/CMakeLists.txt
===================================================================
--- lib/Target/Sparc/MCTargetDesc/CMakeLists.txt
+++ lib/Target/Sparc/MCTargetDesc/CMakeLists.txt
@@ -1,6 +1,8 @@
add_llvm_library(LLVMSparcDesc
+ SparcAsmBackend.cpp
+ SparcMCAsmInfo.cpp
+ SparcMCCodeEmitter.cpp
SparcMCTargetDesc.cpp
- SparcMCAsmInfo.cpp
SparcMCExpr.cpp
SparcTargetStreamer.cpp
)
Index: lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
@@ -0,0 +1,131 @@
+//===-- SparcMCCodeEmitter.cpp - Convert Sparc code to machine code -------===//
+//
+// 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 SparcMCCodeEmitter class.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "mccodeemitter"
+#include "SparcMCTargetDesc.h"
+#include "MCTargetDesc/SparcFixupKinds.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+STATISTIC(MCNumEmitted, "Number of MC instructions emitted");
+
+namespace {
+class SparcMCCodeEmitter : public MCCodeEmitter {
+ SparcMCCodeEmitter(const SparcMCCodeEmitter &) LLVM_DELETED_FUNCTION;
+ void operator=(const SparcMCCodeEmitter &) LLVM_DELETED_FUNCTION;
+ MCContext &Ctx;
+
+public:
+ SparcMCCodeEmitter(MCContext &ctx): Ctx(ctx) {}
+
+ ~SparcMCCodeEmitter() {}
+
+ void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups) const;
+
+ // getBinaryCodeForInstr - TableGen'erated function for getting the
+ // binary encoding for an instruction.
+ uint64_t getBinaryCodeForInstr(const MCInst &MI,
+ SmallVectorImpl<MCFixup> &Fixups) const;
+
+ /// getMachineOpValue - Return binary encoding of operand. If the machine
+ /// operand requires relocation, record the relocation and return zero.
+ unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,
+ SmallVectorImpl<MCFixup> &Fixups) const;
+
+ unsigned getCallTargetOpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups) const;
+ unsigned getBranchTargetOpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups) const;
+
+};
+} // end anonymous namespace
+
+MCCodeEmitter *llvm::createSparcMCCodeEmitter(const MCInstrInfo &MCII,
+ const MCRegisterInfo &MRI,
+ const MCSubtargetInfo &STI,
+ MCContext &Ctx) {
+ return new SparcMCCodeEmitter(Ctx);
+}
+
+void SparcMCCodeEmitter::
+EncodeInstruction(const MCInst &MI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups) const {
+ unsigned Bits = getBinaryCodeForInstr(MI, Fixups);
+
+ // Output the constant in big endian byte order.
+ for (unsigned i = 0; i != 4; ++i) {
+ OS << (char)(Bits >> 24);
+ Bits <<= 8;
+ }
+
+ ++MCNumEmitted; // Keep track of the # of mi's emitted.
+}
+
+
+unsigned SparcMCCodeEmitter::
+getMachineOpValue(const MCInst &MI, const MCOperand &MO,
+ SmallVectorImpl<MCFixup> &Fixups) const {
+
+ if (MO.isReg())
+ return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());
+
+ if (MO.isImm())
+ return MO.getImm();
+
+ assert(MO.isExpr());
+ const MCExpr *Expr = MO.getExpr();
+ int64_t Res;
+ if (Expr->EvaluateAsAbsolute(Res))
+ return Res;
+
+ assert(0 && "Unhandled expression!");
+ return 0;
+}
+
+unsigned SparcMCCodeEmitter::
+getCallTargetOpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
+ if (MO.isReg() || MO.isImm())
+ return getMachineOpValue(MI, MO, Fixups);
+
+ Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
+ (MCFixupKind)Sparc::fixup_sparc_call30));
+ return 0;
+}
+
+unsigned SparcMCCodeEmitter::
+getBranchTargetOpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
+ if (MO.isReg() || MO.isImm())
+ return getMachineOpValue(MI, MO, Fixups);
+
+ Sparc::Fixups fixup = Sparc::fixup_sparc_br22;
+ if (MI.getOpcode() == SP::BPXCC)
+ fixup = Sparc::fixup_sparc_br19;
+
+ Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
+ (MCFixupKind)fixup));
+ return 0;
+}
+
+#include "SparcGenMCCodeEmitter.inc"
Index: lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
@@ -136,6 +136,18 @@ extern "C" void LLVMInitializeSparcTargetMC() {
TargetRegistry::RegisterMCSubtargetInfo(TheSparcV9Target,
createSparcMCSubtargetInfo);
+ // Register the MC Code Emitter.
+ TargetRegistry::RegisterMCCodeEmitter(TheSparcTarget,
+ createSparcMCCodeEmitter);
+ TargetRegistry::RegisterMCCodeEmitter(TheSparcV9Target,
+ createSparcMCCodeEmitter);
+
+ //Register the asm backend.
+ TargetRegistry::RegisterMCAsmBackend(TheSparcTarget,
+ createSparcAsmBackend);
+ TargetRegistry::RegisterMCAsmBackend(TheSparcV9Target,
+ createSparcAsmBackend);
+
TargetRegistry::RegisterAsmStreamer(TheSparcTarget,
createMCAsmStreamer);
TargetRegistry::RegisterAsmStreamer(TheSparcV9Target,
Index: lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
@@ -0,0 +1,101 @@
+//===-- SparcAsmBackend.cpp - Sparc Assembler Backend ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCAsmBackend.h"
+#include "MCTargetDesc/SparcMCTargetDesc.h"
+#include "MCTargetDesc/SparcFixupKinds.h"
+#include "llvm/MC/MCFixupKindInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+namespace {
+ class SparcAsmBackend : public MCAsmBackend {
+
+ public:
+ SparcAsmBackend(const Target &T) : MCAsmBackend() {}
+
+ unsigned getNumFixupKinds() const {
+ return Sparc::NumTargetFixupKinds;
+ }
+
+ const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const {
+ const static MCFixupKindInfo Infos[Sparc::NumTargetFixupKinds] = {
+ // name offset bits flags
+ { "fixup_sparc_call30", 0, 30, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_br22", 0, 22, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_br19", 0, 19, MCFixupKindInfo::FKF_IsPCRel }
+ };
+
+ if (Kind < FirstTargetFixupKind)
+ return MCAsmBackend::getFixupKindInfo(Kind);
+
+ assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
+ "Invalid kind!");
+ return Infos[Kind - FirstTargetFixupKind];
+ }
+
+ bool mayNeedRelaxation(const MCInst &Inst) const {
+ // FIXME.
+ return false;
+ }
+
+ /// fixupNeedsRelaxation - Target specific predicate for whether a given
+ /// fixup requires the associated instruction to be relaxed.
+ bool fixupNeedsRelaxation(const MCFixup &Fixup,
+ uint64_t Value,
+ const MCRelaxableFragment *DF,
+ const MCAsmLayout &Layout) const {
+ // FIXME.
+ assert(0 && "fixupNeedsRelaxation() unimplemented");
+ return false;
+ }
+ void relaxInstruction(const MCInst &Inst, MCInst &Res) const {
+ // FIXME.
+ assert(0 && "relaxInstruction() unimplemented");
+ }
+
+ bool writeNopData(uint64_t Count, MCObjectWriter *OW) const {
+ // FIXME: Zero fill for now.
+ for (uint64_t i = 0; i != Count; ++i)
+ OW->Write8(0);
+ return true;
+ }
+ };
+
+ class ELFSparcAsmBackend : public SparcAsmBackend {
+ public:
+ ELFSparcAsmBackend(const Target &T, Triple::OSType OSType) :
+ SparcAsmBackend(T) { }
+
+ void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
+ uint64_t Value) const {
+ assert(0 && "applyFixup not implemented yet");
+ }
+
+ MCObjectWriter *createObjectWriter(raw_ostream &OS) const {
+ assert(0 && "Object Writer not implemented yet");
+ return 0;
+ }
+
+ virtual bool doesSectionRequireSymbols(const MCSection &Section) const {
+ return false;
+ }
+ };
+
+} // end anonymous namespace
+
+
+MCAsmBackend *llvm::createSparcAsmBackend(const Target &T,
+ const MCRegisterInfo &MRI,
+ StringRef TT,
+ StringRef CPU) {
+ return new ELFSparcAsmBackend(T, Triple(TT).getOS());
+}
Index: lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
+++ lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
@@ -0,0 +1,36 @@
+//===-- SparcFixupKinds.h - Sparc Specific Fixup Entries --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SPARC_FIXUPKINDS_H
+#define LLVM_SPARC_FIXUPKINDS_H
+
+#include "llvm/MC/MCFixup.h"
+
+namespace llvm {
+ namespace Sparc {
+ enum Fixups {
+ // fixup_sparc_call30 - 30-bit PC relative relocation for call
+ fixup_sparc_call30 = FirstTargetFixupKind,
+
+ /// fixup_sparc_br22 - 22-bit PC relative relocation for
+ /// branches
+ fixup_sparc_br22,
+
+ /// fixup_sparc_br22 - 22-bit PC relative relocation for
+ /// branches on icc/xcc
+ fixup_sparc_br19,
+
+ // Marker
+ LastTargetFixupKind,
+ NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
+ };
+ }
+}
+
+#endif
Index: lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h
+++ lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h
@@ -15,11 +15,27 @@
#define SPARCMCTARGETDESC_H
namespace llvm {
+class MCAsmBackend;
+class MCCodeEmitter;
+class MCContext;
+class MCInstrInfo;
+class MCRegisterInfo;
+class MCSubtargetInfo;
class Target;
+class StringRef;
extern Target TheSparcTarget;
extern Target TheSparcV9Target;
+MCCodeEmitter *createSparcMCCodeEmitter(const MCInstrInfo &MCII,
+ const MCRegisterInfo &MRI,
+ const MCSubtargetInfo &STI,
+ MCContext &Ctx);
+MCAsmBackend *createSparcAsmBackend(const Target &T,
+ const MCRegisterInfo &MRI,
+ StringRef TT,
+ StringRef CPU);
+
} // End llvm namespace
// Defines symbolic names for Sparc registers. This defines a mapping from
Index: lib/Target/Sparc/Makefile
===================================================================
--- lib/Target/Sparc/Makefile
+++ lib/Target/Sparc/Makefile
@@ -16,7 +16,7 @@ BUILT_SOURCES = SparcGenRegisterInfo.inc SparcGenI
SparcGenAsmWriter.inc SparcGenAsmMatcher.inc \
SparcGenDAGISel.inc \
SparcGenSubtargetInfo.inc SparcGenCallingConv.inc \
- SparcGenCodeEmitter.inc
+ SparcGenCodeEmitter.inc SparcGenMCCodeEmitter.inc
DIRS = InstPrinter AsmParser TargetInfo MCTargetDesc
Index: lib/Target/Sparc/CMakeLists.txt
===================================================================
--- lib/Target/Sparc/CMakeLists.txt
+++ lib/Target/Sparc/CMakeLists.txt
@@ -3,6 +3,7 @@ set(LLVM_TARGET_DEFINITIONS Sparc.td)
tablegen(LLVM SparcGenRegisterInfo.inc -gen-register-info)
tablegen(LLVM SparcGenInstrInfo.inc -gen-instr-info)
tablegen(LLVM SparcGenCodeEmitter.inc -gen-emitter)
+tablegen(LLVM SparcGenMCCodeEmitter.inc -gen-emitter -mc-emitter)
tablegen(LLVM SparcGenAsmWriter.inc -gen-asm-writer)
tablegen(LLVM SparcGenAsmMatcher.inc -gen-asm-matcher)
tablegen(LLVM SparcGenDAGISel.inc -gen-dag-isel)
Index: lib/Target/Sparc/SparcCodeEmitter.cpp
===================================================================
--- lib/Target/Sparc/SparcCodeEmitter.cpp
+++ lib/Target/Sparc/SparcCodeEmitter.cpp
@@ -72,6 +72,11 @@ class SparcCodeEmitter : public MachineFunctionPas
unsigned getMachineOpValue(const MachineInstr &MI,
const MachineOperand &MO) const;
+ unsigned getCallTargetOpValue(const MachineInstr &MI,
+ unsigned) const;
+ unsigned getBranchTargetOpValue(const MachineInstr &MI,
+ unsigned) const;
+
void emitWord(unsigned Word);
unsigned getRelocation(const MachineInstr &MI,
@@ -181,6 +186,18 @@ unsigned SparcCodeEmitter::getMachineOpValue(const
llvm_unreachable("Unable to encode MachineOperand!");
return 0;
}
+unsigned SparcCodeEmitter::getCallTargetOpValue(const MachineInstr &MI,
+ unsigned opIdx) const {
+ const MachineOperand MO = MI.getOperand(opIdx);
+ return getMachineOpValue(MI, MO);
+}
+
+unsigned SparcCodeEmitter::getBranchTargetOpValue(const MachineInstr &MI,
+ unsigned opIdx) const {
+ const MachineOperand MO = MI.getOperand(opIdx);
+ return getMachineOpValue(MI, MO);
+}
+
unsigned SparcCodeEmitter::getRelocation(const MachineInstr &MI,
const MachineOperand &MO) const {
Index: test/MC/Sparc/sparc-alu-instructions.s
===================================================================
--- test/MC/Sparc/sparc-alu-instructions.s
+++ test/MC/Sparc/sparc-alu-instructions.s
@@ -0,0 +1,72 @@
+! RUN: llvm-mc %s -arch=sparc -show-encoding | FileCheck %s
+! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s
+
+ ! CHECK: add %g0, %g0, %g0 ! encoding: [0x80,0x00,0x00,0x00]
+ add %g0, %g0, %g0
+ ! CHECK: add %g1, %g2, %g3 ! encoding: [0x86,0x00,0x40,0x02]
+ add %g1, %g2, %g3
+ ! CHECK: add %o0, %o1, %l0 ! encoding: [0xa0,0x02,0x00,0x09]
+ add %r8, %r9, %l0
+ ! CHECK: add %o0, 10, %l0 ! encoding: [0xa0,0x02,0x20,0x0a]
+ add %o0, 10, %l0
+
+ ! CHECK: addcc %g1, %g2, %g3 ! encoding: [0x86,0x80,0x40,0x02]
+ addcc %g1, %g2, %g3
+
+ ! CHECK: addxcc %g1, %g2, %g3 ! encoding: [0x86,0xc0,0x40,0x02]
+ addxcc %g1, %g2, %g3
+
+ ! CHECK: udiv %g1, %g2, %g3 ! encoding: [0x86,0x70,0x40,0x02]
+ udiv %g1, %g2, %g3
+
+ ! CHECK: sdiv %g1, %g2, %g3 ! encoding: [0x86,0x78,0x40,0x02]
+ sdiv %g1, %g2, %g3
+
+ ! CHECK: and %g1, %g2, %g3 ! encoding: [0x86,0x08,0x40,0x02]
+ and %g1, %g2, %g3
+ ! CHECK: andn %g1, %g2, %g3 ! encoding: [0x86,0x28,0x40,0x02]
+ andn %g1, %g2, %g3
+ ! CHECK: or %g1, %g2, %g3 ! encoding: [0x86,0x10,0x40,0x02]
+ or %g1, %g2, %g3
+ ! CHECK: orn %g1, %g2, %g3 ! encoding: [0x86,0x30,0x40,0x02]
+ orn %g1, %g2, %g3
+ ! CHECK: xor %g1, %g2, %g3 ! encoding: [0x86,0x18,0x40,0x02]
+ xor %g1, %g2, %g3
+ ! CHECK: xnor %g1, %g2, %g3 ! encoding: [0x86,0x38,0x40,0x02]
+ xnor %g1, %g2, %g3
+
+ ! CHECK: umul %g1, %g2, %g3 ! encoding: [0x86,0x50,0x40,0x02]
+ umul %g1, %g2, %g3
+
+ ! CHECK: smul %g1, %g2, %g3 ! encoding: [0x86,0x58,0x40,0x02]
+ smul %g1, %g2, %g3
+
+ ! CHECK: nop ! encoding: [0x01,0x00,0x00,0x00]
+ nop
+
+ ! CHECK: sethi 10, %l0 ! encoding: [0x21,0x00,0x00,0x0a]
+ sethi 10, %l0
+
+ ! CHECK: sll %g1, %g2, %g3 ! encoding: [0x87,0x28,0x40,0x02]
+ sll %g1, %g2, %g3
+ ! CHECK: sll %g1, 31, %g3 ! encoding: [0x87,0x28,0x60,0x1f]
+ sll %g1, 31, %g3
+
+ ! CHECK: srl %g1, %g2, %g3 ! encoding: [0x87,0x30,0x40,0x02]
+ srl %g1, %g2, %g3
+ ! CHECK: srl %g1, 31, %g3 ! encoding: [0x87,0x30,0x60,0x1f]
+ srl %g1, 31, %g3
+
+ ! CHECK: sra %g1, %g2, %g3 ! encoding: [0x87,0x38,0x40,0x02]
+ sra %g1, %g2, %g3
+ ! CHECK: sra %g1, 31, %g3 ! encoding: [0x87,0x38,0x60,0x1f]
+ sra %g1, 31, %g3
+
+ ! CHECK: sub %g1, %g2, %g3 ! encoding: [0x86,0x20,0x40,0x02]
+ sub %g1, %g2, %g3
+ ! CHECK: subcc %g1, %g2, %g3 ! encoding: [0x86,0xa0,0x40,0x02]
+ subcc %g1, %g2, %g3
+
+ ! CHECK: subxcc %g1, %g2, %g3 ! encoding: [0x86,0xe0,0x40,0x02]
+ subxcc %g1, %g2, %g3
+

View File

@ -0,0 +1,76 @@
Pull in r198565 from upstream llvm trunk (by Venkatraman Govindaraju):
ELF relocation types for sparc.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: include/llvm/Support/ELF.h
===================================================================
--- include/llvm/Support/ELF.h
+++ include/llvm/Support/ELF.h
@@ -1087,6 +1087,65 @@ enum {
R_390_IRELATIVE = 61
};
+// ELF Relocation type for Sparc.
+enum {
+ R_SPARC_NONE = 0,
+ R_SPARC_8 = 1,
+ R_SPARC_16 = 2,
+ R_SPARC_32 = 3,
+ R_SPARC_DISP8 = 4,
+ R_SPARC_DISP16 = 5,
+ R_SPARC_DISP32 = 6,
+ R_SPARC_WDISP30 = 7,
+ R_SPARC_WDISP22 = 8,
+ R_SPARC_HI22 = 9,
+ R_SPARC_22 = 10,
+ R_SPARC_13 = 11,
+ R_SPARC_LO10 = 12,
+ R_SPARC_GOT10 = 13,
+ R_SPARC_GOT13 = 14,
+ R_SPARC_GOT22 = 15,
+ R_SPARC_PC10 = 16,
+ R_SPARC_PC22 = 17,
+ R_SPARC_WPLT30 = 18,
+ R_SPARC_COPY = 19,
+ R_SPARC_GLOB_DAT = 20,
+ R_SPARC_JMP_SLOT = 21,
+ R_SPARC_RELATIVE = 22,
+ R_SPARC_UA32 = 23,
+ R_SPARC_PLT32 = 24,
+ R_SPARC_HIPLT22 = 25,
+ R_SPARC_LOPLT10 = 26,
+ R_SPARC_PCPLT32 = 27,
+ R_SPARC_PCPLT22 = 28,
+ R_SPARC_PCPLT10 = 29,
+ R_SPARC_10 = 30,
+ R_SPARC_11 = 31,
+ R_SPARC_64 = 32,
+ R_SPARC_OLO10 = 33,
+ R_SPARC_HH22 = 34,
+ R_SPARC_HM10 = 35,
+ R_SPARC_LM22 = 36,
+ R_SPARC_PC_HH22 = 37,
+ R_SPARC_PC_HM10 = 38,
+ R_SPARC_PC_LM22 = 39,
+ R_SPARC_WDISP16 = 40,
+ R_SPARC_WDISP19 = 41,
+ R_SPARC_7 = 43,
+ R_SPARC_5 = 44,
+ R_SPARC_6 = 45,
+ R_SPARC_DISP64 = 46,
+ R_SPARC_PLT64 = 47,
+ R_SPARC_HIX22 = 48,
+ R_SPARC_LOX10 = 49,
+ R_SPARC_H44 = 50,
+ R_SPARC_M44 = 51,
+ R_SPARC_L44 = 52,
+ R_SPARC_REGISTER = 53,
+ R_SPARC_UA64 = 54,
+ R_SPARC_UA16 = 55
+};
+
// Section header.
struct Elf32_Shdr {
Elf32_Word sh_name; // Section name (index into string table)

View File

@ -0,0 +1,21 @@
Pull in r198567 from upstream llvm trunk (by Benjamin Kramer):
SPARC: Make helper function static.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcAsmPrinter.cpp
===================================================================
--- lib/Target/Sparc/SparcAsmPrinter.cpp
+++ lib/Target/Sparc/SparcAsmPrinter.cpp
@@ -130,8 +130,8 @@ static void EmitOR(MCStreamer &OutStreamer, MCOper
OutStreamer.EmitInstruction(ORInst);
}
-void EmitADD(MCStreamer &OutStreamer,
- MCOperand &RS1, MCOperand &RS2, MCOperand &RD)
+static void EmitADD(MCStreamer &OutStreamer,
+ MCOperand &RS1, MCOperand &RS2, MCOperand &RD)
{
MCInst ADDInst;
ADDInst.setOpcode(SP::ADDrr);

View File

@ -0,0 +1,460 @@
Pull in r198580 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Add ELF Object Writer for Sparc.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "mccodeemitter"
+#include "SparcMCExpr.h"
#include "SparcMCTargetDesc.h"
#include "MCTargetDesc/SparcFixupKinds.h"
#include "llvm/MC/MCCodeEmitter.h"
@@ -92,6 +93,41 @@ getMachineOpValue(const MCInst &MI, const MCOperan
assert(MO.isExpr());
const MCExpr *Expr = MO.getExpr();
+ if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(Expr)) {
+ switch(SExpr->getKind()) {
+ default: assert(0 && "Unhandled sparc expression!"); break;
+ case SparcMCExpr::VK_Sparc_LO:
+ Fixups.push_back(MCFixup::Create(0, Expr,
+ (MCFixupKind)Sparc::fixup_sparc_lo10));
+ break;
+ case SparcMCExpr::VK_Sparc_HI:
+ Fixups.push_back(MCFixup::Create(0, Expr,
+ (MCFixupKind)Sparc::fixup_sparc_hi22));
+ break;
+ case SparcMCExpr::VK_Sparc_H44:
+ Fixups.push_back(MCFixup::Create(0, Expr,
+ (MCFixupKind)Sparc::fixup_sparc_h44));
+ break;
+ case SparcMCExpr::VK_Sparc_M44:
+ Fixups.push_back(MCFixup::Create(0, Expr,
+ (MCFixupKind)Sparc::fixup_sparc_m44));
+ break;
+ case SparcMCExpr::VK_Sparc_L44:
+ Fixups.push_back(MCFixup::Create(0, Expr,
+ (MCFixupKind)Sparc::fixup_sparc_l44));
+ break;
+ case SparcMCExpr::VK_Sparc_HH:
+ Fixups.push_back(MCFixup::Create(0, Expr,
+ (MCFixupKind)Sparc::fixup_sparc_hh));
+ break;
+ case SparcMCExpr::VK_Sparc_HM:
+ Fixups.push_back(MCFixup::Create(0, Expr,
+ (MCFixupKind)Sparc::fixup_sparc_hm));
+ break;
+ }
+ return 0;
+ }
+
int64_t Res;
if (Expr->EvaluateAsAbsolute(Res))
return Res;
Index: lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
@@ -89,6 +89,14 @@ static MCCodeGenInfo *createSparcV9MCCodeGenInfo(S
return X;
}
+static MCStreamer *createMCStreamer(const Target &T, StringRef TT,
+ MCContext &Context, MCAsmBackend &MAB,
+ raw_ostream &OS, MCCodeEmitter *Emitter,
+ bool RelaxAll, bool NoExecStack) {
+ SparcTargetELFStreamer *S = new SparcTargetELFStreamer();
+ return createELFStreamer(Context, S, MAB, OS, Emitter, RelaxAll, NoExecStack);
+}
+
static MCStreamer *
createMCAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS,
bool isVerboseAsm, bool useLoc, bool useCFI,
@@ -148,6 +156,13 @@ extern "C" void LLVMInitializeSparcTargetMC() {
TargetRegistry::RegisterMCAsmBackend(TheSparcV9Target,
createSparcAsmBackend);
+ // Register the object streamer.
+ TargetRegistry::RegisterMCObjectStreamer(TheSparcTarget,
+ createMCStreamer);
+ TargetRegistry::RegisterMCObjectStreamer(TheSparcV9Target,
+ createMCStreamer);
+
+ // Register the asm streamer.
TargetRegistry::RegisterAsmStreamer(TheSparcTarget,
createMCAsmStreamer);
TargetRegistry::RegisterAsmStreamer(TheSparcV9Target,
Index: lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
@@ -10,6 +10,7 @@
#include "llvm/MC/MCAsmBackend.h"
#include "MCTargetDesc/SparcMCTargetDesc.h"
#include "MCTargetDesc/SparcFixupKinds.h"
+#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCFixupKindInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/Support/TargetRegistry.h"
@@ -16,11 +17,43 @@
using namespace llvm;
+static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
+ switch (Kind) {
+ default:
+ llvm_unreachable("Unknown fixup kind!");
+ case FK_Data_1:
+ case FK_Data_2:
+ case FK_Data_4:
+ case FK_Data_8:
+ return Value;
+ case Sparc::fixup_sparc_call30:
+ return Value & 0x3fffffff;
+ case Sparc::fixup_sparc_br22:
+ return Value & 0x3fffff;
+ case Sparc::fixup_sparc_br19:
+ return Value & 0x1ffff;
+ case Sparc::fixup_sparc_hi22:
+ return (Value >> 10) & 0x3fffff;
+ case Sparc::fixup_sparc_lo10:
+ return Value & 0x3ff;
+ case Sparc::fixup_sparc_h44:
+ return (Value >> 22) & 0x3fffff;
+ case Sparc::fixup_sparc_m44:
+ return (Value >> 12) & 0x3ff;
+ case Sparc::fixup_sparc_l44:
+ return Value & 0xfff;
+ case Sparc::fixup_sparc_hh:
+ return (Value >> 42) & 0x3fffff;
+ case Sparc::fixup_sparc_hm:
+ return (Value >>32) & 0x3ff;
+ }
+}
+
namespace {
class SparcAsmBackend : public MCAsmBackend {
-
+ const Target &TheTarget;
public:
- SparcAsmBackend(const Target &T) : MCAsmBackend() {}
+ SparcAsmBackend(const Target &T) : MCAsmBackend(), TheTarget(T) {}
unsigned getNumFixupKinds() const {
return Sparc::NumTargetFixupKinds;
@@ -31,7 +64,14 @@ namespace {
// name offset bits flags
{ "fixup_sparc_call30", 0, 30, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_br22", 0, 22, MCFixupKindInfo::FKF_IsPCRel },
- { "fixup_sparc_br19", 0, 19, MCFixupKindInfo::FKF_IsPCRel }
+ { "fixup_sparc_br19", 0, 19, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_hi22", 0, 22, 0 },
+ { "fixup_sparc_lo10", 0, 10, 0 },
+ { "fixup_sparc_h44", 0, 22, 0 },
+ { "fixup_sparc_m44", 0, 10, 0 },
+ { "fixup_sparc_l44", 0, 12, 0 },
+ { "fixup_sparc_hh", 0, 21, 0 },
+ { "fixup_sparc_hm", 0, 10, 0 },
};
if (Kind < FirstTargetFixupKind)
@@ -68,21 +108,38 @@ namespace {
OW->Write8(0);
return true;
}
+
+ bool is64Bit() const {
+ StringRef name = TheTarget.getName();
+ return name == "sparcv9";
+ }
};
class ELFSparcAsmBackend : public SparcAsmBackend {
+ Triple::OSType OSType;
public:
ELFSparcAsmBackend(const Target &T, Triple::OSType OSType) :
- SparcAsmBackend(T) { }
+ SparcAsmBackend(T), OSType(OSType) { }
void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
uint64_t Value) const {
- assert(0 && "applyFixup not implemented yet");
+
+ Value = adjustFixupValue(Fixup.getKind(), Value);
+ if (!Value) return; // Doesn't change encoding.
+
+ unsigned Offset = Fixup.getOffset();
+
+ // For each byte of the fragment that the fixup touches, mask in the bits
+ // from the fixup value. The Value has been "split up" into the
+ // appropriate bitfields above.
+ for (unsigned i = 0; i != 4; ++i)
+ Data[Offset + i] |= uint8_t((Value >> ((4 - i - 1)*8)) & 0xff);
+
}
MCObjectWriter *createObjectWriter(raw_ostream &OS) const {
- assert(0 && "Object Writer not implemented yet");
- return 0;
+ uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(OSType);
+ return createSparcELFObjectWriter(OS, is64Bit(), OSABI);
}
virtual bool doesSectionRequireSymbols(const MCSection &Section) const {
Index: lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
+++ lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
@@ -22,10 +22,32 @@ namespace llvm {
/// branches
fixup_sparc_br22,
- /// fixup_sparc_br22 - 22-bit PC relative relocation for
+ /// fixup_sparc_br19 - 19-bit PC relative relocation for
/// branches on icc/xcc
fixup_sparc_br19,
+ /// fixup_sparc_hi22 - 22-bit fixup corresponding to %hi(foo)
+ /// for sethi
+ fixup_sparc_hi22,
+
+ /// fixup_sparc_lo10 - 10-bit fixup corresponding to %lo(foo)
+ fixup_sparc_lo10,
+
+ /// fixup_sparc_h44 - 22-bit fixup corresponding to %h44(foo)
+ fixup_sparc_h44,
+
+ /// fixup_sparc_m44 - 10-bit fixup corresponding to %m44(foo)
+ fixup_sparc_m44,
+
+ /// fixup_sparc_l44 - 12-bit fixup corresponding to %l44(foo)
+ fixup_sparc_l44,
+
+ /// fixup_sparc_hh - 22-bit fixup corresponding to %hh(foo)
+ fixup_sparc_hh,
+
+ /// fixup_sparc_hm - 10-bit fixup corresponding to %hm(foo)
+ fixup_sparc_hm,
+
// Marker
LastTargetFixupKind,
NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
Index: lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
@@ -0,0 +1,86 @@
+//===-- SparcELFObjectWriter.cpp - Sparc ELF Writer -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/SparcMCTargetDesc.h"
+#include "MCTargetDesc/SparcFixupKinds.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/MC/MCELFObjectWriter.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+
+namespace {
+ class SparcELFObjectWriter : public MCELFObjectTargetWriter {
+ public:
+ SparcELFObjectWriter(bool Is64Bit, uint8_t OSABI)
+ : MCELFObjectTargetWriter(Is64Bit, OSABI,
+ Is64Bit ? ELF::EM_SPARCV9 : ELF::EM_SPARC,
+ /*HasRelocationAddend*/ true) {}
+
+ virtual ~SparcELFObjectWriter() {}
+ protected:
+ virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
+ bool IsPCRel, bool IsRelocWithSymbol,
+ int64_t Addend) const;
+
+ };
+}
+
+
+unsigned SparcELFObjectWriter::GetRelocType(const MCValue &Target,
+ const MCFixup &Fixup,
+ bool IsPCRel,
+ bool IsRelocWithSymbol,
+ int64_t Addend) const {
+ if (IsPCRel) {
+ switch((unsigned)Fixup.getKind()) {
+ default:
+ llvm_unreachable("Unimplemented fixup -> relocation");
+ case FK_Data_1: return ELF::R_SPARC_DISP8;
+ case FK_Data_2: return ELF::R_SPARC_DISP16;
+ case FK_Data_4: return ELF::R_SPARC_DISP32;
+ case FK_Data_8: return ELF::R_SPARC_DISP64;
+ case Sparc::fixup_sparc_call30: return ELF::R_SPARC_WDISP30;
+ case Sparc::fixup_sparc_br22: return ELF::R_SPARC_WDISP22;
+ case Sparc::fixup_sparc_br19: return ELF::R_SPARC_WDISP19;
+ }
+ }
+
+ switch((unsigned)Fixup.getKind()) {
+ default:
+ llvm_unreachable("Unimplemented fixup -> relocation");
+ case FK_Data_1: return ELF::R_SPARC_8;
+ case FK_Data_2: return ((Fixup.getOffset() % 2)
+ ? ELF::R_SPARC_UA16
+ : ELF::R_SPARC_16);
+ case FK_Data_4: return ((Fixup.getOffset() % 4)
+ ? ELF::R_SPARC_UA32
+ : ELF::R_SPARC_32);
+ case FK_Data_8: return ((Fixup.getOffset() % 8)
+ ? ELF::R_SPARC_UA64
+ : ELF::R_SPARC_64);
+ case Sparc::fixup_sparc_hi22: return ELF::R_SPARC_HI22;
+ case Sparc::fixup_sparc_lo10: return ELF::R_SPARC_LO10;
+ case Sparc::fixup_sparc_h44: return ELF::R_SPARC_H44;
+ case Sparc::fixup_sparc_m44: return ELF::R_SPARC_M44;
+ case Sparc::fixup_sparc_l44: return ELF::R_SPARC_L44;
+ case Sparc::fixup_sparc_hh: return ELF::R_SPARC_HH22;
+ case Sparc::fixup_sparc_hm: return ELF::R_SPARC_HM10;
+ }
+ return ELF::R_SPARC_NONE;
+}
+
+MCObjectWriter *llvm::createSparcELFObjectWriter(raw_ostream &OS,
+ bool Is64Bit,
+ uint8_t OSABI) {
+ MCELFObjectTargetWriter *MOTW = new SparcELFObjectWriter(Is64Bit, OSABI);
+ return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/false);
+}
Index: lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h
+++ lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h
@@ -14,15 +14,19 @@
#ifndef SPARCMCTARGETDESC_H
#define SPARCMCTARGETDESC_H
+#include "llvm/Support/DataTypes.h"
+
namespace llvm {
class MCAsmBackend;
class MCCodeEmitter;
class MCContext;
class MCInstrInfo;
+class MCObjectWriter;
class MCRegisterInfo;
class MCSubtargetInfo;
class Target;
class StringRef;
+class raw_ostream;
extern Target TheSparcTarget;
extern Target TheSparcV9Target;
@@ -35,7 +39,9 @@ MCAsmBackend *createSparcAsmBackend(const Target &
const MCRegisterInfo &MRI,
StringRef TT,
StringRef CPU);
-
+MCObjectWriter *createSparcELFObjectWriter(raw_ostream &OS,
+ bool Is64Bit,
+ uint8_t OSABI);
} // End llvm namespace
// Defines symbolic names for Sparc registers. This defines a mapping from
Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
@@ -70,15 +70,67 @@ void SparcMCExpr::PrintImpl(raw_ostream &OS) const
bool
SparcMCExpr::EvaluateAsRelocatableImpl(MCValue &Res,
const MCAsmLayout *Layout) const {
- assert(0 && "FIXME: Implement SparcMCExpr::EvaluateAsRelocatableImpl");
return getSubExpr()->EvaluateAsRelocatable(Res, *Layout);
}
+static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) {
+ assert(0 && "Implement fixELFSymbolsInTLSFixupsImpl!");
+}
void SparcMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
- assert(0 && "FIXME: Implement SparcMCExpr::fixELFSymbolsInTLSFixups");
+ switch(getKind()) {
+ default: return;
+ case VK_Sparc_TLS_GD_HI22:
+ case VK_Sparc_TLS_GD_LO10:
+ case VK_Sparc_TLS_GD_ADD:
+ case VK_Sparc_TLS_GD_CALL:
+ case VK_Sparc_TLS_LDM_HI22:
+ case VK_Sparc_TLS_LDM_LO10:
+ case VK_Sparc_TLS_LDM_ADD:
+ case VK_Sparc_TLS_LDM_CALL:
+ case VK_Sparc_TLS_LDO_HIX22:
+ case VK_Sparc_TLS_LDO_LOX10:
+ case VK_Sparc_TLS_LDO_ADD:
+ case VK_Sparc_TLS_IE_HI22:
+ case VK_Sparc_TLS_IE_LO10:
+ case VK_Sparc_TLS_IE_LD:
+ case VK_Sparc_TLS_IE_LDX:
+ case VK_Sparc_TLS_IE_ADD:
+ case VK_Sparc_TLS_LE_HIX22:
+ case VK_Sparc_TLS_LE_LOX10: break;
+ }
+ fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm);
}
+// FIXME: This basically copies MCObjectStreamer::AddValueSymbols. Perhaps
+// that method should be made public?
+// FIXME: really do above: now that at least three other backends are using it.
+static void AddValueSymbolsImpl(const MCExpr *Value, MCAssembler *Asm) {
+ switch (Value->getKind()) {
+ case MCExpr::Target:
+ llvm_unreachable("Can't handle nested target expr!");
+ break;
+
+ case MCExpr::Constant:
+ break;
+
+ case MCExpr::Binary: {
+ const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value);
+ AddValueSymbolsImpl(BE->getLHS(), Asm);
+ AddValueSymbolsImpl(BE->getRHS(), Asm);
+ break;
+ }
+
+ case MCExpr::SymbolRef:
+ Asm->getOrCreateSymbolData(cast<MCSymbolRefExpr>(Value)->getSymbol());
+ break;
+
+ case MCExpr::Unary:
+ AddValueSymbolsImpl(cast<MCUnaryExpr>(Value)->getSubExpr(), Asm);
+ break;
+ }
+}
+
void SparcMCExpr::AddValueSymbols(MCAssembler *Asm) const {
- assert(0 && "FIXME: Implement SparcMCExpr::AddValueSymbols");
+ AddValueSymbolsImpl(getSubExpr(), Asm);
}
Index: lib/Target/Sparc/MCTargetDesc/CMakeLists.txt
===================================================================
--- lib/Target/Sparc/MCTargetDesc/CMakeLists.txt
+++ lib/Target/Sparc/MCTargetDesc/CMakeLists.txt
@@ -1,5 +1,6 @@
add_llvm_library(LLVMSparcDesc
SparcAsmBackend.cpp
+ SparcELFObjectWriter.cpp
SparcMCAsmInfo.cpp
SparcMCCodeEmitter.cpp
SparcMCTargetDesc.cpp

View File

@ -0,0 +1,762 @@
Pull in r198591 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Add initial implementation of disassembler for sparc
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcInstrFormats.td
===================================================================
--- lib/Target/Sparc/SparcInstrFormats.td
+++ lib/Target/Sparc/SparcInstrFormats.td
@@ -12,6 +12,7 @@ class InstSP<dag outs, dag ins, string asmstr, lis
field bits<32> Inst;
let Namespace = "SP";
+ let Size = 4;
bits<2> op;
let Inst{31-30} = op; // Top two bits are the 'op' field
@@ -20,6 +21,9 @@ class InstSP<dag outs, dag ins, string asmstr, lis
dag InOperandList = ins;
let AsmString = asmstr;
let Pattern = pattern;
+
+ let DecoderNamespace = "Sparc";
+ field bits<32> SoftFail = 0;
}
//===----------------------------------------------------------------------===//
@@ -58,6 +62,27 @@ class F2_2<bits<3> op2Val, dag outs, dag ins, stri
let Inst{28-25} = cond;
}
+class F2_3<bits<3> op2Val, bits<2> ccVal, dag outs, dag ins, string asmstr,
+ list<dag> pattern>
+ : InstSP<outs, ins, asmstr, pattern> {
+ bit annul;
+ bits<4> cond;
+ bit pred;
+ bits<19> imm19;
+
+ let op = 0; // op = 0
+
+ bit annul = 0; // currently unused
+ let pred = 1; // default is predict taken
+
+ let Inst{29} = annul;
+ let Inst{28-25} = cond;
+ let Inst{24-22} = op2Val;
+ let Inst{21-20} = ccVal;
+ let Inst{19} = pred;
+ let Inst{18-0} = imm19;
+}
+
//===----------------------------------------------------------------------===//
// Format #3 instruction classes in the Sparc
//===----------------------------------------------------------------------===//
Index: lib/Target/Sparc/LLVMBuild.txt
===================================================================
--- lib/Target/Sparc/LLVMBuild.txt
+++ lib/Target/Sparc/LLVMBuild.txt
@@ -16,13 +16,15 @@
;===------------------------------------------------------------------------===;
[common]
-subdirectories = AsmParser InstPrinter MCTargetDesc TargetInfo
+subdirectories = AsmParser Disassembler InstPrinter MCTargetDesc TargetInfo
[component_0]
type = TargetGroup
name = Sparc
parent = Target
+has_asmparser = 1
has_asmprinter = 1
+has_disassembler = 1
has_jit = 1
[component_1]
Index: lib/Target/Sparc/SparcInstrInfo.td
===================================================================
--- lib/Target/Sparc/SparcInstrInfo.td
+++ lib/Target/Sparc/SparcInstrInfo.td
@@ -230,13 +230,13 @@ def FCC_O : FCC_VAL<29>; // Ordered
multiclass F3_12<string OpcStr, bits<6> Op3Val, SDNode OpNode,
RegisterClass RC, ValueType Ty, Operand immOp> {
def rr : F3_1<2, Op3Val,
- (outs RC:$dst), (ins RC:$b, RC:$c),
- !strconcat(OpcStr, " $b, $c, $dst"),
- [(set Ty:$dst, (OpNode Ty:$b, Ty:$c))]>;
+ (outs RC:$rd), (ins RC:$rs1, RC:$rs2),
+ !strconcat(OpcStr, " $rs1, $rs2, $rd"),
+ [(set Ty:$rd, (OpNode Ty:$rs1, Ty:$rs2))]>;
def ri : F3_2<2, Op3Val,
- (outs RC:$dst), (ins RC:$b, immOp:$c),
- !strconcat(OpcStr, " $b, $c, $dst"),
- [(set Ty:$dst, (OpNode Ty:$b, (Ty simm13:$c)))]>;
+ (outs RC:$rd), (ins RC:$rs1, immOp:$simm13),
+ !strconcat(OpcStr, " $rs1, $simm13, $rd"),
+ [(set Ty:$rd, (OpNode Ty:$rs1, (Ty simm13:$simm13)))]>;
}
/// F3_12np multiclass - Define a normal F3_1/F3_2 pattern in one shot, with no
@@ -243,11 +243,11 @@ multiclass F3_12<string OpcStr, bits<6> Op3Val, SD
/// pattern.
multiclass F3_12np<string OpcStr, bits<6> Op3Val> {
def rr : F3_1<2, Op3Val,
- (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
- !strconcat(OpcStr, " $b, $c, $dst"), []>;
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2),
+ !strconcat(OpcStr, " $rs1, $rs2, $rd"), []>;
def ri : F3_2<2, Op3Val,
- (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c),
- !strconcat(OpcStr, " $b, $c, $dst"), []>;
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, i32imm:$simm13),
+ !strconcat(OpcStr, " $rs1, $simm13, $rd"), []>;
}
//===----------------------------------------------------------------------===//
@@ -488,31 +488,31 @@ let rd = 0, imm22 = 0 in
defm AND : F3_12<"and", 0b000001, and, IntRegs, i32, i32imm>;
def ANDNrr : F3_1<2, 0b000101,
- (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
- "andn $b, $c, $dst",
- [(set i32:$dst, (and i32:$b, (not i32:$c)))]>;
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2),
+ "andn $rs1, $rs2, $rd",
+ [(set i32:$rd, (and i32:$rs1, (not i32:$rs2)))]>;
def ANDNri : F3_2<2, 0b000101,
- (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c),
- "andn $b, $c, $dst", []>;
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, i32imm:$simm13),
+ "andn $rs1, $simm13, $rd", []>;
defm OR : F3_12<"or", 0b000010, or, IntRegs, i32, i32imm>;
def ORNrr : F3_1<2, 0b000110,
- (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
- "orn $b, $c, $dst",
- [(set i32:$dst, (or i32:$b, (not i32:$c)))]>;
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2),
+ "orn $rs1, $rs2, $rd",
+ [(set i32:$rd, (or i32:$rs1, (not i32:$rs2)))]>;
def ORNri : F3_2<2, 0b000110,
- (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c),
- "orn $b, $c, $dst", []>;
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, i32imm:$simm13),
+ "orn $rs1, $simm13, $rd", []>;
defm XOR : F3_12<"xor", 0b000011, xor, IntRegs, i32, i32imm>;
def XNORrr : F3_1<2, 0b000111,
- (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
- "xnor $b, $c, $dst",
- [(set i32:$dst, (not (xor i32:$b, i32:$c)))]>;
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2),
+ "xnor $rs1, $rs2, $rd",
+ [(set i32:$rd, (not (xor i32:$rs1, i32:$rs2)))]>;
def XNORri : F3_2<2, 0b000111,
- (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c),
- "xnor $b, $c, $dst", []>;
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, i32imm:$simm13),
+ "xnor $rs1, $simm13, $rd", []>;
// Section B.12 - Shift Instructions, p. 107
defm SLL : F3_12<"sll", 0b100101, shl, IntRegs, i32, i32imm>;
@@ -545,21 +545,15 @@ let Defs = [ICC] in
let Defs = [ICC], rd = 0 in {
def CMPrr : F3_1<2, 0b010100,
- (outs), (ins IntRegs:$b, IntRegs:$c),
- "cmp $b, $c",
- [(SPcmpicc i32:$b, i32:$c)]>;
+ (outs), (ins IntRegs:$rs1, IntRegs:$rs2),
+ "cmp $rs1, $rs2",
+ [(SPcmpicc i32:$rs1, i32:$rs2)]>;
def CMPri : F3_2<2, 0b010100,
- (outs), (ins IntRegs:$b, i32imm:$c),
- "cmp $b, $c",
- [(SPcmpicc i32:$b, (i32 simm13:$c))]>;
+ (outs), (ins IntRegs:$rs1, i32imm:$simm13),
+ "cmp $rs1, $simm13",
+ [(SPcmpicc i32:$rs1, (i32 simm13:$simm13))]>;
}
-let Uses = [ICC], Defs = [ICC] in
- def SUBXCCrr: F3_1<2, 0b011100,
- (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
- "subxcc $b, $c, $dst", []>;
-
-
// Section B.18 - Multiply Instructions, p. 113
let Defs = [Y] in {
defm UMUL : F3_12np<"umul", 0b001010>;
@@ -858,7 +852,7 @@ let Defs = [FCC] in {
//===----------------------------------------------------------------------===//
// Instructions for Thread Local Storage(TLS).
//===----------------------------------------------------------------------===//
-
+let isCodeGenOnly = 1, isAsmParserOnly = 1 in {
def TLS_ADDrr : F3_1<2, 0b000000,
(outs IntRegs:$rd),
(ins IntRegs:$rs1, IntRegs:$rs2, TLSSym:$sym),
@@ -882,6 +876,7 @@ let Uses = [O6], isCall = 1, hasDelaySlot = 1 in
let op = 1;
let Inst{29-0} = disp;
}
+}
//===----------------------------------------------------------------------===//
// V9 Instructions
Index: lib/Target/Sparc/CMakeLists.txt
===================================================================
--- lib/Target/Sparc/CMakeLists.txt
+++ lib/Target/Sparc/CMakeLists.txt
@@ -3,6 +3,7 @@ set(LLVM_TARGET_DEFINITIONS Sparc.td)
tablegen(LLVM SparcGenRegisterInfo.inc -gen-register-info)
tablegen(LLVM SparcGenInstrInfo.inc -gen-instr-info)
tablegen(LLVM SparcGenCodeEmitter.inc -gen-emitter)
+tablegen(LLVM SparcGenDisassemblerTables.inc -gen-disassembler)
tablegen(LLVM SparcGenMCCodeEmitter.inc -gen-emitter -mc-emitter)
tablegen(LLVM SparcGenAsmWriter.inc -gen-asm-writer)
tablegen(LLVM SparcGenAsmMatcher.inc -gen-asm-matcher)
@@ -34,3 +35,4 @@ add_subdirectory(TargetInfo)
add_subdirectory(MCTargetDesc)
add_subdirectory(InstPrinter)
add_subdirectory(AsmParser)
+add_subdirectory(Disassembler)
Index: lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
===================================================================
--- lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
+++ lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
@@ -0,0 +1,228 @@
+//===- SparcDisassembler.cpp - Disassembler for Sparc -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is part of the Sparc Disassembler.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "sparc-disassembler"
+
+#include "Sparc.h"
+#include "SparcRegisterInfo.h"
+#include "SparcSubtarget.h"
+#include "llvm/MC/MCDisassembler.h"
+#include "llvm/MC/MCFixedLenDisassembler.h"
+#include "llvm/Support/MemoryObject.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+typedef MCDisassembler::DecodeStatus DecodeStatus;
+
+namespace {
+
+/// SparcDisassembler - a disassembler class for Sparc.
+class SparcDisassembler : public MCDisassembler {
+public:
+ /// Constructor - Initializes the disassembler.
+ ///
+ SparcDisassembler(const MCSubtargetInfo &STI, const MCRegisterInfo *Info) :
+ MCDisassembler(STI), RegInfo(Info)
+ {}
+ virtual ~SparcDisassembler() {}
+
+ const MCRegisterInfo *getRegInfo() const { return RegInfo.get(); }
+
+ /// getInstruction - See MCDisassembler.
+ virtual DecodeStatus getInstruction(MCInst &instr,
+ uint64_t &size,
+ const MemoryObject &region,
+ uint64_t address,
+ raw_ostream &vStream,
+ raw_ostream &cStream) const;
+private:
+ OwningPtr<const MCRegisterInfo> RegInfo;
+};
+
+}
+
+namespace llvm {
+ extern Target TheSparcTarget, TheSparcV9Target;
+}
+
+static MCDisassembler *createSparcDisassembler(
+ const Target &T,
+ const MCSubtargetInfo &STI) {
+ return new SparcDisassembler(STI, T.createMCRegInfo(""));
+}
+
+
+extern "C" void LLVMInitializeSparcDisassembler() {
+ // Register the disassembler.
+ TargetRegistry::RegisterMCDisassembler(TheSparcTarget,
+ createSparcDisassembler);
+ TargetRegistry::RegisterMCDisassembler(TheSparcV9Target,
+ createSparcDisassembler);
+}
+
+
+
+static const unsigned IntRegDecoderTable[] = {
+ SP::G0, SP::G1, SP::G2, SP::G3,
+ SP::G4, SP::G5, SP::G6, SP::G7,
+ SP::O0, SP::O1, SP::O2, SP::O3,
+ SP::O4, SP::O5, SP::O6, SP::O7,
+ SP::L0, SP::L1, SP::L2, SP::L3,
+ SP::L4, SP::L5, SP::L6, SP::L7,
+ SP::I0, SP::I1, SP::I2, SP::I3,
+ SP::I4, SP::I5, SP::I6, SP::I7 };
+
+static const unsigned FPRegDecoderTable[] = {
+ SP::F0, SP::F1, SP::F2, SP::F3,
+ SP::F4, SP::F5, SP::F6, SP::F7,
+ SP::F8, SP::F9, SP::F10, SP::F11,
+ SP::F12, SP::F13, SP::F14, SP::F15,
+ SP::F16, SP::F17, SP::F18, SP::F19,
+ SP::F20, SP::F21, SP::F22, SP::F23,
+ SP::F24, SP::F25, SP::F26, SP::F27,
+ SP::F28, SP::F29, SP::F30, SP::F31 };
+
+static const unsigned DFPRegDecoderTable[] = {
+ SP::D0, SP::D16, SP::D1, SP::D17,
+ SP::D2, SP::D18, SP::D3, SP::D19,
+ SP::D4, SP::D20, SP::D5, SP::D21,
+ SP::D6, SP::D22, SP::D7, SP::D23,
+ SP::D8, SP::D24, SP::D9, SP::D25,
+ SP::D10, SP::D26, SP::D11, SP::D27,
+ SP::D12, SP::D28, SP::D13, SP::D29,
+ SP::D14, SP::D30, SP::D15, SP::D31 };
+
+static const unsigned QFPRegDecoderTable[] = {
+ SP::Q0, SP::Q8, -1, -1,
+ SP::Q1, SP::Q9, -1, -1,
+ SP::Q2, SP::Q10, -1, -1,
+ SP::Q3, SP::Q11, -1, -1,
+ SP::Q4, SP::Q12, -1, -1,
+ SP::Q5, SP::Q13, -1, -1,
+ SP::Q6, SP::Q14, -1, -1,
+ SP::Q7, SP::Q15, -1, -1 } ;
+
+static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst,
+ unsigned RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ if (RegNo > 31)
+ return MCDisassembler::Fail;
+ unsigned Reg = IntRegDecoderTable[RegNo];
+ Inst.addOperand(MCOperand::CreateReg(Reg));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeI64RegsRegisterClass(MCInst &Inst,
+ unsigned RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ if (RegNo > 31)
+ return MCDisassembler::Fail;
+ unsigned Reg = IntRegDecoderTable[RegNo];
+ Inst.addOperand(MCOperand::CreateReg(Reg));
+ return MCDisassembler::Success;
+}
+
+
+static DecodeStatus DecodeFPRegsRegisterClass(MCInst &Inst,
+ unsigned RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ if (RegNo > 31)
+ return MCDisassembler::Fail;
+ unsigned Reg = FPRegDecoderTable[RegNo];
+ Inst.addOperand(MCOperand::CreateReg(Reg));
+ return MCDisassembler::Success;
+}
+
+
+static DecodeStatus DecodeDFPRegsRegisterClass(MCInst &Inst,
+ unsigned RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ if (RegNo > 31)
+ return MCDisassembler::Fail;
+ unsigned Reg = DFPRegDecoderTable[RegNo];
+ Inst.addOperand(MCOperand::CreateReg(Reg));
+ return MCDisassembler::Success;
+}
+
+
+static DecodeStatus DecodeQFPRegsRegisterClass(MCInst &Inst,
+ unsigned RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ if (RegNo > 31)
+ return MCDisassembler::Fail;
+
+ unsigned Reg = QFPRegDecoderTable[RegNo];
+ if (Reg == (unsigned)-1)
+ return MCDisassembler::Fail;
+ Inst.addOperand(MCOperand::CreateReg(Reg));
+ return MCDisassembler::Success;
+}
+
+
+#include "SparcGenDisassemblerTables.inc"
+
+/// readInstruction - read four bytes from the MemoryObject
+/// and return 32 bit word.
+static DecodeStatus readInstruction32(const MemoryObject &region,
+ uint64_t address,
+ uint64_t &size,
+ uint32_t &insn) {
+ uint8_t Bytes[4];
+
+ // We want to read exactly 4 Bytes of data.
+ if (region.readBytes(address, 4, Bytes) == -1) {
+ size = 0;
+ return MCDisassembler::Fail;
+ }
+
+ // Encoded as a big-endian 32-bit word in the stream.
+ insn = (Bytes[3] << 0) |
+ (Bytes[2] << 8) |
+ (Bytes[1] << 16) |
+ (Bytes[0] << 24);
+
+ return MCDisassembler::Success;
+}
+
+
+DecodeStatus
+SparcDisassembler::getInstruction(MCInst &instr,
+ uint64_t &Size,
+ const MemoryObject &Region,
+ uint64_t Address,
+ raw_ostream &vStream,
+ raw_ostream &cStream) const {
+ uint32_t Insn;
+
+ DecodeStatus Result = readInstruction32(Region, Address, Size, Insn);
+ if (Result == MCDisassembler::Fail)
+ return MCDisassembler::Fail;
+
+
+ // Calling the auto-generated decoder function.
+ Result = decodeInstruction(DecoderTableSparc32, instr, Insn, Address,
+ this, STI);
+
+ if (Result != MCDisassembler::Fail) {
+ Size = 4;
+ return Result;
+ }
+
+ return MCDisassembler::Fail;
+}
Index: lib/Target/Sparc/Disassembler/LLVMBuild.txt
===================================================================
--- lib/Target/Sparc/Disassembler/LLVMBuild.txt
+++ lib/Target/Sparc/Disassembler/LLVMBuild.txt
@@ -0,0 +1,23 @@
+;===- ./lib/Target/Sparc/Disassembler/LLVMBuild.txt ------------*- Conf -*--===;
+;
+; The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+; http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Library
+name = SparcDisassembler
+parent = Sparc
+required_libraries = MC Support SparcInfo
+add_to_library_groups = Sparc
Index: lib/Target/Sparc/Disassembler/CMakeLists.txt
===================================================================
--- lib/Target/Sparc/Disassembler/CMakeLists.txt
+++ lib/Target/Sparc/Disassembler/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_llvm_library(LLVMSparcDisassembler
+ SparcDisassembler.cpp
+ )
+
+# workaround for hanging compilation on MSVC9 and 10
+if( MSVC_VERSION EQUAL 1400 OR MSVC_VERSION EQUAL 1500
+ OR MSVC_VERSION EQUAL 1600 )
+set_property(
+ SOURCE SparcDisassembler.cpp
+ PROPERTY COMPILE_FLAGS "/Od"
+ )
+endif()
Index: lib/Target/Sparc/Disassembler/Makefile
===================================================================
--- lib/Target/Sparc/Disassembler/Makefile
+++ lib/Target/Sparc/Disassembler/Makefile
@@ -0,0 +1,16 @@
+##===- lib/Target/Sparc/Disassembler/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 = LLVMSparcDisassembler
+
+# Hack: we need to include 'main' Sparc target directory to grab private headers
+CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
+
+include $(LEVEL)/Makefile.common
Index: lib/Target/Sparc/Makefile
===================================================================
--- lib/Target/Sparc/Makefile
+++ lib/Target/Sparc/Makefile
@@ -14,11 +14,11 @@ TARGET = Sparc
# Make sure that tblgen is run, first thing.
BUILT_SOURCES = SparcGenRegisterInfo.inc SparcGenInstrInfo.inc \
SparcGenAsmWriter.inc SparcGenAsmMatcher.inc \
- SparcGenDAGISel.inc \
+ SparcGenDAGISel.inc SparcGenDisassemblerTables.inc \
SparcGenSubtargetInfo.inc SparcGenCallingConv.inc \
SparcGenCodeEmitter.inc SparcGenMCCodeEmitter.inc
-DIRS = InstPrinter AsmParser TargetInfo MCTargetDesc
+DIRS = InstPrinter AsmParser Disassembler TargetInfo MCTargetDesc
include $(LEVEL)/Makefile.common
Index: lib/Target/Sparc/SparcInstr64Bit.td
===================================================================
--- lib/Target/Sparc/SparcInstr64Bit.td
+++ lib/Target/Sparc/SparcInstr64Bit.td
@@ -141,6 +141,7 @@ def : Pat<(i64 imm:$val),
let Predicates = [Is64Bit] in {
// Register-register instructions.
+let isCodeGenOnly = 1 in {
defm ANDX : F3_12<"and", 0b000001, and, I64Regs, i64, i64imm>;
defm ORX : F3_12<"or", 0b000010, or, I64Regs, i64, i64imm>;
defm XORX : F3_12<"xor", 0b000011, xor, I64Regs, i64, i64imm>;
@@ -161,8 +162,6 @@ def XNORXrr : F3_1<2, 0b000111,
defm ADDX : F3_12<"add", 0b000000, add, I64Regs, i64, i64imm>;
defm SUBX : F3_12<"sub", 0b000100, sub, I64Regs, i64, i64imm>;
-def : Pat<(SPcmpicc i64:$a, i64:$b), (CMPrr $a, $b)>;
-
def TLS_ADDXrr : F3_1<2, 0b000000, (outs I64Regs:$rd),
(ins I64Regs:$rs1, I64Regs:$rs2, TLSSym:$sym),
"add $rs1, $rs2, $rd, $sym",
@@ -169,18 +168,17 @@ def TLS_ADDXrr : F3_1<2, 0b000000, (outs I64Regs:$
[(set i64:$rd,
(tlsadd i64:$rs1, i64:$rs2, tglobaltlsaddr:$sym))]>;
-// Register-immediate instructions.
-
-def : Pat<(SPcmpicc i64:$a, (i64 simm13:$b)), (CMPri $a, (as_i32imm $b))>;
-
-def : Pat<(ctpop i64:$src), (POPCrr $src)>;
-
// "LEA" form of add
-let isCodeGenOnly = 1 in
def LEAX_ADDri : F3_2<2, 0b000000,
(outs I64Regs:$dst), (ins MEMri:$addr),
"add ${addr:arith}, $dst",
[(set iPTR:$dst, ADDRri:$addr)]>;
+}
+
+def : Pat<(SPcmpicc i64:$a, i64:$b), (CMPrr $a, $b)>;
+def : Pat<(SPcmpicc i64:$a, (i64 simm13:$b)), (CMPri $a, (as_i32imm $b))>;
+def : Pat<(ctpop i64:$src), (POPCrr $src)>;
+
} // Predicates = [Is64Bit]
@@ -245,7 +243,7 @@ def LDXri : F3_2<3, 0b001011,
(outs I64Regs:$dst), (ins MEMri:$addr),
"ldx [$addr], $dst",
[(set i64:$dst, (load ADDRri:$addr))]>;
-let mayLoad = 1 in
+let mayLoad = 1, isCodeGenOnly = 1, isAsmParserOnly = 1 in
def TLS_LDXrr : F3_1<3, 0b001011,
(outs IntRegs:$dst), (ins MEMrr:$addr, TLSSym:$sym),
"ldx [$addr], $dst, $sym",
@@ -278,11 +276,11 @@ def : Pat<(i64 (extloadi32 ADDRrr:$addr)), (LDrr
def : Pat<(i64 (extloadi32 ADDRri:$addr)), (LDri ADDRri:$addr)>;
// Sign-extending load of i32 into i64 is a new SPARC v9 instruction.
-def LDSWrr : F3_1<3, 0b001011,
+def LDSWrr : F3_1<3, 0b001000,
(outs I64Regs:$dst), (ins MEMrr:$addr),
"ldsw [$addr], $dst",
[(set i64:$dst, (sextloadi32 ADDRrr:$addr))]>;
-def LDSWri : F3_2<3, 0b001011,
+def LDSWri : F3_2<3, 0b001000,
(outs I64Regs:$dst), (ins MEMri:$addr),
"ldsw [$addr], $dst",
[(set i64:$dst, (sextloadi32 ADDRri:$addr))]>;
@@ -289,13 +287,13 @@ def : Pat<(i64 (extloadi32 ADDRri:$addr)), (LDri
// 64-bit stores.
def STXrr : F3_1<3, 0b001110,
- (outs), (ins MEMrr:$addr, I64Regs:$src),
- "stx $src, [$addr]",
- [(store i64:$src, ADDRrr:$addr)]>;
+ (outs), (ins MEMrr:$addr, I64Regs:$rd),
+ "stx $rd, [$addr]",
+ [(store i64:$rd, ADDRrr:$addr)]>;
def STXri : F3_2<3, 0b001110,
- (outs), (ins MEMri:$addr, I64Regs:$src),
- "stx $src, [$addr]",
- [(store i64:$src, ADDRri:$addr)]>;
+ (outs), (ins MEMri:$addr, I64Regs:$rd),
+ "stx $rd, [$addr]",
+ [(store i64:$rd, ADDRri:$addr)]>;
// Truncating stores from i64 are identical to the i32 stores.
def : Pat<(truncstorei8 i64:$src, ADDRrr:$addr), (STBrr ADDRrr:$addr, $src)>;
@@ -315,6 +313,15 @@ def : Pat<(store (i64 0), ADDRri:$dst), (STXri ADD
//===----------------------------------------------------------------------===//
// 64-bit Conditionals.
//===----------------------------------------------------------------------===//
+
+// Conditional branch class on %xcc:
+class XBranchSP<dag ins, string asmstr, list<dag> pattern>
+ : F2_3<0b001, 0b10, (outs), ins, asmstr, pattern> {
+ let isBranch = 1;
+ let isTerminator = 1;
+ let hasDelaySlot = 1;
+}
+
//
// Flag-setting instructions like subcc and addcc set both icc and xcc flags.
// The icc flags correspond to the 32-bit result, and the xcc are for the
@@ -326,7 +333,7 @@ def : Pat<(store (i64 0), ADDRri:$dst), (STXri ADD
let Predicates = [Is64Bit] in {
let Uses = [ICC] in
-def BPXCC : BranchSP<(ins brtarget:$imm22, CCOp:$cond),
+def BPXCC : XBranchSP<(ins brtarget:$imm22, CCOp:$cond),
"b$cond %xcc, $imm22",
[(SPbrxcc bb:$imm22, imm:$cond)]>;
@@ -409,7 +416,7 @@ def : Pat<(SPselectfcc (i64 simm11:$t), i64:$f, im
// 64 bit SETHI
-let Predicates = [Is64Bit] in {
+let Predicates = [Is64Bit], isCodeGenOnly = 1 in {
def SETHIXi : F2_1<0b100,
(outs IntRegs:$rd), (ins i64imm:$imm22),
"sethi $imm22, $rd",
Index: test/MC/Disassembler/Sparc/lit.local.cfg
===================================================================
--- test/MC/Disassembler/Sparc/lit.local.cfg
+++ test/MC/Disassembler/Sparc/lit.local.cfg
@@ -0,0 +1,4 @@
+targets = set(config.root.targets_to_build.split())
+if not 'Sparc' in targets:
+ config.unsupported = True
+
Index: test/MC/Disassembler/Sparc/sparc.txt
===================================================================
--- test/MC/Disassembler/Sparc/sparc.txt
+++ test/MC/Disassembler/Sparc/sparc.txt
@@ -0,0 +1,82 @@
+# RUN: llvm-mc --disassemble %s -triple=sparc-unknown-linux | FileCheck %s
+
+# CHECK: add %g0, %g0, %g0
+0x80 0x00 0x00 0x00
+
+# CHECK: add %g1, %g2, %g3
+0x86 0x00 0x40 0x02
+
+# CHECK: add %o0, %o1, %l0
+0xa0 0x02 0x00 0x09
+
+# CHECK: add %o0, 10, %l0
+0xa0 0x02 0x20 0x0a
+
+# CHECK: addcc %g1, %g2, %g3
+0x86 0x80 0x40 0x02
+
+# CHECK: addxcc %g1, %g2, %g3
+0x86 0xc0 0x40 0x02
+
+# CHECK: udiv %g1, %g2, %g3
+0x86 0x70 0x40 0x02
+
+# CHECK: sdiv %g1, %g2, %g3
+0x86 0x78 0x40 0x02
+
+# CHECK: and %g1, %g2, %g3
+0x86 0x08 0x40 0x02
+
+# CHECK: andn %g1, %g2, %g3
+0x86 0x28 0x40 0x02
+
+# CHECK: or %g1, %g2, %g3
+0x86 0x10 0x40 0x02
+
+# CHECK: orn %g1, %g2, %g3
+0x86 0x30 0x40 0x02
+
+# CHECK: xor %g1, %g2, %g3
+0x86 0x18 0x40 0x02
+
+# CHECK: xnor %g1, %g2, %g3
+0x86 0x38 0x40 0x02
+
+# CHECK: umul %g1, %g2, %g3
+0x86 0x50 0x40 0x02
+
+# CHECK: smul %g1, %g2, %g3
+0x86 0x58 0x40 0x02
+
+# CHECK: nop
+0x01 0x00 0x00 0x00
+
+# CHECK: sethi 10, %l0
+0x21 0x00 0x00 0x0a
+
+# CHECK: sll %g1, %g2, %g3
+0x87 0x28 0x40 0x02
+
+# CHECK: sll %g1, 31, %g3
+0x87 0x28 0x60 0x1f
+
+# CHECK: srl %g1, %g2, %g3
+0x87 0x30 0x40 0x02
+
+# CHECK: srl %g1, 31, %g3
+0x87 0x30 0x60 0x1f
+
+# CHECK: sra %g1, %g2, %g3
+0x87 0x38 0x40 0x02
+
+# CHECK: sra %g1, 31, %g3
+0x87 0x38 0x60 0x1f
+
+# CHECK: sub %g1, %g2, %g3
+0x86 0x20 0x40 0x02
+
+# CHECK: subcc %g1, %g2, %g3
+0x86 0xa0 0x40 0x02
+
+# CHECK: subxcc %g1, %g2, %g3
+0x86 0xe0 0x40 0x02

View File

@ -0,0 +1,33 @@
Pull in r198592 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Explicitly cast -1 to unsigned to fix buildbot errors.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
===================================================================
--- lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
+++ lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
@@ -104,14 +104,14 @@ static const unsigned DFPRegDecoderTable[] = {
SP::D14, SP::D30, SP::D15, SP::D31 };
static const unsigned QFPRegDecoderTable[] = {
- SP::Q0, SP::Q8, -1, -1,
- SP::Q1, SP::Q9, -1, -1,
- SP::Q2, SP::Q10, -1, -1,
- SP::Q3, SP::Q11, -1, -1,
- SP::Q4, SP::Q12, -1, -1,
- SP::Q5, SP::Q13, -1, -1,
- SP::Q6, SP::Q14, -1, -1,
- SP::Q7, SP::Q15, -1, -1 } ;
+ SP::Q0, SP::Q8, (unsigned)-1, (unsigned)-1,
+ SP::Q1, SP::Q9, (unsigned)-1, (unsigned)-1,
+ SP::Q2, SP::Q10, (unsigned)-1, (unsigned)-1,
+ SP::Q3, SP::Q11, (unsigned)-1, (unsigned)-1,
+ SP::Q4, SP::Q12, (unsigned)-1, (unsigned)-1,
+ SP::Q5, SP::Q13, (unsigned)-1, (unsigned)-1,
+ SP::Q6, SP::Q14, (unsigned)-1, (unsigned)-1,
+ SP::Q7, SP::Q15, (unsigned)-1, (unsigned)-1 } ;
static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst,
unsigned RegNo,

View File

@ -0,0 +1,359 @@
Pull in r198658 from upstream llvm trunk:
[Sparc] Add support for parsing memory operands in sparc AsmParser.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: test/MC/Sparc/sparc-ctrl-instructions.s
===================================================================
--- test/MC/Sparc/sparc-ctrl-instructions.s
+++ test/MC/Sparc/sparc-ctrl-instructions.s
@@ -0,0 +1,23 @@
+! RUN: llvm-mc %s -arch=sparc -show-encoding | FileCheck %s
+! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s
+
+ ! CHECK: call foo
+ call foo
+
+ ! CHECK: call %g1+%i2
+ call %g1 + %i2
+
+ ! CHECK: call %o1+8
+ call %o1 + 8
+
+ ! CHECK: call %g1
+ call %g1
+
+ ! CHECK: jmp %g1+%i2
+ jmp %g1 + %i2
+
+ ! CHECK: jmp %o1+8
+ jmp %o1 + 8
+
+ ! CHECK: jmp %g1
+ jmp %g1
Index: test/MC/Sparc/sparc-mem-instructions.s
===================================================================
--- test/MC/Sparc/sparc-mem-instructions.s
+++ test/MC/Sparc/sparc-mem-instructions.s
@@ -0,0 +1,58 @@
+! RUN: llvm-mc %s -arch=sparc -show-encoding | FileCheck %s
+! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s
+
+ ! CHECK: ldsb [%i0+%l6], %o2 ! encoding: [0xd4,0x4e,0x00,0x16]
+ ldsb [%i0 + %l6], %o2
+ ! CHECK: ldsb [%i0+32], %o2 ! encoding: [0xd4,0x4e,0x20,0x20]
+ ldsb [%i0 + 32], %o2
+ ! CHECK: ldsb [%g1], %o4 ! encoding: [0xd8,0x48,0x60,0x00]
+ ldsb [%g1], %o4
+
+ ! CHECK: ldsh [%i0+%l6], %o2 ! encoding: [0xd4,0x56,0x00,0x16]
+ ldsh [%i0 + %l6], %o2
+ ! CHECK: ldsh [%i0+32], %o2 ! encoding: [0xd4,0x56,0x20,0x20]
+ ldsh [%i0 + 32], %o2
+ ! CHECK: ldsh [%g1], %o4 ! encoding: [0xd8,0x50,0x60,0x00]
+ ldsh [%g1], %o4
+
+ ! CHECK: ldub [%i0+%l6], %o2 ! encoding: [0xd4,0x0e,0x00,0x16]
+ ldub [%i0 + %l6], %o2
+ ! CHECK: ldub [%i0+32], %o2 ! encoding: [0xd4,0x0e,0x20,0x20]
+ ldub [%i0 + 32], %o2
+ ! CHECK: ldub [%g1], %o2 ! encoding: [0xd4,0x08,0x60,0x00]
+ ldub [%g1], %o2
+
+ ! CHECK: lduh [%i0+%l6], %o2 ! encoding: [0xd4,0x16,0x00,0x16]
+ lduh [%i0 + %l6], %o2
+ ! CHECK: lduh [%i0+32], %o2 ! encoding: [0xd4,0x16,0x20,0x20]
+ lduh [%i0 + 32], %o2
+ ! CHECK: lduh [%g1], %o2 ! encoding: [0xd4,0x10,0x60,0x00]
+ lduh [%g1], %o2
+
+ ! CHECK: ld [%i0+%l6], %o2 ! encoding: [0xd4,0x06,0x00,0x16]
+ ld [%i0 + %l6], %o2
+ ! CHECK: ld [%i0+32], %o2 ! encoding: [0xd4,0x06,0x20,0x20]
+ ld [%i0 + 32], %o2
+ ! CHECK: ld [%g1], %o2 ! encoding: [0xd4,0x00,0x60,0x00]
+ ld [%g1], %o2
+
+ ! CHECK: stb %o2, [%i0+%l6] ! encoding: [0xd4,0x2e,0x00,0x16]
+ stb %o2, [%i0 + %l6]
+ ! CHECK: stb %o2, [%i0+32] ! encoding: [0xd4,0x2e,0x20,0x20]
+ stb %o2, [%i0 + 32]
+ ! CHECK: stb %o2, [%g1] ! encoding: [0xd4,0x28,0x60,0x00]
+ stb %o2, [%g1]
+
+ ! CHECK: sth %o2, [%i0+%l6] ! encoding: [0xd4,0x36,0x00,0x16]
+ sth %o2, [%i0 + %l6]
+ ! CHECK: sth %o2, [%i0+32] ! encoding: [0xd4,0x36,0x20,0x20]
+ sth %o2, [%i0 + 32]
+ ! CHECK: sth %o2, [%g1] ! encoding: [0xd4,0x30,0x60,0x00]
+ sth %o2, [%g1]
+
+ ! CHECK: st %o2, [%i0+%l6] ! encoding: [0xd4,0x26,0x00,0x16]
+ st %o2, [%i0 + %l6]
+ ! CHECK: st %o2, [%i0+32] ! encoding: [0xd4,0x26,0x20,0x20]
+ st %o2, [%i0 + 32]
+ ! CHECK: st %o2, [%g1] ! encoding: [0xd4,0x20,0x60,0x00]
+ st %o2, [%g1]
Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
===================================================================
--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
+++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
@@ -28,6 +28,7 @@ namespace llvm {
}
namespace {
+class SparcOperand;
class SparcAsmParser : public MCTargetAsmParser {
MCSubtargetInfo &STI;
@@ -55,18 +56,15 @@ class SparcAsmParser : public MCTargetAsmParser {
// Custom parse functions for Sparc specific operands.
OperandMatchResultTy
- parseMEMrrOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands);
- OperandMatchResultTy
- parseMEMriOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands);
+ parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands);
OperandMatchResultTy
- parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
- int ImmOffsetOrReg);
-
- OperandMatchResultTy
parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
StringRef Name);
+ OperandMatchResultTy
+ parseSparcAsmOperand(SparcOperand *&Operand);
+
// returns true if Tok is matched to a register and returns register in RegNo.
bool matchRegisterName(const AsmToken &Tok, unsigned &RegNo, bool isDFP,
bool isQFP);
@@ -298,7 +296,35 @@ class SparcOperand : public MCParsedAsmOperand {
return Op;
}
+ static SparcOperand *MorphToMEMrr(unsigned Base, SparcOperand *Op) {
+ unsigned offsetReg = Op->getReg();
+ Op->Kind = k_MemoryReg;
+ Op->Mem.Base = Base;
+ Op->Mem.OffsetReg = offsetReg;
+ Op->Mem.Off = 0;
+ return Op;
+ }
+ static SparcOperand *CreateMEMri(unsigned Base,
+ const MCExpr *Off,
+ SMLoc S, SMLoc E) {
+ SparcOperand *Op = new SparcOperand(k_MemoryImm);
+ Op->Mem.Base = Base;
+ Op->Mem.OffsetReg = 0;
+ Op->Mem.Off = Off;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
+ static SparcOperand *MorphToMEMri(unsigned Base, SparcOperand *Op) {
+ const MCExpr *Imm = Op->getImm();
+ Op->Kind = k_MemoryImm;
+ Op->Mem.Base = Base;
+ Op->Mem.OffsetReg = 0;
+ Op->Mem.Off = Imm;
+ return Op;
+ }
};
} // end namespace
@@ -412,23 +438,42 @@ ParseDirective(AsmToken DirectiveID)
}
SparcAsmParser::OperandMatchResultTy SparcAsmParser::
-parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
- int ImmOffsetOrReg)
+parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands)
{
- // FIXME: Implement memory operand parsing here.
- return MatchOperand_NoMatch;
-}
-SparcAsmParser::OperandMatchResultTy SparcAsmParser::
-parseMEMrrOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands)
-{
- return parseMEMOperand(Operands, 2);
-}
+ SMLoc S, E;
+ unsigned BaseReg = 0;
-SparcAsmParser::OperandMatchResultTy SparcAsmParser::
-parseMEMriOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands)
-{
- return parseMEMOperand(Operands, 1);
+ if (ParseRegister(BaseReg, S, E)) {
+ return MatchOperand_NoMatch;
+ }
+
+ switch (getLexer().getKind()) {
+ default: return MatchOperand_NoMatch;
+
+ case AsmToken::RBrac:
+ case AsmToken::EndOfStatement:
+ Operands.push_back(SparcOperand::CreateMEMri(BaseReg, 0, S, E));
+ return MatchOperand_Success;
+
+ case AsmToken:: Plus:
+ Parser.Lex(); // Eat the '+'
+ break;
+ case AsmToken::Minus:
+ break;
+ }
+
+ SparcOperand *Offset = 0;
+ OperandMatchResultTy ResTy = parseSparcAsmOperand(Offset);
+ if (ResTy != MatchOperand_Success || !Offset)
+ return MatchOperand_NoMatch;
+
+ Offset = (Offset->isImm()
+ ? SparcOperand::MorphToMEMri(BaseReg, Offset)
+ : SparcOperand::MorphToMEMrr(BaseReg, Offset));
+
+ Operands.push_back(Offset);
+ return MatchOperand_Success;
}
SparcAsmParser::OperandMatchResultTy SparcAsmParser::
@@ -435,20 +480,57 @@ SparcAsmParser::OperandMatchResultTy SparcAsmParse
parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
StringRef Mnemonic)
{
+
OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic);
- if (ResTy == MatchOperand_Success)
- return ResTy;
+
// If there wasn't a custom match, try the generic matcher below. Otherwise,
// there was a match, but an error occurred, in which case, just return that
// the operand parsing failed.
- if (ResTy == MatchOperand_ParseFail)
+ if (ResTy == MatchOperand_Success || ResTy == MatchOperand_ParseFail)
return ResTy;
+ if (getLexer().is(AsmToken::LBrac)) {
+ // Memory operand
+ Operands.push_back(SparcOperand::CreateToken("[",
+ Parser.getTok().getLoc()));
+ Parser.Lex(); // Eat the [
+
+ ResTy = parseMEMOperand(Operands);
+ if (ResTy != MatchOperand_Success)
+ return ResTy;
+
+ if (!getLexer().is(AsmToken::RBrac))
+ return MatchOperand_ParseFail;
+
+ Operands.push_back(SparcOperand::CreateToken("]",
+ Parser.getTok().getLoc()));
+ Parser.Lex(); // Eat the ]
+ return MatchOperand_Success;
+ }
+
+ SparcOperand *Op = 0;
+ ResTy = parseSparcAsmOperand(Op);
+ if (ResTy != MatchOperand_Success || !Op)
+ return MatchOperand_ParseFail;
+
+ // Push the parsed operand into the list of operands
+ Operands.push_back(Op);
+
+ return MatchOperand_Success;
+}
+
+SparcAsmParser::OperandMatchResultTy
+SparcAsmParser::parseSparcAsmOperand(SparcOperand *&Op)
+{
+
SMLoc S = Parser.getTok().getLoc();
SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
const MCExpr *EVal;
- SparcOperand *Op;
+
+ Op = 0;
switch (getLexer().getKind()) {
+ default: break;
+
case AsmToken::Percent:
Parser.Lex(); // Eat the '%'.
unsigned RegNo;
@@ -458,40 +540,30 @@ parseOperand(SmallVectorImpl<MCParsedAsmOperand*>
break;
}
// FIXME: Handle modifiers like %hi, %lo etc.,
- return MatchOperand_ParseFail;
+ break;
case AsmToken::Minus:
case AsmToken::Integer:
- if (getParser().parseExpression(EVal))
- return MatchOperand_ParseFail;
-
- Op = SparcOperand::CreateImm(EVal, S, E);
+ if (!getParser().parseExpression(EVal))
+ Op = SparcOperand::CreateImm(EVal, S, E);
break;
case AsmToken::Identifier: {
StringRef Identifier;
- if (getParser().parseIdentifier(Identifier))
- return MatchOperand_ParseFail;
- SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
- MCSymbol *Sym = getContext().GetOrCreateSymbol(Identifier);
+ if (!getParser().parseIdentifier(Identifier)) {
+ SMLoc E = SMLoc::getFromPointer(Parser.getTok().
+ getLoc().getPointer() - 1);
+ MCSymbol *Sym = getContext().GetOrCreateSymbol(Identifier);
- // Otherwise create a symbol reference.
- const MCExpr *Res = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None,
- getContext());
+ const MCExpr *Res = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None,
+ getContext());
- Op = SparcOperand::CreateImm(Res, S, E);
+ Op = SparcOperand::CreateImm(Res, S, E);
+ }
break;
}
-
- case AsmToken::LBrac: // handle [
- return parseMEMOperand(Operands, 0);
-
- default:
- return MatchOperand_ParseFail;
}
- // Push the parsed operand into the list of operands
- Operands.push_back(Op);
- return MatchOperand_Success;
+ return (Op) ? MatchOperand_Success : MatchOperand_ParseFail;
}
bool SparcAsmParser::matchRegisterName(const AsmToken &Tok,
Index: lib/Target/Sparc/SparcInstrInfo.td
===================================================================
--- lib/Target/Sparc/SparcInstrInfo.td
+++ lib/Target/Sparc/SparcInstrInfo.td
@@ -78,12 +78,12 @@ def ADDRri : ComplexPattern<iPTR, 2, "SelectADDRri
// Address operands
def SparcMEMrrAsmOperand : AsmOperandClass {
let Name = "MEMrr";
- let ParserMethod = "parseMEMrrOperand";
+ let ParserMethod = "parseMEMOperand";
}
def SparcMEMriAsmOperand : AsmOperandClass {
let Name = "MEMri";
- let ParserMethod = "parseMEMriOperand";
+ let ParserMethod = "parseMEMOperand";
}
def MEMrr : Operand<iPTR> {

View File

@ -0,0 +1,298 @@
Pull in r198681 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Add support for parsing sparc asm modifiers such as %hi, %lo etc.,
Also, correct the offsets for FixupsKindInfo.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
@@ -27,11 +27,11 @@ static unsigned adjustFixupValue(unsigned Kind, ui
case FK_Data_8:
return Value;
case Sparc::fixup_sparc_call30:
- return Value & 0x3fffffff;
+ return (Value >> 2) & 0x3fffffff;
case Sparc::fixup_sparc_br22:
- return Value & 0x3fffff;
+ return (Value >> 2) & 0x3fffff;
case Sparc::fixup_sparc_br19:
- return Value & 0x1ffff;
+ return (Value >> 2) & 0x1ffff;
case Sparc::fixup_sparc_hi22:
return (Value >> 10) & 0x3fffff;
case Sparc::fixup_sparc_lo10:
@@ -45,7 +45,7 @@ static unsigned adjustFixupValue(unsigned Kind, ui
case Sparc::fixup_sparc_hh:
return (Value >> 42) & 0x3fffff;
case Sparc::fixup_sparc_hm:
- return (Value >>32) & 0x3ff;
+ return (Value >> 32) & 0x3ff;
}
}
@@ -62,16 +62,16 @@ namespace {
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const {
const static MCFixupKindInfo Infos[Sparc::NumTargetFixupKinds] = {
// name offset bits flags
- { "fixup_sparc_call30", 0, 30, MCFixupKindInfo::FKF_IsPCRel },
- { "fixup_sparc_br22", 0, 22, MCFixupKindInfo::FKF_IsPCRel },
- { "fixup_sparc_br19", 0, 19, MCFixupKindInfo::FKF_IsPCRel },
- { "fixup_sparc_hi22", 0, 22, 0 },
- { "fixup_sparc_lo10", 0, 10, 0 },
- { "fixup_sparc_h44", 0, 22, 0 },
- { "fixup_sparc_m44", 0, 10, 0 },
- { "fixup_sparc_l44", 0, 12, 0 },
- { "fixup_sparc_hh", 0, 21, 0 },
- { "fixup_sparc_hm", 0, 10, 0 },
+ { "fixup_sparc_call30", 2, 30, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_br22", 10, 22, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_br19", 13, 19, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_hi22", 10, 22, 0 },
+ { "fixup_sparc_lo10", 22, 10, 0 },
+ { "fixup_sparc_h44", 10, 22, 0 },
+ { "fixup_sparc_m44", 22, 10, 0 },
+ { "fixup_sparc_l44", 20, 12, 0 },
+ { "fixup_sparc_hh", 10, 22, 0 },
+ { "fixup_sparc_hm", 22, 10, 0 },
};
if (Kind < FirstTargetFixupKind)
Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
@@ -67,6 +67,37 @@ void SparcMCExpr::PrintImpl(raw_ostream &OS) const
OS << ')';
}
+SparcMCExpr::VariantKind SparcMCExpr::parseVariantKind(StringRef name)
+{
+ return StringSwitch<SparcMCExpr::VariantKind>(name)
+ .Case("lo", VK_Sparc_LO)
+ .Case("hi", VK_Sparc_HI)
+ .Case("h44", VK_Sparc_H44)
+ .Case("m44", VK_Sparc_M44)
+ .Case("l44", VK_Sparc_L44)
+ .Case("hh", VK_Sparc_HH)
+ .Case("hm", VK_Sparc_HM)
+ .Case("tgd_hi22", VK_Sparc_TLS_GD_HI22)
+ .Case("tgd_lo10", VK_Sparc_TLS_GD_LO10)
+ .Case("tgd_add", VK_Sparc_TLS_GD_ADD)
+ .Case("tgd_call", VK_Sparc_TLS_GD_CALL)
+ .Case("tldm_hi22", VK_Sparc_TLS_LDM_HI22)
+ .Case("tldm_lo10", VK_Sparc_TLS_LDM_LO10)
+ .Case("tldm_add", VK_Sparc_TLS_LDM_ADD)
+ .Case("tldm_call", VK_Sparc_TLS_LDM_CALL)
+ .Case("tldo_hix22", VK_Sparc_TLS_LDO_HIX22)
+ .Case("tldo_lox10", VK_Sparc_TLS_LDO_LOX10)
+ .Case("tldo_add", VK_Sparc_TLS_LDO_ADD)
+ .Case("tie_hi22", VK_Sparc_TLS_IE_HI22)
+ .Case("tie_lo10", VK_Sparc_TLS_IE_LO10)
+ .Case("tie_ld", VK_Sparc_TLS_IE_LD)
+ .Case("tie_ldx", VK_Sparc_TLS_IE_LDX)
+ .Case("tie_add", VK_Sparc_TLS_IE_ADD)
+ .Case("tle_hix22", VK_Sparc_TLS_LE_HIX22)
+ .Case("tle_lox10", VK_Sparc_TLS_LE_LOX10)
+ .Default(VK_Sparc_None);
+}
+
bool
SparcMCExpr::EvaluateAsRelocatableImpl(MCValue &Res,
const MCAsmLayout *Layout) const {
Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
+++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
@@ -19,6 +19,7 @@
namespace llvm {
+class StringRef;
class SparcMCExpr : public MCTargetExpr {
public:
enum VariantKind {
@@ -90,6 +91,7 @@ class SparcMCExpr : public MCTargetExpr {
static bool classof(const SparcMCExpr *) { return true; }
+ static VariantKind parseVariantKind(StringRef name);
};
Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
===================================================================
--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
+++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/SparcMCTargetDesc.h"
+#include "MCTargetDesc/SparcMCExpr.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInst.h"
@@ -68,6 +69,7 @@ class SparcAsmParser : public MCTargetAsmParser {
// returns true if Tok is matched to a register and returns register in RegNo.
bool matchRegisterName(const AsmToken &Tok, unsigned &RegNo, bool isDFP,
bool isQFP);
+ bool matchSparcAsmModifiers(const MCExpr *&EVal, SMLoc &EndLoc);
public:
SparcAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser,
@@ -536,15 +538,19 @@ SparcAsmParser::parseSparcAsmOperand(SparcOperand
unsigned RegNo;
if (matchRegisterName(Parser.getTok(), RegNo, false, false)) {
Parser.Lex(); // Eat the identifier token.
+ E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
Op = SparcOperand::CreateReg(RegNo, SparcOperand::rk_None, S, E);
break;
}
- // FIXME: Handle modifiers like %hi, %lo etc.,
+ if (matchSparcAsmModifiers(EVal, E)) {
+ E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ Op = SparcOperand::CreateImm(EVal, S, E);
+ }
break;
case AsmToken::Minus:
case AsmToken::Integer:
- if (!getParser().parseExpression(EVal))
+ if (!getParser().parseExpression(EVal, E))
Op = SparcOperand::CreateImm(EVal, S, E);
break;
@@ -551,13 +557,11 @@ SparcAsmParser::parseSparcAsmOperand(SparcOperand
case AsmToken::Identifier: {
StringRef Identifier;
if (!getParser().parseIdentifier(Identifier)) {
- SMLoc E = SMLoc::getFromPointer(Parser.getTok().
- getLoc().getPointer() - 1);
+ E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
MCSymbol *Sym = getContext().GetOrCreateSymbol(Identifier);
const MCExpr *Res = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None,
getContext());
-
Op = SparcOperand::CreateImm(Res, S, E);
}
break;
@@ -675,7 +679,33 @@ bool SparcAsmParser::matchRegisterName(const AsmTo
}
+bool SparcAsmParser::matchSparcAsmModifiers(const MCExpr *&EVal,
+ SMLoc &EndLoc)
+{
+ AsmToken Tok = Parser.getTok();
+ if (!Tok.is(AsmToken::Identifier))
+ return false;
+ StringRef name = Tok.getString();
+
+ SparcMCExpr::VariantKind VK = SparcMCExpr::parseVariantKind(name);
+
+ if (VK == SparcMCExpr::VK_Sparc_None)
+ return false;
+
+ Parser.Lex(); // Eat the identifier.
+ if (Parser.getTok().getKind() != AsmToken::LParen)
+ return false;
+
+ Parser.Lex(); // Eat the LParen token.
+ const MCExpr *subExpr;
+ if (Parser.parseParenExpression(subExpr, EndLoc))
+ return false;
+ EVal = SparcMCExpr::Create(VK, subExpr, getContext());
+ return true;
+}
+
+
extern "C" void LLVMInitializeSparcAsmParser() {
RegisterMCAsmParser<SparcAsmParser> A(TheSparcTarget);
RegisterMCAsmParser<SparcAsmParser> B(TheSparcV9Target);
Index: test/MC/Sparc/sparc-relocations.s
===================================================================
--- test/MC/Sparc/sparc-relocations.s
+++ test/MC/Sparc/sparc-relocations.s
@@ -0,0 +1,33 @@
+! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s
+
+ ! CHECK: call foo ! encoding: [0b01AAAAAA,A,A,A]
+ ! CHECK: ! fixup A - offset: 0, value: foo, kind: fixup_sparc_call30
+ call foo
+
+ ! CHECK: or %g1, %lo(sym), %g3 ! encoding: [0x86,0x10,0b011000AA,A]
+ ! CHECK-NEXT ! fixup A - offset: 0, value: %lo(sym), kind: fixup_sparc_lo10
+ or %g1, %lo(sym), %g3
+
+ ! CHECK: sethi %hi(sym), %l0 ! encoding: [0x21,0b00AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: %hi(sym), kind: fixup_sparc_hi22
+ sethi %hi(sym), %l0
+
+ ! CHECK: sethi %h44(sym), %l0 ! encoding: [0x21,0b00AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: %h44(sym), kind: fixup_sparc_h44
+ sethi %h44(sym), %l0
+
+ ! CHECK: or %g1, %m44(sym), %g3 ! encoding: [0x86,0x10,0b011000AA,A]
+ ! CHECK-NEXT ! fixup A - offset: 0, value: %m44(sym), kind: fixup_sparc_m44
+ or %g1, %m44(sym), %g3
+
+ ! CHECK: or %g1, %l44(sym), %g3 ! encoding: [0x86,0x10,0b0110AAAA,A]
+ ! CHECK-NEXT ! fixup A - offset: 0, value: %l44(sym), kind: fixup_sparc_l44
+ or %g1, %l44(sym), %g3
+
+ ! CHECK: sethi %hh(sym), %l0 ! encoding: [0x21,0b00AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: %hh(sym), kind: fixup_sparc_hh
+ sethi %hh(sym), %l0
+
+ ! CHECK: or %g1, %hm(sym), %g3 ! encoding: [0x86,0x10,0b011000AA,A]
+ ! CHECK-NEXT ! fixup A - offset: 0, value: %hm(sym), kind: fixup_sparc_hm
+ or %g1, %hm(sym), %g3
Index: test/MC/Sparc/sparc-ctrl-instructions.s
===================================================================
--- test/MC/Sparc/sparc-ctrl-instructions.s
+++ test/MC/Sparc/sparc-ctrl-instructions.s
@@ -1,23 +1,33 @@
! RUN: llvm-mc %s -arch=sparc -show-encoding | FileCheck %s
! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s
- ! CHECK: call foo
+ ! CHECK: call foo ! encoding: [0b01AAAAAA,A,A,A]
+ ! CHECK: ! fixup A - offset: 0, value: foo, kind: fixup_sparc_call30
call foo
- ! CHECK: call %g1+%i2
+ ! CHECK: call %g1+%i2 ! encoding: [0x9f,0xc0,0x40,0x1a]
call %g1 + %i2
- ! CHECK: call %o1+8
+ ! CHECK: call %o1+8 ! encoding: [0x9f,0xc2,0x60,0x08]
call %o1 + 8
- ! CHECK: call %g1
+ ! CHECK: call %g1 ! encoding: [0x9f,0xc0,0x60,0x00]
call %g1
- ! CHECK: jmp %g1+%i2
+ ! CHECK: call %g1+%lo(sym) ! encoding: [0x9f,0xc0,0b011000AA,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: %lo(sym), kind: fixup_sparc_lo10
+ call %g1+%lo(sym)
+
+ ! CHECK: jmp %g1+%i2 ! encoding: [0x81,0xc0,0x40,0x1a]
jmp %g1 + %i2
- ! CHECK: jmp %o1+8
+ ! CHECK: jmp %o1+8 ! encoding: [0x81,0xc2,0x60,0x08]
jmp %o1 + 8
- ! CHECK: jmp %g1
+ ! CHECK: jmp %g1 ! encoding: [0x81,0xc0,0x60,0x00]
jmp %g1
+
+ ! CHECK: jmp %g1+%lo(sym) ! encoding: [0x81,0xc0,0b011000AA,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: %lo(sym), kind: fixup_sparc_lo10
+ jmp %g1+%lo(sym)
+

View File

@ -0,0 +1,734 @@
Pull in r198738 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Add support for parsing branch instructions and conditional moves.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: test/MC/Disassembler/Sparc/sparc.txt
===================================================================
--- test/MC/Disassembler/Sparc/sparc.txt
+++ test/MC/Disassembler/Sparc/sparc.txt
@@ -80,3 +80,90 @@
# CHECK: subxcc %g1, %g2, %g3
0x86 0xe0 0x40 0x02
+
+# CHECK: ba 4194303
+0x10 0xbf 0xff 0xff
+
+# CHECK: bne 4194303
+0x12 0xbf 0xff 0xff
+
+# CHECK: be 4194303
+0x02 0xbf 0xff 0xff
+
+# CHECK: bg 4194303
+0x14 0xbf 0xff 0xff
+
+# CHECK: ble 4194303
+0x04 0xbf 0xff 0xff
+
+# CHECK: bge 4194303
+0x16 0xbf 0xff 0xff
+
+# CHECK: bl 4194303
+0x06 0xbf 0xff 0xff
+
+# CHECK: bgu 4194303
+0x18 0xbf 0xff 0xff
+
+# CHECK: bleu 4194303
+0x08 0xbf 0xff 0xff
+
+# CHECK: bcc 4194303
+0x1a 0xbf 0xff 0xff
+
+# CHECK: bcs 4194303
+0x0a 0xbf 0xff 0xff
+
+# CHECK: bpos 4194303
+0x1c 0xbf 0xff 0xff
+
+# CHECK: bneg 4194303
+0x0c 0xbf 0xff 0xff
+
+# CHECK: bvc 4194303
+0x1e 0xbf 0xff 0xff
+
+# CHECK: bvs 4194303
+0x0e 0xbf 0xff 0xff
+
+# CHECK: fbu 4194303
+0x0f 0xbf 0xff 0xff
+
+# CHECK: fbg 4194303
+0x0d 0xbf 0xff 0xff
+
+# CHECK: fbug 4194303
+0x0b 0xbf 0xff 0xff
+
+# CHECK: fbl 4194303
+0x09 0xbf 0xff 0xff
+
+# CHECK: fbul 4194303
+0x07 0xbf 0xff 0xff
+
+# CHECK: fblg 4194303
+0x05 0xbf 0xff 0xff
+
+# CHECK: fbne 4194303
+0x03 0xbf 0xff 0xff
+
+# CHECK: fbe 4194303
+0x13 0xbf 0xff 0xff
+
+# CHECK: fbue 4194303
+0x15 0xbf 0xff 0xff
+
+# CHECK: fbge 4194303
+0x17 0xbf 0xff 0xff
+
+# CHECK: fbuge 4194303
+0x19 0xbf 0xff 0xff
+
+# CHECK: fble 4194303
+0x1b 0xbf 0xff 0xff
+
+# CHECK: fbule 4194303
+0x1d 0xbf 0xff 0xff
+
+# CHECK: fbo 4194303
+0x1f 0xbf 0xff 0xff
Index: test/MC/Sparc/sparc-ctrl-instructions.s
===================================================================
--- test/MC/Sparc/sparc-ctrl-instructions.s
+++ test/MC/Sparc/sparc-ctrl-instructions.s
@@ -31,3 +31,117 @@
! CHECK-NEXT: ! fixup A - offset: 0, value: %lo(sym), kind: fixup_sparc_lo10
jmp %g1+%lo(sym)
+ ! CHECK: ba .BB0 ! encoding: [0x10,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ ba .BB0
+
+ ! CHECK: bne .BB0 ! encoding: [0x12,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ bne .BB0
+
+ ! CHECK: be .BB0 ! encoding: [0x02,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ be .BB0
+
+ ! CHECK: bg .BB0 ! encoding: [0x14,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ bg .BB0
+
+ ! CHECK: ble .BB0 ! encoding: [0x04,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ ble .BB0
+
+ ! CHECK: bge .BB0 ! encoding: [0x16,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ bge .BB0
+
+ ! CHECK: bl .BB0 ! encoding: [0x06,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ bl .BB0
+
+ ! CHECK: bgu .BB0 ! encoding: [0x18,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ bgu .BB0
+
+ ! CHECK: bleu .BB0 ! encoding: [0x08,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ bleu .BB0
+
+ ! CHECK: bcc .BB0 ! encoding: [0x1a,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ bcc .BB0
+
+ ! CHECK: bcs .BB0 ! encoding: [0x0a,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ bcs .BB0
+
+ ! CHECK: bpos .BB0 ! encoding: [0x1c,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ bpos .BB0
+
+ ! CHECK: bneg .BB0 ! encoding: [0x0c,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ bneg .BB0
+
+ ! CHECK: bvc .BB0 ! encoding: [0x1e,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ bvc .BB0
+
+ ! CHECK: bvs .BB0 ! encoding: [0x0e,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ bvs .BB0
+
+ ! CHECK: fbu .BB0 ! encoding: [0x0f,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ fbu .BB0
+
+ ! CHECK: fbg .BB0 ! encoding: [0x0d,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ fbg .BB0
+ ! CHECK: fbug .BB0 ! encoding: [0x0b,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ fbug .BB0
+
+ ! CHECK: fbl .BB0 ! encoding: [0x09,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ fbl .BB0
+
+ ! CHECK: fbul .BB0 ! encoding: [0x07,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ fbul .BB0
+
+ ! CHECK: fblg .BB0 ! encoding: [0x05,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ fblg .BB0
+
+ ! CHECK: fbne .BB0 ! encoding: [0x03,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ fbne .BB0
+
+ ! CHECK: fbe .BB0 ! encoding: [0x13,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ fbe .BB0
+
+ ! CHECK: fbue .BB0 ! encoding: [0x15,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ fbue .BB0
+
+ ! CHECK: fbge .BB0 ! encoding: [0x17,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ fbge .BB0
+
+ ! CHECK: fbuge .BB0 ! encoding: [0x19,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ fbuge .BB0
+
+ ! CHECK: fble .BB0 ! encoding: [0x1b,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ fble .BB0
+
+ ! CHECK: fbule .BB0 ! encoding: [0x1d,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ fbule .BB0
+
+ ! CHECK: fbo .BB0 ! encoding: [0x1f,0b10AAAAAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
+ fbo .BB0
Index: test/MC/Sparc/sparc64-ctrl-instructions.s
===================================================================
--- test/MC/Sparc/sparc64-ctrl-instructions.s
+++ test/MC/Sparc/sparc64-ctrl-instructions.s
@@ -0,0 +1,235 @@
+! RUN: llvm-mc %s -triple=sparc64-unknown-linux-gnu -show-encoding | FileCheck %s
+
+
+ ! CHECK: bne %xcc, .BB0 ! encoding: [0x12,0b01101AAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19
+ bne %xcc, .BB0
+
+ ! CHECK: be %xcc, .BB0 ! encoding: [0x02,0b01101AAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19
+ be %xcc, .BB0
+
+ ! CHECK: bg %xcc, .BB0 ! encoding: [0x14,0b01101AAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19
+ bg %xcc, .BB0
+
+ ! CHECK: ble %xcc, .BB0 ! encoding: [0x04,0b01101AAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19
+ ble %xcc, .BB0
+
+ ! CHECK: bge %xcc, .BB0 ! encoding: [0x16,0b01101AAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19
+ bge %xcc, .BB0
+
+ ! CHECK: bl %xcc, .BB0 ! encoding: [0x06,0b01101AAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19
+ bl %xcc, .BB0
+
+ ! CHECK: bgu %xcc, .BB0 ! encoding: [0x18,0b01101AAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19
+ bgu %xcc, .BB0
+
+ ! CHECK: bleu %xcc, .BB0 ! encoding: [0x08,0b01101AAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19
+ bleu %xcc, .BB0
+
+ ! CHECK: bcc %xcc, .BB0 ! encoding: [0x1a,0b01101AAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19
+ bcc %xcc, .BB0
+
+ ! CHECK: bcs %xcc, .BB0 ! encoding: [0x0a,0b01101AAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19
+ bcs %xcc, .BB0
+
+ ! CHECK: bpos %xcc, .BB0 ! encoding: [0x1c,0b01101AAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19
+ bpos %xcc, .BB0
+
+ ! CHECK: bneg %xcc, .BB0 ! encoding: [0x0c,0b01101AAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19
+ bneg %xcc, .BB0
+
+ ! CHECK: bvc %xcc, .BB0 ! encoding: [0x1e,0b01101AAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19
+ bvc %xcc, .BB0
+
+ ! CHECK: bvs %xcc, .BB0 ! encoding: [0x0e,0b01101AAA,A,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19
+ bvs %xcc, .BB0
+
+
+ ! CHECK: movne %icc, %g1, %g2 ! encoding: [0x85,0x66,0x40,0x01]
+ ! CHECK: move %icc, %g1, %g2 ! encoding: [0x85,0x64,0x40,0x01]
+ ! CHECK: movg %icc, %g1, %g2 ! encoding: [0x85,0x66,0x80,0x01]
+ ! CHECK: movle %icc, %g1, %g2 ! encoding: [0x85,0x64,0x80,0x01]
+ ! CHECK: movge %icc, %g1, %g2 ! encoding: [0x85,0x66,0xc0,0x01]
+ ! CHECK: movl %icc, %g1, %g2 ! encoding: [0x85,0x64,0xc0,0x01]
+ ! CHECK: movgu %icc, %g1, %g2 ! encoding: [0x85,0x67,0x00,0x01]
+ ! CHECK: movleu %icc, %g1, %g2 ! encoding: [0x85,0x65,0x00,0x01]
+ ! CHECK: movcc %icc, %g1, %g2 ! encoding: [0x85,0x67,0x40,0x01]
+ ! CHECK: movcs %icc, %g1, %g2 ! encoding: [0x85,0x65,0x40,0x01]
+ ! CHECK: movpos %icc, %g1, %g2 ! encoding: [0x85,0x67,0x80,0x01]
+ ! CHECK: movneg %icc, %g1, %g2 ! encoding: [0x85,0x65,0x80,0x01]
+ ! CHECK: movvc %icc, %g1, %g2 ! encoding: [0x85,0x67,0xc0,0x01]
+ ! CHECK: movvs %icc, %g1, %g2 ! encoding: [0x85,0x65,0xc0,0x01]
+ movne %icc, %g1, %g2
+ move %icc, %g1, %g2
+ movg %icc, %g1, %g2
+ movle %icc, %g1, %g2
+ movge %icc, %g1, %g2
+ movl %icc, %g1, %g2
+ movgu %icc, %g1, %g2
+ movleu %icc, %g1, %g2
+ movcc %icc, %g1, %g2
+ movcs %icc, %g1, %g2
+ movpos %icc, %g1, %g2
+ movneg %icc, %g1, %g2
+ movvc %icc, %g1, %g2
+ movvs %icc, %g1, %g2
+
+ ! CHECK: movne %xcc, %g1, %g2 ! encoding: [0x85,0x66,0x50,0x01]
+ ! CHECK: move %xcc, %g1, %g2 ! encoding: [0x85,0x64,0x50,0x01]
+ ! CHECK: movg %xcc, %g1, %g2 ! encoding: [0x85,0x66,0x90,0x01]
+ ! CHECK: movle %xcc, %g1, %g2 ! encoding: [0x85,0x64,0x90,0x01]
+ ! CHECK: movge %xcc, %g1, %g2 ! encoding: [0x85,0x66,0xd0,0x01]
+ ! CHECK: movl %xcc, %g1, %g2 ! encoding: [0x85,0x64,0xd0,0x01]
+ ! CHECK: movgu %xcc, %g1, %g2 ! encoding: [0x85,0x67,0x10,0x01]
+ ! CHECK: movleu %xcc, %g1, %g2 ! encoding: [0x85,0x65,0x10,0x01]
+ ! CHECK: movcc %xcc, %g1, %g2 ! encoding: [0x85,0x67,0x50,0x01]
+ ! CHECK: movcs %xcc, %g1, %g2 ! encoding: [0x85,0x65,0x50,0x01]
+ ! CHECK: movpos %xcc, %g1, %g2 ! encoding: [0x85,0x67,0x90,0x01]
+ ! CHECK: movneg %xcc, %g1, %g2 ! encoding: [0x85,0x65,0x90,0x01]
+ ! CHECK: movvc %xcc, %g1, %g2 ! encoding: [0x85,0x67,0xd0,0x01]
+ ! CHECK: movvs %xcc, %g1, %g2 ! encoding: [0x85,0x65,0xd0,0x01]
+ movne %xcc, %g1, %g2
+ move %xcc, %g1, %g2
+ movg %xcc, %g1, %g2
+ movle %xcc, %g1, %g2
+ movge %xcc, %g1, %g2
+ movl %xcc, %g1, %g2
+ movgu %xcc, %g1, %g2
+ movleu %xcc, %g1, %g2
+ movcc %xcc, %g1, %g2
+ movcs %xcc, %g1, %g2
+ movpos %xcc, %g1, %g2
+ movneg %xcc, %g1, %g2
+ movvc %xcc, %g1, %g2
+ movvs %xcc, %g1, %g2
+
+ ! CHECK: movu %fcc0, %g1, %g2 ! encoding: [0x85,0x61,0xc0,0x01]
+ ! CHECK: movg %fcc0, %g1, %g2 ! encoding: [0x85,0x61,0x80,0x01]
+ ! CHECK: movug %fcc0, %g1, %g2 ! encoding: [0x85,0x61,0x40,0x01]
+ ! CHECK: movl %fcc0, %g1, %g2 ! encoding: [0x85,0x61,0x00,0x01]
+ ! CHECK: movul %fcc0, %g1, %g2 ! encoding: [0x85,0x60,0xc0,0x01]
+ ! CHECK: movlg %fcc0, %g1, %g2 ! encoding: [0x85,0x60,0x80,0x01]
+ ! CHECK: movne %fcc0, %g1, %g2 ! encoding: [0x85,0x60,0x40,0x01]
+ ! CHECK: move %fcc0, %g1, %g2 ! encoding: [0x85,0x62,0x40,0x01]
+ ! CHECK: movue %fcc0, %g1, %g2 ! encoding: [0x85,0x62,0x80,0x01]
+ ! CHECK: movge %fcc0, %g1, %g2 ! encoding: [0x85,0x62,0xc0,0x01]
+ ! CHECK: movuge %fcc0, %g1, %g2 ! encoding: [0x85,0x63,0x00,0x01]
+ ! CHECK: movle %fcc0, %g1, %g2 ! encoding: [0x85,0x63,0x40,0x01]
+ ! CHECK: movule %fcc0, %g1, %g2 ! encoding: [0x85,0x63,0x80,0x01]
+ ! CHECK: movo %fcc0, %g1, %g2 ! encoding: [0x85,0x63,0xc0,0x01]
+ movu %fcc0, %g1, %g2
+ movg %fcc0, %g1, %g2
+ movug %fcc0, %g1, %g2
+ movl %fcc0, %g1, %g2
+ movul %fcc0, %g1, %g2
+ movlg %fcc0, %g1, %g2
+ movne %fcc0, %g1, %g2
+ move %fcc0, %g1, %g2
+ movue %fcc0, %g1, %g2
+ movge %fcc0, %g1, %g2
+ movuge %fcc0, %g1, %g2
+ movle %fcc0, %g1, %g2
+ movule %fcc0, %g1, %g2
+ movo %fcc0, %g1, %g2
+
+
+ ! CHECK fmovsne %icc, %f1, %f2 ! encoding: [0x85,0xaa,0x60,0x21]
+ ! CHECK fmovse %icc, %f1, %f2 ! encoding: [0x85,0xa8,0x60,0x21]
+ ! CHECK fmovsg %icc, %f1, %f2 ! encoding: [0x85,0xaa,0xa0,0x21]
+ ! CHECK fmovsle %icc, %f1, %f2 ! encoding: [0x85,0xa8,0xa0,0x21]
+ ! CHECK fmovsge %icc, %f1, %f2 ! encoding: [0x85,0xaa,0xe0,0x21]
+ ! CHECK fmovsl %icc, %f1, %f2 ! encoding: [0x85,0xa8,0xe0,0x21]
+ ! CHECK fmovsgu %icc, %f1, %f2 ! encoding: [0x85,0xab,0x20,0x21]
+ ! CHECK fmovsleu %icc, %f1, %f2 ! encoding: [0x85,0xa9,0x20,0x21]
+ ! CHECK fmovscc %icc, %f1, %f2 ! encoding: [0x85,0xab,0x60,0x21]
+ ! CHECK fmovscs %icc, %f1, %f2 ! encoding: [0x85,0xa9,0x60,0x21]
+ ! CHECK fmovspos %icc, %f1, %f2 ! encoding: [0x85,0xab,0xa0,0x21]
+ ! CHECK fmovsneg %icc, %f1, %f2 ! encoding: [0x85,0xa9,0xa0,0x21]
+ ! CHECK fmovsvc %icc, %f1, %f2 ! encoding: [0x85,0xab,0xe0,0x21]
+ ! CHECK fmovsvs %icc, %f1, %f2 ! encoding: [0x85,0xa9,0xe0,0x21]
+ fmovsne %icc, %f1, %f2
+ fmovse %icc, %f1, %f2
+ fmovsg %icc, %f1, %f2
+ fmovsle %icc, %f1, %f2
+ fmovsge %icc, %f1, %f2
+ fmovsl %icc, %f1, %f2
+ fmovsgu %icc, %f1, %f2
+ fmovsleu %icc, %f1, %f2
+ fmovscc %icc, %f1, %f2
+ fmovscs %icc, %f1, %f2
+ fmovspos %icc, %f1, %f2
+ fmovsneg %icc, %f1, %f2
+ fmovsvc %icc, %f1, %f2
+ fmovsvs %icc, %f1, %f2
+
+ ! CHECK fmovsne %xcc, %f1, %f2 ! encoding: [0x85,0xaa,0x70,0x21]
+ ! CHECK fmovse %xcc, %f1, %f2 ! encoding: [0x85,0xa8,0x70,0x21]
+ ! CHECK fmovsg %xcc, %f1, %f2 ! encoding: [0x85,0xaa,0xb0,0x21]
+ ! CHECK fmovsle %xcc, %f1, %f2 ! encoding: [0x85,0xa8,0xb0,0x21]
+ ! CHECK fmovsge %xcc, %f1, %f2 ! encoding: [0x85,0xaa,0xf0,0x21]
+ ! CHECK fmovsl %xcc, %f1, %f2 ! encoding: [0x85,0xa8,0xf0,0x21]
+ ! CHECK fmovsgu %xcc, %f1, %f2 ! encoding: [0x85,0xab,0x30,0x21]
+ ! CHECK fmovsleu %xcc, %f1, %f2 ! encoding: [0x85,0xa9,0x30,0x21]
+ ! CHECK fmovscc %xcc, %f1, %f2 ! encoding: [0x85,0xab,0x70,0x21]
+ ! CHECK fmovscs %xcc, %f1, %f2 ! encoding: [0x85,0xa9,0x70,0x21]
+ ! CHECK fmovspos %xcc, %f1, %f2 ! encoding: [0x85,0xab,0xb0,0x21]
+ ! CHECK fmovsneg %xcc, %f1, %f2 ! encoding: [0x85,0xa9,0xb0,0x21]
+ ! CHECK fmovsvc %xcc, %f1, %f2 ! encoding: [0x85,0xab,0xf0,0x21]
+ ! CHECK fmovsvs %xcc, %f1, %f2 ! encoding: [0x85,0xa9,0xf0,0x21]
+ fmovsne %xcc, %f1, %f2
+ fmovse %xcc, %f1, %f2
+ fmovsg %xcc, %f1, %f2
+ fmovsle %xcc, %f1, %f2
+ fmovsge %xcc, %f1, %f2
+ fmovsl %xcc, %f1, %f2
+ fmovsgu %xcc, %f1, %f2
+ fmovsleu %xcc, %f1, %f2
+ fmovscc %xcc, %f1, %f2
+ fmovscs %xcc, %f1, %f2
+ fmovspos %xcc, %f1, %f2
+ fmovsneg %xcc, %f1, %f2
+ fmovsvc %xcc, %f1, %f2
+ fmovsvs %xcc, %f1, %f2
+
+ ! CHECK fmovsu %fcc0, %f1, %f2 ! encoding: [0x85,0xa9,0xc0,0x21]
+ ! CHECK fmovsg %fcc0, %f1, %f2 ! encoding: [0x85,0xa9,0x80,0x21]
+ ! CHECK fmovsug %fcc0, %f1, %f2 ! encoding: [0x85,0xa9,0x40,0x21]
+ ! CHECK fmovsl %fcc0, %f1, %f2 ! encoding: [0x85,0xa9,0x00,0x21]
+ ! CHECK fmovsul %fcc0, %f1, %f2 ! encoding: [0x85,0xa8,0xc0,0x21]
+ ! CHECK fmovslg %fcc0, %f1, %f2 ! encoding: [0x85,0xa8,0x80,0x21]
+ ! CHECK fmovsne %fcc0, %f1, %f2 ! encoding: [0x85,0xa8,0x40,0x21]
+ ! CHECK fmovse %fcc0, %f1, %f2 ! encoding: [0x85,0xaa,0x40,0x21]
+ ! CHECK fmovsue %fcc0, %f1, %f2 ! encoding: [0x85,0xaa,0x80,0x21]
+ ! CHECK fmovsge %fcc0, %f1, %f2 ! encoding: [0x85,0xaa,0xc0,0x21]
+ ! CHECK fmovsuge %fcc0, %f1, %f2 ! encoding: [0x85,0xab,0x00,0x21]
+ ! CHECK fmovsle %fcc0, %f1, %f2 ! encoding: [0x85,0xab,0x40,0x21]
+ ! CHECK fmovsule %fcc0, %f1, %f2 ! encoding: [0x85,0xab,0x80,0x21]
+ ! CHECK fmovso %fcc0, %f1, %f2 ! encoding: [0x85,0xab,0xc0,0x21]
+ fmovsu %fcc0, %f1, %f2
+ fmovsg %fcc0, %f1, %f2
+ fmovsug %fcc0, %f1, %f2
+ fmovsl %fcc0, %f1, %f2
+ fmovsul %fcc0, %f1, %f2
+ fmovslg %fcc0, %f1, %f2
+ fmovsne %fcc0, %f1, %f2
+ fmovse %fcc0, %f1, %f2
+ fmovsue %fcc0, %f1, %f2
+ fmovsge %fcc0, %f1, %f2
+ fmovsuge %fcc0, %f1, %f2
+ fmovsle %fcc0, %f1, %f2
+ fmovsule %fcc0, %f1, %f2
+ fmovso %fcc0, %f1, %f2
+
Index: lib/Target/Sparc/SparcInstr64Bit.td
===================================================================
--- lib/Target/Sparc/SparcInstr64Bit.td
+++ lib/Target/Sparc/SparcInstr64Bit.td
@@ -333,32 +333,42 @@ class XBranchSP<dag ins, string asmstr, list<dag>
let Predicates = [Is64Bit] in {
let Uses = [ICC] in
-def BPXCC : XBranchSP<(ins brtarget:$imm22, CCOp:$cond),
- "b$cond %xcc, $imm22",
- [(SPbrxcc bb:$imm22, imm:$cond)]>;
+def BPXCC : XBranchSP<(ins brtarget:$imm19, CCOp:$cond),
+ "b$cond %xcc, $imm19",
+ [(SPbrxcc bb:$imm19, imm:$cond)]>;
// Conditional moves on %xcc.
let Uses = [ICC], Constraints = "$f = $rd" in {
-def MOVXCCrr : Pseudo<(outs IntRegs:$rd),
+let cc = 0b110 in {
+def MOVXCCrr : F4_1<0b101100, (outs IntRegs:$rd),
(ins IntRegs:$rs2, IntRegs:$f, CCOp:$cond),
"mov$cond %xcc, $rs2, $rd",
[(set i32:$rd,
(SPselectxcc i32:$rs2, i32:$f, imm:$cond))]>;
-def MOVXCCri : Pseudo<(outs IntRegs:$rd),
- (ins i32imm:$i, IntRegs:$f, CCOp:$cond),
- "mov$cond %xcc, $i, $rd",
+def MOVXCCri : F4_2<0b101100, (outs IntRegs:$rd),
+ (ins i32imm:$simm11, IntRegs:$f, CCOp:$cond),
+ "mov$cond %xcc, $simm11, $rd",
[(set i32:$rd,
- (SPselectxcc simm11:$i, i32:$f, imm:$cond))]>;
-def FMOVS_XCC : Pseudo<(outs FPRegs:$rd),
+ (SPselectxcc simm11:$simm11, i32:$f, imm:$cond))]>;
+} // cc
+
+let opf_cc = 0b110 in {
+def FMOVS_XCC : F4_3<0b110101, 0b000001, (outs FPRegs:$rd),
(ins FPRegs:$rs2, FPRegs:$f, CCOp:$cond),
"fmovs$cond %xcc, $rs2, $rd",
[(set f32:$rd,
(SPselectxcc f32:$rs2, f32:$f, imm:$cond))]>;
-def FMOVD_XCC : Pseudo<(outs DFPRegs:$rd),
+def FMOVD_XCC : F4_3<0b110101, 0b000010, (outs DFPRegs:$rd),
(ins DFPRegs:$rs2, DFPRegs:$f, CCOp:$cond),
"fmovd$cond %xcc, $rs2, $rd",
[(set f64:$rd,
(SPselectxcc f64:$rs2, f64:$f, imm:$cond))]>;
+def FMOVQ_XCC : F4_3<0b110101, 0b000011, (outs QFPRegs:$rd),
+ (ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond),
+ "fmovq$cond %xcc, $rs2, $rd",
+ [(set f128:$rd,
+ (SPselectxcc f128:$rs2, f128:$f, imm:$cond))]>;
+} // opf_cc
} // Uses, Constraints
//===----------------------------------------------------------------------===//
Index: lib/Target/Sparc/SparcInstrInfo.td
===================================================================
--- lib/Target/Sparc/SparcInstrInfo.td
+++ lib/Target/Sparc/SparcInstrInfo.td
@@ -928,8 +928,9 @@ let Predicates = [HasV9], Constraints = "$f = $rd"
def FMOVQ_ICC
: F4_3<0b110101, 0b000011, (outs QFPRegs:$rd),
(ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond),
- "fmovd$cond %icc, $rs2, $rd",
- [(set f128:$rd, (SPselecticc f128:$rs2, f128:$f, imm:$cond))]>;
+ "fmovq$cond %icc, $rs2, $rd",
+ [(set f128:$rd, (SPselecticc f128:$rs2, f128:$f, imm:$cond))]>,
+ Requires<[HasHardQuad]>;
}
let Uses = [FCC], opf_cc = 0b000 in {
@@ -946,8 +947,9 @@ let Predicates = [HasV9], Constraints = "$f = $rd"
def FMOVQ_FCC
: F4_3<0b110101, 0b000011, (outs QFPRegs:$rd),
(ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond),
- "fmovd$cond %fcc0, $rs2, $rd",
- [(set f128:$rd, (SPselectfcc f128:$rs2, f128:$f, imm:$cond))]>;
+ "fmovq$cond %fcc0, $rs2, $rd",
+ [(set f128:$rd, (SPselectfcc f128:$rs2, f128:$f, imm:$cond))]>,
+ Requires<[HasHardQuad]>;
}
}
@@ -1092,3 +1094,4 @@ def : Pat<(atomic_store ADDRri:$dst, i32:$val), (S
include "SparcInstr64Bit.td"
+include "SparcInstrAliases.td"
Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
===================================================================
--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
+++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
@@ -537,9 +537,29 @@ SparcAsmParser::parseSparcAsmOperand(SparcOperand
Parser.Lex(); // Eat the '%'.
unsigned RegNo;
if (matchRegisterName(Parser.getTok(), RegNo, false, false)) {
+ StringRef name = Parser.getTok().getString();
Parser.Lex(); // Eat the identifier token.
E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
- Op = SparcOperand::CreateReg(RegNo, SparcOperand::rk_None, S, E);
+ switch (RegNo) {
+ default:
+ Op = SparcOperand::CreateReg(RegNo, SparcOperand::rk_None, S, E);
+ break;
+ case Sparc::Y:
+ Op = SparcOperand::CreateToken("%y", S);
+ break;
+
+ case Sparc::ICC:
+ if (name == "xcc")
+ Op = SparcOperand::CreateToken("%xcc", S);
+ else
+ Op = SparcOperand::CreateToken("%icc", S);
+ break;
+
+ case Sparc::FCC:
+ assert(name == "fcc0" && "Cannot handle %fcc other than %fcc0 yet");
+ Op = SparcOperand::CreateToken("%fcc0", S);
+ break;
+ }
break;
}
if (matchSparcAsmModifiers(EVal, E)) {
Index: lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
===================================================================
--- lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
+++ lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
@@ -83,6 +83,17 @@ void SparcInstPrinter::printCCOperand(const MCInst
raw_ostream &O)
{
int CC = (int)MI->getOperand(opNum).getImm();
+ switch (MI->getOpcode()) {
+ default: break;
+ case SP::FBCOND:
+ case SP::MOVFCCrr:
+ case SP::MOVFCCri:
+ case SP::FMOVS_FCC:
+ case SP::FMOVD_FCC:
+ case SP::FMOVQ_FCC: // Make sure CC is a fp conditional flag.
+ CC = (CC < 16) ? (CC + 16) : CC;
+ break;
+ }
O << SPARCCondCodeToString((SPCC::CondCodes)CC);
}
Index: lib/Target/Sparc/SparcInstrAliases.td
===================================================================
--- lib/Target/Sparc/SparcInstrAliases.td
+++ lib/Target/Sparc/SparcInstrAliases.td
@@ -0,0 +1,119 @@
+//===-- SparcInstrAliases.td - Instruction Aliases for Sparc Target -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains instruction aliases for Sparc.
+//===----------------------------------------------------------------------===//
+
+// Instruction aliases for conditional moves.
+
+// mov<cond> <ccreg> rs2, rd
+multiclass cond_mov_alias<string cond, int condVal, string ccreg,
+ Instruction movrr, Instruction movri,
+ Instruction fmovs, Instruction fmovd> {
+
+ // mov<cond> (%icc|%xcc|%fcc0), rs2, rd
+ def : InstAlias<!strconcat(!strconcat(!strconcat("mov", cond), ccreg),
+ ", $rs2, $rd"),
+ (movrr IntRegs:$rd, IntRegs:$rs2, condVal)>;
+
+ // mov<cond> (%icc|%xcc|%fcc0), simm11, rd
+ def : InstAlias<!strconcat(!strconcat(!strconcat("mov", cond), ccreg),
+ ", $simm11, $rd"),
+ (movri IntRegs:$rd, i32imm:$simm11, condVal)>;
+
+ // fmovs<cond> (%icc|%xcc|%fcc0), $rs2, $rd
+ def : InstAlias<!strconcat(!strconcat(!strconcat("fmovs", cond), ccreg),
+ ", $rs2, $rd"),
+ (fmovs FPRegs:$rd, FPRegs:$rs2, condVal)>;
+
+ // fmovd<cond> (%icc|%xcc|%fcc0), $rs2, $rd
+ def : InstAlias<!strconcat(!strconcat(!strconcat("fmovd", cond), ccreg),
+ ", $rs2, $rd"),
+ (fmovd DFPRegs:$rd, DFPRegs:$rs2, condVal)>;
+}
+
+
+// Instruction aliases for integer conditional branches and moves.
+multiclass int_cond_alias<string cond, int condVal> {
+
+ // b<cond> $imm
+ def : InstAlias<!strconcat(!strconcat("b", cond), " $imm"),
+ (BCOND brtarget:$imm, condVal)>;
+
+ // b<cond> %xcc, $imm
+ def : InstAlias<!strconcat(!strconcat("b", cond), " %xcc, $imm"),
+ (BPXCC brtarget:$imm, condVal)>, Requires<[Is64Bit]>;
+
+ defm : cond_mov_alias<cond, condVal, " %icc",
+ MOVICCrr, MOVICCri,
+ FMOVS_ICC, FMOVD_ICC>, Requires<[HasV9]>;
+
+ defm : cond_mov_alias<cond, condVal, " %xcc",
+ MOVXCCrr, MOVXCCri,
+ FMOVS_XCC, FMOVD_XCC>, Requires<[Is64Bit]>;
+
+ // fmovq<cond> (%icc|%xcc), $rs2, $rd
+ def : InstAlias<!strconcat(!strconcat("fmovq", cond), " %icc, $rs2, $rd"),
+ (FMOVQ_ICC QFPRegs:$rd, QFPRegs:$rs2, condVal)>,
+ Requires<[HasV9, HasHardQuad]>;
+ def : InstAlias<!strconcat(!strconcat("fmovq", cond), " %xcc, $rs2, $rd"),
+ (FMOVQ_XCC QFPRegs:$rd, QFPRegs:$rs2, condVal)>,
+ Requires<[Is64Bit, HasHardQuad]>;
+
+}
+
+
+// Instruction aliases for floating point conditional branches and moves.
+multiclass fp_cond_alias<string cond, int condVal> {
+
+ // fb<cond> $imm
+ def : InstAlias<!strconcat(!strconcat("fb", cond), " $imm"),
+ (FBCOND brtarget:$imm, condVal), 0>;
+
+ defm : cond_mov_alias<cond, condVal, " %fcc0",
+ MOVFCCrr, MOVFCCri,
+ FMOVS_FCC, FMOVD_FCC>, Requires<[HasV9]>;
+
+ // fmovq<cond> %fcc0, $rs2, $rd
+ def : InstAlias<!strconcat(!strconcat("fmovq", cond), " %fcc0, $rs2, $rd"),
+ (FMOVQ_ICC QFPRegs:$rd, QFPRegs:$rs2, condVal)>,
+ Requires<[HasV9, HasHardQuad]>;
+}
+
+defm : int_cond_alias<"a", 0b1000>;
+defm : int_cond_alias<"n", 0b0000>;
+defm : int_cond_alias<"ne", 0b1001>;
+defm : int_cond_alias<"e", 0b0001>;
+defm : int_cond_alias<"g", 0b1010>;
+defm : int_cond_alias<"le", 0b0010>;
+defm : int_cond_alias<"ge", 0b1011>;
+defm : int_cond_alias<"l", 0b0011>;
+defm : int_cond_alias<"gu", 0b1100>;
+defm : int_cond_alias<"leu", 0b0100>;
+defm : int_cond_alias<"cc", 0b1101>;
+defm : int_cond_alias<"cs", 0b0101>;
+defm : int_cond_alias<"pos", 0b1110>;
+defm : int_cond_alias<"neg", 0b0110>;
+defm : int_cond_alias<"vc", 0b1111>;
+defm : int_cond_alias<"vs", 0b0111>;
+
+defm : fp_cond_alias<"u", 0b0111>;
+defm : fp_cond_alias<"g", 0b0110>;
+defm : fp_cond_alias<"ug", 0b0101>;
+defm : fp_cond_alias<"l", 0b0100>;
+defm : fp_cond_alias<"ul", 0b0011>;
+defm : fp_cond_alias<"lg", 0b0010>;
+defm : fp_cond_alias<"ne", 0b0001>;
+defm : fp_cond_alias<"e", 0b1001>;
+defm : fp_cond_alias<"ue", 0b1010>;
+defm : fp_cond_alias<"ge", 0b1011>;
+defm : fp_cond_alias<"uge", 0b1100>;
+defm : fp_cond_alias<"le", 0b1101>;
+defm : fp_cond_alias<"ule", 0b1110>;
+defm : fp_cond_alias<"o", 0b1111>;

View File

@ -0,0 +1,19 @@
Pull in r198739 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Correct the mask for fixup_sparc_br19.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
@@ -31,7 +31,7 @@ static unsigned adjustFixupValue(unsigned Kind, ui
case Sparc::fixup_sparc_br22:
return (Value >> 2) & 0x3fffff;
case Sparc::fixup_sparc_br19:
- return (Value >> 2) & 0x1ffff;
+ return (Value >> 2) & 0x7ffff;
case Sparc::fixup_sparc_hi22:
return (Value >> 10) & 0x3fffff;
case Sparc::fixup_sparc_lo10:

View File

@ -0,0 +1,115 @@
Pull in r198740 from upstream llvm trunk (by Venkatraman Govindaraju):
[SparcV9] Rename operands in some sparc64 instructions so that TableGen can encode them correctly.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: test/MC/Sparc/sparc64-alu-instructions.s
===================================================================
--- test/MC/Sparc/sparc64-alu-instructions.s
+++ test/MC/Sparc/sparc64-alu-instructions.s
@@ -0,0 +1,38 @@
+! RUN: llvm-mc %s -triple=sparc64-unknown-linux-gnu -show-encoding | FileCheck %s
+
+ ! CHECK: sllx %g1, %i2, %i0 ! encoding: [0xb1,0x28,0x50,0x1a]
+ sllx %g1, %i2, %i0
+
+ ! CHECK: sllx %g1, 63, %i0 ! encoding: [0xb1,0x28,0x70,0x3f]
+ sllx %g1, 63, %i0
+
+ ! CHECK: srlx %g1, %i2, %i0 ! encoding: [0xb1,0x30,0x50,0x1a]
+ srlx %g1, %i2, %i0
+
+ ! CHECK: srlx %g1, 63, %i0 ! encoding: [0xb1,0x30,0x70,0x3f]
+ srlx %g1, 63, %i0
+
+ ! CHECK: srax %g1, %i2, %i0 ! encoding: [0xb1,0x38,0x50,0x1a]
+ srax %g1, %i2, %i0
+
+ ! CHECK: srax %g1, 63, %i0 ! encoding: [0xb1,0x38,0x70,0x3f]
+ srax %g1, 63, %i0
+
+ ! CHECK: mulx %g1, %i2, %i0 ! encoding: [0xb0,0x48,0x40,0x1a]
+ mulx %g1, %i2, %i0
+
+ ! CHECK: mulx %g1, 63, %i0 ! encoding: [0xb0,0x48,0x60,0x3f]
+ mulx %g1, 63, %i0
+
+ ! CHECK: sdivx %g1, %i2, %i0 ! encoding: [0xb1,0x68,0x40,0x1a]
+ sdivx %g1, %i2, %i0
+
+ ! CHECK: sdivx %g1, 63, %i0 ! encoding: [0xb1,0x68,0x60,0x3f]
+ sdivx %g1, 63, %i0
+
+ ! CHECK: udivx %g1, %i2, %i0 ! encoding: [0xb0,0x68,0x40,0x1a]
+ udivx %g1, %i2, %i0
+
+ ! CHECK: udivx %g1, 63, %i0 ! encoding: [0xb0,0x68,0x60,0x3f]
+ udivx %g1, 63, %i0
+
Index: lib/Target/Sparc/SparcInstr64Bit.td
===================================================================
--- lib/Target/Sparc/SparcInstr64Bit.td
+++ lib/Target/Sparc/SparcInstr64Bit.td
@@ -193,9 +193,9 @@ def MULXrr : F3_1<2, 0b001001,
"mulx $rs1, $rs2, $rd",
[(set i64:$rd, (mul i64:$rs1, i64:$rs2))]>;
def MULXri : F3_2<2, 0b001001,
- (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$i),
- "mulx $rs1, $i, $rd",
- [(set i64:$rd, (mul i64:$rs1, (i64 simm13:$i)))]>;
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$simm13),
+ "mulx $rs1, $simm13, $rd",
+ [(set i64:$rd, (mul i64:$rs1, (i64 simm13:$simm13)))]>;
// Division can trap.
let hasSideEffects = 1 in {
@@ -204,9 +204,9 @@ def SDIVXrr : F3_1<2, 0b101101,
"sdivx $rs1, $rs2, $rd",
[(set i64:$rd, (sdiv i64:$rs1, i64:$rs2))]>;
def SDIVXri : F3_2<2, 0b101101,
- (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$i),
- "sdivx $rs1, $i, $rd",
- [(set i64:$rd, (sdiv i64:$rs1, (i64 simm13:$i)))]>;
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$simm13),
+ "sdivx $rs1, $simm13, $rd",
+ [(set i64:$rd, (sdiv i64:$rs1, (i64 simm13:$simm13)))]>;
def UDIVXrr : F3_1<2, 0b001101,
(outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2),
@@ -213,9 +213,9 @@ def UDIVXrr : F3_1<2, 0b001101,
"udivx $rs1, $rs2, $rd",
[(set i64:$rd, (udiv i64:$rs1, i64:$rs2))]>;
def UDIVXri : F3_2<2, 0b001101,
- (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$i),
- "udivx $rs1, $i, $rd",
- [(set i64:$rd, (udiv i64:$rs1, (i64 simm13:$i)))]>;
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$simm13),
+ "udivx $rs1, $simm13, $rd",
+ [(set i64:$rd, (udiv i64:$rs1, (i64 simm13:$simm13)))]>;
} // hasSideEffects = 1
} // Predicates = [Is64Bit]
Index: lib/Target/Sparc/SparcInstrFormats.td
===================================================================
--- lib/Target/Sparc/SparcInstrFormats.td
+++ lib/Target/Sparc/SparcInstrFormats.td
@@ -193,12 +193,12 @@ class F3_Si<bits<2> opVal, bits<6> op3val, bit xVa
// Define rr and ri shift instructions with patterns.
multiclass F3_S<string OpcStr, bits<6> Op3Val, bit XVal, SDNode OpNode,
ValueType VT, RegisterClass RC> {
- def rr : F3_Sr<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs, IntRegs:$rs2),
- !strconcat(OpcStr, " $rs, $rs2, $rd"),
- [(set VT:$rd, (OpNode VT:$rs, i32:$rs2))]>;
- def ri : F3_Si<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs, i32imm:$shcnt),
- !strconcat(OpcStr, " $rs, $shcnt, $rd"),
- [(set VT:$rd, (OpNode VT:$rs, (i32 imm:$shcnt)))]>;
+ def rr : F3_Sr<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs1, IntRegs:$rs2),
+ !strconcat(OpcStr, " $rs1, $rs2, $rd"),
+ [(set VT:$rd, (OpNode VT:$rs1, i32:$rs2))]>;
+ def ri : F3_Si<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs1, i32imm:$shcnt),
+ !strconcat(OpcStr, " $rs1, $shcnt, $rd"),
+ [(set VT:$rd, (OpNode VT:$rs1, (i32 imm:$shcnt)))]>;
}
class F4<bits<6> op3, dag outs, dag ins, string asmstr, list<dag> pattern>

View File

@ -0,0 +1,236 @@
Pull in r198893 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Multiclass for loads/stores. No functionality change intended.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcInstr64Bit.td
===================================================================
--- lib/Target/Sparc/SparcInstr64Bit.td
+++ lib/Target/Sparc/SparcInstr64Bit.td
@@ -235,14 +235,8 @@ def UDIVXri : F3_2<2, 0b001101,
let Predicates = [Is64Bit] in {
// 64-bit loads.
-def LDXrr : F3_1<3, 0b001011,
- (outs I64Regs:$dst), (ins MEMrr:$addr),
- "ldx [$addr], $dst",
- [(set i64:$dst, (load ADDRrr:$addr))]>;
-def LDXri : F3_2<3, 0b001011,
- (outs I64Regs:$dst), (ins MEMri:$addr),
- "ldx [$addr], $dst",
- [(set i64:$dst, (load ADDRri:$addr))]>;
+defm LDX : Load<"ldx", 0b001011, load, I64Regs, i64>;
+
let mayLoad = 1, isCodeGenOnly = 1, isAsmParserOnly = 1 in
def TLS_LDXrr : F3_1<3, 0b001011,
(outs IntRegs:$dst), (ins MEMrr:$addr, TLSSym:$sym),
@@ -276,24 +270,10 @@ def : Pat<(i64 (extloadi32 ADDRrr:$addr)), (LDrr
def : Pat<(i64 (extloadi32 ADDRri:$addr)), (LDri ADDRri:$addr)>;
// Sign-extending load of i32 into i64 is a new SPARC v9 instruction.
-def LDSWrr : F3_1<3, 0b001000,
- (outs I64Regs:$dst), (ins MEMrr:$addr),
- "ldsw [$addr], $dst",
- [(set i64:$dst, (sextloadi32 ADDRrr:$addr))]>;
-def LDSWri : F3_2<3, 0b001000,
- (outs I64Regs:$dst), (ins MEMri:$addr),
- "ldsw [$addr], $dst",
- [(set i64:$dst, (sextloadi32 ADDRri:$addr))]>;
+defm LDSW : Load<"ldsw", 0b001000, sextloadi32, I64Regs, i64>;
// 64-bit stores.
-def STXrr : F3_1<3, 0b001110,
- (outs), (ins MEMrr:$addr, I64Regs:$rd),
- "stx $rd, [$addr]",
- [(store i64:$rd, ADDRrr:$addr)]>;
-def STXri : F3_2<3, 0b001110,
- (outs), (ins MEMri:$addr, I64Regs:$rd),
- "stx $rd, [$addr]",
- [(store i64:$rd, ADDRri:$addr)]>;
+defm STX : Store<"stx", 0b001110, store, I64Regs, i64>;
// Truncating stores from i64 are identical to the i32 stores.
def : Pat<(truncstorei8 i64:$src, ADDRrr:$addr), (STBrr ADDRrr:$addr, $src)>;
Index: lib/Target/Sparc/SparcInstrInfo.td
===================================================================
--- lib/Target/Sparc/SparcInstrInfo.td
+++ lib/Target/Sparc/SparcInstrInfo.td
@@ -250,6 +250,32 @@ multiclass F3_12np<string OpcStr, bits<6> Op3Val>
!strconcat(OpcStr, " $rs1, $simm13, $rd"), []>;
}
+// Load multiclass - Define both Reg+Reg/Reg+Imm patterns in one shot.
+multiclass Load<string OpcStr, bits<6> Op3Val, SDPatternOperator OpNode,
+ RegisterClass RC, ValueType Ty> {
+ def rr : F3_1<3, Op3Val,
+ (outs RC:$dst), (ins MEMrr:$addr),
+ !strconcat(OpcStr, " [$addr], $dst"),
+ [(set Ty:$dst, (OpNode ADDRrr:$addr))]>;
+ def ri : F3_2<3, Op3Val,
+ (outs RC:$dst), (ins MEMri:$addr),
+ !strconcat(OpcStr, " [$addr], $dst"),
+ [(set Ty:$dst, (OpNode ADDRri:$addr))]>;
+}
+
+// Store multiclass - Define both Reg+Reg/Reg+Imm patterns in one shot.
+multiclass Store<string OpcStr, bits<6> Op3Val, SDPatternOperator OpNode,
+ RegisterClass RC, ValueType Ty> {
+ def rr : F3_1<3, Op3Val,
+ (outs), (ins MEMrr:$addr, RC:$rd),
+ !strconcat(OpcStr, " $rd, [$addr]"),
+ [(OpNode Ty:$rd, ADDRrr:$addr)]>;
+ def ri : F3_2<3, Op3Val,
+ (outs), (ins MEMri:$addr, RC:$rd),
+ !strconcat(OpcStr, " $rd, [$addr]"),
+ [(OpNode Ty:$rd, ADDRri:$addr)]>;
+}
+
//===----------------------------------------------------------------------===//
// Instructions
//===----------------------------------------------------------------------===//
@@ -350,128 +376,28 @@ let isReturn = 1, isTerminator = 1, hasDelaySlot =
}
// Section B.1 - Load Integer Instructions, p. 90
-def LDSBrr : F3_1<3, 0b001001,
- (outs IntRegs:$dst), (ins MEMrr:$addr),
- "ldsb [$addr], $dst",
- [(set i32:$dst, (sextloadi8 ADDRrr:$addr))]>;
-def LDSBri : F3_2<3, 0b001001,
- (outs IntRegs:$dst), (ins MEMri:$addr),
- "ldsb [$addr], $dst",
- [(set i32:$dst, (sextloadi8 ADDRri:$addr))]>;
-def LDSHrr : F3_1<3, 0b001010,
- (outs IntRegs:$dst), (ins MEMrr:$addr),
- "ldsh [$addr], $dst",
- [(set i32:$dst, (sextloadi16 ADDRrr:$addr))]>;
-def LDSHri : F3_2<3, 0b001010,
- (outs IntRegs:$dst), (ins MEMri:$addr),
- "ldsh [$addr], $dst",
- [(set i32:$dst, (sextloadi16 ADDRri:$addr))]>;
-def LDUBrr : F3_1<3, 0b000001,
- (outs IntRegs:$dst), (ins MEMrr:$addr),
- "ldub [$addr], $dst",
- [(set i32:$dst, (zextloadi8 ADDRrr:$addr))]>;
-def LDUBri : F3_2<3, 0b000001,
- (outs IntRegs:$dst), (ins MEMri:$addr),
- "ldub [$addr], $dst",
- [(set i32:$dst, (zextloadi8 ADDRri:$addr))]>;
-def LDUHrr : F3_1<3, 0b000010,
- (outs IntRegs:$dst), (ins MEMrr:$addr),
- "lduh [$addr], $dst",
- [(set i32:$dst, (zextloadi16 ADDRrr:$addr))]>;
-def LDUHri : F3_2<3, 0b000010,
- (outs IntRegs:$dst), (ins MEMri:$addr),
- "lduh [$addr], $dst",
- [(set i32:$dst, (zextloadi16 ADDRri:$addr))]>;
-def LDrr : F3_1<3, 0b000000,
- (outs IntRegs:$dst), (ins MEMrr:$addr),
- "ld [$addr], $dst",
- [(set i32:$dst, (load ADDRrr:$addr))]>;
-def LDri : F3_2<3, 0b000000,
- (outs IntRegs:$dst), (ins MEMri:$addr),
- "ld [$addr], $dst",
- [(set i32:$dst, (load ADDRri:$addr))]>;
+defm LDSB : Load<"ldsb", 0b001001, sextloadi8, IntRegs, i32>;
+defm LDSH : Load<"ldsh", 0b001010, sextloadi16, IntRegs, i32>;
+defm LDUB : Load<"ldub", 0b000001, zextloadi8, IntRegs, i32>;
+defm LDUH : Load<"lduh", 0b000010, zextloadi16, IntRegs, i32>;
+defm LD : Load<"ld", 0b000000, load, IntRegs, i32>;
// Section B.2 - Load Floating-point Instructions, p. 92
-def LDFrr : F3_1<3, 0b100000,
- (outs FPRegs:$dst), (ins MEMrr:$addr),
- "ld [$addr], $dst",
- [(set f32:$dst, (load ADDRrr:$addr))]>;
-def LDFri : F3_2<3, 0b100000,
- (outs FPRegs:$dst), (ins MEMri:$addr),
- "ld [$addr], $dst",
- [(set f32:$dst, (load ADDRri:$addr))]>;
-def LDDFrr : F3_1<3, 0b100011,
- (outs DFPRegs:$dst), (ins MEMrr:$addr),
- "ldd [$addr], $dst",
- [(set f64:$dst, (load ADDRrr:$addr))]>;
-def LDDFri : F3_2<3, 0b100011,
- (outs DFPRegs:$dst), (ins MEMri:$addr),
- "ldd [$addr], $dst",
- [(set f64:$dst, (load ADDRri:$addr))]>;
-def LDQFrr : F3_1<3, 0b100010,
- (outs QFPRegs:$dst), (ins MEMrr:$addr),
- "ldq [$addr], $dst",
- [(set f128:$dst, (load ADDRrr:$addr))]>,
- Requires<[HasV9, HasHardQuad]>;
-def LDQFri : F3_2<3, 0b100010,
- (outs QFPRegs:$dst), (ins MEMri:$addr),
- "ldq [$addr], $dst",
- [(set f128:$dst, (load ADDRri:$addr))]>,
- Requires<[HasV9, HasHardQuad]>;
+defm LDF : Load<"ld", 0b100000, load, FPRegs, f32>;
+defm LDDF : Load<"ldd", 0b100011, load, DFPRegs, f64>;
+defm LDQF : Load<"ldq", 0b100010, load, QFPRegs, f128>,
+ Requires<[HasV9, HasHardQuad]>;
// Section B.4 - Store Integer Instructions, p. 95
-def STBrr : F3_1<3, 0b000101,
- (outs), (ins MEMrr:$addr, IntRegs:$rd),
- "stb $rd, [$addr]",
- [(truncstorei8 i32:$rd, ADDRrr:$addr)]>;
-def STBri : F3_2<3, 0b000101,
- (outs), (ins MEMri:$addr, IntRegs:$rd),
- "stb $rd, [$addr]",
- [(truncstorei8 i32:$rd, ADDRri:$addr)]>;
-def STHrr : F3_1<3, 0b000110,
- (outs), (ins MEMrr:$addr, IntRegs:$rd),
- "sth $rd, [$addr]",
- [(truncstorei16 i32:$rd, ADDRrr:$addr)]>;
-def STHri : F3_2<3, 0b000110,
- (outs), (ins MEMri:$addr, IntRegs:$rd),
- "sth $rd, [$addr]",
- [(truncstorei16 i32:$rd, ADDRri:$addr)]>;
-def STrr : F3_1<3, 0b000100,
- (outs), (ins MEMrr:$addr, IntRegs:$rd),
- "st $rd, [$addr]",
- [(store i32:$rd, ADDRrr:$addr)]>;
-def STri : F3_2<3, 0b000100,
- (outs), (ins MEMri:$addr, IntRegs:$rd),
- "st $rd, [$addr]",
- [(store i32:$rd, ADDRri:$addr)]>;
+defm STB : Store<"stb", 0b000101, truncstorei8, IntRegs, i32>;
+defm STH : Store<"sth", 0b000110, truncstorei16, IntRegs, i32>;
+defm ST : Store<"st", 0b000100, store, IntRegs, i32>;
// Section B.5 - Store Floating-point Instructions, p. 97
-def STFrr : F3_1<3, 0b100100,
- (outs), (ins MEMrr:$addr, FPRegs:$rd),
- "st $rd, [$addr]",
- [(store f32:$rd, ADDRrr:$addr)]>;
-def STFri : F3_2<3, 0b100100,
- (outs), (ins MEMri:$addr, FPRegs:$rd),
- "st $rd, [$addr]",
- [(store f32:$rd, ADDRri:$addr)]>;
-def STDFrr : F3_1<3, 0b100111,
- (outs), (ins MEMrr:$addr, DFPRegs:$rd),
- "std $rd, [$addr]",
- [(store f64:$rd, ADDRrr:$addr)]>;
-def STDFri : F3_2<3, 0b100111,
- (outs), (ins MEMri:$addr, DFPRegs:$rd),
- "std $rd, [$addr]",
- [(store f64:$rd, ADDRri:$addr)]>;
-def STQFrr : F3_1<3, 0b100110,
- (outs), (ins MEMrr:$addr, QFPRegs:$rd),
- "stq $rd, [$addr]",
- [(store f128:$rd, ADDRrr:$addr)]>,
- Requires<[HasV9, HasHardQuad]>;
-def STQFri : F3_2<3, 0b100110,
- (outs), (ins MEMri:$addr, QFPRegs:$rd),
- "stq $rd, [$addr]",
- [(store f128:$rd, ADDRri:$addr)]>,
- Requires<[HasV9, HasHardQuad]>;
+defm STF : Store<"st", 0b100100, store, FPRegs, f32>;
+defm STDF : Store<"std", 0b100111, store, DFPRegs, f64>;
+defm STQF : Store<"stq", 0b100110, store, QFPRegs, f128>,
+ Requires<[HasV9, HasHardQuad]>;
// Section B.9 - SETHI Instruction, p. 104
def SETHIi: F2_1<0b100,

View File

@ -0,0 +1,229 @@
Pull in r198909 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Add support for parsing jmpl instruction and make indirect call and jmp instructions as aliases to jmpl.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
===================================================================
--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
+++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
@@ -453,6 +453,7 @@ parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand
switch (getLexer().getKind()) {
default: return MatchOperand_NoMatch;
+ case AsmToken::Comma:
case AsmToken::RBrac:
case AsmToken::EndOfStatement:
Operands.push_back(SparcOperand::CreateMEMri(BaseReg, 0, S, E));
Index: lib/Target/Sparc/SparcInstrAliases.td
===================================================================
--- lib/Target/Sparc/SparcInstrAliases.td
+++ lib/Target/Sparc/SparcInstrAliases.td
@@ -117,3 +117,14 @@ defm : fp_cond_alias<"uge", 0b1100>;
defm : fp_cond_alias<"le", 0b1101>;
defm : fp_cond_alias<"ule", 0b1110>;
defm : fp_cond_alias<"o", 0b1111>;
+
+
+// Instruction aliases for JMPL.
+
+// jmp addr -> jmpl addr, %g0
+def : InstAlias<"jmp $addr", (JMPLrr G0, MEMrr:$addr)>;
+def : InstAlias<"jmp $addr", (JMPLri G0, MEMri:$addr)>;
+
+// call addr -> jmpl addr, %o7
+def : InstAlias<"call $addr", (JMPLrr O7, MEMrr:$addr)>;
+def : InstAlias<"call $addr", (JMPLri O7, MEMri:$addr)>;
Index: lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
===================================================================
--- lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
+++ lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
@@ -23,6 +23,7 @@
using namespace llvm;
#define GET_INSTRUCTION_NAME
+#define PRINT_ALIAS_INSTR
#include "SparcGenAsmWriter.inc"
void SparcInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const
@@ -33,10 +34,34 @@ void SparcInstPrinter::printRegName(raw_ostream &O
void SparcInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
StringRef Annot)
{
- printInstruction(MI, O);
+ if (!printAliasInstr(MI, O) && !printSparcAliasInstr(MI, O))
+ printInstruction(MI, O);
printAnnotation(O, Annot);
}
+bool SparcInstPrinter::printSparcAliasInstr(const MCInst *MI, raw_ostream &O)
+{
+ switch (MI->getOpcode()) {
+ default: return false;
+ case SP::JMPLrr:
+ case SP::JMPLri: {
+ if (MI->getNumOperands() != 3)
+ return false;
+ if (!MI->getOperand(0).isReg())
+ return false;
+ switch (MI->getOperand(0).getReg()) {
+ default: return false;
+ case SP::G0: // jmp $addr
+ O << "\tjmp "; printMemOperand(MI, 1, O);
+ return true;
+ case SP::O7: // call $addr
+ O << "\tcall "; printMemOperand(MI, 1, O);
+ return true;
+ }
+ }
+ }
+}
+
void SparcInstPrinter::printOperand(const MCInst *MI, int opNum,
raw_ostream &O)
{
Index: lib/Target/Sparc/InstPrinter/SparcInstPrinter.h
===================================================================
--- lib/Target/Sparc/InstPrinter/SparcInstPrinter.h
+++ lib/Target/Sparc/InstPrinter/SparcInstPrinter.h
@@ -29,9 +29,11 @@ class SparcInstPrinter : public MCInstPrinter {
virtual void printRegName(raw_ostream &OS, unsigned RegNo) const;
virtual void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot);
+ bool printSparcAliasInstr(const MCInst *MI, raw_ostream &OS);
// Autogenerated by tblgen.
void printInstruction(const MCInst *MI, raw_ostream &O);
+ bool printAliasInstr(const MCInst *MI, raw_ostream &O);
static const char *getRegisterName(unsigned RegNo);
void printOperand(const MCInst *MI, int opNum, raw_ostream &OS);
Index: lib/Target/Sparc/SparcInstrInfo.td
===================================================================
--- lib/Target/Sparc/SparcInstrInfo.td
+++ lib/Target/Sparc/SparcInstrInfo.td
@@ -362,10 +362,18 @@ let usesCustomInserter = 1, Uses = [FCC] in {
[(set f128:$dst, (SPselectfcc f128:$T, f128:$F, imm:$Cond))]>;
}
+// JMPL Instruction.
+let isTerminator = 1, hasDelaySlot = 1, isBarrier = 1 in {
+ def JMPLrr: F3_1<2, 0b111000, (outs IntRegs:$dst), (ins MEMrr:$addr),
+ "jmpl $addr, $dst", []>;
+ def JMPLri: F3_2<2, 0b111000, (outs IntRegs:$dst), (ins MEMri:$addr),
+ "jmpl $addr, $dst", []>;
+}
// Section A.3 - Synthetic Instructions, p. 85
// special cases of JMPL:
-let isReturn = 1, isTerminator = 1, hasDelaySlot = 1, isBarrier = 1 in {
+let isReturn = 1, isTerminator = 1, hasDelaySlot = 1, isBarrier = 1,
+ isCodeGenOnly = 1 in {
let rd = 0, rs1 = 15 in
def RETL: F3_2<2, 0b111000, (outs), (ins i32imm:$val),
"jmp %o7+$val", [(retflag simm13:$val)]>;
@@ -519,9 +527,8 @@ class BranchSP<dag ins, string asmstr, list<dag> p
}
// Indirect branch instructions.
-let isTerminator = 1, isBarrier = 1,
- hasDelaySlot = 1, isBranch =1,
- isIndirectBranch = 1, rd = 0 in {
+let isTerminator = 1, isBarrier = 1, hasDelaySlot = 1, isBranch =1,
+ isIndirectBranch = 1, rd = 0, isCodeGenOnly = 1 in {
def BINDrr : F3_1<2, 0b111000,
(outs), (ins MEMrr:$ptr),
"jmp $ptr",
@@ -564,15 +571,17 @@ let Uses = [O6],
let Inst{29-0} = disp;
}
- // indirect calls
- def JMPLrr : F3_1<2, 0b111000,
- (outs), (ins MEMrr:$ptr, variable_ops),
- "call $ptr",
- [(call ADDRrr:$ptr)]> { let rd = 15; }
- def JMPLri : F3_2<2, 0b111000,
- (outs), (ins MEMri:$ptr, variable_ops),
- "call $ptr",
- [(call ADDRri:$ptr)]> { let rd = 15; }
+ // indirect calls: special cases of JMPL.
+ let isCodeGenOnly = 1, rd = 15 in {
+ def CALLrr : F3_1<2, 0b111000,
+ (outs), (ins MEMrr:$ptr, variable_ops),
+ "call $ptr",
+ [(call ADDRrr:$ptr)]>;
+ def CALLri : F3_2<2, 0b111000,
+ (outs), (ins MEMri:$ptr, variable_ops),
+ "call $ptr",
+ [(call ADDRri:$ptr)]>;
+ }
}
// Section B.28 - Read State Register Instructions
Index: lib/Target/Sparc/DelaySlotFiller.cpp
===================================================================
--- lib/Target/Sparc/DelaySlotFiller.cpp
+++ lib/Target/Sparc/DelaySlotFiller.cpp
@@ -278,19 +278,19 @@ void Filler::insertCallDefsUses(MachineBasicBlock:
switch(MI->getOpcode()) {
default: llvm_unreachable("Unknown opcode.");
case SP::CALL: break;
- case SP::JMPLrr:
- case SP::JMPLri:
+ case SP::CALLrr:
+ case SP::CALLri:
assert(MI->getNumOperands() >= 2);
const MachineOperand &Reg = MI->getOperand(0);
- assert(Reg.isReg() && "JMPL first operand is not a register.");
- assert(Reg.isUse() && "JMPL first operand is not a use.");
+ assert(Reg.isReg() && "CALL first operand is not a register.");
+ assert(Reg.isUse() && "CALL first operand is not a use.");
RegUses.insert(Reg.getReg());
const MachineOperand &RegOrImm = MI->getOperand(1);
if (RegOrImm.isImm())
break;
- assert(RegOrImm.isReg() && "JMPLrr second operand is not a register.");
- assert(RegOrImm.isUse() && "JMPLrr second operand is not a use.");
+ assert(RegOrImm.isReg() && "CALLrr second operand is not a register.");
+ assert(RegOrImm.isUse() && "CALLrr second operand is not a use.");
RegUses.insert(RegOrImm.getReg());
break;
}
@@ -353,8 +353,8 @@ bool Filler::needsUnimp(MachineBasicBlock::iterato
switch (I->getOpcode()) {
default: llvm_unreachable("Unknown call opcode.");
case SP::CALL: structSizeOpNum = 1; break;
- case SP::JMPLrr:
- case SP::JMPLri: structSizeOpNum = 2; break;
+ case SP::CALLrr:
+ case SP::CALLri: structSizeOpNum = 2; break;
case SP::TLS_CALL: return false;
}
Index: test/MC/Sparc/sparc-ctrl-instructions.s
===================================================================
--- test/MC/Sparc/sparc-ctrl-instructions.s
+++ test/MC/Sparc/sparc-ctrl-instructions.s
@@ -31,6 +31,19 @@
! CHECK-NEXT: ! fixup A - offset: 0, value: %lo(sym), kind: fixup_sparc_lo10
jmp %g1+%lo(sym)
+ ! CHECK: jmpl %g1+%i2, %g2 ! encoding: [0x85,0xc0,0x40,0x1a]
+ jmpl %g1 + %i2, %g2
+
+ ! CHECK: jmpl %o1+8, %g2 ! encoding: [0x85,0xc2,0x60,0x08]
+ jmpl %o1 + 8, %g2
+
+ ! CHECK: jmpl %g1, %g2 ! encoding: [0x85,0xc0,0x60,0x00]
+ jmpl %g1, %g2
+
+ ! CHECK: jmpl %g1+%lo(sym), %g2 ! encoding: [0x85,0xc0,0b011000AA,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: %lo(sym), kind: fixup_sparc_lo10
+ jmpl %g1+%lo(sym), %g2
+
! CHECK: ba .BB0 ! encoding: [0x10,0b10AAAAAA,A,A]
! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22
ba .BB0

View File

@ -0,0 +1,463 @@
Pull in r198910 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Emit retl/ret instead of jmp instruction. It improves the readability of the assembly generated.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: test/CodeGen/SPARC/ctpop.ll
===================================================================
--- test/CodeGen/SPARC/ctpop.ll
+++ test/CodeGen/SPARC/ctpop.ll
@@ -9,12 +9,12 @@ declare i32 @llvm.ctpop.i32(i32)
; V9-LABEL: test
; V9: srl %o0, 0, %o0
-; V9-NEXT: jmp %o7+8
+; V9-NEXT: retl
; V9-NEXT: popc %o0, %o0
; SPARC64-LABEL: test
; SPARC64: srl %o0, 0, %o0
-; SPARC64: jmp %o7+8
+; SPARC64: retl
; SPARC64: popc %o0, %o0
define i32 @test(i32 %X) {
Index: test/CodeGen/SPARC/2011-01-11-Call.ll
===================================================================
--- test/CodeGen/SPARC/2011-01-11-Call.ll
+++ test/CodeGen/SPARC/2011-01-11-Call.ll
@@ -8,7 +8,7 @@
; V8-NEXT: nop
; V8: call bar
; V8-NEXT: nop
-; V8: jmp %i7+8
+; V8: ret
; V8-NEXT: restore
; V9-LABEL: test
@@ -17,7 +17,7 @@
; V9-NEXT: nop
; V9: call bar
; V9-NEXT: nop
-; V9: jmp %i7+8
+; V9: ret
; V9-NEXT: restore
define void @test() nounwind {
@@ -36,7 +36,7 @@ declare void @bar(...)
; V8: save %sp
; V8: call foo
; V8-NEXT: nop
-; V8: jmp %i7+8
+; V8: ret
; V8-NEXT: restore %g0, %o0, %o0
; V9-LABEL: test_tail_call_with_return
@@ -43,7 +43,7 @@ declare void @bar(...)
; V9: save %sp
; V9: call foo
; V9-NEXT: nop
-; V9: jmp %i7+8
+; V9: ret
; V9-NEXT: restore %g0, %o0, %o0
define i32 @test_tail_call_with_return() nounwind {
Index: test/CodeGen/SPARC/leafproc.ll
===================================================================
--- test/CodeGen/SPARC/leafproc.ll
+++ test/CodeGen/SPARC/leafproc.ll
@@ -1,7 +1,7 @@
; RUN: llc -march=sparc -disable-sparc-leaf-proc=0 < %s | FileCheck %s
; CHECK-LABEL: func_nobody:
-; CHECK: jmp %o7+8
+; CHECK: retl
; CHECK-NEXT: nop
define void @func_nobody() {
entry:
@@ -10,7 +10,7 @@ entry:
; CHECK-LABEL: return_int_const:
-; CHECK: jmp %o7+8
+; CHECK: retl
; CHECK-NEXT: or %g0, 1729, %o0
define i32 @return_int_const() {
entry:
@@ -19,7 +19,7 @@ entry:
; CHECK-LABEL: return_double_const:
; CHECK: sethi
-; CHECK: jmp %o7+8
+; CHECK: retl
; CHECK-NEXT: ldd {{.*}}, %f0
define double @return_double_const() {
@@ -29,7 +29,7 @@ entry:
; CHECK-LABEL: leaf_proc_with_args:
; CHECK: add {{%o[0-1]}}, {{%o[0-1]}}, [[R:%[go][0-7]]]
-; CHECK: jmp %o7+8
+; CHECK: retl
; CHECK-NEXT: add [[R]], %o2, %o0
define i32 @leaf_proc_with_args(i32 %a, i32 %b, i32 %c) {
@@ -42,7 +42,7 @@ entry:
; CHECK-LABEL: leaf_proc_with_args_in_stack:
; CHECK-DAG: ld [%sp+92], {{%[go][0-7]}}
; CHECK-DAG: ld [%sp+96], {{%[go][0-7]}}
-; CHECK: jmp %o7+8
+; CHECK: retl
; CHECK-NEXT: add {{.*}}, %o0
define i32 @leaf_proc_with_args_in_stack(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h) {
entry:
@@ -63,7 +63,7 @@ entry:
; CHECK: or %g0, 2, [[R2:%[go][0-7]]]
; CHECK: st [[R2]], [%sp+100]
; CHECK: ld {{.+}}, %o0
-; CHECK: jmp %o7+8
+; CHECK: retl
; CHECK-NEXT: add %sp, 104, %sp
define i32 @leaf_proc_with_local_array(i32 %a, i32 %b, i32 %c) {
Index: test/CodeGen/SPARC/fp128.ll
===================================================================
--- test/CodeGen/SPARC/fp128.ll
+++ test/CodeGen/SPARC/fp128.ll
@@ -45,7 +45,7 @@ entry:
; HARD: std %f{{.+}}, [%[[S1:.+]]]
; HARD-DAG: ldd [%[[S0]]], %f{{.+}}
; HARD-DAG: ldd [%[[S1]]], %f{{.+}}
-; HARD: jmp
+; HARD: jmp %o7+12
; SOFT-LABEL: f128_spill
; SOFT: std %f{{.+}}, [%[[S0:.+]]]
@@ -52,7 +52,7 @@ entry:
; SOFT: std %f{{.+}}, [%[[S1:.+]]]
; SOFT-DAG: ldd [%[[S0]]], %f{{.+}}
; SOFT-DAG: ldd [%[[S1]]], %f{{.+}}
-; SOFT: jmp
+; SOFT: jmp %o7+12
define void @f128_spill(fp128* noalias sret %scalar.result, fp128* byval %a) {
entry:
@@ -132,13 +132,13 @@ entry:
; HARD: ldub
; HARD: faddq
; HARD: stb
-; HARD: jmp
+; HARD: ret
; SOFT-LABEL: fp128_unaligned
; SOFT: ldub
; SOFT: call _Q_add
; SOFT: stb
-; SOFT: jmp
+; SOFT: ret
define void @fp128_unaligned(fp128* %a, fp128* %b, fp128* %c) {
entry:
Index: test/CodeGen/SPARC/2011-01-11-FrameAddr.ll
===================================================================
--- test/CodeGen/SPARC/2011-01-11-FrameAddr.ll
+++ test/CodeGen/SPARC/2011-01-11-FrameAddr.ll
@@ -9,18 +9,18 @@ define i8* @frameaddr() nounwind readnone {
entry:
;V8-LABEL: frameaddr:
;V8: save %sp, -96, %sp
-;V8: jmp %i7+8
+;V8: ret
;V8: restore %g0, %fp, %o0
;V9-LABEL: frameaddr:
;V9: save %sp, -96, %sp
-;V9: jmp %i7+8
+;V9: ret
;V9: restore %g0, %fp, %o0
;SPARC64-LABEL: frameaddr
;SPARC64: save %sp, -128, %sp
;SPARC64: add %fp, 2047, %i0
-;SPARC64: jmp %i7+8
+;SPARC64: ret
;SPARC64: restore %g0, %g0, %g0
%0 = tail call i8* @llvm.frameaddress(i32 0)
Index: test/CodeGen/SPARC/constpool.ll
===================================================================
--- test/CodeGen/SPARC/constpool.ll
+++ test/CodeGen/SPARC/constpool.ll
@@ -12,7 +12,7 @@ entry:
; abs32: floatCP
; abs32: sethi %hi(.LCPI0_0), %[[R:[gilo][0-7]]]
-; abs32: jmp %o7+8
+; abs32: retl
; abs32: ld [%[[R]]+%lo(.LCPI0_0)], %f
@@ -20,7 +20,7 @@ entry:
; abs44: sethi %h44(.LCPI0_0), %[[R1:[gilo][0-7]]]
; abs44: add %[[R1]], %m44(.LCPI0_0), %[[R2:[gilo][0-7]]]
; abs44: sllx %[[R2]], 12, %[[R3:[gilo][0-7]]]
-; abs44: jmp %o7+8
+; abs44: retl
; abs44: ld [%[[R3]]+%l44(.LCPI0_0)], %f1
@@ -30,7 +30,7 @@ entry:
; abs64: sethi %hh(.LCPI0_0), %[[R3:[gilo][0-7]]]
; abs64: add %[[R3]], %hm(.LCPI0_0), %[[R4:[gilo][0-7]]]
; abs64: sllx %[[R4]], 32, %[[R5:[gilo][0-7]]]
-; abs64: jmp %o7+8
+; abs64: retl
; abs64: ld [%[[R5]]+%[[R2]]], %f1
@@ -40,7 +40,7 @@ entry:
; v8pic32: add %[[R1]], %lo(.LCPI0_0), %[[Goffs:[gilo][0-7]]]
; v8pic32: ld [%[[GOT:[gilo][0-7]]]+%[[Goffs]]], %[[Gaddr:[gilo][0-7]]]
; v8pic32: ld [%[[Gaddr]]], %f0
-; v8pic32: jmp %i7+8
+; v8pic32: ret
; v8pic32: restore
@@ -51,7 +51,7 @@ entry:
; v9pic32: add %[[R1]], %lo(.LCPI0_0), %[[Goffs:[gilo][0-7]]]
; v9pic32: ldx [%[[GOT:[gilo][0-7]]]+%[[Goffs]]], %[[Gaddr:[gilo][0-7]]]
; v9pic32: ld [%[[Gaddr]]], %f1
-; v9pic32: jmp %i7+8
+; v9pic32: ret
; v9pic32: restore
Index: test/CodeGen/SPARC/globals.ll
===================================================================
--- test/CodeGen/SPARC/globals.ll
+++ test/CodeGen/SPARC/globals.ll
@@ -14,7 +14,7 @@ define zeroext i8 @loadG() {
; abs32: loadG
; abs32: sethi %hi(G), %[[R:[gilo][0-7]]]
-; abs32: jmp %o7+8
+; abs32: retl
; abs32: ldub [%[[R]]+%lo(G)], %o0
@@ -22,7 +22,7 @@ define zeroext i8 @loadG() {
; abs44: sethi %h44(G), %[[R1:[gilo][0-7]]]
; abs44: add %[[R1]], %m44(G), %[[R2:[gilo][0-7]]]
; abs44: sllx %[[R2]], 12, %[[R3:[gilo][0-7]]]
-; abs44: jmp %o7+8
+; abs44: retl
; abs44: ldub [%[[R3]]+%l44(G)], %o0
@@ -32,7 +32,7 @@ define zeroext i8 @loadG() {
; abs64: sethi %hh(G), %[[R3:[gilo][0-7]]]
; abs64: add %[[R3]], %hm(G), %[[R4:[gilo][0-7]]]
; abs64: sllx %[[R4]], 32, %[[R5:[gilo][0-7]]]
-; abs64: jmp %o7+8
+; abs64: retl
; abs64: ldub [%[[R5]]+%[[R2]]], %o0
@@ -42,7 +42,7 @@ define zeroext i8 @loadG() {
; v8pic32: add %[[R1]], %lo(G), %[[Goffs:[gilo][0-7]]]
; v8pic32: ld [%[[GOT:[gilo][0-7]]]+%[[Goffs]]], %[[Gaddr:[gilo][0-7]]]
; v8pic32: ldub [%[[Gaddr]]], %i0
-; v8pic32: jmp %i7+8
+; v8pic32: ret
; v8pic32: restore
@@ -52,6 +52,6 @@ define zeroext i8 @loadG() {
; v9pic32: add %[[R1]], %lo(G), %[[Goffs:[gilo][0-7]]]
; v9pic32: ldx [%[[GOT:[gilo][0-7]]]+%[[Goffs]]], %[[Gaddr:[gilo][0-7]]]
; v9pic32: ldub [%[[Gaddr]]], %i0
-; v9pic32: jmp %i7+8
+; v9pic32: ret
; v9pic32: restore
Index: test/CodeGen/SPARC/rem.ll
===================================================================
--- test/CodeGen/SPARC/rem.ll
+++ test/CodeGen/SPARC/rem.ll
@@ -3,7 +3,7 @@
; CHECK-LABEL: test1:
; CHECK: sdivx %o0, %o1, %o2
; CHECK-NEXT: mulx %o2, %o1, %o1
-; CHECK-NEXT: jmp %o7+8
+; CHECK-NEXT: retl
; CHECK-NEXT: sub %o0, %o1, %o0
define i64 @test1(i64 %X, i64 %Y) {
@@ -14,7 +14,7 @@ define i64 @test1(i64 %X, i64 %Y) {
; CHECK-LABEL: test2:
; CHECK: udivx %o0, %o1, %o2
; CHECK-NEXT: mulx %o2, %o1, %o1
-; CHECK-NEXT: jmp %o7+8
+; CHECK-NEXT: retl
; CHECK-NEXT: sub %o0, %o1, %o0
define i64 @test2(i64 %X, i64 %Y) {
Index: test/CodeGen/SPARC/2011-01-19-DelaySlot.ll
===================================================================
--- test/CodeGen/SPARC/2011-01-19-DelaySlot.ll
+++ test/CodeGen/SPARC/2011-01-19-DelaySlot.ll
@@ -7,7 +7,7 @@ entry:
; CHECK: test
; CHECK: call bar
; CHECK-NOT: nop
-; CHECK: jmp
+; CHECK: ret
; CHECK-NEXT: restore
%0 = tail call i32 @bar(i32 %a) nounwind
ret i32 %0
@@ -18,7 +18,7 @@ entry:
; CHECK: test_jmpl
; CHECK: call
; CHECK-NOT: nop
-; CHECK: jmp
+; CHECK: ret
; CHECK-NEXT: restore
%0 = tail call i32 %f(i32 %a, i32 %b) nounwind
ret i32 %0
@@ -47,7 +47,7 @@ bb:
bb5: ; preds = %bb, %entry
%a_addr.1.lcssa = phi i32 [ %a, %entry ], [ %a_addr.0, %bb ]
-;CHECK: jmp
+;CHECK: retl
;CHECK-NOT: restore
ret i32 %a_addr.1.lcssa
}
@@ -110,7 +110,7 @@ declare i32 @func(i32*)
define i32 @restore_add(i32 %a, i32 %b) {
entry:
;CHECK-LABEL: restore_add:
-;CHECK: jmp %i7+8
+;CHECK: ret
;CHECK: restore %o0, %i1, %o0
%0 = tail call i32 @bar(i32 %a) nounwind
%1 = add nsw i32 %0, %b
@@ -120,7 +120,7 @@ entry:
define i32 @restore_add_imm(i32 %a) {
entry:
;CHECK-LABEL: restore_add_imm:
-;CHECK: jmp %i7+8
+;CHECK: ret
;CHECK: restore %o0, 20, %o0
%0 = tail call i32 @bar(i32 %a) nounwind
%1 = add nsw i32 %0, 20
@@ -130,7 +130,7 @@ entry:
define i32 @restore_or(i32 %a) {
entry:
;CHECK-LABEL: restore_or:
-;CHECK: jmp %i7+8
+;CHECK: ret
;CHECK: restore %g0, %o0, %o0
%0 = tail call i32 @bar(i32 %a) nounwind
ret i32 %0
@@ -140,7 +140,7 @@ define i32 @restore_or_imm(i32 %a) {
entry:
;CHECK-LABEL: restore_or_imm:
;CHECK: or %o0, 20, %i0
-;CHECK: jmp %i7+8
+;CHECK: ret
;CHECK: restore %g0, %g0, %g0
%0 = tail call i32 @bar(i32 %a) nounwind
%1 = or i32 %0, 20
Index: test/CodeGen/SPARC/64bit.ll
===================================================================
--- test/CodeGen/SPARC/64bit.ll
+++ test/CodeGen/SPARC/64bit.ll
@@ -5,7 +5,7 @@
; CHECK: or %g0, %i1, %i0
; OPT-LABEL: ret2:
-; OPT: jmp %o7+8
+; OPT: retl
; OPT: or %g0, %o1, %o0
define i64 @ret2(i64 %a, i64 %b) {
ret i64 %b
@@ -15,7 +15,7 @@ define i64 @ret2(i64 %a, i64 %b) {
; CHECK: sllx %i0, 7, %i0
; OPT-LABEL: shl_imm:
-; OPT: jmp %o7+8
+; OPT: retl
; OPT: sllx %o0, 7, %o0
define i64 @shl_imm(i64 %a) {
%x = shl i64 %a, 7
@@ -26,7 +26,7 @@ define i64 @shl_imm(i64 %a) {
; CHECK: srax %i0, %i1, %i0
; OPT-LABEL: sra_reg:
-; OPT: jmp %o7+8
+; OPT: retl
; OPT: srax %o0, %o1, %o0
define i64 @sra_reg(i64 %a, i64 %b) {
%x = ashr i64 %a, %b
@@ -42,7 +42,7 @@ define i64 @sra_reg(i64 %a, i64 %b) {
; CHECK: or %g0, 0, %i0
; OPT: ret_imm0
-; OPT: jmp %o7+8
+; OPT: retl
; OPT: or %g0, 0, %o0
define i64 @ret_imm0() {
ret i64 0
@@ -52,7 +52,7 @@ define i64 @ret_imm0() {
; CHECK: or %g0, -4096, %i0
; OPT: ret_simm13
-; OPT: jmp %o7+8
+; OPT: retl
; OPT: or %g0, -4096, %o0
define i64 @ret_simm13() {
ret i64 -4096
@@ -64,7 +64,7 @@ define i64 @ret_simm13() {
; CHECK: restore
; OPT: ret_sethi
-; OPT: jmp %o7+8
+; OPT: retl
; OPT: sethi 4, %o0
define i64 @ret_sethi() {
ret i64 4096
@@ -76,7 +76,7 @@ define i64 @ret_sethi() {
; OPT: ret_sethi_or
; OPT: sethi 4, [[R:%[go][0-7]]]
-; OPT: jmp %o7+8
+; OPT: retl
; OPT: or [[R]], 1, %o0
define i64 @ret_sethi_or() {
@@ -89,7 +89,7 @@ define i64 @ret_sethi_or() {
; OPT: ret_nimm33
; OPT: sethi 4, [[R:%[go][0-7]]]
-; OPT: jmp %o7+8
+; OPT: retl
; OPT: xor [[R]], -4, %o0
define i64 @ret_nimm33() {
Index: lib/Target/Sparc/SparcInstrAliases.td
===================================================================
--- lib/Target/Sparc/SparcInstrAliases.td
+++ lib/Target/Sparc/SparcInstrAliases.td
@@ -128,3 +128,9 @@ def : InstAlias<"jmp $addr", (JMPLri G0, MEMri:$ad
// call addr -> jmpl addr, %o7
def : InstAlias<"call $addr", (JMPLrr O7, MEMrr:$addr)>;
def : InstAlias<"call $addr", (JMPLri O7, MEMri:$addr)>;
+
+// retl -> RETL 8
+def : InstAlias<"retl", (RETL 8)>;
+
+// ret -> RET 8
+def : InstAlias<"ret", (RET 8)>;

View File

@ -0,0 +1,133 @@
Pull in r199014 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Bundle instruction with delay slow and its filler. Now, we can use -verify-machineinstrs with SPARC backend.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/DelaySlotFiller.cpp
===================================================================
--- lib/Target/Sparc/DelaySlotFiller.cpp
+++ lib/Target/Sparc/DelaySlotFiller.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
@@ -55,6 +56,11 @@ namespace {
bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
bool runOnMachineFunction(MachineFunction &F) {
bool Changed = false;
+
+ // This pass invalidates liveness information when it reorders
+ // instructions to fill delay slot.
+ F.getRegInfo().invalidateLiveness();
+
for (MachineFunction::iterator FI = F.begin(), FE = F.end();
FI != FE; ++FI)
Changed |= runOnMachineBasicBlock(*FI);
@@ -61,9 +67,6 @@ namespace {
return Changed;
}
- bool isDelayFiller(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator candidate);
-
void insertCallDefsUses(MachineBasicBlock::iterator MI,
SmallSet<unsigned, 32>& RegDefs,
SmallSet<unsigned, 32>& RegUses);
@@ -152,6 +155,10 @@ bool Filler::runOnMachineBasicBlock(MachineBasicBl
assert (J != MBB.end() && "MI needs a delay instruction.");
BuildMI(MBB, ++J, MI->getDebugLoc(),
TII->get(SP::UNIMP)).addImm(structSize);
+ // Bundle the delay filler and unimp with the instruction.
+ MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), J);
+ } else {
+ MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), I);
}
}
return Changed;
@@ -209,7 +216,7 @@ Filler::findDelayInstr(MachineBasicBlock &MBB,
|| I->isInlineAsm()
|| I->isLabel()
|| I->hasDelaySlot()
- || isDelayFiller(MBB, I))
+ || I->isBundledWithSucc())
break;
if (delayHasHazard(I, sawLoad, sawStore, RegDefs, RegUses)) {
@@ -332,18 +339,6 @@ bool Filler::IsRegInSet(SmallSet<unsigned, 32>& Re
return false;
}
-// return true if the candidate is a delay filler.
-bool Filler::isDelayFiller(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator candidate)
-{
- if (candidate == MBB.begin())
- return false;
- if (candidate->getOpcode() == SP::UNIMP)
- return true;
- --candidate;
- return candidate->hasDelaySlot();
-}
-
bool Filler::needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize)
{
if (!I->isCall())
@@ -484,10 +479,10 @@ bool Filler::tryCombineRestoreWithPrevInst(Machine
&& MBBI->getOperand(1).getReg() == SP::G0
&& MBBI->getOperand(2).getReg() == SP::G0);
- MachineBasicBlock::iterator PrevInst = MBBI; --PrevInst;
+ MachineBasicBlock::iterator PrevInst = llvm::prior(MBBI);
- // It cannot combine with a delay filler.
- if (isDelayFiller(MBB, PrevInst))
+ // It cannot be combined with a bundled instruction.
+ if (PrevInst->isBundledWithSucc())
return false;
const TargetInstrInfo *TII = TM.getInstrInfo();
Index: lib/Target/Sparc/SparcAsmPrinter.cpp
===================================================================
--- lib/Target/Sparc/SparcAsmPrinter.cpp
+++ lib/Target/Sparc/SparcAsmPrinter.cpp
@@ -184,7 +184,6 @@ static void LowerGETPCXAndEmitMCInsts(const Machin
void SparcAsmPrinter::EmitInstruction(const MachineInstr *MI)
{
- MCInst TmpInst;
switch (MI->getOpcode()) {
default: break;
@@ -195,8 +194,13 @@ void SparcAsmPrinter::EmitInstruction(const Machin
LowerGETPCXAndEmitMCInsts(MI, OutStreamer, OutContext);
return;
}
- LowerSparcMachineInstrToMCInst(MI, TmpInst, *this);
- OutStreamer.EmitInstruction(TmpInst);
+ MachineBasicBlock::const_instr_iterator I = MI;
+ MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
+ do {
+ MCInst TmpInst;
+ LowerSparcMachineInstrToMCInst(I, TmpInst, *this);
+ OutStreamer.EmitInstruction(TmpInst);
+ } while ((++I != E) && I->isInsideBundle()); // Delay slot check.
}
void SparcAsmPrinter::EmitFunctionBodyStart() {
Index: test/CodeGen/SPARC/2011-01-19-DelaySlot.ll
===================================================================
--- test/CodeGen/SPARC/2011-01-19-DelaySlot.ll
+++ test/CodeGen/SPARC/2011-01-19-DelaySlot.ll
@@ -1,5 +1,5 @@
-;RUN: llc -march=sparc < %s | FileCheck %s
-;RUN: llc -march=sparc -O0 < %s | FileCheck %s -check-prefix=UNOPT
+;RUN: llc -march=sparc < %s -verify-machineinstrs | FileCheck %s
+;RUN: llc -march=sparc -O0 < %s -verify-machineinstrs | FileCheck %s -check-prefix=UNOPT
define i32 @test(i32 %a) nounwind {

View File

@ -0,0 +1,69 @@
Pull in r199024 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Add missing processor types: v7 and niagara
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/Sparc.td
===================================================================
--- lib/Target/Sparc/Sparc.td
+++ lib/Target/Sparc/Sparc.td
@@ -56,6 +56,7 @@ class Proc<string Name, list<SubtargetFeature> Fea
: Processor<Name, NoItineraries, Features>;
def : Proc<"generic", []>;
+def : Proc<"v7", []>;
def : Proc<"v8", []>;
def : Proc<"supersparc", []>;
def : Proc<"sparclite", []>;
@@ -67,7 +68,10 @@ def : Proc<"tsc701", []>;
def : Proc<"v9", [FeatureV9]>;
def : Proc<"ultrasparc", [FeatureV9, FeatureV8Deprecated]>;
def : Proc<"ultrasparc3", [FeatureV9, FeatureV8Deprecated]>;
-def : Proc<"ultrasparc3-vis", [FeatureV9, FeatureV8Deprecated, FeatureVIS]>;
+def : Proc<"niagara", [FeatureV9, FeatureV8Deprecated]>;
+def : Proc<"niagara2", [FeatureV9, FeatureV8Deprecated]>;
+def : Proc<"niagara3", [FeatureV9, FeatureV8Deprecated]>;
+def : Proc<"niagara4", [FeatureV9, FeatureV8Deprecated]>;
def SparcAsmWriter : AsmWriter {
string AsmWriterClassName = "InstPrinter";
Index: lib/Target/Sparc/SparcSubtarget.cpp
===================================================================
--- lib/Target/Sparc/SparcSubtarget.cpp
+++ lib/Target/Sparc/SparcSubtarget.cpp
@@ -35,13 +35,8 @@ SparcSubtarget::SparcSubtarget(const std::string &
// Determine default and user specified characteristics
std::string CPUName = CPU;
- if (CPUName.empty()) {
- if (is64Bit)
- CPUName = "v9";
- else
- CPUName = "v8";
- }
- IsV9 = CPUName == "v9";
+ if (CPUName.empty())
+ CPUName = (is64Bit) ? "v9" : "v8";
// Parse features string.
ParseSubtargetFeatures(CPUName, FS);
Index: test/CodeGen/SPARC/ctpop.ll
===================================================================
--- test/CodeGen/SPARC/ctpop.ll
+++ test/CodeGen/SPARC/ctpop.ll
@@ -1,6 +1,13 @@
; RUN: llc < %s -march=sparc -mattr=-v9 | FileCheck %s -check-prefix=V8
; RUN: llc < %s -march=sparc -mattr=+v9 | FileCheck %s -check-prefix=V9
-; RUN: llc < %s -march=sparcv9 | FileCheck %s -check-prefix=SPARC64
+; RUN: llc < %s -march=sparc -mcpu=v9 | FileCheck %s -check-prefix=V9
+; RUN: llc < %s -march=sparc -mcpu=ultrasparc | FileCheck %s -check-prefix=V9
+; RUN: llc < %s -march=sparc -mcpu=ultrasparc3 | FileCheck %s -check-prefix=V9
+; RUN: llc < %s -march=sparc -mcpu=niagara | FileCheck %s -check-prefix=V9
+; RUN: llc < %s -march=sparc -mcpu=niagara2 | FileCheck %s -check-prefix=V9
+; RUN: llc < %s -march=sparc -mcpu=niagara3 | FileCheck %s -check-prefix=V9
+; RUN: llc < %s -march=sparc -mcpu=niagara4 | FileCheck %s -check-prefix=V9
+; RUN: llc < %s -march=sparcv9 | FileCheck %s -check-prefix=SPARC64
declare i32 @llvm.ctpop.i32(i32)

View File

@ -0,0 +1,147 @@
Pull in r199028 from upstream llvm trunk (by Jakob Stoklund Olesen):
The SPARCv9 ABI returns a float in %f0.
This is different from the argument passing convention which puts the
first float argument in %f1.
With this patch, all returned floats are treated as if the 'inreg' flag
were set. This means multiple float return values get packed in %f0,
%f1, %f2, ...
Note that when returning a struct in registers, clang will set the
'inreg' flag on the return value, so that behavior is unchanged. This
also happens when returning a float _Complex.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: test/CodeGen/SPARC/64abi.ll
===================================================================
--- test/CodeGen/SPARC/64abi.ll
+++ test/CodeGen/SPARC/64abi.ll
@@ -180,7 +180,7 @@ define void @call_inreg_fi(i32* %p, i32 %i1, float
}
; CHECK: inreg_ff
-; CHECK: fsubs %f0, %f1, %f1
+; CHECK: fsubs %f0, %f1, %f0
define float @inreg_ff(float inreg %a0, ; %f0
float inreg %a1) { ; %f1
%rv = fsub float %a0, %a1
@@ -262,10 +262,10 @@ define void @call_ret_i64_pair(i64* %i0) {
ret void
}
-; This is not a C struct, each member uses 8 bytes.
+; This is not a C struct, the i32 member uses 8 bytes, but the float only 4.
; CHECK: ret_i32_float_pair
; CHECK: ld [%i2], %i0
-; CHECK: ld [%i3], %f3
+; CHECK: ld [%i3], %f2
define { i32, float } @ret_i32_float_pair(i32 %a0, i32 %a1,
i32* %p, float* %q) {
%r1 = load i32* %p
@@ -279,7 +279,7 @@ define { i32, float } @ret_i32_float_pair(i32 %a0,
; CHECK: call_ret_i32_float_pair
; CHECK: call ret_i32_float_pair
; CHECK: st %o0, [%i0]
-; CHECK: st %f3, [%i1]
+; CHECK: st %f2, [%i1]
define void @call_ret_i32_float_pair(i32* %i0, float* %i1) {
%rv = call { i32, float } @ret_i32_float_pair(i32 undef, i32 undef,
i32* undef, float* undef)
Index: test/CodeGen/SPARC/constpool.ll
===================================================================
--- test/CodeGen/SPARC/constpool.ll
+++ test/CodeGen/SPARC/constpool.ll
@@ -21,7 +21,7 @@ entry:
; abs44: add %[[R1]], %m44(.LCPI0_0), %[[R2:[gilo][0-7]]]
; abs44: sllx %[[R2]], 12, %[[R3:[gilo][0-7]]]
; abs44: retl
-; abs44: ld [%[[R3]]+%l44(.LCPI0_0)], %f1
+; abs44: ld [%[[R3]]+%l44(.LCPI0_0)], %f0
; abs64: floatCP
@@ -31,7 +31,7 @@ entry:
; abs64: add %[[R3]], %hm(.LCPI0_0), %[[R4:[gilo][0-7]]]
; abs64: sllx %[[R4]], 32, %[[R5:[gilo][0-7]]]
; abs64: retl
-; abs64: ld [%[[R5]]+%[[R2]]], %f1
+; abs64: ld [%[[R5]]+%[[R2]]], %f0
; v8pic32: floatCP
@@ -50,7 +50,7 @@ entry:
; v9pic32: sethi %hi(.LCPI0_0), %[[R1:[gilo][0-7]]]
; v9pic32: add %[[R1]], %lo(.LCPI0_0), %[[Goffs:[gilo][0-7]]]
; v9pic32: ldx [%[[GOT:[gilo][0-7]]]+%[[Goffs]]], %[[Gaddr:[gilo][0-7]]]
-; v9pic32: ld [%[[Gaddr]]], %f1
+; v9pic32: ld [%[[Gaddr]]], %f0
; v9pic32: ret
; v9pic32: restore
Index: test/CodeGen/SPARC/64cond.ll
===================================================================
--- test/CodeGen/SPARC/64cond.ll
+++ test/CodeGen/SPARC/64cond.ll
@@ -80,7 +80,7 @@ entry:
; CHECK: selectf32_xcc
; CHECK: cmp %i0, %i1
; CHECK: fmovsg %xcc, %f5, %f7
-; CHECK: fmovs %f7, %f1
+; CHECK: fmovs %f7, %f0
define float @selectf32_xcc(i64 %x, i64 %y, float %a, float %b) {
entry:
%tobool = icmp sgt i64 %x, %y
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -254,7 +254,7 @@ SparcTargetLowering::LowerReturn_64(SDValue Chain,
DAG.getTarget(), RVLocs, *DAG.getContext());
// Analyze return values.
- CCInfo.AnalyzeReturn(Outs, CC_Sparc64);
+ CCInfo.AnalyzeReturn(Outs, RetCC_Sparc64);
SDValue Flag;
SmallVector<SDValue, 4> RetOps(1, Chain);
@@ -1258,7 +1258,7 @@ SparcTargetLowering::LowerCall_64(TargetLowering::
if (CLI.Ins.size() == 1 && CLI.Ins[0].VT == MVT::f32 && CLI.CS == 0)
CLI.Ins[0].Flags.setInReg();
- RVInfo.AnalyzeCallResult(CLI.Ins, CC_Sparc64);
+ RVInfo.AnalyzeCallResult(CLI.Ins, RetCC_Sparc64);
// Copy all of the result registers out of their specified physreg.
for (unsigned i = 0; i != RVLocs.size(); ++i) {
Index: lib/Target/Sparc/SparcCallingConv.td
===================================================================
--- lib/Target/Sparc/SparcCallingConv.td
+++ lib/Target/Sparc/SparcCallingConv.td
@@ -103,7 +103,7 @@ def RetCC_Sparc32 : CallingConv<[
// Function return values are passed exactly like function arguments, except a
// struct up to 32 bytes in size can be returned in registers.
-// Function arguments AND return values.
+// Function arguments AND most return values.
def CC_Sparc64 : CallingConv<[
// The frontend uses the inreg flag to indicate i32 and float arguments from
// structs. These arguments are not promoted to 64 bits, but they can still
@@ -118,6 +118,15 @@ def CC_Sparc64 : CallingConv<[
CCCustom<"CC_Sparc64_Full">
]>;
+def RetCC_Sparc64 : CallingConv<[
+ // A single f32 return value always goes in %f0. The ABI doesn't specify what
+ // happens to multiple f32 return values outside a struct.
+ CCIfType<[f32], CCCustom<"CC_Sparc64_Half">>,
+
+ // Otherwise, return values are passed exactly like arguments.
+ CCDelegateTo<CC_Sparc64>
+]>;
+
// Callee-saved registers are handled by the register window mechanism.
def CSR : CalleeSavedRegs<(add)> {
let OtherPreserved = (add (sequence "I%u", 0, 7),

View File

@ -0,0 +1,42 @@
Pull in r199031 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Replace (unsigned)-1 with ~OU as suggested by Reid Kleckner.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
===================================================================
--- lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
+++ lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
@@ -104,14 +104,14 @@ static const unsigned DFPRegDecoderTable[] = {
SP::D14, SP::D30, SP::D15, SP::D31 };
static const unsigned QFPRegDecoderTable[] = {
- SP::Q0, SP::Q8, (unsigned)-1, (unsigned)-1,
- SP::Q1, SP::Q9, (unsigned)-1, (unsigned)-1,
- SP::Q2, SP::Q10, (unsigned)-1, (unsigned)-1,
- SP::Q3, SP::Q11, (unsigned)-1, (unsigned)-1,
- SP::Q4, SP::Q12, (unsigned)-1, (unsigned)-1,
- SP::Q5, SP::Q13, (unsigned)-1, (unsigned)-1,
- SP::Q6, SP::Q14, (unsigned)-1, (unsigned)-1,
- SP::Q7, SP::Q15, (unsigned)-1, (unsigned)-1 } ;
+ SP::Q0, SP::Q8, ~0U, ~0U,
+ SP::Q1, SP::Q9, ~0U, ~0U,
+ SP::Q2, SP::Q10, ~0U, ~0U,
+ SP::Q3, SP::Q11, ~0U, ~0U,
+ SP::Q4, SP::Q12, ~0U, ~0U,
+ SP::Q5, SP::Q13, ~0U, ~0U,
+ SP::Q6, SP::Q14, ~0U, ~0U,
+ SP::Q7, SP::Q15, ~0U, ~0U } ;
static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst,
unsigned RegNo,
@@ -168,7 +168,7 @@ static DecodeStatus DecodeQFPRegsRegisterClass(MCI
return MCDisassembler::Fail;
unsigned Reg = QFPRegDecoderTable[RegNo];
- if (Reg == (unsigned)-1)
+ if (Reg == ~0U)
return MCDisassembler::Fail;
Inst.addOperand(MCOperand::CreateReg(Reg));
return MCDisassembler::Success;

View File

@ -0,0 +1,944 @@
Pull in r199033 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Add support for parsing floating point instructions.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcInstrInfo.td
===================================================================
--- lib/Target/Sparc/SparcInstrInfo.td
+++ lib/Target/Sparc/SparcInstrInfo.td
@@ -601,91 +601,91 @@ let Defs = [Y], rd = 0 in {
}
// Convert Integer to Floating-point Instructions, p. 141
def FITOS : F3_3u<2, 0b110100, 0b011000100,
- (outs FPRegs:$dst), (ins FPRegs:$src),
- "fitos $src, $dst",
- [(set FPRegs:$dst, (SPitof FPRegs:$src))]>;
+ (outs FPRegs:$rd), (ins FPRegs:$rs2),
+ "fitos $rs2, $rd",
+ [(set FPRegs:$rd, (SPitof FPRegs:$rs2))]>;
def FITOD : F3_3u<2, 0b110100, 0b011001000,
- (outs DFPRegs:$dst), (ins FPRegs:$src),
- "fitod $src, $dst",
- [(set DFPRegs:$dst, (SPitof FPRegs:$src))]>;
+ (outs DFPRegs:$rd), (ins FPRegs:$rs2),
+ "fitod $rs2, $rd",
+ [(set DFPRegs:$rd, (SPitof FPRegs:$rs2))]>;
def FITOQ : F3_3u<2, 0b110100, 0b011001100,
- (outs QFPRegs:$dst), (ins FPRegs:$src),
- "fitoq $src, $dst",
- [(set QFPRegs:$dst, (SPitof FPRegs:$src))]>,
+ (outs QFPRegs:$rd), (ins FPRegs:$rs2),
+ "fitoq $rs2, $rd",
+ [(set QFPRegs:$rd, (SPitof FPRegs:$rs2))]>,
Requires<[HasHardQuad]>;
// Convert Floating-point to Integer Instructions, p. 142
def FSTOI : F3_3u<2, 0b110100, 0b011010001,
- (outs FPRegs:$dst), (ins FPRegs:$src),
- "fstoi $src, $dst",
- [(set FPRegs:$dst, (SPftoi FPRegs:$src))]>;
+ (outs FPRegs:$rd), (ins FPRegs:$rs2),
+ "fstoi $rs2, $rd",
+ [(set FPRegs:$rd, (SPftoi FPRegs:$rs2))]>;
def FDTOI : F3_3u<2, 0b110100, 0b011010010,
- (outs FPRegs:$dst), (ins DFPRegs:$src),
- "fdtoi $src, $dst",
- [(set FPRegs:$dst, (SPftoi DFPRegs:$src))]>;
+ (outs FPRegs:$rd), (ins DFPRegs:$rs2),
+ "fdtoi $rs2, $rd",
+ [(set FPRegs:$rd, (SPftoi DFPRegs:$rs2))]>;
def FQTOI : F3_3u<2, 0b110100, 0b011010011,
- (outs FPRegs:$dst), (ins QFPRegs:$src),
- "fqtoi $src, $dst",
- [(set FPRegs:$dst, (SPftoi QFPRegs:$src))]>,
+ (outs FPRegs:$rd), (ins QFPRegs:$rs2),
+ "fqtoi $rs2, $rd",
+ [(set FPRegs:$rd, (SPftoi QFPRegs:$rs2))]>,
Requires<[HasHardQuad]>;
// Convert between Floating-point Formats Instructions, p. 143
def FSTOD : F3_3u<2, 0b110100, 0b011001001,
- (outs DFPRegs:$dst), (ins FPRegs:$src),
- "fstod $src, $dst",
- [(set f64:$dst, (fextend f32:$src))]>;
+ (outs DFPRegs:$rd), (ins FPRegs:$rs2),
+ "fstod $rs2, $rd",
+ [(set f64:$rd, (fextend f32:$rs2))]>;
def FSTOQ : F3_3u<2, 0b110100, 0b011001101,
- (outs QFPRegs:$dst), (ins FPRegs:$src),
- "fstoq $src, $dst",
- [(set f128:$dst, (fextend f32:$src))]>,
+ (outs QFPRegs:$rd), (ins FPRegs:$rs2),
+ "fstoq $rs2, $rd",
+ [(set f128:$rd, (fextend f32:$rs2))]>,
Requires<[HasHardQuad]>;
def FDTOS : F3_3u<2, 0b110100, 0b011000110,
- (outs FPRegs:$dst), (ins DFPRegs:$src),
- "fdtos $src, $dst",
- [(set f32:$dst, (fround f64:$src))]>;
-def FDTOQ : F3_3u<2, 0b110100, 0b01101110,
- (outs QFPRegs:$dst), (ins DFPRegs:$src),
- "fdtoq $src, $dst",
- [(set f128:$dst, (fextend f64:$src))]>,
+ (outs FPRegs:$rd), (ins DFPRegs:$rs2),
+ "fdtos $rs2, $rd",
+ [(set f32:$rd, (fround f64:$rs2))]>;
+def FDTOQ : F3_3u<2, 0b110100, 0b011001110,
+ (outs QFPRegs:$rd), (ins DFPRegs:$rs2),
+ "fdtoq $rs2, $rd",
+ [(set f128:$rd, (fextend f64:$rs2))]>,
Requires<[HasHardQuad]>;
def FQTOS : F3_3u<2, 0b110100, 0b011000111,
- (outs FPRegs:$dst), (ins QFPRegs:$src),
- "fqtos $src, $dst",
- [(set f32:$dst, (fround f128:$src))]>,
+ (outs FPRegs:$rd), (ins QFPRegs:$rs2),
+ "fqtos $rs2, $rd",
+ [(set f32:$rd, (fround f128:$rs2))]>,
Requires<[HasHardQuad]>;
def FQTOD : F3_3u<2, 0b110100, 0b011001011,
- (outs DFPRegs:$dst), (ins QFPRegs:$src),
- "fqtod $src, $dst",
- [(set f64:$dst, (fround f128:$src))]>,
+ (outs DFPRegs:$rd), (ins QFPRegs:$rs2),
+ "fqtod $rs2, $rd",
+ [(set f64:$rd, (fround f128:$rs2))]>,
Requires<[HasHardQuad]>;
// Floating-point Move Instructions, p. 144
def FMOVS : F3_3u<2, 0b110100, 0b000000001,
- (outs FPRegs:$dst), (ins FPRegs:$src),
- "fmovs $src, $dst", []>;
+ (outs FPRegs:$rd), (ins FPRegs:$rs2),
+ "fmovs $rs2, $rd", []>;
def FNEGS : F3_3u<2, 0b110100, 0b000000101,
- (outs FPRegs:$dst), (ins FPRegs:$src),
- "fnegs $src, $dst",
- [(set f32:$dst, (fneg f32:$src))]>;
+ (outs FPRegs:$rd), (ins FPRegs:$rs2),
+ "fnegs $rs2, $rd",
+ [(set f32:$rd, (fneg f32:$rs2))]>;
def FABSS : F3_3u<2, 0b110100, 0b000001001,
- (outs FPRegs:$dst), (ins FPRegs:$src),
- "fabss $src, $dst",
- [(set f32:$dst, (fabs f32:$src))]>;
+ (outs FPRegs:$rd), (ins FPRegs:$rs2),
+ "fabss $rs2, $rd",
+ [(set f32:$rd, (fabs f32:$rs2))]>;
// Floating-point Square Root Instructions, p.145
def FSQRTS : F3_3u<2, 0b110100, 0b000101001,
- (outs FPRegs:$dst), (ins FPRegs:$src),
- "fsqrts $src, $dst",
- [(set f32:$dst, (fsqrt f32:$src))]>;
+ (outs FPRegs:$rd), (ins FPRegs:$rs2),
+ "fsqrts $rs2, $rd",
+ [(set f32:$rd, (fsqrt f32:$rs2))]>;
def FSQRTD : F3_3u<2, 0b110100, 0b000101010,
- (outs DFPRegs:$dst), (ins DFPRegs:$src),
- "fsqrtd $src, $dst",
- [(set f64:$dst, (fsqrt f64:$src))]>;
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs2),
+ "fsqrtd $rs2, $rd",
+ [(set f64:$rd, (fsqrt f64:$rs2))]>;
def FSQRTQ : F3_3u<2, 0b110100, 0b000101011,
- (outs QFPRegs:$dst), (ins QFPRegs:$src),
- "fsqrtq $src, $dst",
- [(set f128:$dst, (fsqrt f128:$src))]>,
+ (outs QFPRegs:$rd), (ins QFPRegs:$rs2),
+ "fsqrtq $rs2, $rd",
+ [(set f128:$rd, (fsqrt f128:$rs2))]>,
Requires<[HasHardQuad]>;
@@ -692,73 +692,73 @@ def FSQRTQ : F3_3u<2, 0b110100, 0b000101011,
// Floating-point Add and Subtract Instructions, p. 146
def FADDS : F3_3<2, 0b110100, 0b001000001,
- (outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2),
- "fadds $src1, $src2, $dst",
- [(set f32:$dst, (fadd f32:$src1, f32:$src2))]>;
+ (outs FPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2),
+ "fadds $rs1, $rs2, $rd",
+ [(set f32:$rd, (fadd f32:$rs1, f32:$rs2))]>;
def FADDD : F3_3<2, 0b110100, 0b001000010,
- (outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
- "faddd $src1, $src2, $dst",
- [(set f64:$dst, (fadd f64:$src1, f64:$src2))]>;
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "faddd $rs1, $rs2, $rd",
+ [(set f64:$rd, (fadd f64:$rs1, f64:$rs2))]>;
def FADDQ : F3_3<2, 0b110100, 0b001000011,
- (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2),
- "faddq $src1, $src2, $dst",
- [(set f128:$dst, (fadd f128:$src1, f128:$src2))]>,
+ (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2),
+ "faddq $rs1, $rs2, $rd",
+ [(set f128:$rd, (fadd f128:$rs1, f128:$rs2))]>,
Requires<[HasHardQuad]>;
def FSUBS : F3_3<2, 0b110100, 0b001000101,
- (outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2),
- "fsubs $src1, $src2, $dst",
- [(set f32:$dst, (fsub f32:$src1, f32:$src2))]>;
+ (outs FPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2),
+ "fsubs $rs1, $rs2, $rd",
+ [(set f32:$rd, (fsub f32:$rs1, f32:$rs2))]>;
def FSUBD : F3_3<2, 0b110100, 0b001000110,
- (outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
- "fsubd $src1, $src2, $dst",
- [(set f64:$dst, (fsub f64:$src1, f64:$src2))]>;
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fsubd $rs1, $rs2, $rd",
+ [(set f64:$rd, (fsub f64:$rs1, f64:$rs2))]>;
def FSUBQ : F3_3<2, 0b110100, 0b001000111,
- (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2),
- "fsubq $src1, $src2, $dst",
- [(set f128:$dst, (fsub f128:$src1, f128:$src2))]>,
+ (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2),
+ "fsubq $rs1, $rs2, $rd",
+ [(set f128:$rd, (fsub f128:$rs1, f128:$rs2))]>,
Requires<[HasHardQuad]>;
// Floating-point Multiply and Divide Instructions, p. 147
def FMULS : F3_3<2, 0b110100, 0b001001001,
- (outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2),
- "fmuls $src1, $src2, $dst",
- [(set f32:$dst, (fmul f32:$src1, f32:$src2))]>;
+ (outs FPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2),
+ "fmuls $rs1, $rs2, $rd",
+ [(set f32:$rd, (fmul f32:$rs1, f32:$rs2))]>;
def FMULD : F3_3<2, 0b110100, 0b001001010,
- (outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
- "fmuld $src1, $src2, $dst",
- [(set f64:$dst, (fmul f64:$src1, f64:$src2))]>;
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fmuld $rs1, $rs2, $rd",
+ [(set f64:$rd, (fmul f64:$rs1, f64:$rs2))]>;
def FMULQ : F3_3<2, 0b110100, 0b001001011,
- (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2),
- "fmulq $src1, $src2, $dst",
- [(set f128:$dst, (fmul f128:$src1, f128:$src2))]>,
+ (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2),
+ "fmulq $rs1, $rs2, $rd",
+ [(set f128:$rd, (fmul f128:$rs1, f128:$rs2))]>,
Requires<[HasHardQuad]>;
def FSMULD : F3_3<2, 0b110100, 0b001101001,
- (outs DFPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2),
- "fsmuld $src1, $src2, $dst",
- [(set f64:$dst, (fmul (fextend f32:$src1),
- (fextend f32:$src2)))]>;
+ (outs DFPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2),
+ "fsmuld $rs1, $rs2, $rd",
+ [(set f64:$rd, (fmul (fextend f32:$rs1),
+ (fextend f32:$rs2)))]>;
def FDMULQ : F3_3<2, 0b110100, 0b001101110,
- (outs QFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
- "fdmulq $src1, $src2, $dst",
- [(set f128:$dst, (fmul (fextend f64:$src1),
- (fextend f64:$src2)))]>,
+ (outs QFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fdmulq $rs1, $rs2, $rd",
+ [(set f128:$rd, (fmul (fextend f64:$rs1),
+ (fextend f64:$rs2)))]>,
Requires<[HasHardQuad]>;
def FDIVS : F3_3<2, 0b110100, 0b001001101,
- (outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2),
- "fdivs $src1, $src2, $dst",
- [(set f32:$dst, (fdiv f32:$src1, f32:$src2))]>;
+ (outs FPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2),
+ "fdivs $rs1, $rs2, $rd",
+ [(set f32:$rd, (fdiv f32:$rs1, f32:$rs2))]>;
def FDIVD : F3_3<2, 0b110100, 0b001001110,
- (outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
- "fdivd $src1, $src2, $dst",
- [(set f64:$dst, (fdiv f64:$src1, f64:$src2))]>;
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fdivd $rs1, $rs2, $rd",
+ [(set f64:$rd, (fdiv f64:$rs1, f64:$rs2))]>;
def FDIVQ : F3_3<2, 0b110100, 0b001001111,
- (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2),
- "fdivq $src1, $src2, $dst",
- [(set f128:$dst, (fdiv f128:$src1, f128:$src2))]>,
+ (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2),
+ "fdivq $rs1, $rs2, $rd",
+ [(set f128:$rd, (fdiv f128:$rs1, f128:$rs2))]>,
Requires<[HasHardQuad]>;
// Floating-point Compare Instructions, p. 148
@@ -770,17 +770,17 @@ def FDIVQ : F3_3<2, 0b110100, 0b001001111,
let Defs = [FCC] in {
def FCMPS : F3_3c<2, 0b110101, 0b001010001,
- (outs), (ins FPRegs:$src1, FPRegs:$src2),
- "fcmps $src1, $src2",
- [(SPcmpfcc f32:$src1, f32:$src2)]>;
+ (outs), (ins FPRegs:$rs1, FPRegs:$rs2),
+ "fcmps $rs1, $rs2",
+ [(SPcmpfcc f32:$rs1, f32:$rs2)]>;
def FCMPD : F3_3c<2, 0b110101, 0b001010010,
- (outs), (ins DFPRegs:$src1, DFPRegs:$src2),
- "fcmpd $src1, $src2",
- [(SPcmpfcc f64:$src1, f64:$src2)]>;
+ (outs), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fcmpd $rs1, $rs2",
+ [(SPcmpfcc f64:$rs1, f64:$rs2)]>;
def FCMPQ : F3_3c<2, 0b110101, 0b001010011,
- (outs), (ins QFPRegs:$src1, QFPRegs:$src2),
- "fcmpq $src1, $src2",
- [(SPcmpfcc f128:$src1, f128:$src2)]>,
+ (outs), (ins QFPRegs:$rs1, QFPRegs:$rs2),
+ "fcmpq $rs1, $rs2",
+ [(SPcmpfcc f128:$rs1, f128:$rs2)]>,
Requires<[HasHardQuad]>;
}
@@ -892,29 +892,29 @@ let Predicates = [HasV9], Constraints = "$f = $rd"
// Floating-Point Move Instructions, p. 164 of the V9 manual.
let Predicates = [HasV9] in {
def FMOVD : F3_3u<2, 0b110100, 0b000000010,
- (outs DFPRegs:$dst), (ins DFPRegs:$src),
- "fmovd $src, $dst", []>;
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs2),
+ "fmovd $rs2, $rd", []>;
def FMOVQ : F3_3u<2, 0b110100, 0b000000011,
- (outs QFPRegs:$dst), (ins QFPRegs:$src),
- "fmovq $src, $dst", []>,
+ (outs QFPRegs:$rd), (ins QFPRegs:$rs2),
+ "fmovq $rs2, $rd", []>,
Requires<[HasHardQuad]>;
def FNEGD : F3_3u<2, 0b110100, 0b000000110,
- (outs DFPRegs:$dst), (ins DFPRegs:$src),
- "fnegd $src, $dst",
- [(set f64:$dst, (fneg f64:$src))]>;
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs2),
+ "fnegd $rs2, $rd",
+ [(set f64:$rd, (fneg f64:$rs2))]>;
def FNEGQ : F3_3u<2, 0b110100, 0b000000111,
- (outs QFPRegs:$dst), (ins QFPRegs:$src),
- "fnegq $src, $dst",
- [(set f128:$dst, (fneg f128:$src))]>,
+ (outs QFPRegs:$rd), (ins QFPRegs:$rs2),
+ "fnegq $rs2, $rd",
+ [(set f128:$rd, (fneg f128:$rs2))]>,
Requires<[HasHardQuad]>;
def FABSD : F3_3u<2, 0b110100, 0b000001010,
- (outs DFPRegs:$dst), (ins DFPRegs:$src),
- "fabsd $src, $dst",
- [(set f64:$dst, (fabs f64:$src))]>;
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs2),
+ "fabsd $rs2, $rd",
+ [(set f64:$rd, (fabs f64:$rs2))]>;
def FABSQ : F3_3u<2, 0b110100, 0b000001011,
- (outs QFPRegs:$dst), (ins QFPRegs:$src),
- "fabsq $src, $dst",
- [(set f128:$dst, (fabs f128:$src))]>,
+ (outs QFPRegs:$rd), (ins QFPRegs:$rs2),
+ "fabsq $rs2, $rd",
+ [(set f128:$rd, (fabs f128:$rs2))]>,
Requires<[HasHardQuad]>;
}
Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
===================================================================
--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
+++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
@@ -54,6 +54,8 @@ class SparcAsmParser : public MCTargetAsmParser {
SmallVectorImpl<MCParsedAsmOperand*> &Operands);
bool ParseDirective(AsmToken DirectiveID);
+ virtual unsigned validateTargetOperandClass(MCParsedAsmOperand *Op,
+ unsigned Kind);
// Custom parse functions for Sparc specific operands.
OperandMatchResultTy
@@ -67,8 +69,9 @@ class SparcAsmParser : public MCTargetAsmParser {
parseSparcAsmOperand(SparcOperand *&Operand);
// returns true if Tok is matched to a register and returns register in RegNo.
- bool matchRegisterName(const AsmToken &Tok, unsigned &RegNo, bool isDFP,
- bool isQFP);
+ bool matchRegisterName(const AsmToken &Tok, unsigned &RegNo,
+ unsigned &RegKind);
+
bool matchSparcAsmModifiers(const MCExpr *&EVal, SMLoc &EndLoc);
public:
@@ -178,6 +181,16 @@ class SparcOperand : public MCParsedAsmOperand {
bool isMEMrr() const { return Kind == k_MemoryReg; }
bool isMEMri() const { return Kind == k_MemoryImm; }
+ bool isFloatReg() const {
+ return (Kind == k_Register && Reg.Kind == rk_FloatReg);
+ }
+
+ bool isFloatOrDoubleReg() const {
+ return (Kind == k_Register && (Reg.Kind == rk_FloatReg
+ || Reg.Kind == rk_DoubleReg));
+ }
+
+
StringRef getToken() const {
assert(Kind == k_Token && "Invalid access!");
return StringRef(Tok.Data, Tok.Length);
@@ -280,11 +293,11 @@ class SparcOperand : public MCParsedAsmOperand {
}
static SparcOperand *CreateReg(unsigned RegNum,
- SparcOperand::RegisterKind Kind,
+ unsigned Kind,
SMLoc S, SMLoc E) {
SparcOperand *Op = new SparcOperand(k_Register);
Op->Reg.RegNum = RegNum;
- Op->Reg.Kind = Kind;
+ Op->Reg.Kind = (SparcOperand::RegisterKind)Kind;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
@@ -298,6 +311,40 @@ class SparcOperand : public MCParsedAsmOperand {
return Op;
}
+ static SparcOperand *MorphToDoubleReg(SparcOperand *Op) {
+ unsigned Reg = Op->getReg();
+ assert(Op->Reg.Kind == rk_FloatReg);
+ unsigned regIdx = Reg - Sparc::F0;
+ if (regIdx % 2 || regIdx > 31)
+ return 0;
+ Op->Reg.RegNum = DoubleRegs[regIdx / 2];
+ Op->Reg.Kind = rk_DoubleReg;
+ return Op;
+ }
+
+ static SparcOperand *MorphToQuadReg(SparcOperand *Op) {
+ unsigned Reg = Op->getReg();
+ unsigned regIdx = 0;
+ switch (Op->Reg.Kind) {
+ default: assert(0 && "Unexpected register kind!");
+ case rk_FloatReg:
+ regIdx = Reg - Sparc::F0;
+ if (regIdx % 4 || regIdx > 31)
+ return 0;
+ Reg = QuadFPRegs[regIdx / 4];
+ break;
+ case rk_DoubleReg:
+ regIdx = Reg - Sparc::D0;
+ if (regIdx % 2 || regIdx > 31)
+ return 0;
+ Reg = QuadFPRegs[regIdx / 2];
+ break;
+ }
+ Op->Reg.RegNum = Reg;
+ Op->Reg.Kind = rk_QuadReg;
+ return Op;
+ }
+
static SparcOperand *MorphToMEMrr(unsigned Base, SparcOperand *Op) {
unsigned offsetReg = Op->getReg();
Op->Kind = k_MemoryReg;
@@ -383,7 +430,8 @@ ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SM
if (getLexer().getKind() != AsmToken::Percent)
return false;
Parser.Lex();
- if (matchRegisterName(Tok, RegNo, false, false)) {
+ unsigned regKind = SparcOperand::rk_None;
+ if (matchRegisterName(Tok, RegNo, regKind)) {
Parser.Lex();
return false;
}
@@ -537,13 +585,14 @@ SparcAsmParser::parseSparcAsmOperand(SparcOperand
case AsmToken::Percent:
Parser.Lex(); // Eat the '%'.
unsigned RegNo;
- if (matchRegisterName(Parser.getTok(), RegNo, false, false)) {
+ unsigned RegKind;
+ if (matchRegisterName(Parser.getTok(), RegNo, RegKind)) {
StringRef name = Parser.getTok().getString();
Parser.Lex(); // Eat the identifier token.
E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
switch (RegNo) {
default:
- Op = SparcOperand::CreateReg(RegNo, SparcOperand::rk_None, S, E);
+ Op = SparcOperand::CreateReg(RegNo, RegKind, S, E);
break;
case Sparc::Y:
Op = SparcOperand::CreateToken("%y", S);
@@ -593,11 +642,11 @@ SparcAsmParser::parseSparcAsmOperand(SparcOperand
bool SparcAsmParser::matchRegisterName(const AsmToken &Tok,
unsigned &RegNo,
- bool isDFP,
- bool isQFP)
+ unsigned &RegKind)
{
int64_t intVal = 0;
RegNo = 0;
+ RegKind = SparcOperand::rk_None;
if (Tok.is(AsmToken::Identifier)) {
StringRef name = Tok.getString();
@@ -604,21 +653,25 @@ bool SparcAsmParser::matchRegisterName(const AsmTo
// %fp
if (name.equals("fp")) {
RegNo = Sparc::I6;
+ RegKind = SparcOperand::rk_IntReg;
return true;
}
// %sp
if (name.equals("sp")) {
RegNo = Sparc::O6;
+ RegKind = SparcOperand::rk_IntReg;
return true;
}
if (name.equals("y")) {
RegNo = Sparc::Y;
+ RegKind = SparcOperand::rk_Y;
return true;
}
if (name.equals("icc")) {
RegNo = Sparc::ICC;
+ RegKind = SparcOperand::rk_CCReg;
return true;
}
@@ -625,6 +678,7 @@ bool SparcAsmParser::matchRegisterName(const AsmTo
if (name.equals("xcc")) {
// FIXME:: check 64bit.
RegNo = Sparc::ICC;
+ RegKind = SparcOperand::rk_CCReg;
return true;
}
@@ -634,6 +688,7 @@ bool SparcAsmParser::matchRegisterName(const AsmTo
&& intVal < 4) {
// FIXME: check 64bit and handle %fcc1 - %fcc3
RegNo = Sparc::FCC;
+ RegKind = SparcOperand::rk_CCReg;
return true;
}
@@ -642,6 +697,7 @@ bool SparcAsmParser::matchRegisterName(const AsmTo
&& !name.substr(1).getAsInteger(10, intVal)
&& intVal < 8) {
RegNo = IntRegs[intVal];
+ RegKind = SparcOperand::rk_IntReg;
return true;
}
// %o0 - %o7
@@ -649,6 +705,7 @@ bool SparcAsmParser::matchRegisterName(const AsmTo
&& !name.substr(1).getAsInteger(10, intVal)
&& intVal < 8) {
RegNo = IntRegs[8 + intVal];
+ RegKind = SparcOperand::rk_IntReg;
return true;
}
if (name.substr(0, 1).equals_lower("l")
@@ -655,6 +712,7 @@ bool SparcAsmParser::matchRegisterName(const AsmTo
&& !name.substr(1).getAsInteger(10, intVal)
&& intVal < 8) {
RegNo = IntRegs[16 + intVal];
+ RegKind = SparcOperand::rk_IntReg;
return true;
}
if (name.substr(0, 1).equals_lower("i")
@@ -661,18 +719,14 @@ bool SparcAsmParser::matchRegisterName(const AsmTo
&& !name.substr(1).getAsInteger(10, intVal)
&& intVal < 8) {
RegNo = IntRegs[24 + intVal];
+ RegKind = SparcOperand::rk_IntReg;
return true;
}
// %f0 - %f31
if (name.substr(0, 1).equals_lower("f")
&& !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 32) {
- if (isDFP && (intVal%2 == 0)) {
- RegNo = DoubleRegs[intVal/2];
- } else if (isQFP && (intVal%4 == 0)) {
- RegNo = QuadFPRegs[intVal/4];
- } else {
- RegNo = FloatRegs[intVal];
- }
+ RegNo = FloatRegs[intVal];
+ RegKind = SparcOperand::rk_FloatReg;
return true;
}
// %f32 - %f62
@@ -679,13 +733,9 @@ bool SparcAsmParser::matchRegisterName(const AsmTo
if (name.substr(0, 1).equals_lower("f")
&& !name.substr(1, 2).getAsInteger(10, intVal)
&& intVal >= 32 && intVal <= 62 && (intVal % 2 == 0)) {
- if (isDFP) {
- RegNo = DoubleRegs[16 + intVal/2];
- } else if (isQFP && (intVal % 4 == 0)) {
- RegNo = QuadFPRegs[8 + intVal/4];
- } else {
- return false;
- }
+ // FIXME: Check V9
+ RegNo = DoubleRegs[16 + intVal/2];
+ RegKind = SparcOperand::rk_DoubleReg;
return true;
}
@@ -693,6 +743,7 @@ bool SparcAsmParser::matchRegisterName(const AsmTo
if (name.substr(0, 1).equals_lower("r")
&& !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 31) {
RegNo = IntRegs[intVal];
+ RegKind = SparcOperand::rk_IntReg;
return true;
}
}
@@ -735,3 +786,26 @@ extern "C" void LLVMInitializeSparcAsmParser() {
#define GET_REGISTER_MATCHER
#define GET_MATCHER_IMPLEMENTATION
#include "SparcGenAsmMatcher.inc"
+
+
+
+unsigned SparcAsmParser::
+validateTargetOperandClass(MCParsedAsmOperand *GOp,
+ unsigned Kind)
+{
+ SparcOperand *Op = (SparcOperand*)GOp;
+ if (Op->isFloatOrDoubleReg()) {
+ switch (Kind) {
+ default: break;
+ case MCK_DFPRegs:
+ if (!Op->isFloatReg() || SparcOperand::MorphToDoubleReg(Op))
+ return MCTargetAsmParser::Match_Success;
+ break;
+ case MCK_QFPRegs:
+ if (SparcOperand::MorphToQuadReg(Op))
+ return MCTargetAsmParser::Match_Success;
+ break;
+ }
+ }
+ return Match_InvalidOperand;
+}
Index: lib/Target/Sparc/SparcInstr64Bit.td
===================================================================
--- lib/Target/Sparc/SparcInstr64Bit.td
+++ lib/Target/Sparc/SparcInstr64Bit.td
@@ -358,31 +358,31 @@ def FMOVQ_XCC : F4_3<0b110101, 0b000011, (outs QFP
let Predicates = [Is64Bit] in {
def FXTOS : F3_3u<2, 0b110100, 0b010000100,
- (outs FPRegs:$dst), (ins DFPRegs:$src),
- "fxtos $src, $dst",
- [(set FPRegs:$dst, (SPxtof DFPRegs:$src))]>;
+ (outs FPRegs:$rd), (ins DFPRegs:$rs2),
+ "fxtos $rs2, $rd",
+ [(set FPRegs:$rd, (SPxtof DFPRegs:$rs2))]>;
def FXTOD : F3_3u<2, 0b110100, 0b010001000,
- (outs DFPRegs:$dst), (ins DFPRegs:$src),
- "fxtod $src, $dst",
- [(set DFPRegs:$dst, (SPxtof DFPRegs:$src))]>;
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs2),
+ "fxtod $rs2, $rd",
+ [(set DFPRegs:$rd, (SPxtof DFPRegs:$rs2))]>;
def FXTOQ : F3_3u<2, 0b110100, 0b010001100,
- (outs QFPRegs:$dst), (ins DFPRegs:$src),
- "fxtoq $src, $dst",
- [(set QFPRegs:$dst, (SPxtof DFPRegs:$src))]>,
+ (outs QFPRegs:$rd), (ins DFPRegs:$rs2),
+ "fxtoq $rs2, $rd",
+ [(set QFPRegs:$rd, (SPxtof DFPRegs:$rs2))]>,
Requires<[HasHardQuad]>;
def FSTOX : F3_3u<2, 0b110100, 0b010000001,
- (outs DFPRegs:$dst), (ins FPRegs:$src),
- "fstox $src, $dst",
- [(set DFPRegs:$dst, (SPftox FPRegs:$src))]>;
+ (outs DFPRegs:$rd), (ins FPRegs:$rs2),
+ "fstox $rs2, $rd",
+ [(set DFPRegs:$rd, (SPftox FPRegs:$rs2))]>;
def FDTOX : F3_3u<2, 0b110100, 0b010000010,
- (outs DFPRegs:$dst), (ins DFPRegs:$src),
- "fdtox $src, $dst",
- [(set DFPRegs:$dst, (SPftox DFPRegs:$src))]>;
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs2),
+ "fdtox $rs2, $rd",
+ [(set DFPRegs:$rd, (SPftox DFPRegs:$rs2))]>;
def FQTOX : F3_3u<2, 0b110100, 0b010000011,
- (outs DFPRegs:$dst), (ins QFPRegs:$src),
- "fqtox $src, $dst",
- [(set DFPRegs:$dst, (SPftox QFPRegs:$src))]>,
+ (outs DFPRegs:$rd), (ins QFPRegs:$rs2),
+ "fqtox $rs2, $rd",
+ [(set DFPRegs:$rd, (SPftox QFPRegs:$rs2))]>,
Requires<[HasHardQuad]>;
} // Predicates = [Is64Bit]
Index: test/MC/Disassembler/Sparc/sparc-fp.txt
===================================================================
--- test/MC/Disassembler/Sparc/sparc-fp.txt
+++ test/MC/Disassembler/Sparc/sparc-fp.txt
@@ -0,0 +1,142 @@
+# RUN: llvm-mc --disassemble %s -triple=sparc64-linux-gnu | FileCheck %s
+
+
+# CHECK: fitos %f0, %f4
+0x89 0xa0 0x18 0x80
+
+# CHECK: fitod %f0, %f4
+0x89 0xa0 0x19 0x00
+
+# CHECK: fitoq %f0, %f4
+0x89 0xa0 0x19 0x80
+
+# CHECK: fstoi %f0, %f4
+0x89 0xa0 0x1a 0x20
+
+# CHECK: fdtoi %f0, %f4
+0x89 0xa0 0x1a 0x40
+
+# CHECK: fqtoi %f0, %f4
+0x89 0xa0 0x1a 0x60
+
+# CHECK: fstod %f0, %f4
+0x89 0xa0 0x19 0x20
+# CHECK: fstoq %f0, %f4
+0x89 0xa0 0x19 0xa0
+
+# CHECK: fdtos %f0, %f4
+0x89 0xa0 0x18 0xc0
+
+# CHECK: fdtoq %f0, %f4
+0x89 0xa0 0x19 0xc0
+
+# CHECK: fqtos %f0, %f4
+0x89 0xa0 0x18 0xe0
+
+# CHECK: fqtod %f0, %f4
+0x89 0xa0 0x19 0x60
+
+# CHECK: fmovs %f0, %f4
+0x89 0xa0 0x00 0x20
+
+# CHECK: fmovd %f0, %f4
+0x89 0xa0 0x00 0x40
+
+# CHECK: fmovq %f0, %f4
+0x89 0xa0 0x00 0x60
+
+# CHECK: fnegs %f0, %f4
+0x89 0xa0 0x00 0xa0
+
+# CHECK: fnegd %f0, %f4
+0x89 0xa0 0x00 0xc0
+
+# CHECK: fnegq %f0, %f4
+0x89 0xa0 0x00 0xe0
+
+# CHECK: fabss %f0, %f4
+0x89 0xa0 0x01 0x20
+
+# CHECK: fabsd %f0, %f4
+0x89 0xa0 0x01 0x40
+
+# CHECK: fabsq %f0, %f4
+0x89 0xa0 0x01 0x60
+
+# CHECK: fsqrts %f0, %f4
+0x89 0xa0 0x05 0x20
+
+# CHECK: fsqrtd %f0, %f4
+0x89 0xa0 0x05 0x40
+
+# CHECK: fsqrtq %f0, %f4
+0x89 0xa0 0x05 0x60
+
+# CHECK: fadds %f0, %f4, %f8
+0x91 0xa0 0x08 0x24
+
+# CHECK: faddd %f0, %f4, %f8
+0x91 0xa0 0x08 0x44
+
+# CHECK: faddq %f0, %f4, %f8
+0x91 0xa0 0x08 0x64
+
+# CHECK: fsubs %f0, %f4, %f8
+0x91 0xa0 0x08 0xa4
+
+# CHECK: fsubd %f0, %f4, %f8
+0x91 0xa0 0x08 0xc4
+
+# CHECK: fsubq %f0, %f4, %f8
+0x91 0xa0 0x08 0xe4
+
+# CHECK: fmuls %f0, %f4, %f8
+0x91 0xa0 0x09 0x24
+
+# CHECK: fmuld %f0, %f4, %f8
+0x91 0xa0 0x09 0x44
+
+# CHECK: fmulq %f0, %f4, %f8
+0x91 0xa0 0x09 0x64
+
+# CHECK: fsmuld %f0, %f4, %f8
+0x91 0xa0 0x0d 0x24
+
+# CHECK: fdmulq %f0, %f4, %f8
+0x91 0xa0 0x0d 0xc4
+
+# CHECK: fdivs %f0, %f4, %f8
+0x91 0xa0 0x09 0xa4
+
+# CHECK: fdivd %f0, %f4, %f8
+0x91 0xa0 0x09 0xc4
+
+# CHECK: fdivq %f0, %f4, %f8
+0x91 0xa0 0x09 0xe4
+
+# CHECK: fcmps %f0, %f4
+0x81 0xa8 0x0a 0x24
+
+# CHECK: fcmpd %f0, %f4
+0x81 0xa8 0x0a 0x44
+
+# CHECK: fcmpq %f0, %f4
+0x81 0xa8 0x0a 0x64
+
+# CHECK: fxtos %f0, %f4
+0x89 0xa0 0x10 0x80
+
+# CHECK: fxtod %f0, %f4
+0x89 0xa0 0x11 0x00
+
+# CHECK: fxtoq %f0, %f4
+0x89 0xa0 0x11 0x80
+
+# CHECK: fstox %f0, %f4
+0x89 0xa0 0x10 0x20
+
+# CHECK: fdtox %f0, %f4
+0x89 0xa0 0x10 0x40
+
+# CHECK: fqtox %f0, %f4
+0x89 0xa0 0x10 0x60
Index: test/MC/Sparc/sparc-fp-instructions.s
===================================================================
--- test/MC/Sparc/sparc-fp-instructions.s
+++ test/MC/Sparc/sparc-fp-instructions.s
@@ -0,0 +1,113 @@
+! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s
+
+ ! CHECK: fitos %f0, %f4 ! encoding: [0x89,0xa0,0x18,0x80]
+ ! CHECK: fitod %f0, %f4 ! encoding: [0x89,0xa0,0x19,0x00]
+ ! CHECK: fitoq %f0, %f4 ! encoding: [0x89,0xa0,0x19,0x80]
+ fitos %f0, %f4
+ fitod %f0, %f4
+ fitoq %f0, %f4
+
+ ! CHECK: fstoi %f0, %f4 ! encoding: [0x89,0xa0,0x1a,0x20]
+ ! CHECK: fdtoi %f0, %f4 ! encoding: [0x89,0xa0,0x1a,0x40]
+ ! CHECK: fqtoi %f0, %f4 ! encoding: [0x89,0xa0,0x1a,0x60]
+ fstoi %f0, %f4
+ fdtoi %f0, %f4
+ fqtoi %f0, %f4
+
+ ! CHECK: fstod %f0, %f4 ! encoding: [0x89,0xa0,0x19,0x20]
+ ! CHECK: fstoq %f0, %f4 ! encoding: [0x89,0xa0,0x19,0xa0]
+ fstod %f0, %f4
+ fstoq %f0, %f4
+
+ ! CHECK: fdtos %f0, %f4 ! encoding: [0x89,0xa0,0x18,0xc0]
+ ! CHECK: fdtoq %f0, %f4 ! encoding: [0x89,0xa0,0x19,0xc0]
+ fdtos %f0, %f4
+ fdtoq %f0, %f4
+
+ ! CHECK: fqtos %f0, %f4 ! encoding: [0x89,0xa0,0x18,0xe0]
+ ! CHECK: fqtod %f0, %f4 ! encoding: [0x89,0xa0,0x19,0x60]
+ fqtos %f0, %f4
+ fqtod %f0, %f4
+
+ ! CHECK: fmovs %f0, %f4 ! encoding: [0x89,0xa0,0x00,0x20]
+ ! CHECK: fmovd %f0, %f4 ! encoding: [0x89,0xa0,0x00,0x40]
+ ! CHECK: fmovq %f0, %f4 ! encoding: [0x89,0xa0,0x00,0x60]
+ fmovs %f0, %f4
+ fmovd %f0, %f4
+ fmovq %f0, %f4
+
+ ! CHECK: fnegs %f0, %f4 ! encoding: [0x89,0xa0,0x00,0xa0]
+ ! CHECK: fnegd %f0, %f4 ! encoding: [0x89,0xa0,0x00,0xc0]
+ ! CHECK: fnegq %f0, %f4 ! encoding: [0x89,0xa0,0x00,0xe0]
+ fnegs %f0, %f4
+ fnegd %f0, %f4
+ fnegq %f0, %f4
+
+ ! CHECK: fabss %f0, %f4 ! encoding: [0x89,0xa0,0x01,0x20]
+ ! CHECK: fabsd %f0, %f4 ! encoding: [0x89,0xa0,0x01,0x40]
+ ! CHECK: fabsq %f0, %f4 ! encoding: [0x89,0xa0,0x01,0x60]
+ fabss %f0, %f4
+ fabsd %f0, %f4
+ fabsq %f0, %f4
+
+ ! CHECK: fsqrts %f0, %f4 ! encoding: [0x89,0xa0,0x05,0x20]
+ ! CHECK: fsqrtd %f0, %f4 ! encoding: [0x89,0xa0,0x05,0x40]
+ ! CHECK: fsqrtq %f0, %f4 ! encoding: [0x89,0xa0,0x05,0x60]
+ fsqrts %f0, %f4
+ fsqrtd %f0, %f4
+ fsqrtq %f0, %f4
+
+ ! CHECK: fadds %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0x24]
+ ! CHECK: faddd %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0x44]
+ ! CHECK: faddq %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0x64]
+ fadds %f0, %f4, %f8
+ faddd %f0, %f4, %f8
+ faddq %f0, %f4, %f8
+
+ ! CHECK: fsubs %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0xa4]
+ ! CHECK: fsubd %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0xc4]
+ ! CHECK: fsubq %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0xe4]
+ fsubs %f0, %f4, %f8
+ fsubd %f0, %f4, %f8
+ fsubq %f0, %f4, %f8
+
+ ! CHECK: fmuls %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x09,0x24]
+ ! CHECK: fmuld %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x09,0x44]
+ ! CHECK: fmulq %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x09,0x64]
+ fmuls %f0, %f4, %f8
+ fmuld %f0, %f4, %f8
+ fmulq %f0, %f4, %f8
+
+ ! CHECK: fsmuld %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x0d,0x24]
+ ! CHECK: fdmulq %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x0d,0xc4]
+ fsmuld %f0, %f4, %f8
+ fdmulq %f0, %f4, %f8
+
+ ! CHECK: fdivs %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x09,0xa4]
+ ! CHECK: fdivd %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x09,0xc4]
+ ! CHECK: fdivq %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x09,0xe4]
+ fdivs %f0, %f4, %f8
+ fdivd %f0, %f4, %f8
+ fdivq %f0, %f4, %f8
+
+ ! CHECK: fcmps %f0, %f4 ! encoding: [0x81,0xa8,0x0a,0x24]
+ ! CHECK: fcmpd %f0, %f4 ! encoding: [0x81,0xa8,0x0a,0x44]
+ ! CHECK: fcmpq %f0, %f4 ! encoding: [0x81,0xa8,0x0a,0x64]
+ fcmps %f0, %f4
+ fcmpd %f0, %f4
+ fcmpq %f0, %f4
+
+ ! CHECK: fxtos %f0, %f4 ! encoding: [0x89,0xa0,0x10,0x80]
+ ! CHECK: fxtod %f0, %f4 ! encoding: [0x89,0xa0,0x11,0x00]
+ ! CHECK: fxtoq %f0, %f4 ! encoding: [0x89,0xa0,0x11,0x80]
+ fxtos %f0, %f4
+ fxtod %f0, %f4
+ fxtoq %f0, %f4
+
+ ! CHECK: fstox %f0, %f4 ! encoding: [0x89,0xa0,0x10,0x20]
+ ! CHECK: fdtox %f0, %f4 ! encoding: [0x89,0xa0,0x10,0x40]
+ ! CHECK: fqtox %f0, %f4 ! encoding: [0x89,0xa0,0x10,0x60]
+ fstox %f0, %f4
+ fdtox %f0, %f4
+ fqtox %f0, %f4
+

View File

@ -0,0 +1,126 @@
Pull in r199061 from upstream llvm trunk (by Jakob Stoklund Olesen):
Handle bundled terminators in isBlockOnlyReachableByFallthrough.
Targets like SPARC and MIPS have delay slots and normally bundle the
delay slot instruction with the corresponding terminator.
Teach isBlockOnlyReachableByFallthrough to find any MBB operands on
bundled terminators so SPARC doesn't need to specialize this function.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: test/CodeGen/SPARC/missinglabel.ll
===================================================================
--- test/CodeGen/SPARC/missinglabel.ll
+++ test/CodeGen/SPARC/missinglabel.ll
@@ -0,0 +1,23 @@
+; RUN: llc < %s -verify-machineinstrs | FileCheck %s
+target datalayout = "E-m:e-i64:64-n32:64-S128"
+target triple = "sparc64-unknown-linux-gnu"
+
+define void @f() align 2 {
+entry:
+; CHECK: %xcc, .LBB0_1
+ %cmp = icmp eq i64 undef, 0
+ br i1 %cmp, label %targetblock, label %cond.false
+
+cond.false:
+ unreachable
+
+; CHECK: .LBB0_1: ! %targetblock
+targetblock:
+ br i1 undef, label %cond.false.i83, label %exit.i85
+
+cond.false.i83:
+ unreachable
+
+exit.i85:
+ unreachable
+}
Index: lib/Target/Sparc/SparcAsmPrinter.cpp
===================================================================
--- lib/Target/Sparc/SparcAsmPrinter.cpp
+++ lib/Target/Sparc/SparcAsmPrinter.cpp
@@ -65,10 +65,6 @@ namespace {
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &O);
-
- virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB)
- const;
-
};
} // end of anonymous namespace
@@ -390,37 +386,6 @@ bool SparcAsmPrinter::PrintAsmMemoryOperand(const
return false;
}
-/// isBlockOnlyReachableByFallthough - Return true if the basic block has
-/// exactly one predecessor and the control transfer mechanism between
-/// the predecessor and this block is a fall-through.
-///
-/// This overrides AsmPrinter's implementation to handle delay slots.
-bool SparcAsmPrinter::
-isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const {
- // If this is a landing pad, it isn't a fall through. If it has no preds,
- // then nothing falls through to it.
- if (MBB->isLandingPad() || MBB->pred_empty())
- return false;
-
- // If there isn't exactly one predecessor, it can't be a fall through.
- MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PI2 = PI;
- ++PI2;
- if (PI2 != MBB->pred_end())
- return false;
-
- // The predecessor has to be immediately before this block.
- const MachineBasicBlock *Pred = *PI;
-
- if (!Pred->isLayoutSuccessor(MBB))
- return false;
-
- // Check if the last terminator is an unconditional branch.
- MachineBasicBlock::const_iterator I = Pred->end();
- while (I != Pred->begin() && !(--I)->isTerminator())
- ; // Noop
- return I == Pred->end() || !I->isBarrier();
-}
-
// Force static initialization.
extern "C" void LLVMInitializeSparcAsmPrinter() {
RegisterAsmPrinter<SparcAsmPrinter> X(TheSparcTarget);
Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp
===================================================================
--- lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -23,6 +23,7 @@
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstrBundle.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
@@ -2221,14 +2222,13 @@ isBlockOnlyReachableByFallthrough(const MachineBas
if (!MI.isBranch() || MI.isIndirectBranch())
return false;
- // If we are the operands of one of the branches, this is not
- // a fall through.
- for (MachineInstr::mop_iterator OI = MI.operands_begin(),
- OE = MI.operands_end(); OI != OE; ++OI) {
- const MachineOperand& OP = *OI;
- if (OP.isJTI())
+ // If we are the operands of one of the branches, this is not a fall
+ // through. Note that targets with delay slots will usually bundle
+ // terminators with the delay slot instruction.
+ for (ConstMIBundleOperands OP(&MI); OP.isValid(); ++OP) {
+ if (OP->isJTI())
return false;
- if (OP.isMBB() && OP.getMBB() == MBB)
+ if (OP->isMBB() && OP->getMBB() == MBB)
return false;
}
}

View File

@ -0,0 +1,28 @@
Pull in r199186 from upstream llvm trunk (by Jakob Stoklund Olesen):
Switch the NEON register class from QPR to DPair.
The already allocatable DPair superclass contains odd-even D register
pair in addition to the even-odd pairs in the QPR register class. There
is no reason to constrain the set of D register pairs that can be used
for NEON values. Any NEON instructions that require a Q register will
automatically constrain the register class to QPR.
The allocation order for DPair begins with the QPR registers, so
register allocation is unlikely to change much.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/ARM/ARMISelLowering.cpp
===================================================================
--- lib/Target/ARM/ARMISelLowering.cpp
+++ lib/Target/ARM/ARMISelLowering.cpp
@@ -156,7 +156,7 @@ void ARMTargetLowering::addDRTypeForNEON(MVT VT) {
}
void ARMTargetLowering::addQRTypeForNEON(MVT VT) {
- addRegisterClass(VT, &ARM::QPRRegClass);
+ addRegisterClass(VT, &ARM::DPairRegClass);
addTypeForNEON(VT, MVT::v2f64, MVT::v4i32);
}

View File

@ -0,0 +1,81 @@
Pull in r199187 from upstream llvm trunk (by Jakob Stoklund Olesen):
Always let value types influence register classes.
When creating a virtual register for a def, the value type should be
used to pick the register class. If we only use the register class
constraint on the instruction, we might pick a too large register class.
Some registers can store values of different sizes. For example, the x86
xmm registers can hold f32, f64, and 128-bit vectors. The three
different value sizes are represented by register classes with identical
register sets: FR32, FR64, and VR128. These register classes have
different spill slot sizes, so it is important to use the right one.
The register class constraint on an instruction doesn't necessarily care
about the size of the value its defining. The value type determines
that.
This fixes a problem where InstrEmitter was picking 32-bit register
classes for 64-bit values on SPARC.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: test/CodeGen/SPARC/spillsize.ll
===================================================================
--- test/CodeGen/SPARC/spillsize.ll
+++ test/CodeGen/SPARC/spillsize.ll
@@ -0,0 +1,25 @@
+; RUN: llc < %s -verify-machineinstrs | FileCheck %s
+target datalayout = "E-m:e-i64:64-n32:64-S128"
+target triple = "sparcv9"
+
+; CHECK-LABEL: spill4
+; This function spills two values: %p and the materialized large constant.
+; Both must use 8-byte spill and fill instructions.
+; CHECK: stx %{{..}}, [%fp+
+; CHECK: stx %{{..}}, [%fp+
+; CHECK: ldx [%fp+
+; CHECK: ldx [%fp+
+define void @spill4(i64* nocapture %p) {
+entry:
+ %val0 = load i64* %p
+ %cmp0 = icmp ult i64 %val0, 385672958347594845
+ %cm80 = zext i1 %cmp0 to i64
+ store i64 %cm80, i64* %p, align 8
+ tail call void asm sideeffect "", "~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{g2},~{g3},~{g4},~{g5},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o7}"()
+ %arrayidx1 = getelementptr inbounds i64* %p, i64 1
+ %val = load i64* %arrayidx1
+ %cmp = icmp ult i64 %val, 385672958347594845
+ %cm8 = select i1 %cmp, i64 10, i64 20
+ store i64 %cm8, i64* %arrayidx1, align 8
+ ret void
+}
Index: lib/CodeGen/SelectionDAG/InstrEmitter.cpp
===================================================================
--- lib/CodeGen/SelectionDAG/InstrEmitter.cpp
+++ lib/CodeGen/SelectionDAG/InstrEmitter.cpp
@@ -220,10 +220,19 @@ void InstrEmitter::CreateVirtualRegisters(SDNode *
unsigned VRBase = 0;
const TargetRegisterClass *RC =
TRI->getAllocatableClass(TII->getRegClass(II, i, TRI, *MF));
- // If the register class is unknown for the given definition, then try to
- // infer one from the value type.
- if (!RC && i < NumResults)
- RC = TLI->getRegClassFor(Node->getSimpleValueType(i));
+ // Always let the value type influence the used register class. The
+ // constraints on the instruction may be too lax to represent the value
+ // type correctly. For example, a 64-bit float (X86::FR64) can't live in
+ // the 32-bit float super-class (X86::FR32).
+ if (i < NumResults && TLI->isTypeLegal(Node->getSimpleValueType(i))) {
+ const TargetRegisterClass *VTRC =
+ TLI->getRegClassFor(Node->getSimpleValueType(i));
+ if (RC)
+ VTRC = TRI->getCommonSubClass(RC, VTRC);
+ if (VTRC)
+ RC = VTRC;
+ }
+
if (II.OpInfo[i].isOptionalDef()) {
// Optional def must be a physical register.
unsigned NumResults = CountResults(Node);

View File

@ -0,0 +1,200 @@
Pull in r199775 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Do not add PC to _GLOBAL_OFFSET_TABLE_ address to access GOT in absolute code.
Fixes PR#18521
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcAsmPrinter.cpp
===================================================================
--- lib/Target/Sparc/SparcAsmPrinter.cpp
+++ lib/Target/Sparc/SparcAsmPrinter.cpp
@@ -65,18 +65,24 @@ namespace {
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &O);
+
+ void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI);
+
};
} // end of anonymous namespace
-static MCOperand createPCXCallOP(MCSymbol *Label,
- MCContext &OutContext)
-{
- const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Label,
+static MCOperand createSparcMCOperand(SparcMCExpr::VariantKind Kind,
+ MCSymbol *Sym, MCContext &OutContext) {
+ const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Sym,
OutContext);
- const SparcMCExpr *expr = SparcMCExpr::Create(SparcMCExpr::VK_Sparc_None,
- MCSym, OutContext);
+ const SparcMCExpr *expr = SparcMCExpr::Create(Kind, MCSym, OutContext);
return MCOperand::CreateExpr(expr);
+
}
+static MCOperand createPCXCallOP(MCSymbol *Label,
+ MCContext &OutContext) {
+ return createSparcMCOperand(SparcMCExpr::VK_Sparc_None, Label, OutContext);
+}
static MCOperand createPCXRelExprOp(SparcMCExpr::VariantKind Kind,
MCSymbol *GOTLabel, MCSymbol *StartLabel,
@@ -115,43 +121,101 @@ static void EmitSETHI(MCStreamer &OutStreamer,
OutStreamer.EmitInstruction(SETHIInst);
}
-static void EmitOR(MCStreamer &OutStreamer, MCOperand &RS1,
- MCOperand &Imm, MCOperand &RD)
+static void EmitBinary(MCStreamer &OutStreamer, unsigned Opcode,
+ MCOperand &RS1, MCOperand &Src2, MCOperand &RD)
{
- MCInst ORInst;
- ORInst.setOpcode(SP::ORri);
- ORInst.addOperand(RD);
- ORInst.addOperand(RS1);
- ORInst.addOperand(Imm);
- OutStreamer.EmitInstruction(ORInst);
+ MCInst Inst;
+ Inst.setOpcode(Opcode);
+ Inst.addOperand(RD);
+ Inst.addOperand(RS1);
+ Inst.addOperand(Src2);
+ OutStreamer.EmitInstruction(Inst);
}
+static void EmitOR(MCStreamer &OutStreamer,
+ MCOperand &RS1, MCOperand &Imm, MCOperand &RD) {
+ EmitBinary(OutStreamer, SP::ORri, RS1, Imm, RD);
+}
+
static void EmitADD(MCStreamer &OutStreamer,
- MCOperand &RS1, MCOperand &RS2, MCOperand &RD)
-{
- MCInst ADDInst;
- ADDInst.setOpcode(SP::ADDrr);
- ADDInst.addOperand(RD);
- ADDInst.addOperand(RS1);
- ADDInst.addOperand(RS2);
- OutStreamer.EmitInstruction(ADDInst);
+ MCOperand &RS1, MCOperand &RS2, MCOperand &RD) {
+ EmitBinary(OutStreamer, SP::ADDrr, RS1, RS2, RD);
}
-static void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,
- MCStreamer &OutStreamer,
- MCContext &OutContext)
+static void EmitSHL(MCStreamer &OutStreamer,
+ MCOperand &RS1, MCOperand &Imm, MCOperand &RD) {
+ EmitBinary(OutStreamer, SP::SLLri, RS1, Imm, RD);
+}
+
+
+static void EmitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym,
+ SparcMCExpr::VariantKind HiKind,
+ SparcMCExpr::VariantKind LoKind,
+ MCOperand &RD,
+ MCContext &OutContext) {
+
+ MCOperand hi = createSparcMCOperand(HiKind, GOTSym, OutContext);
+ MCOperand lo = createSparcMCOperand(LoKind, GOTSym, OutContext);
+ EmitSETHI(OutStreamer, hi, RD);
+ EmitOR(OutStreamer, RD, lo, RD);
+}
+
+void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI)
{
- const MachineOperand &MO = MI->getOperand(0);
- MCSymbol *StartLabel = OutContext.CreateTempSymbol();
- MCSymbol *EndLabel = OutContext.CreateTempSymbol();
- MCSymbol *SethiLabel = OutContext.CreateTempSymbol();
MCSymbol *GOTLabel =
OutContext.GetOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
+ const MachineOperand &MO = MI->getOperand(0);
assert(MO.getReg() != SP::O7 &&
"%o7 is assigned as destination for getpcx!");
MCOperand MCRegOP = MCOperand::CreateReg(MO.getReg());
+
+
+ if (TM.getRelocationModel() != Reloc::PIC_) {
+ // Just load the address of GOT to MCRegOP.
+ switch(TM.getCodeModel()) {
+ default:
+ llvm_unreachable("Unsupported absolute code model");
+ case CodeModel::Small:
+ EmitHiLo(OutStreamer, GOTLabel,
+ SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO,
+ MCRegOP, OutContext);
+ break;
+ case CodeModel::Medium: {
+ EmitHiLo(OutStreamer, GOTLabel,
+ SparcMCExpr::VK_Sparc_H44, SparcMCExpr::VK_Sparc_M44,
+ MCRegOP, OutContext);
+ MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(12,
+ OutContext));
+ EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP);
+ MCOperand lo = createSparcMCOperand(SparcMCExpr::VK_Sparc_L44,
+ GOTLabel, OutContext);
+ EmitOR(OutStreamer, MCRegOP, lo, MCRegOP);
+ break;
+ }
+ case CodeModel::Large: {
+ EmitHiLo(OutStreamer, GOTLabel,
+ SparcMCExpr::VK_Sparc_HH, SparcMCExpr::VK_Sparc_HM,
+ MCRegOP, OutContext);
+ MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(32,
+ OutContext));
+ EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP);
+ // Use register %o7 to load the lower 32 bits.
+ MCOperand RegO7 = MCOperand::CreateReg(SP::O7);
+ EmitHiLo(OutStreamer, GOTLabel,
+ SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO,
+ RegO7, OutContext);
+ EmitADD(OutStreamer, MCRegOP, RegO7, MCRegOP);
+ }
+ }
+ return;
+ }
+
+ MCSymbol *StartLabel = OutContext.CreateTempSymbol();
+ MCSymbol *EndLabel = OutContext.CreateTempSymbol();
+ MCSymbol *SethiLabel = OutContext.CreateTempSymbol();
+
MCOperand RegO7 = MCOperand::CreateReg(SP::O7);
// <StartLabel>:
@@ -187,7 +251,7 @@ void SparcAsmPrinter::EmitInstruction(const Machin
// FIXME: Debug Value.
return;
case SP::GETPCX:
- LowerGETPCXAndEmitMCInsts(MI, OutStreamer, OutContext);
+ LowerGETPCXAndEmitMCInsts(MI);
return;
}
MachineBasicBlock::const_instr_iterator I = MI;
Index: test/CodeGen/SPARC/tls.ll
===================================================================
--- test/CodeGen/SPARC/tls.ll
+++ test/CodeGen/SPARC/tls.ll
@@ -38,8 +38,7 @@ entry:
; v8abs-LABEL: test_tls_extern
-; v8abs: or {{%[goli][0-7]}}, %lo(_GLOBAL_OFFSET_TABLE_+{{.+}}), [[PC:%[goli][0-7]]]
-; v8abs: add [[PC]], %o7, %[[GOTBASE:[goli][0-7]]]
+; v8abs: or {{%[goli][0-7]}}, %lo(_GLOBAL_OFFSET_TABLE_), %[[GOTBASE:[goli][0-7]]]
; v8abs: sethi %tie_hi22(extern_symbol), [[R1:%[goli][0-7]]]
; v8abs: add [[R1]], %tie_lo10(extern_symbol), %[[R2:[goli][0-7]]]
; v8abs: ld [%[[GOTBASE]]+%[[R2]]], [[R3:%[goli][0-7]]], %tie_ld(extern_symbol)
@@ -47,8 +46,7 @@ entry:
; v8abs: ld [%[[R4]]]
; v9abs-LABEL: test_tls_extern
-; v9abs: or {{%[goli][0-7]}}, %lo(_GLOBAL_OFFSET_TABLE_+{{.+}}), [[PC:%[goli][0-7]]]
-; v9abs: add [[PC]], %o7, %[[GOTBASE:[goli][0-7]]]
+; v9abs: or {{%[goli][0-7]}}, %l44(_GLOBAL_OFFSET_TABLE_), %[[GOTBASE:[goli][0-7]]]
; v9abs: sethi %tie_hi22(extern_symbol), [[R1:%[goli][0-7]]]
; v9abs: add [[R1]], %tie_lo10(extern_symbol), %[[R2:[goli][0-7]]]
; v9abs: ldx [%[[GOTBASE]]+%[[R2]]], [[R3:%[goli][0-7]]], %tie_ldx(extern_symbol)

View File

@ -0,0 +1,142 @@
Pull in r199781 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Add support for inline assembly constraint 'I'.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: test/CodeGen/SPARC/inlineasm.ll
===================================================================
--- test/CodeGen/SPARC/inlineasm.ll
+++ test/CodeGen/SPARC/inlineasm.ll
@@ -0,0 +1,35 @@
+; RUN: llc -march=sparc <%s | FileCheck %s
+
+; CHECK-LABEL: test_constraint_r
+; CHECK: add %o1, %o0, %o0
+define i32 @test_constraint_r(i32 %a, i32 %b) {
+entry:
+ %0 = tail call i32 asm sideeffect "add $2, $1, $0", "=r,r,r"(i32 %a, i32 %b)
+ ret i32 %0
+}
+
+; CHECK-LABEL: test_constraint_I
+; CHECK: add %o0, 1023, %o0
+define i32 @test_constraint_I(i32 %a) {
+entry:
+ %0 = tail call i32 asm sideeffect "add $1, $2, $0", "=r,r,rI"(i32 %a, i32 1023)
+ ret i32 %0
+}
+
+; CHECK-LABEL: test_constraint_I_neg
+; CHECK: add %o0, -4096, %o0
+define i32 @test_constraint_I_neg(i32 %a) {
+entry:
+ %0 = tail call i32 asm sideeffect "add $1, $2, $0", "=r,r,rI"(i32 %a, i32 -4096)
+ ret i32 %0
+}
+
+; CHECK-LABEL: test_constraint_I_largeimm
+; CHECK: sethi 9, [[R0:%[gilo][0-7]]]
+; CHECK: or [[R0]], 784, [[R1:%[gilo][0-7]]]
+; CHECK: add %o0, [[R1]], %o0
+define i32 @test_constraint_I_largeimm(i32 %a) {
+entry:
+ %0 = tail call i32 asm sideeffect "add $1, $2, $0", "=r,r,rI"(i32 %a, i32 10000)
+ ret i32 %0
+}
Index: lib/Target/Sparc/SparcISelLowering.h
===================================================================
--- lib/Target/Sparc/SparcISelLowering.h
+++ lib/Target/Sparc/SparcISelLowering.h
@@ -73,6 +73,13 @@ namespace llvm {
virtual const char *getTargetNodeName(unsigned Opcode) const;
ConstraintType getConstraintType(const std::string &Constraint) const;
+ ConstraintWeight
+ getSingleConstraintMatchWeight(AsmOperandInfo &info,
+ const char *constraint) const;
+ void LowerAsmOperandForConstraint(SDValue Op,
+ std::string &Constraint,
+ std::vector<SDValue> &Ops,
+ SelectionDAG &DAG) const;
std::pair<unsigned, const TargetRegisterClass*>
getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const;
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -2918,6 +2918,8 @@ SparcTargetLowering::getConstraintType(const std::
switch (Constraint[0]) {
default: break;
case 'r': return C_RegisterClass;
+ case 'I': // SIMM13
+ return C_Other;
}
}
@@ -2924,6 +2926,64 @@ SparcTargetLowering::getConstraintType(const std::
return TargetLowering::getConstraintType(Constraint);
}
+TargetLowering::ConstraintWeight SparcTargetLowering::
+getSingleConstraintMatchWeight(AsmOperandInfo &info,
+ const char *constraint) const {
+ ConstraintWeight weight = CW_Invalid;
+ Value *CallOperandVal = info.CallOperandVal;
+ // If we don't have a value, we can't do a match,
+ // but allow it at the lowest weight.
+ if (CallOperandVal == NULL)
+ return CW_Default;
+
+ // Look at the constraint type.
+ switch (*constraint) {
+ default:
+ weight = TargetLowering::getSingleConstraintMatchWeight(info, constraint);
+ break;
+ case 'I': // SIMM13
+ if (ConstantInt *C = dyn_cast<ConstantInt>(info.CallOperandVal)) {
+ if (isInt<13>(C->getSExtValue()))
+ weight = CW_Constant;
+ }
+ break;
+ }
+ return weight;
+}
+
+/// LowerAsmOperandForConstraint - Lower the specified operand into the Ops
+/// vector. If it is invalid, don't add anything to Ops.
+void SparcTargetLowering::
+LowerAsmOperandForConstraint(SDValue Op,
+ std::string &Constraint,
+ std::vector<SDValue> &Ops,
+ SelectionDAG &DAG) const {
+ SDValue Result(0, 0);
+
+ // Only support length 1 constraints for now.
+ if (Constraint.length() > 1)
+ return;
+
+ char ConstraintLetter = Constraint[0];
+ switch (ConstraintLetter) {
+ default: break;
+ case 'I':
+ if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) {
+ if (isInt<13>(C->getSExtValue())) {
+ Result = DAG.getTargetConstant(C->getSExtValue(), Op.getValueType());
+ break;
+ }
+ return;
+ }
+ }
+
+ if (Result.getNode()) {
+ Ops.push_back(Result);
+ return;
+ }
+ TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
+}
+
std::pair<unsigned, const TargetRegisterClass*>
SparcTargetLowering::getRegForInlineAsmConstraint(const std::string &Constraint,
MVT VT) const {

View File

@ -0,0 +1,55 @@
Pull in r199786 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Add support for inline assembly constraints which specify registers by their aliases.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -2992,6 +2992,26 @@ SparcTargetLowering::getRegForInlineAsmConstraint(
case 'r':
return std::make_pair(0U, &SP::IntRegsRegClass);
}
+ } else if (!Constraint.empty() && Constraint.size() <= 5
+ && Constraint[0] == '{' && *(Constraint.end()-1) == '}') {
+ // constraint = '{r<d>}'
+ // Remove the braces from around the name.
+ StringRef name(Constraint.data()+1, Constraint.size()-2);
+ // Handle register aliases:
+ // r0-r7 -> g0-g7
+ // r8-r15 -> o0-o7
+ // r16-r23 -> l0-l7
+ // r24-r31 -> i0-i7
+ uint64_t intVal = 0;
+ if (name.substr(0, 1).equals("r")
+ && !name.substr(1).getAsInteger(10, intVal) && intVal <= 31) {
+ const char regTypes[] = { 'g', 'o', 'l', 'i' };
+ char regType = regTypes[intVal/8];
+ char regIdx = '0' + (intVal % 8);
+ char tmp[] = { '{', regType, regIdx, '}', 0 };
+ std::string newConstraint = std::string(tmp);
+ return TargetLowering::getRegForInlineAsmConstraint(newConstraint, VT);
+ }
}
return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT);
Index: test/CodeGen/SPARC/inlineasm.ll
===================================================================
--- test/CodeGen/SPARC/inlineasm.ll
+++ test/CodeGen/SPARC/inlineasm.ll
@@ -33,3 +33,13 @@ entry:
%0 = tail call i32 asm sideeffect "add $1, $2, $0", "=r,r,rI"(i32 %a, i32 10000)
ret i32 %0
}
+
+; CHECK-LABEL: test_constraint_reg
+; CHECK: ldda [%o1] 43, %g2
+; CHECK: ldda [%o1] 43, %g3
+define void @test_constraint_reg(i32 %s, i32* %ptr) {
+entry:
+ %0 = tail call i64 asm sideeffect "ldda [$1] $2, $0", "={r2},r,n"(i32* %ptr, i32 43)
+ %1 = tail call i64 asm sideeffect "ldda [$1] $2, $0", "={g3},r,n"(i32* %ptr, i32 43)
+ ret void
+}

View File

@ -0,0 +1,21 @@
Pull in r199940 from upstream llvm trunk (by Eric Christopher):
Fix out of bounds access to the double regs array. Given the
code this looks correct, but could use review. The previous
was definitely not correct.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
===================================================================
--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
+++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
@@ -734,7 +734,7 @@ bool SparcAsmParser::matchRegisterName(const AsmTo
&& !name.substr(1, 2).getAsInteger(10, intVal)
&& intVal >= 32 && intVal <= 62 && (intVal % 2 == 0)) {
// FIXME: Check V9
- RegNo = DoubleRegs[16 + intVal/2];
+ RegNo = DoubleRegs[intVal/2];
RegKind = SparcOperand::rk_DoubleReg;
return true;
}

View File

@ -0,0 +1,54 @@
Pull in r199974 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Correct quad register list in the asm parser.
Add test cases to check parsing of v9 double registers and their aliased quad registers.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: test/MC/Disassembler/Sparc/sparc-fp.txt
===================================================================
--- test/MC/Disassembler/Sparc/sparc-fp.txt
+++ test/MC/Disassembler/Sparc/sparc-fp.txt
@@ -81,6 +81,12 @@
# CHECK: faddq %f0, %f4, %f8
0x91 0xa0 0x08 0x64
+# CHECK: faddd %f32, %f34, %f62
+0xbf 0xa0 0x48 0x43
+
+# CHECK: faddq %f32, %f36, %f60
+0xbb 0xa0 0x48 0x65
+
# CHECK: fsubs %f0, %f4, %f8
0x91 0xa0 0x08 0xa4
Index: test/MC/Sparc/sparc-fp-instructions.s
===================================================================
--- test/MC/Sparc/sparc-fp-instructions.s
+++ test/MC/Sparc/sparc-fp-instructions.s
@@ -64,6 +64,12 @@
faddd %f0, %f4, %f8
faddq %f0, %f4, %f8
+ ! make sure we can handle V9 double registers and their aliased quad registers.
+ ! CHECK: faddd %f32, %f34, %f62 ! encoding: [0xbf,0xa0,0x48,0x43]
+ ! CHECK: faddq %f32, %f36, %f60 ! encoding: [0xbb,0xa0,0x48,0x65]
+ faddd %f32, %f34, %f62
+ faddq %f32, %f36, %f60
+
! CHECK: fsubs %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0xa4]
! CHECK: fsubd %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0xc4]
! CHECK: fsubq %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0xe4]
Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
===================================================================
--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
+++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
@@ -117,7 +117,7 @@ class SparcAsmParser : public MCTargetAsmParser {
static unsigned QuadFPRegs[32] = {
Sparc::Q0, Sparc::Q1, Sparc::Q2, Sparc::Q3,
Sparc::Q4, Sparc::Q5, Sparc::Q6, Sparc::Q7,
- Sparc::Q8, Sparc::Q7, Sparc::Q8, Sparc::Q9,
+ Sparc::Q8, Sparc::Q9, Sparc::Q10, Sparc::Q11,
Sparc::Q12, Sparc::Q13, Sparc::Q14, Sparc::Q15 };

View File

@ -0,0 +1,344 @@
Pull in r199975 from upstream llvm trunk (by Jakob Stoklund Olesen):
Implement atomicrmw operations in 32 and 64 bits for SPARCv9.
These all use the compare-and-swap CASA/CASXA instructions.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: test/CodeGen/SPARC/atomics.ll
===================================================================
--- test/CodeGen/SPARC/atomics.ll
+++ test/CodeGen/SPARC/atomics.ll
@@ -1,4 +1,4 @@
-; RUN: llc < %s -march=sparcv9 | FileCheck %s
+; RUN: llc < %s -march=sparcv9 -verify-machineinstrs | FileCheck %s
; CHECK-LABEL: test_atomic_i32
; CHECK: ld [%o0]
@@ -61,3 +61,84 @@ entry:
%b = atomicrmw xchg i32* %ptr, i32 42 monotonic
ret i32 %b
}
+
+; CHECK-LABEL: test_load_add_32
+; CHECK: membar
+; CHECK: add
+; CHECK: cas [%o0]
+; CHECK: membar
+define zeroext i32 @test_load_add_32(i32* %p, i32 zeroext %v) {
+entry:
+ %0 = atomicrmw add i32* %p, i32 %v seq_cst
+ ret i32 %0
+}
+
+; CHECK-LABEL: test_load_sub_64
+; CHECK: membar
+; CHECK: sub
+; CHECK: casx [%o0]
+; CHECK: membar
+define zeroext i64 @test_load_sub_64(i64* %p, i64 zeroext %v) {
+entry:
+ %0 = atomicrmw sub i64* %p, i64 %v seq_cst
+ ret i64 %0
+}
+
+; CHECK-LABEL: test_load_xor_32
+; CHECK: membar
+; CHECK: xor
+; CHECK: cas [%o0]
+; CHECK: membar
+define zeroext i32 @test_load_xor_32(i32* %p, i32 zeroext %v) {
+entry:
+ %0 = atomicrmw xor i32* %p, i32 %v seq_cst
+ ret i32 %0
+}
+
+; CHECK-LABEL: test_load_and_32
+; CHECK: membar
+; CHECK: and
+; CHECK-NOT: xor
+; CHECK: cas [%o0]
+; CHECK: membar
+define zeroext i32 @test_load_and_32(i32* %p, i32 zeroext %v) {
+entry:
+ %0 = atomicrmw and i32* %p, i32 %v seq_cst
+ ret i32 %0
+}
+
+; CHECK-LABEL: test_load_nand_32
+; CHECK: membar
+; CHECK: and
+; CHECK: xor
+; CHECK: cas [%o0]
+; CHECK: membar
+define zeroext i32 @test_load_nand_32(i32* %p, i32 zeroext %v) {
+entry:
+ %0 = atomicrmw nand i32* %p, i32 %v seq_cst
+ ret i32 %0
+}
+
+; CHECK-LABEL: test_load_max_64
+; CHECK: membar
+; CHECK: cmp
+; CHECK: movg %xcc
+; CHECK: casx [%o0]
+; CHECK: membar
+define zeroext i64 @test_load_max_64(i64* %p, i64 zeroext %v) {
+entry:
+ %0 = atomicrmw max i64* %p, i64 %v seq_cst
+ ret i64 %0
+}
+
+; CHECK-LABEL: test_load_umin_32
+; CHECK: membar
+; CHECK: cmp
+; CHECK: movleu %icc
+; CHECK: cas [%o0]
+; CHECK: membar
+define zeroext i32 @test_load_umin_32(i32* %p, i32 zeroext %v) {
+entry:
+ %0 = atomicrmw umin i32* %p, i32 %v seq_cst
+ ret i32 %0
+}
Index: lib/Target/Sparc/SparcInstr64Bit.td
===================================================================
--- lib/Target/Sparc/SparcInstr64Bit.td
+++ lib/Target/Sparc/SparcInstr64Bit.td
@@ -438,6 +438,31 @@ def : Pat<(atomic_store ADDRri:$dst, i64:$val), (S
} // Predicates = [Is64Bit]
+let usesCustomInserter = 1, hasCtrlDep = 1, mayLoad = 1, mayStore = 1,
+ Defs = [ICC] in
+multiclass AtomicRMW<SDPatternOperator op32, SDPatternOperator op64> {
+
+ def _32 : Pseudo<(outs IntRegs:$rd),
+ (ins ptr_rc:$addr, IntRegs:$rs2), "",
+ [(set i32:$rd, (op32 iPTR:$addr, i32:$rs2))]>;
+
+ let Predicates = [Is64Bit] in
+ def _64 : Pseudo<(outs I64Regs:$rd),
+ (ins ptr_rc:$addr, I64Regs:$rs2), "",
+ [(set i64:$rd, (op64 iPTR:$addr, i64:$rs2))]>;
+}
+
+defm ATOMIC_LOAD_ADD : AtomicRMW<atomic_load_add_32, atomic_load_add_64>;
+defm ATOMIC_LOAD_SUB : AtomicRMW<atomic_load_sub_32, atomic_load_sub_64>;
+defm ATOMIC_LOAD_AND : AtomicRMW<atomic_load_and_32, atomic_load_and_64>;
+defm ATOMIC_LOAD_OR : AtomicRMW<atomic_load_or_32, atomic_load_or_64>;
+defm ATOMIC_LOAD_XOR : AtomicRMW<atomic_load_xor_32, atomic_load_xor_64>;
+defm ATOMIC_LOAD_NAND : AtomicRMW<atomic_load_nand_32, atomic_load_nand_64>;
+defm ATOMIC_LOAD_MIN : AtomicRMW<atomic_load_min_32, atomic_load_min_64>;
+defm ATOMIC_LOAD_MAX : AtomicRMW<atomic_load_max_32, atomic_load_max_64>;
+defm ATOMIC_LOAD_UMIN : AtomicRMW<atomic_load_umin_32, atomic_load_umin_64>;
+defm ATOMIC_LOAD_UMAX : AtomicRMW<atomic_load_umax_32, atomic_load_umax_64>;
+
// Global addresses, constant pool entries
let Predicates = [Is64Bit] in {
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -2831,11 +2831,6 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) cons
MachineBasicBlock *
SparcTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
MachineBasicBlock *BB) const {
- const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo();
- unsigned BROpcode;
- unsigned CC;
- DebugLoc dl = MI->getDebugLoc();
- // Figure out the conditional branch opcode to use for this select_cc.
switch (MI->getOpcode()) {
default: llvm_unreachable("Unknown SELECT_CC!");
case SP::SELECT_CC_Int_ICC:
@@ -2842,17 +2837,64 @@ SparcTargetLowering::EmitInstrWithCustomInserter(M
case SP::SELECT_CC_FP_ICC:
case SP::SELECT_CC_DFP_ICC:
case SP::SELECT_CC_QFP_ICC:
- BROpcode = SP::BCOND;
- break;
+ return expandSelectCC(MI, BB, SP::BCOND);
case SP::SELECT_CC_Int_FCC:
case SP::SELECT_CC_FP_FCC:
case SP::SELECT_CC_DFP_FCC:
case SP::SELECT_CC_QFP_FCC:
- BROpcode = SP::FBCOND;
- break;
+ return expandSelectCC(MI, BB, SP::FBCOND);
+
+ case SP::ATOMIC_LOAD_ADD_32:
+ return expandAtomicRMW(MI, BB, SP::ADDrr);
+ case SP::ATOMIC_LOAD_ADD_64:
+ return expandAtomicRMW(MI, BB, SP::ADDXrr);
+ case SP::ATOMIC_LOAD_SUB_32:
+ return expandAtomicRMW(MI, BB, SP::SUBrr);
+ case SP::ATOMIC_LOAD_SUB_64:
+ return expandAtomicRMW(MI, BB, SP::SUBXrr);
+ case SP::ATOMIC_LOAD_AND_32:
+ return expandAtomicRMW(MI, BB, SP::ANDrr);
+ case SP::ATOMIC_LOAD_AND_64:
+ return expandAtomicRMW(MI, BB, SP::ANDXrr);
+ case SP::ATOMIC_LOAD_OR_32:
+ return expandAtomicRMW(MI, BB, SP::ORrr);
+ case SP::ATOMIC_LOAD_OR_64:
+ return expandAtomicRMW(MI, BB, SP::ORXrr);
+ case SP::ATOMIC_LOAD_XOR_32:
+ return expandAtomicRMW(MI, BB, SP::XORrr);
+ case SP::ATOMIC_LOAD_XOR_64:
+ return expandAtomicRMW(MI, BB, SP::XORXrr);
+ case SP::ATOMIC_LOAD_NAND_32:
+ return expandAtomicRMW(MI, BB, SP::ANDrr);
+ case SP::ATOMIC_LOAD_NAND_64:
+ return expandAtomicRMW(MI, BB, SP::ANDXrr);
+
+ case SP::ATOMIC_LOAD_MAX_32:
+ return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_G);
+ case SP::ATOMIC_LOAD_MAX_64:
+ return expandAtomicRMW(MI, BB, SP::MOVXCCrr, SPCC::ICC_G);
+ case SP::ATOMIC_LOAD_MIN_32:
+ return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_LE);
+ case SP::ATOMIC_LOAD_MIN_64:
+ return expandAtomicRMW(MI, BB, SP::MOVXCCrr, SPCC::ICC_LE);
+ case SP::ATOMIC_LOAD_UMAX_32:
+ return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_GU);
+ case SP::ATOMIC_LOAD_UMAX_64:
+ return expandAtomicRMW(MI, BB, SP::MOVXCCrr, SPCC::ICC_GU);
+ case SP::ATOMIC_LOAD_UMIN_32:
+ return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_LEU);
+ case SP::ATOMIC_LOAD_UMIN_64:
+ return expandAtomicRMW(MI, BB, SP::MOVXCCrr, SPCC::ICC_LEU);
}
+}
- CC = (SPCC::CondCodes)MI->getOperand(3).getImm();
+MachineBasicBlock*
+SparcTargetLowering::expandSelectCC(MachineInstr *MI,
+ MachineBasicBlock *BB,
+ unsigned BROpcode) const {
+ const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo();
+ DebugLoc dl = MI->getDebugLoc();
+ unsigned CC = (SPCC::CondCodes)MI->getOperand(3).getImm();
// To "insert" a SELECT_CC instruction, we actually have to insert the diamond
// control-flow pattern. The incoming instruction knows the destination vreg
@@ -2906,6 +2948,100 @@ SparcTargetLowering::EmitInstrWithCustomInserter(M
return BB;
}
+MachineBasicBlock*
+SparcTargetLowering::expandAtomicRMW(MachineInstr *MI,
+ MachineBasicBlock *MBB,
+ unsigned Opcode,
+ unsigned CondCode) const {
+ const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo();
+ MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo();
+ DebugLoc DL = MI->getDebugLoc();
+
+ // MI is an atomic read-modify-write instruction of the form:
+ //
+ // rd = atomicrmw<op> addr, rs2
+ //
+ // All three operands are registers.
+ unsigned DestReg = MI->getOperand(0).getReg();
+ unsigned AddrReg = MI->getOperand(1).getReg();
+ unsigned Rs2Reg = MI->getOperand(2).getReg();
+
+ // SelectionDAG has already inserted memory barriers before and after MI, so
+ // we simply have to implement the operatiuon in terms of compare-and-swap.
+ //
+ // %val0 = load %addr
+ // loop:
+ // %val = phi %val0, %dest
+ // %upd = op %val, %rs2
+ // %dest = cas %addr, %upd, %val
+ // cmp %val, %dest
+ // bne loop
+ // done:
+ //
+ bool is64Bit = SP::I64RegsRegClass.hasSubClassEq(MRI.getRegClass(DestReg));
+ const TargetRegisterClass *ValueRC =
+ is64Bit ? &SP::I64RegsRegClass : &SP::IntRegsRegClass;
+ unsigned Val0Reg = MRI.createVirtualRegister(ValueRC);
+
+ BuildMI(*MBB, MI, DL, TII.get(is64Bit ? SP::LDXri : SP::LDri), Val0Reg)
+ .addReg(AddrReg).addImm(0);
+
+ // Split the basic block MBB before MI and insert the loop block in the hole.
+ MachineFunction::iterator MFI = MBB;
+ const BasicBlock *LLVM_BB = MBB->getBasicBlock();
+ MachineFunction *MF = MBB->getParent();
+ MachineBasicBlock *LoopMBB = MF->CreateMachineBasicBlock(LLVM_BB);
+ MachineBasicBlock *DoneMBB = MF->CreateMachineBasicBlock(LLVM_BB);
+ ++MFI;
+ MF->insert(MFI, LoopMBB);
+ MF->insert(MFI, DoneMBB);
+
+ // Move MI and following instructions to DoneMBB.
+ DoneMBB->splice(DoneMBB->begin(), MBB, MI, MBB->end());
+ DoneMBB->transferSuccessorsAndUpdatePHIs(MBB);
+
+ // Connect the CFG again.
+ MBB->addSuccessor(LoopMBB);
+ LoopMBB->addSuccessor(LoopMBB);
+ LoopMBB->addSuccessor(DoneMBB);
+
+ // Build the loop block.
+ unsigned ValReg = MRI.createVirtualRegister(ValueRC);
+ unsigned UpdReg = MRI.createVirtualRegister(ValueRC);
+
+ BuildMI(LoopMBB, DL, TII.get(SP::PHI), ValReg)
+ .addReg(Val0Reg).addMBB(MBB)
+ .addReg(DestReg).addMBB(LoopMBB);
+
+ if (CondCode) {
+ // This is one of the min/max operations. We need a CMPrr followed by a
+ // MOVXCC/MOVICC.
+ BuildMI(LoopMBB, DL, TII.get(SP::CMPrr)).addReg(ValReg).addReg(Rs2Reg);
+ BuildMI(LoopMBB, DL, TII.get(Opcode), UpdReg)
+ .addReg(ValReg).addReg(Rs2Reg).addImm(CondCode);
+ } else {
+ BuildMI(LoopMBB, DL, TII.get(Opcode), UpdReg)
+ .addReg(ValReg).addReg(Rs2Reg);
+ }
+
+ if (MI->getOpcode() == SP::ATOMIC_LOAD_NAND_32 ||
+ MI->getOpcode() == SP::ATOMIC_LOAD_NAND_64) {
+ unsigned TmpReg = UpdReg;
+ UpdReg = MRI.createVirtualRegister(ValueRC);
+ BuildMI(LoopMBB, DL, TII.get(SP::XORri), UpdReg).addReg(TmpReg).addImm(-1);
+ }
+
+ BuildMI(LoopMBB, DL, TII.get(is64Bit ? SP::CASXrr : SP::CASrr), DestReg)
+ .addReg(AddrReg).addReg(UpdReg).addReg(ValReg)
+ .setMemRefs(MI->memoperands_begin(), MI->memoperands_end());
+ BuildMI(LoopMBB, DL, TII.get(SP::CMPrr)).addReg(ValReg).addReg(DestReg);
+ BuildMI(LoopMBB, DL, TII.get(is64Bit ? SP::BPXCC : SP::BCOND))
+ .addMBB(LoopMBB).addImm(SPCC::ICC_NE);
+
+ MI->eraseFromParent();
+ return DoneMBB;
+}
+
//===----------------------------------------------------------------------===//
// Sparc Inline Assembly Support
//===----------------------------------------------------------------------===//
Index: lib/Target/Sparc/SparcISelLowering.h
===================================================================
--- lib/Target/Sparc/SparcISelLowering.h
+++ lib/Target/Sparc/SparcISelLowering.h
@@ -165,6 +165,13 @@ namespace llvm {
virtual void ReplaceNodeResults(SDNode *N,
SmallVectorImpl<SDValue>& Results,
SelectionDAG &DAG) const;
+
+ MachineBasicBlock *expandSelectCC(MachineInstr *MI, MachineBasicBlock *BB,
+ unsigned BROpcode) const;
+ MachineBasicBlock *expandAtomicRMW(MachineInstr *MI,
+ MachineBasicBlock *BB,
+ unsigned Opcode,
+ unsigned CondCode = 0) const;
};
} // end namespace llvm

View File

@ -0,0 +1,377 @@
Pull in r199977 from upstream llvm trunk (by Venkatraman Govindaraju):
[SparcV9] Add support for JIT in Sparc64.
With this change, all supported tests in test/ExecutionEngine pass in sparcv9.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcJITInfo.cpp
===================================================================
--- lib/Target/Sparc/SparcJITInfo.cpp
+++ lib/Target/Sparc/SparcJITInfo.cpp
@@ -12,8 +12,9 @@
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "jit"
#include "SparcJITInfo.h"
+#include "Sparc.h"
#include "SparcRelocations.h"
-
+#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/JITCodeEmitter.h"
#include "llvm/Support/Memory.h"
@@ -35,18 +36,17 @@ extern "C" {
"SparcCompilationCallback:\n"
// Save current register window.
"\tsave %sp, -192, %sp\n"
- // stubaddr+4 is in %g1.
+ // stubaddr is in %g1.
"\tcall SparcCompilationCallbackC\n"
- "\t sub %g1, 4, %o0\n"
+ "\t mov %g1, %o0\n"
// restore original register window and
// copy %o0 to %g1
- "\t restore %o0, 0, %g1\n"
+ "\trestore %o0, 0, %g1\n"
// call the new stub
"\tjmp %g1\n"
"\t nop\n"
"\t.size SparcCompilationCallback, .-SparcCompilationCallback"
);
-
#else
void SparcCompilationCallback() {
llvm_unreachable(
@@ -55,33 +55,120 @@ extern "C" {
#endif
}
-#define HI(Val) (((unsigned)(Val)) >> 10)
-#define LO(Val) (((unsigned)(Val)) & 0x3FF)
#define SETHI_INST(imm, rd) (0x01000000 | ((rd) << 25) | ((imm) & 0x3FFFFF))
#define JMP_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x38 << 19) \
| ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF))
#define NOP_INST SETHI_INST(0, 0)
+#define OR_INST_I(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x02 << 19) \
+ | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF))
+#define OR_INST_R(rs1, rs2, rd) (0x80000000 | ((rd) << 25) | (0x02 << 19) \
+ | ((rs1) << 14) | (0 << 13) | ((rs2) & 0x1F))
+#define RDPC_INST(rd) (0x80000000 | ((rd) << 25) | (0x28 << 19) \
+ | (5 << 14))
+#define LDX_INST(rs1, imm, rd) (0xC0000000 | ((rd) << 25) | (0x0B << 19) \
+ | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF))
+#define SLLX_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x25 << 19) \
+ | ((rs1) << 14) | (3 << 12) | ((imm) & 0x3F))
+#define SUB_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x04 << 19) \
+ | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF))
+#define XOR_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x03 << 19) \
+ | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF))
+#define BA_INST(tgt) (0x10800000 | ((tgt) & 0x3FFFFF))
+// Emit instructions to jump to Addr and store the starting address of
+// the instructions emitted in the scratch register.
+static void emitInstrForIndirectJump(intptr_t Addr,
+ unsigned scratch,
+ SmallVectorImpl<uint32_t> &Insts) {
+
+ if (isInt<13>(Addr)) {
+ // Emit: jmpl %g0+Addr, <scratch>
+ // nop
+ Insts.push_back(JMP_INST(0, LO10(Addr), scratch));
+ Insts.push_back(NOP_INST);
+ return;
+ }
+
+ if (isUInt<32>(Addr)) {
+ // Emit: sethi %hi(Addr), scratch
+ // jmpl scratch+%lo(Addr), scratch
+ // sub scratch, 4, scratch
+ Insts.push_back(SETHI_INST(HI22(Addr), scratch));
+ Insts.push_back(JMP_INST(scratch, LO10(Addr), scratch));
+ Insts.push_back(SUB_INST(scratch, 4, scratch));
+ return;
+ }
+
+ if (Addr < 0 && isInt<33>(Addr)) {
+ // Emit: sethi %hix(Addr), scratch)
+ // xor scratch, %lox(Addr), scratch
+ // jmpl scratch+0, scratch
+ // sub scratch, 8, scratch
+ Insts.push_back(SETHI_INST(HIX22(Addr), scratch));
+ Insts.push_back(XOR_INST(scratch, LOX10(Addr), scratch));
+ Insts.push_back(JMP_INST(scratch, 0, scratch));
+ Insts.push_back(SUB_INST(scratch, 8, scratch));
+ return;
+ }
+
+ // Emit: rd %pc, scratch
+ // ldx [scratch+16], scratch
+ // jmpl scratch+0, scratch
+ // sub scratch, 8, scratch
+ // <Addr: 8 byte>
+ Insts.push_back(RDPC_INST(scratch));
+ Insts.push_back(LDX_INST(scratch, 16, scratch));
+ Insts.push_back(JMP_INST(scratch, 0, scratch));
+ Insts.push_back(SUB_INST(scratch, 8, scratch));
+ Insts.push_back((uint32_t)(((int64_t)Addr) >> 32) & 0xffffffff);
+ Insts.push_back((uint32_t)(Addr & 0xffffffff));
+
+ // Instruction sequence without rdpc instruction
+ // 7 instruction and 2 scratch register
+ // Emit: sethi %hh(Addr), scratch
+ // or scratch, %hm(Addr), scratch
+ // sllx scratch, 32, scratch
+ // sethi %hi(Addr), scratch2
+ // or scratch, scratch2, scratch
+ // jmpl scratch+%lo(Addr), scratch
+ // sub scratch, 20, scratch
+ // Insts.push_back(SETHI_INST(HH22(Addr), scratch));
+ // Insts.push_back(OR_INST_I(scratch, HM10(Addr), scratch));
+ // Insts.push_back(SLLX_INST(scratch, 32, scratch));
+ // Insts.push_back(SETHI_INST(HI22(Addr), scratch2));
+ // Insts.push_back(OR_INST_R(scratch, scratch2, scratch));
+ // Insts.push_back(JMP_INST(scratch, LO10(Addr), scratch));
+ // Insts.push_back(SUB_INST(scratch, 20, scratch));
+}
+
extern "C" void *SparcCompilationCallbackC(intptr_t StubAddr) {
// Get the address of the compiled code for this function.
intptr_t NewVal = (intptr_t) JITCompilerFunction((void*) StubAddr);
// Rewrite the function stub so that we don't end up here every time we
- // execute the call. We're replacing the first three instructions of the
- // stub with code that jumps to the compiled function:
- // sethi %hi(NewVal), %g1
- // jmp %g1+%lo(NewVal)
- // nop
+ // execute the call. We're replacing the stub instructions with code
+ // that jumps to the compiled function:
- *(intptr_t *)(StubAddr) = SETHI_INST(HI(NewVal), 1);
- *(intptr_t *)(StubAddr + 4) = JMP_INST(1, LO(NewVal), 0);
- *(intptr_t *)(StubAddr + 8) = NOP_INST;
+ SmallVector<uint32_t, 8> Insts;
+ intptr_t diff = (NewVal - StubAddr) >> 2;
+ if (isInt<22>(diff)) {
+ // Use branch instruction to jump
+ Insts.push_back(BA_INST(diff));
+ Insts.push_back(NOP_INST);
+ } else {
+ // Otherwise, use indirect jump to the compiled function
+ emitInstrForIndirectJump(NewVal, 1, Insts);
+ }
- sys::Memory::InvalidateInstructionCache((void*) StubAddr, 12);
+ for (unsigned i = 0, e = Insts.size(); i != e; ++i)
+ *(uint32_t *)(StubAddr + i*4) = Insts[i];
+
+ sys::Memory::InvalidateInstructionCache((void*) StubAddr, Insts.size() * 4);
return (void*)StubAddr;
}
+
void SparcJITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
assert(0 && "FIXME: Implement SparcJITInfo::replaceMachineCodeForFunction");
}
@@ -88,10 +175,10 @@ void SparcJITInfo::replaceMachineCodeForFunction(v
TargetJITInfo::StubLayout SparcJITInfo::getStubLayout() {
- // The stub contains 3 4-byte instructions, aligned at 4 bytes. See
- // emitFunctionStub for details.
-
- StubLayout Result = { 3*4, 4 };
+ // The stub contains maximum of 4 4-byte instructions and 8 bytes for address,
+ // aligned at 32 bytes.
+ // See emitFunctionStub and emitInstrForIndirectJump for details.
+ StubLayout Result = { 4*4 + 8, 32 };
return Result;
}
@@ -98,32 +185,41 @@ TargetJITInfo::StubLayout SparcJITInfo::getStubLay
void *SparcJITInfo::emitFunctionStub(const Function *F, void *Fn,
JITCodeEmitter &JCE)
{
- JCE.emitAlignment(4);
+ JCE.emitAlignment(32);
void *Addr = (void*) (JCE.getCurrentPCValue());
- if (!sys::Memory::setRangeWritable(Addr, 12))
- llvm_unreachable("ERROR: Unable to mark stub writable.");
+ intptr_t CurrentAddr = (intptr_t)Addr;
intptr_t EmittedAddr;
- if (Fn != (void*)(intptr_t)SparcCompilationCallback)
+ SmallVector<uint32_t, 8> Insts;
+ if (Fn != (void*)(intptr_t)SparcCompilationCallback) {
EmittedAddr = (intptr_t)Fn;
- else
+ intptr_t diff = (EmittedAddr - CurrentAddr) >> 2;
+ if (isInt<22>(diff)) {
+ Insts.push_back(BA_INST(diff));
+ Insts.push_back(NOP_INST);
+ }
+ } else {
EmittedAddr = (intptr_t)SparcCompilationCallback;
+ }
- // sethi %hi(EmittedAddr), %g1
- // jmp %g1+%lo(EmittedAddr), %g1
- // nop
+ if (Insts.size() == 0)
+ emitInstrForIndirectJump(EmittedAddr, 1, Insts);
- JCE.emitWordBE(SETHI_INST(HI(EmittedAddr), 1));
- JCE.emitWordBE(JMP_INST(1, LO(EmittedAddr), 1));
- JCE.emitWordBE(NOP_INST);
- sys::Memory::InvalidateInstructionCache(Addr, 12);
- if (!sys::Memory::setRangeExecutable(Addr, 12))
+ if (!sys::Memory::setRangeWritable(Addr, 4 * Insts.size()))
+ llvm_unreachable("ERROR: Unable to mark stub writable.");
+
+ for (unsigned i = 0, e = Insts.size(); i != e; ++i)
+ JCE.emitWordBE(Insts[i]);
+
+ sys::Memory::InvalidateInstructionCache(Addr, 4 * Insts.size());
+ if (!sys::Memory::setRangeExecutable(Addr, 4 * Insts.size()))
llvm_unreachable("ERROR: Unable to mark stub executable.");
return Addr;
}
+
TargetJITInfo::LazyResolverFn
SparcJITInfo::getLazyResolverFunction(JITCompilerFn F) {
JITCompilerFunction = F;
@@ -159,6 +255,27 @@ void SparcJITInfo::relocate(void *Function, Machin
case SP::reloc_sparc_pc19:
ResultPtr = ((ResultPtr - (intptr_t)RelocPos) >> 2) & 0x7ffff;
break;
+
+ case SP::reloc_sparc_h44:
+ ResultPtr = (ResultPtr >> 22) & 0x3fffff;
+ break;
+
+ case SP::reloc_sparc_m44:
+ ResultPtr = (ResultPtr >> 12) & 0x3ff;
+ break;
+
+ case SP::reloc_sparc_l44:
+ ResultPtr = (ResultPtr & 0xfff);
+ break;
+
+ case SP::reloc_sparc_hh:
+ ResultPtr = (((int64_t)ResultPtr) >> 42) & 0x3fffff;
+ break;
+
+ case SP::reloc_sparc_hm:
+ ResultPtr = (((int64_t)ResultPtr) >> 32) & 0x3ff;
+ break;
+
}
*((unsigned*) RelocPos) |= (unsigned) ResultPtr;
}
Index: lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
@@ -68,9 +68,13 @@ static MCCodeGenInfo *createSparcMCCodeGenInfo(Str
CodeGenOpt::Level OL) {
MCCodeGenInfo *X = new MCCodeGenInfo();
- // The default 32-bit code model is abs32/pic32.
- if (CM == CodeModel::Default)
- CM = RM == Reloc::PIC_ ? CodeModel::Medium : CodeModel::Small;
+ // The default 32-bit code model is abs32/pic32 and the default 32-bit
+ // code model for JIT is abs32.
+ switch (CM) {
+ default: break;
+ case CodeModel::Default:
+ case CodeModel::JITDefault: CM = CodeModel::Small; break;
+ }
X->InitMCCodeGenInfo(RM, CM, OL);
return X;
@@ -81,9 +85,17 @@ static MCCodeGenInfo *createSparcV9MCCodeGenInfo(S
CodeGenOpt::Level OL) {
MCCodeGenInfo *X = new MCCodeGenInfo();
- // The default 64-bit code model is abs44/pic32.
- if (CM == CodeModel::Default)
- CM = CodeModel::Medium;
+ // The default 64-bit code model is abs44/pic32 and the default 64-bit
+ // code model for JIT is abs64.
+ switch (CM) {
+ default: break;
+ case CodeModel::Default:
+ CM = RM == Reloc::PIC_ ? CodeModel::Small : CodeModel::Medium;
+ break;
+ case CodeModel::JITDefault:
+ CM = CodeModel::Large;
+ break;
+ }
X->InitMCCodeGenInfo(RM, CM, OL);
return X;
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -1810,7 +1810,6 @@ SDValue SparcTargetLowering::makeAddress(SDValue O
switch(getTargetMachine().getCodeModel()) {
default:
llvm_unreachable("Unsupported absolute code model");
- case CodeModel::JITDefault:
case CodeModel::Small:
// abs32.
return makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG);
Index: lib/Target/Sparc/SparcCodeEmitter.cpp
===================================================================
--- lib/Target/Sparc/SparcCodeEmitter.cpp
+++ lib/Target/Sparc/SparcCodeEmitter.cpp
@@ -207,11 +207,11 @@ unsigned SparcCodeEmitter::getRelocation(const Mac
case SPII::MO_NO_FLAG: break;
case SPII::MO_LO: return SP::reloc_sparc_lo;
case SPII::MO_HI: return SP::reloc_sparc_hi;
- case SPII::MO_H44:
- case SPII::MO_M44:
- case SPII::MO_L44:
- case SPII::MO_HH:
- case SPII::MO_HM: assert(0 && "FIXME: Implement Medium/Large code model.");
+ case SPII::MO_H44: return SP::reloc_sparc_h44;
+ case SPII::MO_M44: return SP::reloc_sparc_m44;
+ case SPII::MO_L44: return SP::reloc_sparc_l44;
+ case SPII::MO_HH: return SP::reloc_sparc_hh;
+ case SPII::MO_HM: return SP::reloc_sparc_hm;
}
unsigned Opc = MI.getOpcode();
Index: lib/Target/Sparc/SparcRelocations.h
===================================================================
--- lib/Target/Sparc/SparcRelocations.h
+++ lib/Target/Sparc/SparcRelocations.h
@@ -33,7 +33,22 @@ namespace llvm {
reloc_sparc_pc22 = 4,
// reloc_sparc_pc22 - pc rel. 19 bits for branch with icc/xcc
- reloc_sparc_pc19 = 5
+ reloc_sparc_pc19 = 5,
+
+ // reloc_sparc_h44 - 43-22 bits
+ reloc_sparc_h44 = 6,
+
+ // reloc_sparc_m44 - 21-12 bits
+ reloc_sparc_m44 = 7,
+
+ // reloc_sparc_l44 - lower 12 bits
+ reloc_sparc_l44 = 8,
+
+ // reloc_sparc_hh - 63-42 bits
+ reloc_sparc_hh = 9,
+
+ // reloc_sparc_hm - 41-32 bits
+ reloc_sparc_hm = 10
};
}
}

View File

@ -0,0 +1,49 @@
Pull in r200103 from upstream llvm trunk (by Venkatraman Govindaraju):
Missing ELF relocations for Sparc.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: include/llvm/Support/ELF.h
===================================================================
--- include/llvm/Support/ELF.h
+++ include/llvm/Support/ELF.h
@@ -1143,7 +1143,37 @@ enum {
R_SPARC_L44 = 52,
R_SPARC_REGISTER = 53,
R_SPARC_UA64 = 54,
- R_SPARC_UA16 = 55
+ R_SPARC_UA16 = 55,
+ R_SPARC_UA16 = 55,
+ R_SPARC_TLS_GD_HI22 = 56,
+ R_SPARC_TLS_GD_LO10 = 57,
+ R_SPARC_TLS_GD_ADD = 58,
+ R_SPARC_TLS_GD_CALL = 59,
+ R_SPARC_TLS_LDM_HI22 = 60,
+ R_SPARC_TLS_LDM_LO10 = 61,
+ R_SPARC_TLS_LDM_ADD = 62,
+ R_SPARC_TLS_LDM_CALL = 63,
+ R_SPARC_TLS_LDO_HIX22 = 64,
+ R_SPARC_TLS_LDO_LOX10 = 65,
+ R_SPARC_TLS_LDO_ADD = 66,
+ R_SPARC_TLS_IE_HI22 = 67,
+ R_SPARC_TLS_IE_LO10 = 68,
+ R_SPARC_TLS_IE_LD = 69,
+ R_SPARC_TLS_IE_LDX = 70,
+ R_SPARC_TLS_IE_ADD = 71,
+ R_SPARC_TLS_LE_HIX22 = 72,
+ R_SPARC_TLS_LE_LOX10 = 73,
+ R_SPARC_TLS_DTPMOD32 = 74,
+ R_SPARC_TLS_DTPMOD64 = 75,
+ R_SPARC_TLS_DTPOFF32 = 76,
+ R_SPARC_TLS_DTPOFF64 = 77,
+ R_SPARC_TLS_TPOFF32 = 78,
+ R_SPARC_TLS_TPOFF64 = 79,
+ R_SPARC_GOTDATA_HIX22 = 80,
+ R_SPARC_GOTDATA_LOX22 = 81,
+ R_SPARC_GOTDATA_OP_HIX22 = 82,
+ R_SPARC_GOTDATA_OP_LOX22 = 83,
+ R_SPARC_GOTDATA_OP = 84
};
// Section header.

View File

@ -0,0 +1,18 @@
Pull in r200104 from upstream llvm trunk (by Venkatraman Govindaraju):
removing duplicate enum value
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: include/llvm/Support/ELF.h
===================================================================
--- include/llvm/Support/ELF.h
+++ include/llvm/Support/ELF.h
@@ -1144,7 +1144,6 @@ enum {
R_SPARC_REGISTER = 53,
R_SPARC_UA64 = 54,
R_SPARC_UA16 = 55,
- R_SPARC_UA16 = 55,
R_SPARC_TLS_GD_HI22 = 56,
R_SPARC_TLS_GD_LO10 = 57,
R_SPARC_TLS_GD_ADD = 58,

View File

@ -0,0 +1,169 @@
Pull in r200112 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Add support for sparc relocation types in ELF object file.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: test/MC/Sparc/sparc-relocations.s
===================================================================
--- test/MC/Sparc/sparc-relocations.s
+++ test/MC/Sparc/sparc-relocations.s
@@ -1,5 +1,18 @@
! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s
+! RUN: llvm-mc %s -arch=sparcv9 -filetype=obj | llvm-readobj -r | FileCheck %s --check-prefix=CHECK-OBJ
+ ! CHECK-OBJ: Format: ELF64-sparc
+ ! CHECK-OBJ: Relocations [
+ ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_WDISP30 foo
+ ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_LO10 sym
+ ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_HI22 sym
+ ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_H44 sym
+ ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_M44 sym
+ ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_L44 sym
+ ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_HH22 sym
+ ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_HM10 sym
+ ! CHECK-ELF: ]
+
! CHECK: call foo ! encoding: [0b01AAAAAA,A,A,A]
! CHECK: ! fixup A - offset: 0, value: foo, kind: fixup_sparc_call30
call foo
Index: include/llvm/Object/ELFObjectFile.h
===================================================================
--- include/llvm/Object/ELFObjectFile.h
+++ include/llvm/Object/ELFObjectFile.h
@@ -922,6 +922,9 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName()
return "ELF32-mips";
case ELF::EM_PPC:
return "ELF32-ppc";
+ case ELF::EM_SPARC:
+ case ELF::EM_SPARC32PLUS:
+ return "ELF32-sparc";
default:
return "ELF32-unknown";
}
@@ -937,6 +940,8 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName()
return "ELF64-ppc64";
case ELF::EM_S390:
return "ELF64-s390";
+ case ELF::EM_SPARCV9:
+ return "ELF64-sparc";
default:
return "ELF64-unknown";
}
@@ -967,6 +972,13 @@ unsigned ELFObjectFile<ELFT>::getArch() const {
: Triple::ppc64;
case ELF::EM_S390:
return Triple::systemz;
+
+ case ELF::EM_SPARC:
+ case ELF::EM_SPARC32PLUS:
+ return Triple::sparc;
+ case ELF::EM_SPARCV9:
+ return Triple::sparcv9;
+
default:
return Triple::UnknownArch;
}
Index: lib/Object/ELF.cpp
===================================================================
--- lib/Object/ELF.cpp
+++ lib/Object/ELF.cpp
@@ -702,6 +702,98 @@ StringRef getELFRelocationTypeName(uint32_t Machin
break;
}
break;
+ case ELF::EM_SPARC:
+ case ELF::EM_SPARC32PLUS:
+ case ELF::EM_SPARCV9:
+ switch (Type) {
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_NONE);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_8);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_16);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_32);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_DISP8);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_DISP16);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_DISP32);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WDISP30);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WDISP22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HI22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_13);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_LO10);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOT10);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOT13);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOT22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC10);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WPLT30);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_COPY);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GLOB_DAT);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_JMP_SLOT);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_RELATIVE);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_UA32);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PLT32);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HIPLT22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_LOPLT10);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PCPLT32);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PCPLT22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PCPLT10);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_10);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_11);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_64);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_OLO10);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HH22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HM10);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_LM22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC_HH22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC_HM10);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC_LM22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WDISP16);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WDISP19);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_7);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_5);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_6);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_DISP64);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PLT64);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HIX22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_LOX10);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_H44);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_M44);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_L44);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_REGISTER);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_UA64);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_UA16);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_GD_HI22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_GD_LO10);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_GD_ADD);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_GD_CALL);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDM_HI22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDM_LO10);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDM_ADD);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDM_CALL);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDO_HIX22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDO_LOX10);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDO_ADD);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_HI22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_LO10);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_LD);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_LDX);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_ADD);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LE_HIX22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LE_LOX10);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_DTPMOD32);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_DTPMOD64);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_DTPOFF32);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_DTPOFF64);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_TPOFF32);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_TPOFF64);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_HIX22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_LOX22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_OP_HIX22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_OP_LOX22);
+ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_OP);
+ default:
+ break;
+ }
+ break;
default:
break;
}

View File

@ -0,0 +1,45 @@
Pull in r200130 from upstream llvm trunk (by Jakob Stoklund Olesen):
Fix swapped CASA operands.
Found by SingleSource/UnitTests/AtomicOps.c
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -2972,7 +2972,7 @@ SparcTargetLowering::expandAtomicRMW(MachineInstr
// loop:
// %val = phi %val0, %dest
// %upd = op %val, %rs2
- // %dest = cas %addr, %upd, %val
+ // %dest = cas %addr, %val, %upd
// cmp %val, %dest
// bne loop
// done:
@@ -3031,7 +3031,7 @@ SparcTargetLowering::expandAtomicRMW(MachineInstr
}
BuildMI(LoopMBB, DL, TII.get(is64Bit ? SP::CASXrr : SP::CASrr), DestReg)
- .addReg(AddrReg).addReg(UpdReg).addReg(ValReg)
+ .addReg(AddrReg).addReg(ValReg).addReg(UpdReg)
.setMemRefs(MI->memoperands_begin(), MI->memoperands_end());
BuildMI(LoopMBB, DL, TII.get(SP::CMPrr)).addReg(ValReg).addReg(DestReg);
BuildMI(LoopMBB, DL, TII.get(is64Bit ? SP::BPXCC : SP::BCOND))
Index: test/CodeGen/SPARC/atomics.ll
===================================================================
--- test/CodeGen/SPARC/atomics.ll
+++ test/CodeGen/SPARC/atomics.ll
@@ -64,8 +64,8 @@ entry:
; CHECK-LABEL: test_load_add_32
; CHECK: membar
-; CHECK: add
-; CHECK: cas [%o0]
+; CHECK: add [[V:%[gilo][0-7]]], %o1, [[U:%[gilo][0-7]]]
+; CHECK: cas [%o0], [[V]], [[U]]
; CHECK: membar
define zeroext i32 @test_load_add_32(i32* %p, i32 zeroext %v) {
entry:

View File

@ -0,0 +1,117 @@
Pull in r200131 from upstream llvm trunk (by Jakob Stoklund Olesen):
Only generate the popc instruction for SPARC CPUs that implement it.
The popc instruction is defined in the SPARCv9 instruction set
architecture, but it was emulated on CPUs older than Niagara 2.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -1461,7 +1461,8 @@ SparcTargetLowering::SparcTargetLowering(TargetMac
setOperationAction(ISD::BR_CC, MVT::i64, Custom);
setOperationAction(ISD::SELECT_CC, MVT::i64, Custom);
- setOperationAction(ISD::CTPOP, MVT::i64, Legal);
+ if (Subtarget->usePopc())
+ setOperationAction(ISD::CTPOP, MVT::i64, Legal);
setOperationAction(ISD::CTTZ , MVT::i64, Expand);
setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i64, Expand);
setOperationAction(ISD::CTLZ , MVT::i64, Expand);
@@ -1567,7 +1568,7 @@ SparcTargetLowering::SparcTargetLowering(TargetMac
setStackPointerRegisterToSaveRestore(SP::O6);
- if (Subtarget->isV9())
+ if (Subtarget->isV9() && Subtarget->usePopc())
setOperationAction(ISD::CTPOP, MVT::i32, Legal);
if (Subtarget->isV9() && Subtarget->hasHardQuad()) {
Index: lib/Target/Sparc/Sparc.td
===================================================================
--- lib/Target/Sparc/Sparc.td
+++ lib/Target/Sparc/Sparc.td
@@ -34,6 +34,9 @@ def FeatureHardQuad
: SubtargetFeature<"hard-quad-float", "HasHardQuad", "true",
"Enable quad-word floating point instructions">;
+def UsePopc : SubtargetFeature<"popc", "UsePopc", "true",
+ "Use the popc (population count) instruction">;
+
//===----------------------------------------------------------------------===//
// Register File, Calling Conv, Instruction Descriptions
//===----------------------------------------------------------------------===//
@@ -69,9 +72,9 @@ def : Proc<"v9", [FeatureV9]>;
def : Proc<"ultrasparc", [FeatureV9, FeatureV8Deprecated]>;
def : Proc<"ultrasparc3", [FeatureV9, FeatureV8Deprecated]>;
def : Proc<"niagara", [FeatureV9, FeatureV8Deprecated]>;
-def : Proc<"niagara2", [FeatureV9, FeatureV8Deprecated]>;
-def : Proc<"niagara3", [FeatureV9, FeatureV8Deprecated]>;
-def : Proc<"niagara4", [FeatureV9, FeatureV8Deprecated]>;
+def : Proc<"niagara2", [FeatureV9, FeatureV8Deprecated, UsePopc]>;
+def : Proc<"niagara3", [FeatureV9, FeatureV8Deprecated, UsePopc]>;
+def : Proc<"niagara4", [FeatureV9, FeatureV8Deprecated, UsePopc]>;
def SparcAsmWriter : AsmWriter {
string AsmWriterClassName = "InstPrinter";
Index: lib/Target/Sparc/SparcSubtarget.h
===================================================================
--- lib/Target/Sparc/SparcSubtarget.h
+++ lib/Target/Sparc/SparcSubtarget.h
@@ -30,6 +30,7 @@ class SparcSubtarget : public SparcGenSubtargetInf
bool IsVIS;
bool Is64Bit;
bool HasHardQuad;
+ bool UsePopc;
public:
SparcSubtarget(const std::string &TT, const std::string &CPU,
@@ -39,6 +40,7 @@ class SparcSubtarget : public SparcGenSubtargetInf
bool isVIS() const { return IsVIS; }
bool useDeprecatedV8Instructions() const { return V8DeprecatedInsts; }
bool hasHardQuad() const { return HasHardQuad; }
+ bool usePopc() const { return UsePopc; }
/// ParseSubtargetFeatures - Parses features string setting specified
/// subtarget options. Definition of function is auto generated by tblgen.
Index: lib/Target/Sparc/SparcSubtarget.cpp
===================================================================
--- lib/Target/Sparc/SparcSubtarget.cpp
+++ lib/Target/Sparc/SparcSubtarget.cpp
@@ -31,7 +31,8 @@ SparcSubtarget::SparcSubtarget(const std::string &
V8DeprecatedInsts(false),
IsVIS(false),
Is64Bit(is64Bit),
- HasHardQuad(false) {
+ HasHardQuad(false),
+ UsePopc(false) {
// Determine default and user specified characteristics
std::string CPUName = CPU;
Index: test/CodeGen/SPARC/ctpop.ll
===================================================================
--- test/CodeGen/SPARC/ctpop.ll
+++ test/CodeGen/SPARC/ctpop.ll
@@ -1,13 +1,13 @@
; RUN: llc < %s -march=sparc -mattr=-v9 | FileCheck %s -check-prefix=V8
-; RUN: llc < %s -march=sparc -mattr=+v9 | FileCheck %s -check-prefix=V9
-; RUN: llc < %s -march=sparc -mcpu=v9 | FileCheck %s -check-prefix=V9
-; RUN: llc < %s -march=sparc -mcpu=ultrasparc | FileCheck %s -check-prefix=V9
-; RUN: llc < %s -march=sparc -mcpu=ultrasparc3 | FileCheck %s -check-prefix=V9
-; RUN: llc < %s -march=sparc -mcpu=niagara | FileCheck %s -check-prefix=V9
+; RUN: llc < %s -march=sparc -mattr=+v9,+popc | FileCheck %s -check-prefix=V9
+; RUN: llc < %s -march=sparc -mcpu=v9 | FileCheck %s -check-prefix=V8
+; RUN: llc < %s -march=sparc -mcpu=ultrasparc | FileCheck %s -check-prefix=V8
+; RUN: llc < %s -march=sparc -mcpu=ultrasparc3 | FileCheck %s -check-prefix=V8
+; RUN: llc < %s -march=sparc -mcpu=niagara | FileCheck %s -check-prefix=V8
; RUN: llc < %s -march=sparc -mcpu=niagara2 | FileCheck %s -check-prefix=V9
; RUN: llc < %s -march=sparc -mcpu=niagara3 | FileCheck %s -check-prefix=V9
; RUN: llc < %s -march=sparc -mcpu=niagara4 | FileCheck %s -check-prefix=V9
-; RUN: llc < %s -march=sparcv9 | FileCheck %s -check-prefix=SPARC64
+; RUN: llc < %s -march=sparcv9 -mattr=+popc | FileCheck %s -check-prefix=SPARC64
declare i32 @llvm.ctpop.i32(i32)

View File

@ -0,0 +1,67 @@
Pull in r200141 from upstream llvm trunk (by Jakob Stoklund Olesen):
Clean up the Legal/Expand logic for SPARC popc.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcSubtarget.cpp
===================================================================
--- lib/Target/Sparc/SparcSubtarget.cpp
+++ lib/Target/Sparc/SparcSubtarget.cpp
@@ -41,6 +41,10 @@ SparcSubtarget::SparcSubtarget(const std::string &
// Parse features string.
ParseSubtargetFeatures(CPUName, FS);
+
+ // Popc is a v9-only instruction.
+ if (!IsV9)
+ UsePopc = false;
}
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -1461,8 +1461,8 @@ SparcTargetLowering::SparcTargetLowering(TargetMac
setOperationAction(ISD::BR_CC, MVT::i64, Custom);
setOperationAction(ISD::SELECT_CC, MVT::i64, Custom);
- if (Subtarget->usePopc())
- setOperationAction(ISD::CTPOP, MVT::i64, Legal);
+ setOperationAction(ISD::CTPOP, MVT::i64,
+ Subtarget->usePopc() ? Legal : Expand);
setOperationAction(ISD::CTTZ , MVT::i64, Expand);
setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i64, Expand);
setOperationAction(ISD::CTLZ , MVT::i64, Expand);
@@ -1518,7 +1518,6 @@ SparcTargetLowering::SparcTargetLowering(TargetMac
setOperationAction(ISD::FSINCOS, MVT::f32, Expand);
setOperationAction(ISD::FREM , MVT::f32, Expand);
setOperationAction(ISD::FMA , MVT::f32, Expand);
- setOperationAction(ISD::CTPOP, MVT::i32, Expand);
setOperationAction(ISD::CTTZ , MVT::i32, Expand);
setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i32, Expand);
setOperationAction(ISD::CTLZ , MVT::i32, Expand);
@@ -1568,8 +1567,8 @@ SparcTargetLowering::SparcTargetLowering(TargetMac
setStackPointerRegisterToSaveRestore(SP::O6);
- if (Subtarget->isV9() && Subtarget->usePopc())
- setOperationAction(ISD::CTPOP, MVT::i32, Legal);
+ setOperationAction(ISD::CTPOP, MVT::i32,
+ Subtarget->usePopc() ? Legal : Expand);
if (Subtarget->isV9() && Subtarget->hasHardQuad()) {
setOperationAction(ISD::LOAD, MVT::f128, Legal);
Index: test/CodeGen/SPARC/64bit.ll
===================================================================
--- test/CodeGen/SPARC/64bit.ll
+++ test/CodeGen/SPARC/64bit.ll
@@ -1,5 +1,5 @@
-; RUN: llc < %s -march=sparcv9 -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s
-; RUN: llc < %s -march=sparcv9 | FileCheck %s -check-prefix=OPT
+; RUN: llc < %s -march=sparcv9 -mattr=+popc -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s
+; RUN: llc < %s -march=sparcv9 -mattr=+popc | FileCheck %s -check-prefix=OPT
; CHECK-LABEL: ret2:
; CHECK: or %g0, %i1, %i0

View File

@ -0,0 +1,183 @@
Pull in r200282 from upstream llvm trunk (by Jakob Stoklund Olesen):
Fix the DWARF EH encodings for Sparc PIC code.
Also emit the stubs that were generated for references to typeinfo
symbols.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcAsmPrinter.cpp
===================================================================
--- lib/Target/Sparc/SparcAsmPrinter.cpp
+++ lib/Target/Sparc/SparcAsmPrinter.cpp
@@ -23,7 +23,9 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineModuleInfoImpls.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInst.h"
@@ -54,6 +56,7 @@ namespace {
virtual void EmitFunctionBodyStart();
virtual void EmitInstruction(const MachineInstr *MI);
+ virtual void EmitEndOfAsmFile(Module &M);
static const char *getRegisterName(unsigned RegNo) {
return SparcInstPrinter::getRegisterName(RegNo);
@@ -450,6 +453,23 @@ bool SparcAsmPrinter::PrintAsmMemoryOperand(const
return false;
}
+void SparcAsmPrinter::EmitEndOfAsmFile(Module &M) {
+ const TargetLoweringObjectFileELF &TLOFELF =
+ static_cast<const TargetLoweringObjectFileELF &>(getObjFileLowering());
+ MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>();
+
+ // Generate stubs for global variables.
+ MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList();
+ if (!Stubs.empty()) {
+ OutStreamer.SwitchSection(TLOFELF.getDataSection());
+ unsigned PtrSize = TM.getDataLayout()->getPointerSize(0);
+ for (unsigned i = 0, e = Stubs.size(); i != e; ++i) {
+ OutStreamer.EmitLabel(Stubs[i].first);
+ OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(), PtrSize);
+ }
+ }
+}
+
// Force static initialization.
extern "C" void LLVMInitializeSparcAsmPrinter() {
RegisterAsmPrinter<SparcAsmPrinter> X(TheSparcTarget);
Index: lib/MC/MCObjectFileInfo.cpp
===================================================================
--- lib/MC/MCObjectFileInfo.cpp
+++ lib/MC/MCObjectFileInfo.cpp
@@ -310,6 +310,33 @@ void MCObjectFileInfo::InitELFMCObjectFileInfo(Tri
FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8;
TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
dwarf::DW_EH_PE_udata8;
+ } else if (T.getArch() == Triple::sparc) {
+ if (RelocM == Reloc::PIC_) {
+ LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
+ PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
+ dwarf::DW_EH_PE_sdata4;
+ FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
+ TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
+ dwarf::DW_EH_PE_sdata4;
+ } else {
+ LSDAEncoding = dwarf::DW_EH_PE_absptr;
+ PersonalityEncoding = dwarf::DW_EH_PE_absptr;
+ FDEEncoding = dwarf::DW_EH_PE_udata4;
+ TTypeEncoding = dwarf::DW_EH_PE_absptr;
+ }
+ } else if (T.getArch() == Triple::sparcv9) {
+ LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
+ if (RelocM == Reloc::PIC_) {
+ PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
+ dwarf::DW_EH_PE_sdata4;
+ FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
+ TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
+ dwarf::DW_EH_PE_sdata4;
+ } else {
+ PersonalityEncoding = dwarf::DW_EH_PE_absptr;
+ FDEEncoding = dwarf::DW_EH_PE_udata4;
+ TTypeEncoding = dwarf::DW_EH_PE_absptr;
+ }
} else if (T.getArch() == Triple::systemz) {
// All currently-defined code models guarantee that 4-byte PC-relative
// values will be in range.
Index: test/CodeGen/SPARC/exception.ll
===================================================================
--- test/CodeGen/SPARC/exception.ll
+++ test/CodeGen/SPARC/exception.ll
@@ -1,4 +1,7 @@
-; RUN: llc < %s -march=sparc | FileCheck %s
+; RUN: llc < %s -march=sparc -relocation-model=static | FileCheck -check-prefix=V8ABS %s
+; RUN: llc < %s -march=sparc -relocation-model=pic | FileCheck -check-prefix=V8PIC %s
+; RUN: llc < %s -march=sparcv9 -relocation-model=static | FileCheck -check-prefix=V9ABS %s
+; RUN: llc < %s -march=sparcv9 -relocation-model=pic | FileCheck -check-prefix=V9PIC %s
%struct.__fundamental_type_info_pseudo = type { %struct.__type_info_pseudo }
@@ -9,23 +12,64 @@
@.cst = linker_private unnamed_addr constant [12 x i8] c"catched int\00", align 64
@.cst1 = linker_private unnamed_addr constant [14 x i8] c"catched float\00", align 64
-; CHECK-LABEL: main:
-; CHECK: .cfi_startproc
-; CHECK: .cfi_def_cfa_register {{30|%fp}}
-; CHECK: .cfi_window_save
-; CHECK: .cfi_register 15, 31
+; V8ABS-LABEL: main:
+; V8ABS: .cfi_startproc
+; V8ABS: .cfi_personality 0, __gxx_personality_v0
+; V8ABS: .cfi_lsda 0,
+; V8ABS: .cfi_def_cfa_register {{30|%fp}}
+; V8ABS: .cfi_window_save
+; V8ABS: .cfi_register 15, 31
-; CHECK: call __cxa_throw
-; CHECK: call __cxa_throw
+; V8ABS: call __cxa_throw
+; V8ABS: call __cxa_throw
-; CHECK: call __cxa_begin_catch
-; CHECK: call __cxa_end_catch
+; V8ABS: call __cxa_begin_catch
+; V8ABS: call __cxa_end_catch
-; CHECK: call __cxa_begin_catch
-; CHECK: call __cxa_end_catch
+; V8ABS: call __cxa_begin_catch
+; V8ABS: call __cxa_end_catch
-; CHECK: .cfi_endproc
+; V8ABS: .cfi_endproc
+; V8PIC-LABEL: main:
+; V8PIC: .cfi_startproc
+; V8PIC: .cfi_personality 155, DW.ref.__gxx_personality_v0
+; V8PIC: .cfi_lsda 27,
+; V8PIC: .cfi_def_cfa_register {{30|%fp}}
+; V8PIC: .cfi_window_save
+; V8PIC: .cfi_register 15, 31
+; V8PIC: .section .gcc_except_table
+; V8PIC-NOT: .section
+; V8PIC: .word .L_ZTIi.DW.stub-
+; V8PIC: .data
+; V8PIC: .L_ZTIi.DW.stub:
+; V8PIC-NEXT: .word _ZTIi
+
+; V9ABS-LABEL: main:
+; V9ABS: .cfi_startproc
+; V9ABS: .cfi_personality 0, __gxx_personality_v0
+; V9ABS: .cfi_lsda 27,
+; V9ABS: .cfi_def_cfa_register {{30|%fp}}
+; V9ABS: .cfi_window_save
+; V9ABS: .cfi_register 15, 31
+; V9ABS: .section .gcc_except_table
+; V9ABS-NOT: .section
+; V9ABS: .xword _ZTIi
+
+; V9PIC-LABEL: main:
+; V9PIC: .cfi_startproc
+; V9PIC: .cfi_personality 155, DW.ref.__gxx_personality_v0
+; V9PIC: .cfi_lsda 27,
+; V9PIC: .cfi_def_cfa_register {{30|%fp}}
+; V9PIC: .cfi_window_save
+; V9PIC: .cfi_register 15, 31
+; V9PIC: .section .gcc_except_table
+; V9PIC-NOT: .section
+; V9PIC: .word .L_ZTIi.DW.stub-
+; V9PIC: .data
+; V9PIC: .L_ZTIi.DW.stub:
+; V9PIC-NEXT: .xword _ZTIi
+
define i32 @main(i32 %argc, i8** nocapture readnone %argv) unnamed_addr #0 {
entry:
%0 = icmp eq i32 %argc, 2

View File

@ -0,0 +1,88 @@
Pull r200368 from upstream llvm trunk (by Venkatraman Govindaraju):
[SparcV9] Use correct register class (I64RegClass) to hold the address of _GLOBAL_OFFSET_TABLE_ in sparcv9.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcInstrInfo.cpp
===================================================================
--- lib/Target/Sparc/SparcInstrInfo.cpp
+++ lib/Target/Sparc/SparcInstrInfo.cpp
@@ -431,9 +431,10 @@ unsigned SparcInstrInfo::getGlobalBaseReg(MachineF
MachineBasicBlock::iterator MBBI = FirstMBB.begin();
MachineRegisterInfo &RegInfo = MF->getRegInfo();
- GlobalBaseReg = RegInfo.createVirtualRegister(&SP::IntRegsRegClass);
+ const TargetRegisterClass *PtrRC =
+ Subtarget.is64Bit() ? &SP::I64RegsRegClass : &SP::IntRegsRegClass;
+ GlobalBaseReg = RegInfo.createVirtualRegister(PtrRC);
-
DebugLoc dl;
BuildMI(FirstMBB, MBBI, dl, get(SP::GETPCX), GlobalBaseReg);
Index: lib/Target/Sparc/SparcInstrInfo.td
===================================================================
--- lib/Target/Sparc/SparcInstrInfo.td
+++ lib/Target/Sparc/SparcInstrInfo.td
@@ -180,7 +180,7 @@ def tlscall : SDNode<"SPISD::TLS_CALL", SDT_
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
SDNPVariadic]>;
-def getPCX : Operand<i32> {
+def getPCX : Operand<iPTR> {
let PrintMethod = "printGetPCX";
}
Index: test/CodeGen/SPARC/2009-08-28-PIC.ll
===================================================================
--- test/CodeGen/SPARC/2009-08-28-PIC.ll
+++ test/CodeGen/SPARC/2009-08-28-PIC.ll
@@ -1,9 +1,45 @@
-; RUN: llc -march=sparc --relocation-model=pic < %s | grep _GLOBAL_OFFSET_TABLE_
+; RUN: llc -march=sparc --relocation-model=pic < %s | FileCheck %s --check-prefix=V8
+; RUN: llc -march=sparcv9 --relocation-model=pic < %s | FileCheck %s --check-prefix=V9
+; RUN: llc -march=sparc --relocation-model=pic < %s -O0 | FileCheck %s --check-prefix=V8UNOPT
+; RUN: llc -march=sparcv9 --relocation-model=pic < %s -O0 | FileCheck %s --check-prefix=V9UNOPT
+
+; V8-LABEL: func
+; V8: _GLOBAL_OFFSET_TABLE_
+
+; V9-LABEL: func
+; V9: _GLOBAL_OFFSET_TABLE_
+
@foo = global i32 0 ; <i32*> [#uses=1]
-define i32 @func() nounwind readonly {
+define i32 @func(i32 %a) nounwind readonly {
entry:
%0 = load i32* @foo, align 4 ; <i32> [#uses=1]
ret i32 %0
}
+
+; V8UNOPT-LABEL: test_spill
+; V8UNOPT: sethi %hi(_GLOBAL_OFFSET_TABLE_+{{.+}}), [[R:%[goli][0-7]]]
+; V8UNOPT: or [[R]], %lo(_GLOBAL_OFFSET_TABLE_+{{.+}}), [[R]]
+; V8UNOPT: add [[R]], %o7, [[R]]
+; V8UNOPT: st [[R]], [%fp+{{.+}}]
+
+; V9UNOPT-LABEL: test_spill
+; V9UNOPT: sethi %hi(_GLOBAL_OFFSET_TABLE_+{{.+}}), [[R:%[goli][0-7]]]
+; V9UNOPT: or [[R]], %lo(_GLOBAL_OFFSET_TABLE_+{{.+}}), [[R]]
+; V9UNOPT: add [[R]], %o7, [[R]]
+; V9UNOPT: stx [[R]], [%fp+{{.+}}]
+
+define i32 @test_spill(i32 %a, i32 %b) {
+entry:
+ %cmp = icmp eq i32 %b, 0
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then:
+ %ret = load i32* @foo, align 4
+ ret i32 %ret
+
+if.end:
+ %add = add nsw i32 %b, %a
+ ret i32 %add
+}

View File

@ -0,0 +1,296 @@
Pull in r200373 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Use %r_disp32 for pc_rel entries in gcc_except_table and eh_frame.
Otherwise, assembler (gas) fails to assemble them with error message "operation
combines symbols in different segments". This is because MC computes
pc_rel entries with subtract expression between labels from different sections.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcTargetObjectFile.h
===================================================================
--- lib/Target/Sparc/SparcTargetObjectFile.h
+++ lib/Target/Sparc/SparcTargetObjectFile.h
@@ -0,0 +1,34 @@
+//===-- SparcTargetObjectFile.h - Sparc Object Info -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TARGET_SPARC_TARGETOBJECTFILE_H
+#define LLVM_TARGET_SPARC_TARGETOBJECTFILE_H
+
+#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
+
+namespace llvm {
+
+class MCContext;
+class TargetMachine;
+
+class SparcELFTargetObjectFile : public TargetLoweringObjectFileELF {
+public:
+ SparcELFTargetObjectFile() :
+ TargetLoweringObjectFileELF()
+ {}
+
+ const MCExpr *
+ getTTypeGlobalReference(const GlobalValue *GV, Mangler *Mang,
+ MachineModuleInfo *MMI, unsigned Encoding,
+ MCStreamer &Streamer) const;
+};
+
+} // end namespace llvm
+
+#endif
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -16,6 +16,7 @@
#include "SparcMachineFunctionInfo.h"
#include "SparcRegisterInfo.h"
#include "SparcTargetMachine.h"
+#include "SparcTargetObjectFile.h"
#include "MCTargetDesc/SparcBaseInfo.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
@@ -1361,7 +1362,7 @@ static SPCC::CondCodes FPCondCCodeToFCC(ISD::CondC
}
SparcTargetLowering::SparcTargetLowering(TargetMachine &TM)
- : TargetLowering(TM, new TargetLoweringObjectFileELF()) {
+ : TargetLowering(TM, new SparcELFTargetObjectFile()) {
Subtarget = &TM.getSubtarget<SparcSubtarget>();
// Set up the register classes.
Index: lib/Target/Sparc/SparcTargetObjectFile.cpp
===================================================================
--- lib/Target/Sparc/SparcTargetObjectFile.cpp
+++ lib/Target/Sparc/SparcTargetObjectFile.cpp
@@ -0,0 +1,48 @@
+//===------- SparcTargetObjectFile.cpp - Sparc Object Info Impl -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcTargetObjectFile.h"
+#include "MCTargetDesc/SparcMCExpr.h"
+#include "llvm/CodeGen/MachineModuleInfoImpls.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Target/Mangler.h"
+
+using namespace llvm;
+
+
+const MCExpr *SparcELFTargetObjectFile::
+getTTypeGlobalReference(const GlobalValue *GV, Mangler *Mang,
+ MachineModuleInfo *MMI, unsigned Encoding,
+ MCStreamer &Streamer) const {
+
+ if (Encoding & dwarf::DW_EH_PE_pcrel) {
+ MachineModuleInfoELF &ELFMMI = MMI->getObjFileInfo<MachineModuleInfoELF>();
+
+ //MCSymbol *SSym = getSymbolWithGlobalValueBase(*Mang, GV, ".DW.stub");
+ SmallString<60> NameStr;
+ Mang->getNameWithPrefix(NameStr, GV, true);
+ NameStr.append(".DW.stub");
+ MCSymbol *SSym = getContext().GetOrCreateSymbol(NameStr.str());
+
+ // Add information about the stub reference to ELFMMI so that the stub
+ // gets emitted by the asmprinter.
+ MachineModuleInfoImpl::StubValueTy &StubSym = ELFMMI.getGVStubEntry(SSym);
+ if (StubSym.getPointer() == 0) {
+ MCSymbol *Sym = getSymbol(*Mang, GV);
+ StubSym = MachineModuleInfoImpl::StubValueTy(Sym, !GV->hasLocalLinkage());
+ }
+
+ MCContext &Ctx = getContext();
+ return SparcMCExpr::Create(SparcMCExpr::VK_Sparc_R_DISP32,
+ MCSymbolRefExpr::Create(SSym, Ctx), Ctx);
+ }
+
+ return TargetLoweringObjectFileELF::
+ getTTypeGlobalReference(GV, Mang, MMI, Encoding, Streamer);
+}
Index: lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp
@@ -12,7 +12,9 @@
//===----------------------------------------------------------------------===//
#include "SparcMCAsmInfo.h"
+#include "SparcMCExpr.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/MC/MCStreamer.h"
using namespace llvm;
@@ -44,4 +46,15 @@ SparcELFMCAsmInfo::SparcELFMCAsmInfo(StringRef TT)
PrivateGlobalPrefix = ".L";
}
+const MCExpr*
+SparcELFMCAsmInfo::getExprForPersonalitySymbol(const MCSymbol *Sym,
+ unsigned Encoding,
+ MCStreamer &Streamer) const {
+ if (Encoding & dwarf::DW_EH_PE_pcrel) {
+ MCContext &Ctx = Streamer.getContext();
+ return SparcMCExpr::Create(SparcMCExpr::VK_Sparc_R_DISP32,
+ MCSymbolRefExpr::Create(Sym, Ctx), Ctx);
+ }
+ return MCAsmInfo::getExprForPersonalitySymbol(Sym, Encoding, Streamer);
+}
Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
@@ -41,6 +41,7 @@ void SparcMCExpr::PrintImpl(raw_ostream &OS) const
case VK_Sparc_L44: OS << "%l44("; break;
case VK_Sparc_HH: OS << "%hh("; break;
case VK_Sparc_HM: OS << "%hm("; break;
+ case VK_Sparc_R_DISP32: OS << "%r_disp32("; break;
case VK_Sparc_TLS_GD_HI22: OS << "%tgd_hi22("; break;
case VK_Sparc_TLS_GD_LO10: OS << "%tgd_lo10("; break;
case VK_Sparc_TLS_GD_ADD: OS << "%tgd_add("; break;
@@ -77,6 +78,7 @@ SparcMCExpr::VariantKind SparcMCExpr::parseVariant
.Case("l44", VK_Sparc_L44)
.Case("hh", VK_Sparc_HH)
.Case("hm", VK_Sparc_HM)
+ .Case("r_disp32", VK_Sparc_R_DISP32)
.Case("tgd_hi22", VK_Sparc_TLS_GD_HI22)
.Case("tgd_lo10", VK_Sparc_TLS_GD_LO10)
.Case("tgd_add", VK_Sparc_TLS_GD_ADD)
@@ -101,6 +103,8 @@ SparcMCExpr::VariantKind SparcMCExpr::parseVariant
bool
SparcMCExpr::EvaluateAsRelocatableImpl(MCValue &Res,
const MCAsmLayout *Layout) const {
+ if (!Layout)
+ return false;
return getSubExpr()->EvaluateAsRelocatable(Res, *Layout);
}
Index: lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h
+++ lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h
@@ -17,13 +17,16 @@
#include "llvm/MC/MCAsmInfoELF.h"
namespace llvm {
- class StringRef;
+class StringRef;
- class SparcELFMCAsmInfo : public MCAsmInfoELF {
- virtual void anchor();
- public:
- explicit SparcELFMCAsmInfo(StringRef TT);
- };
+class SparcELFMCAsmInfo : public MCAsmInfoELF {
+ virtual void anchor();
+public:
+ explicit SparcELFMCAsmInfo(StringRef TT);
+ virtual const MCExpr* getExprForPersonalitySymbol(const MCSymbol *Sym,
+ unsigned Encoding,
+ MCStreamer &Streamer) const;
+};
} // namespace llvm
Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
+++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
@@ -31,6 +31,7 @@ class SparcMCExpr : public MCTargetExpr {
VK_Sparc_L44,
VK_Sparc_HH,
VK_Sparc_HM,
+ VK_Sparc_R_DISP32,
VK_Sparc_TLS_GD_HI22,
VK_Sparc_TLS_GD_LO10,
VK_Sparc_TLS_GD_ADD,
Index: lib/Target/Sparc/CMakeLists.txt
===================================================================
--- lib/Target/Sparc/CMakeLists.txt
+++ lib/Target/Sparc/CMakeLists.txt
@@ -27,6 +27,7 @@ add_llvm_target(SparcCodeGen
SparcJITInfo.cpp
SparcCodeEmitter.cpp
SparcMCInstLower.cpp
+ SparcTargetObjectFile.cpp
)
add_dependencies(LLVMSparcCodeGen SparcCommonTableGen intrinsics_gen)
Index: test/CodeGen/SPARC/exception.ll
===================================================================
--- test/CodeGen/SPARC/exception.ll
+++ test/CodeGen/SPARC/exception.ll
@@ -1,7 +1,9 @@
; RUN: llc < %s -march=sparc -relocation-model=static | FileCheck -check-prefix=V8ABS %s
; RUN: llc < %s -march=sparc -relocation-model=pic | FileCheck -check-prefix=V8PIC %s
+; RUN: llc < %s -march=sparc -relocation-model=pic -disable-cfi | FileCheck -check-prefix=V8PIC_NOCFI %s
; RUN: llc < %s -march=sparcv9 -relocation-model=static | FileCheck -check-prefix=V9ABS %s
; RUN: llc < %s -march=sparcv9 -relocation-model=pic | FileCheck -check-prefix=V9PIC %s
+; RUN: llc < %s -march=sparcv9 -relocation-model=pic -disable-cfi | FileCheck -check-prefix=V9PIC_NOCFI %s
%struct.__fundamental_type_info_pseudo = type { %struct.__type_info_pseudo }
@@ -40,11 +42,23 @@
; V8PIC: .cfi_register 15, 31
; V8PIC: .section .gcc_except_table
; V8PIC-NOT: .section
-; V8PIC: .word .L_ZTIi.DW.stub-
+; V8PIC: .word %r_disp32(.L_ZTIi.DW.stub)
; V8PIC: .data
; V8PIC: .L_ZTIi.DW.stub:
; V8PIC-NEXT: .word _ZTIi
+; V8PIC_NOCFI-LABEL: main:
+; V8PIC_NOCFI: .section .gcc_except_table
+; V8PIC_NOCFI-NOT: .section
+; V8PIC_NOCFI: .word %r_disp32(.L_ZTIi.DW.stub)
+; V8PIC_NOCFI: .data
+; V8PIC_NOCFI: .L_ZTIi.DW.stub:
+; V8PIC_NOCFI-NEXT: .word _ZTIi
+; V8PIC_NOCFI: .section .eh_frame
+; V8PIC_NOCFI-NOT: .section
+; V8PIC_NOCFI: .word %r_disp32(DW.ref.__gxx_personality_v0)
+
+
; V9ABS-LABEL: main:
; V9ABS: .cfi_startproc
; V9ABS: .cfi_personality 0, __gxx_personality_v0
@@ -65,11 +79,22 @@
; V9PIC: .cfi_register 15, 31
; V9PIC: .section .gcc_except_table
; V9PIC-NOT: .section
-; V9PIC: .word .L_ZTIi.DW.stub-
+; V9PIC: .word %r_disp32(.L_ZTIi.DW.stub)
; V9PIC: .data
; V9PIC: .L_ZTIi.DW.stub:
; V9PIC-NEXT: .xword _ZTIi
+; V9PIC_NOCFI-LABEL: main:
+; V9PIC_NOCFI: .section .gcc_except_table
+; V9PIC_NOCFI-NOT: .section
+; V9PIC_NOCFI: .word %r_disp32(.L_ZTIi.DW.stub)
+; V9PIC_NOCFI: .data
+; V9PIC_NOCFI: .L_ZTIi.DW.stub:
+; V9PIC_NOCFI-NEXT: .xword _ZTIi
+; V9PIC_NOCFI: .section .eh_frame
+; V9PIC_NOCFI-NOT: .section
+; V9PIC_NOCFI: .word %r_disp32(DW.ref.__gxx_personality_v0)
+
define i32 @main(i32 %argc, i8** nocapture readnone %argv) unnamed_addr #0 {
entry:
%0 = icmp eq i32 %argc, 2

View File

@ -0,0 +1,76 @@
Pull in r200376 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Use %r_disp32 for pc_rel entries in FDE as well.
This makes MCAsmInfo::getExprForFDESymbol() a virtual function and overrides it in SparcMCAsmInfo.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h
+++ lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h
@@ -26,6 +26,10 @@ class SparcELFMCAsmInfo : public MCAsmInfoELF {
virtual const MCExpr* getExprForPersonalitySymbol(const MCSymbol *Sym,
unsigned Encoding,
MCStreamer &Streamer) const;
+ virtual const MCExpr* getExprForFDESymbol(const MCSymbol *Sym,
+ unsigned Encoding,
+ MCStreamer &Streamer) const;
+
};
} // namespace llvm
Index: lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp
@@ -58,3 +58,15 @@ SparcELFMCAsmInfo::getExprForPersonalitySymbol(con
return MCAsmInfo::getExprForPersonalitySymbol(Sym, Encoding, Streamer);
}
+
+const MCExpr*
+SparcELFMCAsmInfo::getExprForFDESymbol(const MCSymbol *Sym,
+ unsigned Encoding,
+ MCStreamer &Streamer) const {
+ if (Encoding & dwarf::DW_EH_PE_pcrel) {
+ MCContext &Ctx = Streamer.getContext();
+ return SparcMCExpr::Create(SparcMCExpr::VK_Sparc_R_DISP32,
+ MCSymbolRefExpr::Create(Sym, Ctx), Ctx);
+ }
+ return MCAsmInfo::getExprForFDESymbol(Sym, Encoding, Streamer);
+}
Index: test/CodeGen/SPARC/exception.ll
===================================================================
--- test/CodeGen/SPARC/exception.ll
+++ test/CodeGen/SPARC/exception.ll
@@ -57,6 +57,7 @@
; V8PIC_NOCFI: .section .eh_frame
; V8PIC_NOCFI-NOT: .section
; V8PIC_NOCFI: .word %r_disp32(DW.ref.__gxx_personality_v0)
+; V8PIC_NOCFI: .word %r_disp32(.Ltmp{{.+}}) ! FDE initial location
; V9ABS-LABEL: main:
@@ -94,6 +95,7 @@
; V9PIC_NOCFI: .section .eh_frame
; V9PIC_NOCFI-NOT: .section
; V9PIC_NOCFI: .word %r_disp32(DW.ref.__gxx_personality_v0)
+; V9PIC_NOCFI: .word %r_disp32(.Ltmp{{.+}}) ! FDE initial location
define i32 @main(i32 %argc, i8** nocapture readnone %argv) unnamed_addr #0 {
entry:
Index: include/llvm/MC/MCAsmInfo.h
===================================================================
--- include/llvm/MC/MCAsmInfo.h
+++ include/llvm/MC/MCAsmInfo.h
@@ -371,7 +371,7 @@ namespace llvm {
unsigned Encoding,
MCStreamer &Streamer) const;
- const MCExpr *
+ virtual const MCExpr *
getExprForFDESymbol(const MCSymbol *Sym,
unsigned Encoding,
MCStreamer &Streamer) const;

View File

@ -0,0 +1,73 @@
Pull in r200509 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Save and restore float registers that may be used for parameter passing.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcJITInfo.cpp
===================================================================
--- lib/Target/Sparc/SparcJITInfo.cpp
+++ lib/Target/Sparc/SparcJITInfo.cpp
@@ -28,6 +28,13 @@ extern "C" void SparcCompilationCallback();
extern "C" {
#if defined (__sparc__)
+
+#if defined(__arch64__)
+#define FRAME_PTR(X) #X "+2047"
+#else
+#define FRAME_PTR(X) #X
+#endif
+
asm(
".text\n"
"\t.align 4\n"
@@ -34,11 +41,46 @@ extern "C" {
"\t.global SparcCompilationCallback\n"
"\t.type SparcCompilationCallback, #function\n"
"SparcCompilationCallback:\n"
- // Save current register window.
- "\tsave %sp, -192, %sp\n"
+ // Save current register window and create stack.
+ // 128 (save area) + 6*8 (for arguments) + 16*8 (for float regfile) = 304
+ "\tsave %sp, -304, %sp\n"
+ // save float regfile to the stack.
+ "\tstd %f0, [" FRAME_PTR(%fp) "-0]\n"
+ "\tstd %f2, [" FRAME_PTR(%fp) "-8]\n"
+ "\tstd %f4, [" FRAME_PTR(%fp) "-16]\n"
+ "\tstd %f6, [" FRAME_PTR(%fp) "-24]\n"
+ "\tstd %f8, [" FRAME_PTR(%fp) "-32]\n"
+ "\tstd %f10, [" FRAME_PTR(%fp) "-40]\n"
+ "\tstd %f12, [" FRAME_PTR(%fp) "-48]\n"
+ "\tstd %f14, [" FRAME_PTR(%fp) "-56]\n"
+ "\tstd %f16, [" FRAME_PTR(%fp) "-64]\n"
+ "\tstd %f18, [" FRAME_PTR(%fp) "-72]\n"
+ "\tstd %f20, [" FRAME_PTR(%fp) "-80]\n"
+ "\tstd %f22, [" FRAME_PTR(%fp) "-88]\n"
+ "\tstd %f24, [" FRAME_PTR(%fp) "-96]\n"
+ "\tstd %f26, [" FRAME_PTR(%fp) "-104]\n"
+ "\tstd %f28, [" FRAME_PTR(%fp) "-112]\n"
+ "\tstd %f30, [" FRAME_PTR(%fp) "-120]\n"
// stubaddr is in %g1.
"\tcall SparcCompilationCallbackC\n"
"\t mov %g1, %o0\n"
+ // restore float regfile from the stack.
+ "\tldd [" FRAME_PTR(%fp) "-0], %f0\n"
+ "\tldd [" FRAME_PTR(%fp) "-8], %f2\n"
+ "\tldd [" FRAME_PTR(%fp) "-16], %f4\n"
+ "\tldd [" FRAME_PTR(%fp) "-24], %f6\n"
+ "\tldd [" FRAME_PTR(%fp) "-32], %f8\n"
+ "\tldd [" FRAME_PTR(%fp) "-40], %f10\n"
+ "\tldd [" FRAME_PTR(%fp) "-48], %f12\n"
+ "\tldd [" FRAME_PTR(%fp) "-56], %f14\n"
+ "\tldd [" FRAME_PTR(%fp) "-64], %f16\n"
+ "\tldd [" FRAME_PTR(%fp) "-72], %f18\n"
+ "\tldd [" FRAME_PTR(%fp) "-80], %f20\n"
+ "\tldd [" FRAME_PTR(%fp) "-88], %f22\n"
+ "\tldd [" FRAME_PTR(%fp) "-96], %f24\n"
+ "\tldd [" FRAME_PTR(%fp) "-104], %f26\n"
+ "\tldd [" FRAME_PTR(%fp) "-112], %f28\n"
+ "\tldd [" FRAME_PTR(%fp) "-120], %f30\n"
// restore original register window and
// copy %o0 to %g1
"\trestore %o0, 0, %g1\n"

View File

@ -0,0 +1,97 @@
Pull in r200617 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Set %o7 as the return address register instead of %i7 in MCRegisterInfo. Also, add CFI instructions to initialize the frame correctly.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
@@ -33,6 +33,25 @@
using namespace llvm;
+
+static MCAsmInfo *createSparcMCAsmInfo(const MCRegisterInfo &MRI,
+ StringRef TT) {
+ MCAsmInfo *MAI = new SparcELFMCAsmInfo(TT);
+ unsigned Reg = MRI.getDwarfRegNum(SP::O6, true);
+ MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(0, Reg, 0);
+ MAI->addInitialFrameState(Inst);
+ return MAI;
+}
+
+static MCAsmInfo *createSparcV9MCAsmInfo(const MCRegisterInfo &MRI,
+ StringRef TT) {
+ MCAsmInfo *MAI = new SparcELFMCAsmInfo(TT);
+ unsigned Reg = MRI.getDwarfRegNum(SP::O6, true);
+ MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(0, Reg, 2047);
+ MAI->addInitialFrameState(Inst);
+ return MAI;
+}
+
static MCInstrInfo *createSparcMCInstrInfo() {
MCInstrInfo *X = new MCInstrInfo();
InitSparcMCInstrInfo(X);
@@ -41,7 +60,7 @@ static MCInstrInfo *createSparcMCInstrInfo() {
static MCRegisterInfo *createSparcMCRegisterInfo(StringRef TT) {
MCRegisterInfo *X = new MCRegisterInfo();
- InitSparcMCRegisterInfo(X, SP::I7);
+ InitSparcMCRegisterInfo(X, SP::O7);
return X;
}
@@ -132,8 +151,8 @@ static MCInstPrinter *createSparcMCInstPrinter(con
extern "C" void LLVMInitializeSparcTargetMC() {
// Register the MC asm info.
- RegisterMCAsmInfo<SparcELFMCAsmInfo> X(TheSparcTarget);
- RegisterMCAsmInfo<SparcELFMCAsmInfo> Y(TheSparcV9Target);
+ RegisterMCAsmInfoFn X(TheSparcTarget, createSparcMCAsmInfo);
+ RegisterMCAsmInfoFn Y(TheSparcV9Target, createSparcV9MCAsmInfo);
// Register the MC codegen info.
TargetRegistry::RegisterMCCodeGenInfo(TheSparcTarget,
Index: lib/Target/Sparc/SparcRegisterInfo.cpp
===================================================================
--- lib/Target/Sparc/SparcRegisterInfo.cpp
+++ lib/Target/Sparc/SparcRegisterInfo.cpp
@@ -35,7 +35,7 @@ ReserveAppRegisters("sparc-reserve-app-registers",
cl::desc("Reserve application registers (%g2-%g4)"));
SparcRegisterInfo::SparcRegisterInfo(SparcSubtarget &st)
- : SparcGenRegisterInfo(SP::I7), Subtarget(st) {
+ : SparcGenRegisterInfo(SP::O7), Subtarget(st) {
}
const uint16_t* SparcRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF)
Index: test/CodeGen/SPARC/exception.ll
===================================================================
--- test/CodeGen/SPARC/exception.ll
+++ test/CodeGen/SPARC/exception.ll
@@ -56,7 +56,11 @@
; V8PIC_NOCFI-NEXT: .word _ZTIi
; V8PIC_NOCFI: .section .eh_frame
; V8PIC_NOCFI-NOT: .section
+; V8PIC_NOCFI: .byte 15 ! CIE Return Address Column
; V8PIC_NOCFI: .word %r_disp32(DW.ref.__gxx_personality_v0)
+; V8PIC_NOCFI: .byte 12 ! DW_CFA_def_cfa
+; V8PIC_NOCFI: .byte 14 ! Reg 14
+; V8PIC_NOCFI-NEXT: .byte 0 ! Offset 0
; V8PIC_NOCFI: .word %r_disp32(.Ltmp{{.+}}) ! FDE initial location
@@ -94,7 +98,11 @@
; V9PIC_NOCFI-NEXT: .xword _ZTIi
; V9PIC_NOCFI: .section .eh_frame
; V9PIC_NOCFI-NOT: .section
+; V9PIC_NOCFI: .byte 15 ! CIE Return Address Column
; V9PIC_NOCFI: .word %r_disp32(DW.ref.__gxx_personality_v0)
+; V9PIC_NOCFI: .byte 12 ! DW_CFA_def_cfa
+; V9PIC_NOCFI-NEXT: .byte 14 ! Reg 14
+; V9PIC_NOCFI: .ascii "\377\017" ! Offset 2047
; V9PIC_NOCFI: .word %r_disp32(.Ltmp{{.+}}) ! FDE initial location
define i32 @main(i32 %argc, i8** nocapture readnone %argv) unnamed_addr #0 {

View File

@ -0,0 +1,512 @@
Pull in r200960 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Use SparcMCExpr::VariantKind itself as MachineOperand's target flags.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -13,11 +13,11 @@
//===----------------------------------------------------------------------===//
#include "SparcISelLowering.h"
+#include "MCTargetDesc/SparcMCExpr.h"
#include "SparcMachineFunctionInfo.h"
#include "SparcRegisterInfo.h"
#include "SparcTargetMachine.h"
#include "SparcTargetObjectFile.h"
-#include "MCTargetDesc/SparcBaseInfo.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
@@ -1796,7 +1796,8 @@ SDValue SparcTargetLowering::makeAddress(SDValue O
// Handle PIC mode first.
if (getTargetMachine().getRelocationModel() == Reloc::PIC_) {
// This is the pic32 code model, the GOT is known to be smaller than 4GB.
- SDValue HiLo = makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG);
+ SDValue HiLo = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HI,
+ SparcMCExpr::VK_Sparc_LO, DAG);
SDValue GlobalBase = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, VT);
SDValue AbsAddr = DAG.getNode(ISD::ADD, DL, VT, GlobalBase, HiLo);
// GLOBAL_BASE_REG codegen'ed with call. Inform MFI that this
@@ -1813,20 +1814,24 @@ SDValue SparcTargetLowering::makeAddress(SDValue O
llvm_unreachable("Unsupported absolute code model");
case CodeModel::Small:
// abs32.
- return makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG);
+ return makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HI,
+ SparcMCExpr::VK_Sparc_LO, DAG);
case CodeModel::Medium: {
// abs44.
- SDValue H44 = makeHiLoPair(Op, SPII::MO_H44, SPII::MO_M44, DAG);
+ SDValue H44 = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_H44,
+ SparcMCExpr::VK_Sparc_M44, DAG);
H44 = DAG.getNode(ISD::SHL, DL, VT, H44, DAG.getConstant(12, MVT::i32));
- SDValue L44 = withTargetFlags(Op, SPII::MO_L44, DAG);
+ SDValue L44 = withTargetFlags(Op, SparcMCExpr::VK_Sparc_L44, DAG);
L44 = DAG.getNode(SPISD::Lo, DL, VT, L44);
return DAG.getNode(ISD::ADD, DL, VT, H44, L44);
}
case CodeModel::Large: {
// abs64.
- SDValue Hi = makeHiLoPair(Op, SPII::MO_HH, SPII::MO_HM, DAG);
+ SDValue Hi = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HH,
+ SparcMCExpr::VK_Sparc_HM, DAG);
Hi = DAG.getNode(ISD::SHL, DL, VT, Hi, DAG.getConstant(32, MVT::i32));
- SDValue Lo = makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG);
+ SDValue Lo = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HI,
+ SparcMCExpr::VK_Sparc_LO, DAG);
return DAG.getNode(ISD::ADD, DL, VT, Hi, Lo);
}
}
@@ -1858,14 +1863,18 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress
TLSModel::Model model = getTargetMachine().getTLSModel(GV);
if (model == TLSModel::GeneralDynamic || model == TLSModel::LocalDynamic) {
- unsigned HiTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_HI22
- : SPII::MO_TLS_LDM_HI22);
- unsigned LoTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_LO10
- : SPII::MO_TLS_LDM_LO10);
- unsigned addTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_ADD
- : SPII::MO_TLS_LDM_ADD);
- unsigned callTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_CALL
- : SPII::MO_TLS_LDM_CALL);
+ unsigned HiTF = ((model == TLSModel::GeneralDynamic)
+ ? SparcMCExpr::VK_Sparc_TLS_GD_HI22
+ : SparcMCExpr::VK_Sparc_TLS_LDM_HI22);
+ unsigned LoTF = ((model == TLSModel::GeneralDynamic)
+ ? SparcMCExpr::VK_Sparc_TLS_GD_LO10
+ : SparcMCExpr::VK_Sparc_TLS_LDM_LO10);
+ unsigned addTF = ((model == TLSModel::GeneralDynamic)
+ ? SparcMCExpr::VK_Sparc_TLS_GD_ADD
+ : SparcMCExpr::VK_Sparc_TLS_LDM_ADD);
+ unsigned callTF = ((model == TLSModel::GeneralDynamic)
+ ? SparcMCExpr::VK_Sparc_TLS_GD_CALL
+ : SparcMCExpr::VK_Sparc_TLS_LDM_CALL);
SDValue HiLo = makeHiLoPair(Op, HiTF, LoTF, DAG);
SDValue Base = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, PtrVT);
@@ -1903,17 +1912,17 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress
return Ret;
SDValue Hi = DAG.getNode(SPISD::Hi, DL, PtrVT,
- withTargetFlags(Op, SPII::MO_TLS_LDO_HIX22, DAG));
+ withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LDO_HIX22, DAG));
SDValue Lo = DAG.getNode(SPISD::Lo, DL, PtrVT,
- withTargetFlags(Op, SPII::MO_TLS_LDO_LOX10, DAG));
+ withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LDO_LOX10, DAG));
HiLo = DAG.getNode(ISD::XOR, DL, PtrVT, Hi, Lo);
return DAG.getNode(SPISD::TLS_ADD, DL, PtrVT, Ret, HiLo,
- withTargetFlags(Op, SPII::MO_TLS_LDO_ADD, DAG));
+ withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LDO_ADD, DAG));
}
if (model == TLSModel::InitialExec) {
- unsigned ldTF = ((PtrVT == MVT::i64)? SPII::MO_TLS_IE_LDX
- : SPII::MO_TLS_IE_LD);
+ unsigned ldTF = ((PtrVT == MVT::i64)? SparcMCExpr::VK_Sparc_TLS_IE_LDX
+ : SparcMCExpr::VK_Sparc_TLS_IE_LD);
SDValue Base = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, PtrVT);
@@ -1923,7 +1932,8 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress
MFI->setHasCalls(true);
SDValue TGA = makeHiLoPair(Op,
- SPII::MO_TLS_IE_HI22, SPII::MO_TLS_IE_LO10, DAG);
+ SparcMCExpr::VK_Sparc_TLS_IE_HI22,
+ SparcMCExpr::VK_Sparc_TLS_IE_LO10, DAG);
SDValue Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, Base, TGA);
SDValue Offset = DAG.getNode(SPISD::TLS_LD,
DL, PtrVT, Ptr,
@@ -1930,14 +1940,15 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress
withTargetFlags(Op, ldTF, DAG));
return DAG.getNode(SPISD::TLS_ADD, DL, PtrVT,
DAG.getRegister(SP::G7, PtrVT), Offset,
- withTargetFlags(Op, SPII::MO_TLS_IE_ADD, DAG));
+ withTargetFlags(Op,
+ SparcMCExpr::VK_Sparc_TLS_IE_ADD, DAG));
}
assert(model == TLSModel::LocalExec);
SDValue Hi = DAG.getNode(SPISD::Hi, DL, PtrVT,
- withTargetFlags(Op, SPII::MO_TLS_LE_HIX22, DAG));
+ withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LE_HIX22, DAG));
SDValue Lo = DAG.getNode(SPISD::Lo, DL, PtrVT,
- withTargetFlags(Op, SPII::MO_TLS_LE_LOX10, DAG));
+ withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LE_LOX10, DAG));
SDValue Offset = DAG.getNode(ISD::XOR, DL, PtrVT, Hi, Lo);
return DAG.getNode(ISD::ADD, DL, PtrVT,
Index: lib/Target/Sparc/SparcCodeEmitter.cpp
===================================================================
--- lib/Target/Sparc/SparcCodeEmitter.cpp
+++ lib/Target/Sparc/SparcCodeEmitter.cpp
@@ -14,7 +14,7 @@
#define DEBUG_TYPE "jit"
#include "Sparc.h"
-#include "MCTargetDesc/SparcBaseInfo.h"
+#include "MCTargetDesc/SparcMCExpr.h"
#include "SparcRelocations.h"
#include "SparcTargetMachine.h"
#include "llvm/ADT/Statistic.h"
@@ -204,14 +204,14 @@ unsigned SparcCodeEmitter::getRelocation(const Mac
unsigned TF = MO.getTargetFlags();
switch (TF) {
default:
- case SPII::MO_NO_FLAG: break;
- case SPII::MO_LO: return SP::reloc_sparc_lo;
- case SPII::MO_HI: return SP::reloc_sparc_hi;
- case SPII::MO_H44: return SP::reloc_sparc_h44;
- case SPII::MO_M44: return SP::reloc_sparc_m44;
- case SPII::MO_L44: return SP::reloc_sparc_l44;
- case SPII::MO_HH: return SP::reloc_sparc_hh;
- case SPII::MO_HM: return SP::reloc_sparc_hm;
+ case SparcMCExpr::VK_Sparc_None: break;
+ case SparcMCExpr::VK_Sparc_LO: return SP::reloc_sparc_lo;
+ case SparcMCExpr::VK_Sparc_HI: return SP::reloc_sparc_hi;
+ case SparcMCExpr::VK_Sparc_H44: return SP::reloc_sparc_h44;
+ case SparcMCExpr::VK_Sparc_M44: return SP::reloc_sparc_m44;
+ case SparcMCExpr::VK_Sparc_L44: return SP::reloc_sparc_l44;
+ case SparcMCExpr::VK_Sparc_HH: return SP::reloc_sparc_hh;
+ case SparcMCExpr::VK_Sparc_HM: return SP::reloc_sparc_hm;
}
unsigned Opc = MI.getOpcode();
Index: lib/Target/Sparc/SparcMCInstLower.cpp
===================================================================
--- lib/Target/Sparc/SparcMCInstLower.cpp
+++ lib/Target/Sparc/SparcMCInstLower.cpp
@@ -13,7 +13,6 @@
//===----------------------------------------------------------------------===//
#include "Sparc.h"
-#include "MCTargetDesc/SparcBaseInfo.h"
#include "MCTargetDesc/SparcMCExpr.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineFunction.h"
@@ -33,41 +32,10 @@ static MCOperand LowerSymbolOperand(const MachineI
const MachineOperand &MO,
AsmPrinter &AP) {
- SparcMCExpr::VariantKind Kind;
+ SparcMCExpr::VariantKind Kind =
+ (SparcMCExpr::VariantKind)MO.getTargetFlags();
const MCSymbol *Symbol = 0;
- unsigned TF = MO.getTargetFlags();
-
- switch(TF) {
- default: llvm_unreachable("Unknown target flags on operand");
- case SPII::MO_NO_FLAG: Kind = SparcMCExpr::VK_Sparc_None; break;
- case SPII::MO_LO: Kind = SparcMCExpr::VK_Sparc_LO; break;
- case SPII::MO_HI: Kind = SparcMCExpr::VK_Sparc_HI; break;
- case SPII::MO_H44: Kind = SparcMCExpr::VK_Sparc_H44; break;
- case SPII::MO_M44: Kind = SparcMCExpr::VK_Sparc_M44; break;
- case SPII::MO_L44: Kind = SparcMCExpr::VK_Sparc_L44; break;
- case SPII::MO_HH: Kind = SparcMCExpr::VK_Sparc_HH; break;
- case SPII::MO_HM: Kind = SparcMCExpr::VK_Sparc_HM; break;
- case SPII::MO_TLS_GD_HI22: Kind = SparcMCExpr::VK_Sparc_TLS_GD_HI22; break;
- case SPII::MO_TLS_GD_LO10: Kind = SparcMCExpr::VK_Sparc_TLS_GD_LO10; break;
- case SPII::MO_TLS_GD_ADD: Kind = SparcMCExpr::VK_Sparc_TLS_GD_ADD; break;
- case SPII::MO_TLS_GD_CALL: Kind = SparcMCExpr::VK_Sparc_TLS_GD_CALL; break;
- case SPII::MO_TLS_LDM_HI22: Kind = SparcMCExpr::VK_Sparc_TLS_LDM_HI22; break;
- case SPII::MO_TLS_LDM_LO10: Kind = SparcMCExpr::VK_Sparc_TLS_LDM_LO10; break;
- case SPII::MO_TLS_LDM_ADD: Kind = SparcMCExpr::VK_Sparc_TLS_LDM_ADD; break;
- case SPII::MO_TLS_LDM_CALL: Kind = SparcMCExpr::VK_Sparc_TLS_LDM_CALL; break;
- case SPII::MO_TLS_LDO_HIX22:Kind = SparcMCExpr::VK_Sparc_TLS_LDO_HIX22; break;
- case SPII::MO_TLS_LDO_LOX10:Kind = SparcMCExpr::VK_Sparc_TLS_LDO_LOX10; break;
- case SPII::MO_TLS_LDO_ADD: Kind = SparcMCExpr::VK_Sparc_TLS_LDO_ADD; break;
- case SPII::MO_TLS_IE_HI22: Kind = SparcMCExpr::VK_Sparc_TLS_IE_HI22; break;
- case SPII::MO_TLS_IE_LO10: Kind = SparcMCExpr::VK_Sparc_TLS_IE_LO10; break;
- case SPII::MO_TLS_IE_LD: Kind = SparcMCExpr::VK_Sparc_TLS_IE_LD; break;
- case SPII::MO_TLS_IE_LDX: Kind = SparcMCExpr::VK_Sparc_TLS_IE_LDX; break;
- case SPII::MO_TLS_IE_ADD: Kind = SparcMCExpr::VK_Sparc_TLS_IE_ADD; break;
- case SPII::MO_TLS_LE_HIX22: Kind = SparcMCExpr::VK_Sparc_TLS_LE_HIX22; break;
- case SPII::MO_TLS_LE_LOX10: Kind = SparcMCExpr::VK_Sparc_TLS_LE_LOX10; break;
- }
-
switch(MO.getType()) {
default: llvm_unreachable("Unknown type in LowerSymbolOperand");
case MachineOperand::MO_MachineBasicBlock:
Index: lib/Target/Sparc/SparcAsmPrinter.cpp
===================================================================
--- lib/Target/Sparc/SparcAsmPrinter.cpp
+++ lib/Target/Sparc/SparcAsmPrinter.cpp
@@ -18,7 +18,6 @@
#include "SparcTargetMachine.h"
#include "SparcTargetStreamer.h"
#include "InstPrinter/SparcInstPrinter.h"
-#include "MCTargetDesc/SparcBaseInfo.h"
#include "MCTargetDesc/SparcMCExpr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/CodeGen/AsmPrinter.h"
@@ -287,83 +286,60 @@ void SparcAsmPrinter::EmitFunctionBodyStart() {
void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
raw_ostream &O) {
const MachineOperand &MO = MI->getOperand (opNum);
- unsigned TF = MO.getTargetFlags();
+ SparcMCExpr::VariantKind TF = (SparcMCExpr::VariantKind) MO.getTargetFlags();
+
#ifndef NDEBUG
// Verify the target flags.
if (MO.isGlobal() || MO.isSymbol() || MO.isCPI()) {
if (MI->getOpcode() == SP::CALL)
- assert(TF == SPII::MO_NO_FLAG &&
+ assert(TF == SparcMCExpr::VK_Sparc_None &&
"Cannot handle target flags on call address");
else if (MI->getOpcode() == SP::SETHIi || MI->getOpcode() == SP::SETHIXi)
- assert((TF == SPII::MO_HI || TF == SPII::MO_H44 || TF == SPII::MO_HH
- || TF == SPII::MO_TLS_GD_HI22
- || TF == SPII::MO_TLS_LDM_HI22
- || TF == SPII::MO_TLS_LDO_HIX22
- || TF == SPII::MO_TLS_IE_HI22
- || TF == SPII::MO_TLS_LE_HIX22) &&
+ assert((TF == SparcMCExpr::VK_Sparc_HI
+ || TF == SparcMCExpr::VK_Sparc_H44
+ || TF == SparcMCExpr::VK_Sparc_HH
+ || TF == SparcMCExpr::VK_Sparc_TLS_GD_HI22
+ || TF == SparcMCExpr::VK_Sparc_TLS_LDM_HI22
+ || TF == SparcMCExpr::VK_Sparc_TLS_LDO_HIX22
+ || TF == SparcMCExpr::VK_Sparc_TLS_IE_HI22
+ || TF == SparcMCExpr::VK_Sparc_TLS_LE_HIX22) &&
"Invalid target flags for address operand on sethi");
else if (MI->getOpcode() == SP::TLS_CALL)
- assert((TF == SPII::MO_NO_FLAG
- || TF == SPII::MO_TLS_GD_CALL
- || TF == SPII::MO_TLS_LDM_CALL) &&
+ assert((TF == SparcMCExpr::VK_Sparc_None
+ || TF == SparcMCExpr::VK_Sparc_TLS_GD_CALL
+ || TF == SparcMCExpr::VK_Sparc_TLS_LDM_CALL) &&
"Cannot handle target flags on tls call address");
else if (MI->getOpcode() == SP::TLS_ADDrr)
- assert((TF == SPII::MO_TLS_GD_ADD || TF == SPII::MO_TLS_LDM_ADD
- || TF == SPII::MO_TLS_LDO_ADD || TF == SPII::MO_TLS_IE_ADD) &&
+ assert((TF == SparcMCExpr::VK_Sparc_TLS_GD_ADD
+ || TF == SparcMCExpr::VK_Sparc_TLS_LDM_ADD
+ || TF == SparcMCExpr::VK_Sparc_TLS_LDO_ADD
+ || TF == SparcMCExpr::VK_Sparc_TLS_IE_ADD) &&
"Cannot handle target flags on add for TLS");
else if (MI->getOpcode() == SP::TLS_LDrr)
- assert(TF == SPII::MO_TLS_IE_LD &&
+ assert(TF == SparcMCExpr::VK_Sparc_TLS_IE_LD &&
"Cannot handle target flags on ld for TLS");
else if (MI->getOpcode() == SP::TLS_LDXrr)
- assert(TF == SPII::MO_TLS_IE_LDX &&
+ assert(TF == SparcMCExpr::VK_Sparc_TLS_IE_LDX &&
"Cannot handle target flags on ldx for TLS");
else if (MI->getOpcode() == SP::XORri || MI->getOpcode() == SP::XORXri)
- assert((TF == SPII::MO_TLS_LDO_LOX10 || TF == SPII::MO_TLS_LE_LOX10) &&
+ assert((TF == SparcMCExpr::VK_Sparc_TLS_LDO_LOX10
+ || TF == SparcMCExpr::VK_Sparc_TLS_LE_LOX10) &&
"Cannot handle target flags on xor for TLS");
else
- assert((TF == SPII::MO_LO || TF == SPII::MO_M44 || TF == SPII::MO_L44
- || TF == SPII::MO_HM
- || TF == SPII::MO_TLS_GD_LO10
- || TF == SPII::MO_TLS_LDM_LO10
- || TF == SPII::MO_TLS_IE_LO10 ) &&
+ assert((TF == SparcMCExpr::VK_Sparc_LO
+ || TF == SparcMCExpr::VK_Sparc_M44
+ || TF == SparcMCExpr::VK_Sparc_L44
+ || TF == SparcMCExpr::VK_Sparc_HM
+ || TF == SparcMCExpr::VK_Sparc_TLS_GD_LO10
+ || TF == SparcMCExpr::VK_Sparc_TLS_LDM_LO10
+ || TF == SparcMCExpr::VK_Sparc_TLS_IE_LO10 ) &&
"Invalid target flags for small address operand");
}
#endif
- bool CloseParen = true;
- switch (TF) {
- default:
- llvm_unreachable("Unknown target flags on operand");
- case SPII::MO_NO_FLAG:
- CloseParen = false;
- break;
- case SPII::MO_LO: O << "%lo("; break;
- case SPII::MO_HI: O << "%hi("; break;
- case SPII::MO_H44: O << "%h44("; break;
- case SPII::MO_M44: O << "%m44("; break;
- case SPII::MO_L44: O << "%l44("; break;
- case SPII::MO_HH: O << "%hh("; break;
- case SPII::MO_HM: O << "%hm("; break;
- case SPII::MO_TLS_GD_HI22: O << "%tgd_hi22("; break;
- case SPII::MO_TLS_GD_LO10: O << "%tgd_lo10("; break;
- case SPII::MO_TLS_GD_ADD: O << "%tgd_add("; break;
- case SPII::MO_TLS_GD_CALL: O << "%tgd_call("; break;
- case SPII::MO_TLS_LDM_HI22: O << "%tldm_hi22("; break;
- case SPII::MO_TLS_LDM_LO10: O << "%tldm_lo10("; break;
- case SPII::MO_TLS_LDM_ADD: O << "%tldm_add("; break;
- case SPII::MO_TLS_LDM_CALL: O << "%tldm_call("; break;
- case SPII::MO_TLS_LDO_HIX22: O << "%tldo_hix22("; break;
- case SPII::MO_TLS_LDO_LOX10: O << "%tldo_lox10("; break;
- case SPII::MO_TLS_LDO_ADD: O << "%tldo_add("; break;
- case SPII::MO_TLS_IE_HI22: O << "%tie_hi22("; break;
- case SPII::MO_TLS_IE_LO10: O << "%tie_lo10("; break;
- case SPII::MO_TLS_IE_LD: O << "%tie_ld("; break;
- case SPII::MO_TLS_IE_LDX: O << "%tie_ldx("; break;
- case SPII::MO_TLS_IE_ADD: O << "%tie_add("; break;
- case SPII::MO_TLS_LE_HIX22: O << "%tle_hix22("; break;
- case SPII::MO_TLS_LE_LOX10: O << "%tle_lox10("; break;
- }
+ bool CloseParen = SparcMCExpr::printVariantKind(O, TF);
+
switch (MO.getType()) {
case MachineOperand::MO_Register:
O << "%" << StringRef(getRegisterName(MO.getReg())).lower();
Index: lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
===================================================================
--- lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
+++ lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
@@ -15,7 +15,6 @@
#include "SparcInstPrinter.h"
#include "Sparc.h"
-#include "MCTargetDesc/SparcBaseInfo.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCSymbol.h"
Index: lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h
+++ lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h
@@ -1,82 +0,0 @@
-//===-- SparcBaseInfo.h - Top level definitions for Sparc ---- --*- 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 small standalone helper functions and enum definitions
-// for the Sparc target useful for the compiler back-end and the MC libraries.
-// As such, it deliberately does not include references to LLVM core code gen
-// types, passes, etc..
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef SPARCBASEINFO_H
-#define SPARCBASEINFO_H
-
-namespace llvm {
-
-/// SPII - This namespace holds target specific flags for instruction info.
-namespace SPII {
-
-/// Target Operand Flags. Sparc specific TargetFlags for MachineOperands and
-/// SDNodes.
-enum TOF {
- MO_NO_FLAG,
-
- // Extract the low 10 bits of an address.
- // Assembler: %lo(addr)
- MO_LO,
-
- // Extract bits 31-10 of an address. Only for sethi.
- // Assembler: %hi(addr) or %lm(addr)
- MO_HI,
-
- // Extract bits 43-22 of an adress. Only for sethi.
- // Assembler: %h44(addr)
- MO_H44,
-
- // Extract bits 21-12 of an address.
- // Assembler: %m44(addr)
- MO_M44,
-
- // Extract bits 11-0 of an address.
- // Assembler: %l44(addr)
- MO_L44,
-
- // Extract bits 63-42 of an address. Only for sethi.
- // Assembler: %hh(addr)
- MO_HH,
-
- // Extract bits 41-32 of an address.
- // Assembler: %hm(addr)
- MO_HM,
-
- // TargetFlags for Thread Local Storage.
- MO_TLS_GD_HI22,
- MO_TLS_GD_LO10,
- MO_TLS_GD_ADD,
- MO_TLS_GD_CALL,
- MO_TLS_LDM_HI22,
- MO_TLS_LDM_LO10,
- MO_TLS_LDM_ADD,
- MO_TLS_LDM_CALL,
- MO_TLS_LDO_HIX22,
- MO_TLS_LDO_LOX10,
- MO_TLS_LDO_ADD,
- MO_TLS_IE_HI22,
- MO_TLS_IE_LO10,
- MO_TLS_IE_LD,
- MO_TLS_IE_LDX,
- MO_TLS_IE_ADD,
- MO_TLS_LE_HIX22,
- MO_TLS_LE_LOX10
-};
-
-} // end namespace SPII
-} // end namespace llvm
-
-#endif
Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
@@ -29,8 +29,21 @@ SparcMCExpr::Create(VariantKind Kind, const MCExpr
}
+
void SparcMCExpr::PrintImpl(raw_ostream &OS) const
{
+
+ bool closeParen = printVariantKind(OS, Kind);
+
+ const MCExpr *Expr = getSubExpr();
+ Expr->print(OS);
+
+ if (closeParen)
+ OS << ')';
+}
+
+bool SparcMCExpr::printVariantKind(raw_ostream &OS, VariantKind Kind)
+{
bool closeParen = true;
switch (Kind) {
case VK_Sparc_None: closeParen = false; break;
@@ -61,11 +74,7 @@ void SparcMCExpr::PrintImpl(raw_ostream &OS) const
case VK_Sparc_TLS_LE_HIX22: OS << "%tle_hix22("; break;
case VK_Sparc_TLS_LE_LOX10: OS << "%tle_lox10("; break;
}
-
- const MCExpr *Expr = getSubExpr();
- Expr->print(OS);
- if (closeParen)
- OS << ')';
+ return closeParen;
}
SparcMCExpr::VariantKind SparcMCExpr::parseVariantKind(StringRef name)
Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
+++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
@@ -93,7 +93,7 @@ class SparcMCExpr : public MCTargetExpr {
static bool classof(const SparcMCExpr *) { return true; }
static VariantKind parseVariantKind(StringRef name);
-
+ static bool printVariantKind(raw_ostream &OS, VariantKind Kind);
};
} // end namespace llvm.

View File

@ -0,0 +1,443 @@
Pull in r200961 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Emit correct relocations for PIC code when integrated assembler is used.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: test/CodeGen/SPARC/obj-relocs.ll
===================================================================
--- test/CodeGen/SPARC/obj-relocs.ll
+++ test/CodeGen/SPARC/obj-relocs.ll
@@ -0,0 +1,33 @@
+; RUN: llc < %s -march=sparcv9 -filetype=obj --relocation-model=static | llvm-readobj -r | FileCheck %s --check-prefix=CHECK-ABS
+; RUN: llc < %s -march=sparcv9 -filetype=obj --relocation-model=pic | llvm-readobj -r | FileCheck %s --check-prefix=CHECK-PIC
+
+;CHECK-ABS: Relocations [
+;CHECK-ABS: 0x{{[0-9,A-F]+}} R_SPARC_H44 AGlobalVar 0x0
+;CHECK-ABS: 0x{{[0-9,A-F]+}} R_SPARC_M44 AGlobalVar 0x0
+;CHECK-ABS: 0x{{[0-9,A-F]+}} R_SPARC_L44 AGlobalVar 0x0
+;CHECK-ABS: 0x{{[0-9,A-F]+}} R_SPARC_WDISP30 bar 0x0
+;CHECK-ABS:]
+
+; CHECK-PIC: Relocations [
+; CHECK-PIC: 0x{{[0-9,A-F]+}} R_SPARC_PC22 _GLOBAL_OFFSET_TABLE_ 0x4
+; CHECK-PIC: 0x{{[0-9,A-F]+}} R_SPARC_PC10 _GLOBAL_OFFSET_TABLE_ 0x8
+; CHECK-PIC: 0x{{[0-9,A-F]+}} R_SPARC_GOT22 AGlobalVar 0x0
+; CHECK-PIC: 0x{{[0-9,A-F]+}} R_SPARC_GOT10 AGlobalVar 0x0
+; CHECK-PIC: 0x{{[0-9,A-F]+}} R_SPARC_WPLT30 bar 0x0
+; CHECK-PIC: ]
+
+
+@AGlobalVar = global i64 0, align 8
+
+; CHECK-ASM: sethi %h44(AGlobalVar), [[R:%[goli][0-7]]]
+; CHECK-ASM: add [[R]], %m44(AGlobalVar), [[R]]
+define i64 @foo(i64 %a) {
+entry:
+ %0 = load i64* @AGlobalVar, align 4
+ %1 = add i64 %a, %0
+ %2 = call i64 @bar(i64 %1)
+ ret i64 %2
+}
+
+
+declare i64 @bar(i64)
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -895,10 +895,12 @@ SparcTargetLowering::LowerCall_32(TargetLowering::
// 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.
+ unsigned TF = ((getTargetMachine().getRelocationModel() == Reloc::PIC_)
+ ? SparcMCExpr::VK_Sparc_WPLT30 : 0);
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
- Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32);
+ Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32, 0, TF);
else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee))
- Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32);
+ Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32, TF);
// Returns a chain & a flag for retval copy to use
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
@@ -1209,10 +1211,13 @@ SparcTargetLowering::LowerCall_64(TargetLowering::
// Likewise ExternalSymbol -> TargetExternalSymbol.
SDValue Callee = CLI.Callee;
bool hasReturnsTwice = hasReturnsTwiceAttr(DAG, Callee, CLI.CS);
+ unsigned TF = ((getTargetMachine().getRelocationModel() == Reloc::PIC_)
+ ? SparcMCExpr::VK_Sparc_WPLT30 : 0);
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
- Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, getPointerTy());
+ Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, getPointerTy(), 0,
+ TF);
else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee))
- Callee = DAG.getTargetExternalSymbol(E->getSymbol(), getPointerTy());
+ Callee = DAG.getTargetExternalSymbol(E->getSymbol(), getPointerTy(), TF);
// Build the operands for the call instruction itself.
SmallVector<SDValue, 8> Ops;
@@ -1796,8 +1801,8 @@ SDValue SparcTargetLowering::makeAddress(SDValue O
// Handle PIC mode first.
if (getTargetMachine().getRelocationModel() == Reloc::PIC_) {
// This is the pic32 code model, the GOT is known to be smaller than 4GB.
- SDValue HiLo = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HI,
- SparcMCExpr::VK_Sparc_LO, DAG);
+ SDValue HiLo = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_GOT22,
+ SparcMCExpr::VK_Sparc_GOT10, DAG);
SDValue GlobalBase = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, VT);
SDValue AbsAddr = DAG.getNode(ISD::ADD, DL, VT, GlobalBase, HiLo);
// GLOBAL_BASE_REG codegen'ed with call. Inform MFI that this
Index: lib/Target/Sparc/SparcAsmPrinter.cpp
===================================================================
--- lib/Target/Sparc/SparcAsmPrinter.cpp
+++ lib/Target/Sparc/SparcAsmPrinter.cpp
@@ -232,12 +232,12 @@ void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(co
MCOperand Callee = createPCXCallOP(EndLabel, OutContext);
EmitCall(OutStreamer, Callee);
OutStreamer.EmitLabel(SethiLabel);
- MCOperand hiImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_HI,
+ MCOperand hiImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC22,
GOTLabel, StartLabel, SethiLabel,
OutContext);
EmitSETHI(OutStreamer, hiImm, MCRegOP);
OutStreamer.EmitLabel(EndLabel);
- MCOperand loImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_LO,
+ MCOperand loImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC10,
GOTLabel, StartLabel, EndLabel,
OutContext);
EmitOR(OutStreamer, MCRegOP, loImm, MCRegOP);
Index: lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
@@ -26,6 +26,7 @@ static unsigned adjustFixupValue(unsigned Kind, ui
case FK_Data_4:
case FK_Data_8:
return Value;
+ case Sparc::fixup_sparc_wplt30:
case Sparc::fixup_sparc_call30:
return (Value >> 2) & 0x3fffffff;
case Sparc::fixup_sparc_br22:
@@ -32,8 +33,12 @@ static unsigned adjustFixupValue(unsigned Kind, ui
return (Value >> 2) & 0x3fffff;
case Sparc::fixup_sparc_br19:
return (Value >> 2) & 0x7ffff;
+ case Sparc::fixup_sparc_pc22:
+ case Sparc::fixup_sparc_got22:
case Sparc::fixup_sparc_hi22:
return (Value >> 10) & 0x3fffff;
+ case Sparc::fixup_sparc_pc10:
+ case Sparc::fixup_sparc_got10:
case Sparc::fixup_sparc_lo10:
return Value & 0x3ff;
case Sparc::fixup_sparc_h44:
@@ -72,6 +77,11 @@ namespace {
{ "fixup_sparc_l44", 20, 12, 0 },
{ "fixup_sparc_hh", 10, 22, 0 },
{ "fixup_sparc_hm", 22, 10, 0 },
+ { "fixup_sparc_pc22", 10, 22, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_pc10", 22, 10, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_got22", 10, 22, 0 },
+ { "fixup_sparc_got10", 22, 10, 0 },
+ { "fixup_sparc_wplt30", 2, 30, MCFixupKindInfo::FKF_IsPCRel }
};
if (Kind < FirstTargetFixupKind)
@@ -82,6 +92,20 @@ namespace {
return Infos[Kind - FirstTargetFixupKind];
}
+ void processFixupValue(const MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ const MCFixup &Fixup,
+ const MCFragment *DF,
+ MCValue & Target,
+ uint64_t &Value,
+ bool &IsResolved) {
+ switch ((Sparc::Fixups)Fixup.getKind()) {
+ default: break;
+ case Sparc::fixup_sparc_wplt30: IsResolved = false; break;
+ }
+ }
+
+
bool mayNeedRelaxation(const MCInst &Inst) const {
// FIXME.
return false;
Index: lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
+++ lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
@@ -48,6 +48,21 @@ namespace llvm {
/// fixup_sparc_hm - 10-bit fixup corresponding to %hm(foo)
fixup_sparc_hm,
+ /// fixup_sparc_pc22 - 22-bit fixup corresponding to %pc22(foo)
+ fixup_sparc_pc22,
+
+ /// fixup_sparc_pc10 - 10-bit fixup corresponding to %pc10(foo)
+ fixup_sparc_pc10,
+
+ /// fixup_sparc_got22 - 22-bit fixup corresponding to %got22(foo)
+ fixup_sparc_got22,
+
+ /// fixup_sparc_got10 - 10-bit fixup corresponding to %got10(foo)
+ fixup_sparc_got10,
+
+ /// fixup_sparc_wplt30
+ fixup_sparc_wplt30,
+
// Marker
LastTargetFixupKind,
NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
Index: lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
@@ -7,8 +7,9 @@
//
//===----------------------------------------------------------------------===//
+#include "MCTargetDesc/SparcFixupKinds.h"
+#include "MCTargetDesc/SparcMCExpr.h"
#include "MCTargetDesc/SparcMCTargetDesc.h"
-#include "MCTargetDesc/SparcFixupKinds.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCExpr.h"
@@ -31,6 +32,11 @@ namespace {
bool IsPCRel, bool IsRelocWithSymbol,
int64_t Addend) const;
+ virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm,
+ const MCValue &Target,
+ const MCFragment &F,
+ const MCFixup &Fixup,
+ bool IsPCRel) const;
};
}
@@ -40,6 +46,12 @@ unsigned SparcELFObjectWriter::GetRelocType(const
bool IsPCRel,
bool IsRelocWithSymbol,
int64_t Addend) const {
+
+ if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(Fixup.getValue())) {
+ if (SExpr->getKind() == SparcMCExpr::VK_Sparc_R_DISP32)
+ return ELF::R_SPARC_DISP32;
+ }
+
if (IsPCRel) {
switch((unsigned)Fixup.getKind()) {
default:
@@ -51,6 +63,9 @@ unsigned SparcELFObjectWriter::GetRelocType(const
case Sparc::fixup_sparc_call30: return ELF::R_SPARC_WDISP30;
case Sparc::fixup_sparc_br22: return ELF::R_SPARC_WDISP22;
case Sparc::fixup_sparc_br19: return ELF::R_SPARC_WDISP19;
+ case Sparc::fixup_sparc_pc22: return ELF::R_SPARC_PC22;
+ case Sparc::fixup_sparc_pc10: return ELF::R_SPARC_PC10;
+ case Sparc::fixup_sparc_wplt30: return ELF::R_SPARC_WPLT30;
}
}
@@ -74,10 +89,30 @@ unsigned SparcELFObjectWriter::GetRelocType(const
case Sparc::fixup_sparc_l44: return ELF::R_SPARC_L44;
case Sparc::fixup_sparc_hh: return ELF::R_SPARC_HH22;
case Sparc::fixup_sparc_hm: return ELF::R_SPARC_HM10;
+ case Sparc::fixup_sparc_got22: return ELF::R_SPARC_GOT22;
+ case Sparc::fixup_sparc_got10: return ELF::R_SPARC_GOT10;
}
+
return ELF::R_SPARC_NONE;
}
+const MCSymbol *SparcELFObjectWriter::ExplicitRelSym(const MCAssembler &Asm,
+ const MCValue &Target,
+ const MCFragment &F,
+ const MCFixup &Fixup,
+ bool IsPCRel) const {
+
+ if (!Target.getSymA())
+ return NULL;
+ switch((unsigned)Fixup.getKind()) {
+ default: break;
+ case Sparc::fixup_sparc_got22:
+ case Sparc::fixup_sparc_got10:
+ return &Target.getSymA()->getSymbol().AliasedSymbol();
+ }
+ return NULL;
+}
+
MCObjectWriter *llvm::createSparcELFObjectWriter(raw_ostream &OS,
bool Is64Bit,
uint8_t OSABI) {
Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
@@ -17,6 +17,7 @@
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCELF.h"
+#include "llvm/MC/MCSymbol.h"
#include "llvm/Object/ELF.h"
@@ -54,6 +55,13 @@ bool SparcMCExpr::printVariantKind(raw_ostream &OS
case VK_Sparc_L44: OS << "%l44("; break;
case VK_Sparc_HH: OS << "%hh("; break;
case VK_Sparc_HM: OS << "%hm("; break;
+ // FIXME: use %pc22/%pc10, if system assembler supports them.
+ case VK_Sparc_PC22: OS << "%hi("; break;
+ case VK_Sparc_PC10: OS << "%lo("; break;
+ // FIXME: use %got22/%got10, if system assembler supports them.
+ case VK_Sparc_GOT22: OS << "%hi("; break;
+ case VK_Sparc_GOT10: OS << "%lo("; break;
+ case VK_Sparc_WPLT30: closeParen = false; break;
case VK_Sparc_R_DISP32: OS << "%r_disp32("; break;
case VK_Sparc_TLS_GD_HI22: OS << "%tgd_hi22("; break;
case VK_Sparc_TLS_GD_LO10: OS << "%tgd_lo10("; break;
@@ -87,6 +95,10 @@ SparcMCExpr::VariantKind SparcMCExpr::parseVariant
.Case("l44", VK_Sparc_L44)
.Case("hh", VK_Sparc_HH)
.Case("hm", VK_Sparc_HM)
+ .Case("pc22", VK_Sparc_PC22)
+ .Case("pc10", VK_Sparc_PC10)
+ .Case("got22", VK_Sparc_GOT22)
+ .Case("got10", VK_Sparc_GOT10)
.Case("r_disp32", VK_Sparc_R_DISP32)
.Case("tgd_hi22", VK_Sparc_TLS_GD_HI22)
.Case("tgd_lo10", VK_Sparc_TLS_GD_LO10)
@@ -109,9 +121,26 @@ SparcMCExpr::VariantKind SparcMCExpr::parseVariant
.Default(VK_Sparc_None);
}
+Sparc::Fixups SparcMCExpr::getFixupKind(SparcMCExpr::VariantKind Kind) {
+ switch (Kind) {
+ default: assert(0 && "Unhandled SparcMCExpr::VariantKind");
+ case VK_Sparc_LO: return Sparc::fixup_sparc_lo10;
+ case VK_Sparc_HI: return Sparc::fixup_sparc_hi22;
+ case VK_Sparc_H44: return Sparc::fixup_sparc_h44;
+ case VK_Sparc_M44: return Sparc::fixup_sparc_m44;
+ case VK_Sparc_L44: return Sparc::fixup_sparc_l44;
+ case VK_Sparc_HH: return Sparc::fixup_sparc_hh;
+ case VK_Sparc_HM: return Sparc::fixup_sparc_hm;
+ case VK_Sparc_PC22: return Sparc::fixup_sparc_pc22;
+ case VK_Sparc_PC10: return Sparc::fixup_sparc_pc10;
+ case VK_Sparc_GOT22: return Sparc::fixup_sparc_got22;
+ case VK_Sparc_GOT10: return Sparc::fixup_sparc_got10;
+ }
+}
+
bool
SparcMCExpr::EvaluateAsRelocatableImpl(MCValue &Res,
- const MCAsmLayout *Layout) const {
+ const MCAsmLayout *Layout) const {
if (!Layout)
return false;
return getSubExpr()->EvaluateAsRelocatable(Res, *Layout);
Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
+++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
@@ -15,6 +15,7 @@
#ifndef LLVM_SPARCMCEXPR_H
#define LLVM_SPARCMCEXPR_H
+#include "SparcFixupKinds.h"
#include "llvm/MC/MCExpr.h"
namespace llvm {
@@ -31,6 +32,11 @@ class SparcMCExpr : public MCTargetExpr {
VK_Sparc_L44,
VK_Sparc_HH,
VK_Sparc_HM,
+ VK_Sparc_PC22,
+ VK_Sparc_PC10,
+ VK_Sparc_GOT22,
+ VK_Sparc_GOT10,
+ VK_Sparc_WPLT30,
VK_Sparc_R_DISP32,
VK_Sparc_TLS_GD_HI22,
VK_Sparc_TLS_GD_LO10,
@@ -75,6 +81,9 @@ class SparcMCExpr : public MCTargetExpr {
/// getSubExpr - Get the child of this expression.
const MCExpr *getSubExpr() const { return Expr; }
+ /// getFixupKind - Get the fixup kind of this expression.
+ Sparc::Fixups getFixupKind() const { return getFixupKind(Kind); }
+
/// @}
void PrintImpl(raw_ostream &OS) const;
bool EvaluateAsRelocatableImpl(MCValue &Res,
@@ -94,6 +103,7 @@ class SparcMCExpr : public MCTargetExpr {
static VariantKind parseVariantKind(StringRef name);
static bool printVariantKind(raw_ostream &OS, VariantKind Kind);
+ static Sparc::Fixups getFixupKind(VariantKind Kind);
};
} // end namespace llvm.
Index: lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
@@ -94,37 +94,8 @@ getMachineOpValue(const MCInst &MI, const MCOperan
assert(MO.isExpr());
const MCExpr *Expr = MO.getExpr();
if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(Expr)) {
- switch(SExpr->getKind()) {
- default: assert(0 && "Unhandled sparc expression!"); break;
- case SparcMCExpr::VK_Sparc_LO:
- Fixups.push_back(MCFixup::Create(0, Expr,
- (MCFixupKind)Sparc::fixup_sparc_lo10));
- break;
- case SparcMCExpr::VK_Sparc_HI:
- Fixups.push_back(MCFixup::Create(0, Expr,
- (MCFixupKind)Sparc::fixup_sparc_hi22));
- break;
- case SparcMCExpr::VK_Sparc_H44:
- Fixups.push_back(MCFixup::Create(0, Expr,
- (MCFixupKind)Sparc::fixup_sparc_h44));
- break;
- case SparcMCExpr::VK_Sparc_M44:
- Fixups.push_back(MCFixup::Create(0, Expr,
- (MCFixupKind)Sparc::fixup_sparc_m44));
- break;
- case SparcMCExpr::VK_Sparc_L44:
- Fixups.push_back(MCFixup::Create(0, Expr,
- (MCFixupKind)Sparc::fixup_sparc_l44));
- break;
- case SparcMCExpr::VK_Sparc_HH:
- Fixups.push_back(MCFixup::Create(0, Expr,
- (MCFixupKind)Sparc::fixup_sparc_hh));
- break;
- case SparcMCExpr::VK_Sparc_HM:
- Fixups.push_back(MCFixup::Create(0, Expr,
- (MCFixupKind)Sparc::fixup_sparc_hm));
- break;
- }
+ MCFixupKind Kind = (MCFixupKind)SExpr->getFixupKind();
+ Fixups.push_back(MCFixup::Create(0, Expr, Kind));
return 0;
}
@@ -143,8 +114,15 @@ getCallTargetOpValue(const MCInst &MI, unsigned Op
if (MO.isReg() || MO.isImm())
return getMachineOpValue(MI, MO, Fixups);
- Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
- (MCFixupKind)Sparc::fixup_sparc_call30));
+ MCFixupKind fixupKind = (MCFixupKind)Sparc::fixup_sparc_call30;
+
+ if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(MO.getExpr())) {
+ if (SExpr->getKind() == SparcMCExpr::VK_Sparc_WPLT30)
+ fixupKind = (MCFixupKind)Sparc::fixup_sparc_wplt30;
+ }
+
+ Fixups.push_back(MCFixup::Create(0, MO.getExpr(), fixupKind));
+
return 0;
}

View File

@ -0,0 +1,378 @@
Pull in r200962 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Emit relocations for Thread Local Storage (TLS) when integrated assembler is used.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
@@ -26,31 +26,65 @@ static unsigned adjustFixupValue(unsigned Kind, ui
case FK_Data_4:
case FK_Data_8:
return Value;
+
case Sparc::fixup_sparc_wplt30:
case Sparc::fixup_sparc_call30:
return (Value >> 2) & 0x3fffffff;
+
case Sparc::fixup_sparc_br22:
return (Value >> 2) & 0x3fffff;
+
case Sparc::fixup_sparc_br19:
return (Value >> 2) & 0x7ffff;
+
case Sparc::fixup_sparc_pc22:
case Sparc::fixup_sparc_got22:
+ case Sparc::fixup_sparc_tls_gd_hi22:
+ case Sparc::fixup_sparc_tls_ldm_hi22:
+ case Sparc::fixup_sparc_tls_ie_hi22:
case Sparc::fixup_sparc_hi22:
return (Value >> 10) & 0x3fffff;
+
case Sparc::fixup_sparc_pc10:
case Sparc::fixup_sparc_got10:
+ case Sparc::fixup_sparc_tls_gd_lo10:
+ case Sparc::fixup_sparc_tls_ldm_lo10:
+ case Sparc::fixup_sparc_tls_ie_lo10:
case Sparc::fixup_sparc_lo10:
return Value & 0x3ff;
+
+ case Sparc::fixup_sparc_tls_ldo_hix22:
+ case Sparc::fixup_sparc_tls_le_hix22:
+ return (~Value >> 10) & 0x3fffff;
+
+ case Sparc::fixup_sparc_tls_ldo_lox10:
+ case Sparc::fixup_sparc_tls_le_lox10:
+ return (~(~Value & 0x3ff)) & 0x1fff;
+
case Sparc::fixup_sparc_h44:
return (Value >> 22) & 0x3fffff;
+
case Sparc::fixup_sparc_m44:
return (Value >> 12) & 0x3ff;
+
case Sparc::fixup_sparc_l44:
return Value & 0xfff;
+
case Sparc::fixup_sparc_hh:
return (Value >> 42) & 0x3fffff;
+
case Sparc::fixup_sparc_hm:
return (Value >> 32) & 0x3ff;
+
+ case Sparc::fixup_sparc_tls_gd_add:
+ case Sparc::fixup_sparc_tls_gd_call:
+ case Sparc::fixup_sparc_tls_ldm_add:
+ case Sparc::fixup_sparc_tls_ldm_call:
+ case Sparc::fixup_sparc_tls_ldo_add:
+ case Sparc::fixup_sparc_tls_ie_ld:
+ case Sparc::fixup_sparc_tls_ie_ldx:
+ case Sparc::fixup_sparc_tls_ie_add:
+ return 0;
}
}
@@ -81,7 +115,25 @@ namespace {
{ "fixup_sparc_pc10", 22, 10, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_got22", 10, 22, 0 },
{ "fixup_sparc_got10", 22, 10, 0 },
- { "fixup_sparc_wplt30", 2, 30, MCFixupKindInfo::FKF_IsPCRel }
+ { "fixup_sparc_wplt30", 2, 30, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_tls_gd_hi22", 10, 22, 0 },
+ { "fixup_sparc_tls_gd_lo10", 22, 10, 0 },
+ { "fixup_sparc_tls_gd_add", 0, 0, 0 },
+ { "fixup_sparc_tls_gd_call", 0, 0, 0 },
+ { "fixup_sparc_tls_ldm_hi22", 10, 22, 0 },
+ { "fixup_sparc_tls_ldm_lo10", 22, 10, 0 },
+ { "fixup_sparc_tls_ldm_add", 0, 0, 0 },
+ { "fixup_sparc_tls_ldm_call", 0, 0, 0 },
+ { "fixup_sparc_tls_ldo_hix22", 10, 22, 0 },
+ { "fixup_sparc_tls_ldo_lox10", 22, 10, 0 },
+ { "fixup_sparc_tls_ldo_add", 0, 0, 0 },
+ { "fixup_sparc_tls_ie_hi22", 10, 22, 0 },
+ { "fixup_sparc_tls_ie_lo10", 22, 10, 0 },
+ { "fixup_sparc_tls_ie_ld", 0, 0, 0 },
+ { "fixup_sparc_tls_ie_ldx", 0, 0, 0 },
+ { "fixup_sparc_tls_ie_add", 0, 0, 0 },
+ { "fixup_sparc_tls_le_hix22", 0, 0, 0 },
+ { "fixup_sparc_tls_le_lox10", 0, 0, 0 }
};
if (Kind < FirstTargetFixupKind)
@@ -101,11 +153,28 @@ namespace {
bool &IsResolved) {
switch ((Sparc::Fixups)Fixup.getKind()) {
default: break;
- case Sparc::fixup_sparc_wplt30: IsResolved = false; break;
+ case Sparc::fixup_sparc_wplt30:
+ case Sparc::fixup_sparc_tls_gd_hi22:
+ case Sparc::fixup_sparc_tls_gd_lo10:
+ case Sparc::fixup_sparc_tls_gd_add:
+ case Sparc::fixup_sparc_tls_gd_call:
+ case Sparc::fixup_sparc_tls_ldm_hi22:
+ case Sparc::fixup_sparc_tls_ldm_lo10:
+ case Sparc::fixup_sparc_tls_ldm_add:
+ case Sparc::fixup_sparc_tls_ldm_call:
+ case Sparc::fixup_sparc_tls_ldo_hix22:
+ case Sparc::fixup_sparc_tls_ldo_lox10:
+ case Sparc::fixup_sparc_tls_ldo_add:
+ case Sparc::fixup_sparc_tls_ie_hi22:
+ case Sparc::fixup_sparc_tls_ie_lo10:
+ case Sparc::fixup_sparc_tls_ie_ld:
+ case Sparc::fixup_sparc_tls_ie_ldx:
+ case Sparc::fixup_sparc_tls_ie_add:
+ case Sparc::fixup_sparc_tls_le_hix22:
+ case Sparc::fixup_sparc_tls_le_lox10: IsResolved = false; break;
}
}
-
bool mayNeedRelaxation(const MCInst &Inst) const {
// FIXME.
return false;
Index: lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
+++ lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
@@ -63,6 +63,26 @@ namespace llvm {
/// fixup_sparc_wplt30
fixup_sparc_wplt30,
+ /// fixups for Thread Local Storage
+ fixup_sparc_tls_gd_hi22,
+ fixup_sparc_tls_gd_lo10,
+ fixup_sparc_tls_gd_add,
+ fixup_sparc_tls_gd_call,
+ fixup_sparc_tls_ldm_hi22,
+ fixup_sparc_tls_ldm_lo10,
+ fixup_sparc_tls_ldm_add,
+ fixup_sparc_tls_ldm_call,
+ fixup_sparc_tls_ldo_hix22,
+ fixup_sparc_tls_ldo_lox10,
+ fixup_sparc_tls_ldo_add,
+ fixup_sparc_tls_ie_hi22,
+ fixup_sparc_tls_ie_lo10,
+ fixup_sparc_tls_ie_ld,
+ fixup_sparc_tls_ie_ldx,
+ fixup_sparc_tls_ie_add,
+ fixup_sparc_tls_le_hix22,
+ fixup_sparc_tls_le_lox10,
+
// Marker
LastTargetFixupKind,
NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
Index: lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
@@ -91,6 +91,24 @@ unsigned SparcELFObjectWriter::GetRelocType(const
case Sparc::fixup_sparc_hm: return ELF::R_SPARC_HM10;
case Sparc::fixup_sparc_got22: return ELF::R_SPARC_GOT22;
case Sparc::fixup_sparc_got10: return ELF::R_SPARC_GOT10;
+ case Sparc::fixup_sparc_tls_gd_hi22: return ELF::R_SPARC_TLS_GD_HI22;
+ case Sparc::fixup_sparc_tls_gd_lo10: return ELF::R_SPARC_TLS_GD_LO10;
+ case Sparc::fixup_sparc_tls_gd_add: return ELF::R_SPARC_TLS_GD_ADD;
+ case Sparc::fixup_sparc_tls_gd_call: return ELF::R_SPARC_TLS_GD_CALL;
+ case Sparc::fixup_sparc_tls_ldm_hi22: return ELF::R_SPARC_TLS_LDM_HI22;
+ case Sparc::fixup_sparc_tls_ldm_lo10: return ELF::R_SPARC_TLS_LDM_LO10;
+ case Sparc::fixup_sparc_tls_ldm_add: return ELF::R_SPARC_TLS_LDM_ADD;
+ case Sparc::fixup_sparc_tls_ldm_call: return ELF::R_SPARC_TLS_LDM_CALL;
+ case Sparc::fixup_sparc_tls_ldo_hix22: return ELF::R_SPARC_TLS_LDO_HIX22;
+ case Sparc::fixup_sparc_tls_ldo_lox10: return ELF::R_SPARC_TLS_LDO_LOX10;
+ case Sparc::fixup_sparc_tls_ldo_add: return ELF::R_SPARC_TLS_LDO_ADD;
+ case Sparc::fixup_sparc_tls_ie_hi22: return ELF::R_SPARC_TLS_IE_HI22;
+ case Sparc::fixup_sparc_tls_ie_lo10: return ELF::R_SPARC_TLS_IE_LO10;
+ case Sparc::fixup_sparc_tls_ie_ld: return ELF::R_SPARC_TLS_IE_LD;
+ case Sparc::fixup_sparc_tls_ie_ldx: return ELF::R_SPARC_TLS_IE_LDX;
+ case Sparc::fixup_sparc_tls_ie_add: return ELF::R_SPARC_TLS_IE_ADD;
+ case Sparc::fixup_sparc_tls_le_hix22: return ELF::R_SPARC_TLS_LE_HIX22;
+ case Sparc::fixup_sparc_tls_le_lox10: return ELF::R_SPARC_TLS_LE_LOX10;
}
return ELF::R_SPARC_NONE;
Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
@@ -135,6 +135,25 @@ Sparc::Fixups SparcMCExpr::getFixupKind(SparcMCExp
case VK_Sparc_PC10: return Sparc::fixup_sparc_pc10;
case VK_Sparc_GOT22: return Sparc::fixup_sparc_got22;
case VK_Sparc_GOT10: return Sparc::fixup_sparc_got10;
+ case VK_Sparc_WPLT30: return Sparc::fixup_sparc_wplt30;
+ case VK_Sparc_TLS_GD_HI22: return Sparc::fixup_sparc_tls_gd_hi22;
+ case VK_Sparc_TLS_GD_LO10: return Sparc::fixup_sparc_tls_gd_lo10;
+ case VK_Sparc_TLS_GD_ADD: return Sparc::fixup_sparc_tls_gd_add;
+ case VK_Sparc_TLS_GD_CALL: return Sparc::fixup_sparc_tls_gd_call;
+ case VK_Sparc_TLS_LDM_HI22: return Sparc::fixup_sparc_tls_ldm_hi22;
+ case VK_Sparc_TLS_LDM_LO10: return Sparc::fixup_sparc_tls_ldm_lo10;
+ case VK_Sparc_TLS_LDM_ADD: return Sparc::fixup_sparc_tls_ldm_add;
+ case VK_Sparc_TLS_LDM_CALL: return Sparc::fixup_sparc_tls_ldm_call;
+ case VK_Sparc_TLS_LDO_HIX22: return Sparc::fixup_sparc_tls_ldo_hix22;
+ case VK_Sparc_TLS_LDO_LOX10: return Sparc::fixup_sparc_tls_ldo_lox10;
+ case VK_Sparc_TLS_LDO_ADD: return Sparc::fixup_sparc_tls_ldo_add;
+ case VK_Sparc_TLS_IE_HI22: return Sparc::fixup_sparc_tls_ie_hi22;
+ case VK_Sparc_TLS_IE_LO10: return Sparc::fixup_sparc_tls_ie_lo10;
+ case VK_Sparc_TLS_IE_LD: return Sparc::fixup_sparc_tls_ie_ld;
+ case VK_Sparc_TLS_IE_LDX: return Sparc::fixup_sparc_tls_ie_ldx;
+ case VK_Sparc_TLS_IE_ADD: return Sparc::fixup_sparc_tls_ie_add;
+ case VK_Sparc_TLS_LE_HIX22: return Sparc::fixup_sparc_tls_le_hix22;
+ case VK_Sparc_TLS_LE_LOX10: return Sparc::fixup_sparc_tls_le_lox10;
}
}
@@ -147,7 +166,33 @@ SparcMCExpr::EvaluateAsRelocatableImpl(MCValue &Re
}
static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) {
- assert(0 && "Implement fixELFSymbolsInTLSFixupsImpl!");
+ switch (Expr->getKind()) {
+ case MCExpr::Target:
+ llvm_unreachable("Can't handle nested target expr!");
+ break;
+
+ case MCExpr::Constant:
+ break;
+
+ case MCExpr::Binary: {
+ const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);
+ fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm);
+ fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm);
+ break;
+ }
+
+ case MCExpr::SymbolRef: {
+ const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr);
+ MCSymbolData &SD = Asm.getOrCreateSymbolData(SymRef.getSymbol());
+ MCELF::SetType(SD, ELF::STT_TLS);
+ break;
+ }
+
+ case MCExpr::Unary:
+ fixELFSymbolsInTLSFixupsImpl(cast<MCUnaryExpr>(Expr)->getSubExpr(), Asm);
+ break;
+ }
+
}
void SparcMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
Index: lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
===================================================================
--- lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
+++ lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
@@ -20,6 +20,7 @@
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSymbol.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/raw_ostream.h"
@@ -76,6 +77,21 @@ EncodeInstruction(const MCInst &MI, raw_ostream &O
OS << (char)(Bits >> 24);
Bits <<= 8;
}
+ unsigned tlsOpNo = 0;
+ switch (MI.getOpcode()) {
+ default: break;
+ case SP::TLS_CALL: tlsOpNo = 1; break;
+ case SP::TLS_ADDrr:
+ case SP::TLS_ADDXrr:
+ case SP::TLS_LDrr:
+ case SP::TLS_LDXrr: tlsOpNo = 3; break;
+ }
+ if (tlsOpNo != 0) {
+ const MCOperand &MO = MI.getOperand(tlsOpNo);
+ uint64_t op = getMachineOpValue(MI, MO, Fixups);
+ assert(op == 0 && "Unexpected operand value!");
+ (void)op; // suppress warning.
+ }
++MCNumEmitted; // Keep track of the # of mi's emitted.
}
@@ -114,6 +130,21 @@ getCallTargetOpValue(const MCInst &MI, unsigned Op
if (MO.isReg() || MO.isImm())
return getMachineOpValue(MI, MO, Fixups);
+ if (MI.getOpcode() == SP::TLS_CALL) {
+ // No fixups for __tls_get_addr. Will emit for fixups for tls_symbol in
+ // EncodeInstruction.
+#ifndef NDEBUG
+ // Verify that the callee is actually __tls_get_addr.
+ const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(MO.getExpr());
+ assert(SExpr && SExpr->getSubExpr()->getKind() == MCExpr::SymbolRef &&
+ "Unexpected expression in TLS_CALL");
+ const MCSymbolRefExpr *SymExpr = cast<MCSymbolRefExpr>(SExpr->getSubExpr());
+ assert(SymExpr->getSymbol().getName() == "__tls_get_addr" &&
+ "Unexpected function for TLS_CALL");
+#endif
+ return 0;
+ }
+
MCFixupKind fixupKind = (MCFixupKind)Sparc::fixup_sparc_call30;
if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(MO.getExpr())) {
Index: test/CodeGen/SPARC/tls.ll
===================================================================
--- test/CodeGen/SPARC/tls.ll
+++ test/CodeGen/SPARC/tls.ll
@@ -3,6 +3,10 @@
; RUN: llc <%s -march=sparc -relocation-model=pic | FileCheck %s --check-prefix=pic
; RUN: llc <%s -march=sparcv9 -relocation-model=pic | FileCheck %s --check-prefix=pic
+; RUN: llc <%s -march=sparc -relocation-model=static -filetype=obj | llvm-readobj -r | FileCheck %s --check-prefix=v8abs-obj
+; RUN: llc <%s -march=sparcv9 -relocation-model=static -filetype=obj | llvm-readobj -r | FileCheck %s --check-prefix=v9abs-obj
+; RUN: llc <%s -march=sparc -relocation-model=pic -filetype=obj | llvm-readobj -r | FileCheck %s --check-prefix=pic-obj
+; RUN: llc <%s -march=sparcv9 -relocation-model=pic -filetype=obj | llvm-readobj -r | FileCheck %s --check-prefix=pic-obj
@local_symbol = internal thread_local global i32 0
@extern_symbol = external thread_local global i32
@@ -69,3 +73,47 @@ entry:
store i32 %1, i32* @extern_symbol, align 4
ret i32 %1
}
+
+
+; v8abs-obj: Relocations [
+; v8abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LE_HIX22 local_symbol 0x0
+; v8abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LE_LOX10 local_symbol 0x0
+; v8abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_HI22 _GLOBAL_OFFSET_TABLE_ 0x0
+; v8abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_LO10 _GLOBAL_OFFSET_TABLE_ 0x0
+; v8abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_IE_HI22 extern_symbol 0x0
+; v8abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_IE_LO10 extern_symbol 0x0
+; v8abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_IE_LD extern_symbol 0x0
+; v8abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_IE_ADD extern_symbol 0x0
+; v8abs-obj: ]
+
+; v9abs-obj: Relocations [
+; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LE_HIX22 local_symbol 0x0
+; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LE_LOX10 local_symbol 0x0
+; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_H44 _GLOBAL_OFFSET_TABLE_ 0x0
+; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_M44 _GLOBAL_OFFSET_TABLE_ 0x0
+; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_L44 _GLOBAL_OFFSET_TABLE_ 0x0
+; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_IE_HI22 extern_symbol 0x0
+; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_IE_LO10 extern_symbol 0x0
+; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_IE_LDX extern_symbol 0x0
+; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_IE_ADD extern_symbol 0x0
+; v9abs-obj: ]
+
+; pic-obj: Relocations [
+; pic-obj: Section (2) .rela.text {
+; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_PC22 _GLOBAL_OFFSET_TABLE_ 0x4
+; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_PC10 _GLOBAL_OFFSET_TABLE_ 0x8
+; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDO_HIX22 local_symbol 0x0
+; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDO_LOX10 local_symbol 0x0
+; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDM_HI22 local_symbol 0x0
+; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDM_LO10 local_symbol 0x0
+; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDM_ADD local_symbol 0x0
+; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDM_CALL local_symbol 0x0
+; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDO_ADD local_symbol 0x0
+; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_PC22 _GLOBAL_OFFSET_TABLE_ 0x4
+; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_PC10 _GLOBAL_OFFSET_TABLE_ 0x8
+; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_GD_HI22 extern_symbol 0x0
+; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_GD_LO10 extern_symbol 0x0
+; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_GD_ADD extern_symbol 0x0
+; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_GD_CALL extern_symbol 0x0
+; pic-obj: ]
+

View File

@ -0,0 +1,131 @@
Pull in r200963 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Emit correct encoding for atomic instructions. Also, add support for parsing CAS instructions to test the CAS encoding.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: test/MC/Sparc/sparc-atomic-instructions.s
===================================================================
--- test/MC/Sparc/sparc-atomic-instructions.s
+++ test/MC/Sparc/sparc-atomic-instructions.s
@@ -0,0 +1,19 @@
+! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s
+
+ ! CHECK: membar 15 ! encoding: [0x81,0x43,0xe0,0x0f]
+ membar 15
+
+ ! CHECK: stbar ! encoding: [0x81,0x43,0xc0,0x00]
+ stbar
+
+ ! CHECK: swap [%i0+%l6], %o2 ! encoding: [0xd4,0x7e,0x00,0x16]
+ swap [%i0+%l6], %o2
+
+ ! CHECK: swap [%i0+32], %o2 ! encoding: [0xd4,0x7e,0x20,0x20]
+ swap [%i0+32], %o2
+
+ ! CHECK: cas [%i0], %l6, %o2 ! encoding: [0xd5,0xe6,0x10,0x16]
+ cas [%i0], %l6, %o2
+
+ ! CHECK: casx [%i0], %l6, %o2 ! encoding: [0xd5,0xf6,0x10,0x16]
+ casx [%i0], %l6, %o2
Index: lib/Target/Sparc/SparcInstrInfo.td
===================================================================
--- lib/Target/Sparc/SparcInstrInfo.td
+++ lib/Target/Sparc/SparcInstrInfo.td
@@ -935,19 +935,19 @@ let Predicates = [HasV9], hasSideEffects = 1, rd =
def MEMBARi : F3_2<2, 0b101000, (outs), (ins i32imm:$simm13),
"membar $simm13", []>;
-let Constraints = "$val = $rd" in {
+let Constraints = "$val = $dst" in {
def SWAPrr : F3_1<3, 0b001111,
- (outs IntRegs:$rd), (ins IntRegs:$val, MEMrr:$addr),
- "swap [$addr], $rd",
- [(set i32:$rd, (atomic_swap_32 ADDRrr:$addr, i32:$val))]>;
+ (outs IntRegs:$dst), (ins MEMrr:$addr, IntRegs:$val),
+ "swap [$addr], $dst",
+ [(set i32:$dst, (atomic_swap_32 ADDRrr:$addr, i32:$val))]>;
def SWAPri : F3_2<3, 0b001111,
- (outs IntRegs:$rd), (ins IntRegs:$val, MEMri:$addr),
- "swap [$addr], $rd",
- [(set i32:$rd, (atomic_swap_32 ADDRri:$addr, i32:$val))]>;
+ (outs IntRegs:$dst), (ins MEMri:$addr, IntRegs:$val),
+ "swap [$addr], $dst",
+ [(set i32:$dst, (atomic_swap_32 ADDRri:$addr, i32:$val))]>;
}
let Predicates = [HasV9], Constraints = "$swap = $rd" in
- def CASrr: F3_1<3, 0b111100,
+ def CASrr: F3_1_asi<3, 0b111100, 0b10000000,
(outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2,
IntRegs:$swap),
"cas [$rs1], $rs2, $rd",
Index: lib/Target/Sparc/SparcInstrFormats.td
===================================================================
--- lib/Target/Sparc/SparcInstrFormats.td
+++ lib/Target/Sparc/SparcInstrFormats.td
@@ -100,9 +100,8 @@ class F3<dag outs, dag ins, string asmstr, list<da
// Specific F3 classes: SparcV8 manual, page 44
//
-class F3_1<bits<2> opVal, bits<6> op3val, dag outs, dag ins,
+class F3_1_asi<bits<2> opVal, bits<6> op3val, bits<8> asi, dag outs, dag ins,
string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> {
- bits<8> asi = 0; // asi not currently used
bits<5> rs2;
let op = opVal;
@@ -113,6 +112,10 @@ class F3<dag outs, dag ins, string asmstr, list<da
let Inst{4-0} = rs2;
}
+class F3_1<bits<2> opVal, bits<6> op3val, dag outs, dag ins, string asmstr,
+ list<dag> pattern> : F3_1_asi<opVal, op3val, 0, outs, ins,
+ asmstr, pattern>;
+
class F3_2<bits<2> opVal, bits<6> op3val, dag outs, dag ins,
string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> {
bits<13> simm13;
Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
===================================================================
--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
+++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
@@ -546,7 +546,24 @@ parseOperand(SmallVectorImpl<MCParsedAsmOperand*>
Parser.getTok().getLoc()));
Parser.Lex(); // Eat the [
- ResTy = parseMEMOperand(Operands);
+ if (Mnemonic == "cas" || Mnemonic == "casx") {
+ SMLoc S = Parser.getTok().getLoc();
+ if (getLexer().getKind() != AsmToken::Percent)
+ return MatchOperand_NoMatch;
+ Parser.Lex(); // eat %
+
+ unsigned RegNo, RegKind;
+ if (!matchRegisterName(Parser.getTok(), RegNo, RegKind))
+ return MatchOperand_NoMatch;
+
+ Parser.Lex(); // Eat the identifier token.
+ SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer()-1);
+ Operands.push_back(SparcOperand::CreateReg(RegNo, RegKind, S, E));
+ ResTy = MatchOperand_Success;
+ } else {
+ ResTy = parseMEMOperand(Operands);
+ }
+
if (ResTy != MatchOperand_Success)
return ResTy;
Index: lib/Target/Sparc/SparcInstr64Bit.td
===================================================================
--- lib/Target/Sparc/SparcInstr64Bit.td
+++ lib/Target/Sparc/SparcInstr64Bit.td
@@ -415,7 +415,7 @@ def SETHIXi : F2_1<0b100,
// ATOMICS.
let Predicates = [Is64Bit], Constraints = "$swap = $rd" in {
- def CASXrr: F3_1<3, 0b111110,
+ def CASXrr: F3_1_asi<3, 0b111110, 0b10000000,
(outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2,
I64Regs:$swap),
"casx [$rs1], $rs2, $rd",

View File

@ -0,0 +1,33 @@
Pull in r200965 from upstream llvm trunk (by Venkatraman Govindaraju):
[Sparc] Add support for parsing synthetic instruction 'mov'.
Introduced here: http://svn.freebsd.org/changeset/base/262261
Index: lib/Target/Sparc/SparcInstrAliases.td
===================================================================
--- lib/Target/Sparc/SparcInstrAliases.td
+++ lib/Target/Sparc/SparcInstrAliases.td
@@ -134,3 +134,9 @@ def : InstAlias<"retl", (RETL 8)>;
// ret -> RET 8
def : InstAlias<"ret", (RET 8)>;
+
+// mov reg, rd -> or %g0, reg, rd
+def : InstAlias<"mov $rs2, $rd", (ORrr IntRegs:$rd, G0, IntRegs:$rs2)>;
+
+// mov simm13, rd -> or %g0, simm13, rd
+def : InstAlias<"mov $simm13, $rd", (ORri IntRegs:$rd, G0, i32imm:$simm13)>;
Index: test/MC/Sparc/sparc-alu-instructions.s
===================================================================
--- test/MC/Sparc/sparc-alu-instructions.s
+++ test/MC/Sparc/sparc-alu-instructions.s
@@ -70,3 +70,8 @@
! CHECK: subxcc %g1, %g2, %g3 ! encoding: [0x86,0xe0,0x40,0x02]
subxcc %g1, %g2, %g3
+ ! CHECK: or %g0, %g1, %g3 ! encoding: [0x86,0x10,0x00,0x01]
+ mov %g1, %g3
+
+ ! CHECK: or %g0, 255, %g3 ! encoding: [0x86,0x10,0x20,0xff]
+ mov 0xff, %g3

View File

@ -0,0 +1,31 @@
Pull in r198311 from upstream clang trunk (by Roman Divacky):
In the FreeBSD assembler driver, inform the sparc assembler that we're producing
PIC code.
Introduced here: http://svn.freebsd.org/changeset/base/262262
Index: tools/clang/lib/Driver/Tools.cpp
===================================================================
--- tools/clang/lib/Driver/Tools.cpp
+++ tools/clang/lib/Driver/Tools.cpp
@@ -5785,6 +5785,19 @@ void freebsd::Assemble::ConstructJob(Compilation &
default:
CmdArgs.push_back("-matpcs");
}
+ } else if (getToolChain().getArch() == llvm::Triple::sparc ||
+ getToolChain().getArch() == llvm::Triple::sparcv9) {
+ Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
+ options::OPT_fpic, options::OPT_fno_pic,
+ options::OPT_fPIE, options::OPT_fno_PIE,
+ options::OPT_fpie, options::OPT_fno_pie);
+ if (LastPICArg &&
+ (LastPICArg->getOption().matches(options::OPT_fPIC) ||
+ LastPICArg->getOption().matches(options::OPT_fpic) ||
+ LastPICArg->getOption().matches(options::OPT_fPIE) ||
+ LastPICArg->getOption().matches(options::OPT_fpie))) {
+ CmdArgs.push_back("-KPIC");
+ }
}
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,

View File

@ -0,0 +1,19 @@
Pull in r198312 from upstream clang trunk (by Roman Divacky):
Remove a tab that snuck in.
Introduced here: http://svn.freebsd.org/changeset/base/262262
Index: tools/clang/lib/Driver/Tools.cpp
===================================================================
--- tools/clang/lib/Driver/Tools.cpp
+++ tools/clang/lib/Driver/Tools.cpp
@@ -5786,7 +5786,7 @@ void freebsd::Assemble::ConstructJob(Compilation &
CmdArgs.push_back("-matpcs");
}
} else if (getToolChain().getArch() == llvm::Triple::sparc ||
- getToolChain().getArch() == llvm::Triple::sparcv9) {
+ getToolChain().getArch() == llvm::Triple::sparcv9) {
Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
options::OPT_fpic, options::OPT_fno_pic,
options::OPT_fPIE, options::OPT_fno_PIE,

View File

@ -0,0 +1,46 @@
Pull in r198911 from upstream clang trunk (by Jakob Stoklund Olesen):
Pass -32/-64 to the assembler when building for sparc/sparc64.
Introduced here: http://svn.freebsd.org/changeset/base/262262
Index: tools/clang/test/Driver/linux-as.c
===================================================================
--- tools/clang/test/Driver/linux-as.c
+++ tools/clang/test/Driver/linux-as.c
@@ -60,6 +60,20 @@
// RUN: | FileCheck -check-prefix=CHECK-PPC-NO-MCPU %s
// CHECK-PPC-NO-MCPU-NOT: as{{.*}} "-mcpu=invalid-cpu"
//
+// RUN: %clang -target sparc64-linux -mcpu=invalid-cpu -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-SPARCV9 %s
+// CHECK-SPARCV9: as
+// CHECK-SPARCV9: -64
+// CHECK-SPARCV9: -o
+//
+// RUN: %clang -target sparc-linux -mcpu=invalid-cpu -### \
+// RUN: -no-integrated-as -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-SPARCV8 %s
+// CHECK-SPARCV8: as
+// CHECK-SPARCV8: -32
+// CHECK-SPARCV8: -o
+//
// RUN: %clang -target s390x-linux -### -no-integrated-as -c %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-Z-DEFAULT-ARCH %s
// CHECK-Z-DEFAULT-ARCH: as{{.*}} "-march=z10"
Index: tools/clang/lib/Driver/Tools.cpp
===================================================================
--- tools/clang/lib/Driver/Tools.cpp
+++ tools/clang/lib/Driver/Tools.cpp
@@ -6226,6 +6226,10 @@ void gnutools::Assemble::ConstructJob(Compilation
CmdArgs.push_back("-a64");
CmdArgs.push_back("-mppc64le");
CmdArgs.push_back("-many");
+ } else if (getToolChain().getArch() == llvm::Triple::sparc) {
+ CmdArgs.push_back("-32");
+ } else if (getToolChain().getArch() == llvm::Triple::sparcv9) {
+ CmdArgs.push_back("-64");
} else if (getToolChain().getArch() == llvm::Triple::arm) {
StringRef MArch = getToolChain().getArchName();
if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a")

View File

@ -0,0 +1,44 @@
Pull in r198912 from upstream clang trunk (by Jakob Stoklund Olesen):
Give the linker the right ELF type for SPARC targets.
Introduced here: http://svn.freebsd.org/changeset/base/262262
Index: tools/clang/lib/Driver/Tools.cpp
===================================================================
--- tools/clang/lib/Driver/Tools.cpp
+++ tools/clang/lib/Driver/Tools.cpp
@@ -6461,6 +6461,10 @@ void gnutools::Link::ConstructJob(Compilation &C,
CmdArgs.push_back("elf32ppclinux");
else if (ToolChain.getArch() == llvm::Triple::ppc64)
CmdArgs.push_back("elf64ppc");
+ else if (ToolChain.getArch() == llvm::Triple::sparc)
+ CmdArgs.push_back("elf32_sparc");
+ else if (ToolChain.getArch() == llvm::Triple::sparcv9)
+ CmdArgs.push_back("elf64_sparc");
else if (ToolChain.getArch() == llvm::Triple::mips)
CmdArgs.push_back("elf32btsmip");
else if (ToolChain.getArch() == llvm::Triple::mipsel)
Index: tools/clang/test/Driver/linux-ld.c
===================================================================
--- tools/clang/test/Driver/linux-ld.c
+++ tools/clang/test/Driver/linux-ld.c
@@ -384,6 +384,18 @@
// CHECK-MIPS64EL-N32: "-dynamic-linker" "{{.*}}/lib32/ld.so.1"
// CHECK-MIPS64EL-N32-NOT: "--hash-style={{gnu|both}}"
//
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: --target=sparc-linux-gnu \
+// RUN: | FileCheck --check-prefix=CHECK-SPARCV8 %s
+// CHECK-SPARCV8: "{{.*}}ld{{(.exe)?}}"
+// CHECK-SPARCV8: "-m" "elf32_sparc"
+//
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: --target=sparcv9-linux-gnu \
+// RUN: | FileCheck --check-prefix=CHECK-SPARCV9 %s
+// CHECK-SPARCV9: "{{.*}}ld{{(.exe)?}}"
+// CHECK-SPARCV9: "-m" "elf64_sparc"
+//
// Thoroughly exercise the Debian multiarch environment.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=i686-linux-gnu \

View File

@ -0,0 +1,59 @@
Pull in r198918 from upstream clang trunk (by Jakob Stoklund Olesen):
Locate GCC installations on SPARC systems.
Introduced here: http://svn.freebsd.org/changeset/base/262262
Index: tools/clang/lib/Driver/ToolChains.cpp
===================================================================
--- tools/clang/lib/Driver/ToolChains.cpp
+++ tools/clang/lib/Driver/ToolChains.cpp
@@ -1164,6 +1164,13 @@ void Generic_GCC::GCCInstallationDetector::print(r
"powerpc64le-suse-linux",
"ppc64le-redhat-linux" };
+ static const char *const SPARCv8LibDirs[] = { "/lib32", "/lib" };
+ static const char *const SPARCv8Triples[] = { "sparc-linux-gnu",
+ "sparcv8-linux-gnu" };
+ static const char *const SPARCv9LibDirs[] = { "/lib64", "/lib" };
+ static const char *const SPARCv9Triples[] = { "sparc64-linux-gnu",
+ "sparcv9-linux-gnu" };
+
static const char *const SystemZLibDirs[] = { "/lib64", "/lib" };
static const char *const SystemZTriples[] = {
"s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu",
@@ -1283,6 +1290,26 @@ void Generic_GCC::GCCInstallationDetector::print(r
TripleAliases.append(PPC64LETriples,
PPC64LETriples + llvm::array_lengthof(PPC64LETriples));
break;
+ case llvm::Triple::sparc:
+ LibDirs.append(SPARCv8LibDirs,
+ SPARCv8LibDirs + llvm::array_lengthof(SPARCv8LibDirs));
+ TripleAliases.append(SPARCv8Triples,
+ SPARCv8Triples + llvm::array_lengthof(SPARCv8Triples));
+ BiarchLibDirs.append(SPARCv9LibDirs,
+ SPARCv9LibDirs + llvm::array_lengthof(SPARCv9LibDirs));
+ BiarchTripleAliases.append(
+ SPARCv9Triples, SPARCv9Triples + llvm::array_lengthof(SPARCv9Triples));
+ break;
+ case llvm::Triple::sparcv9:
+ LibDirs.append(SPARCv9LibDirs,
+ SPARCv9LibDirs + llvm::array_lengthof(SPARCv9LibDirs));
+ TripleAliases.append(SPARCv9Triples,
+ SPARCv9Triples + llvm::array_lengthof(SPARCv9Triples));
+ BiarchLibDirs.append(SPARCv8LibDirs,
+ SPARCv8LibDirs + llvm::array_lengthof(SPARCv8LibDirs));
+ BiarchTripleAliases.append(
+ SPARCv8Triples, SPARCv8Triples + llvm::array_lengthof(SPARCv8Triples));
+ break;
case llvm::Triple::systemz:
LibDirs.append(SystemZLibDirs,
SystemZLibDirs + llvm::array_lengthof(SystemZLibDirs));
@@ -1379,6 +1406,7 @@ static bool findTargetBiarchSuffix(std::string &Su
Suffix = "/n32";
else if (TargetArch == llvm::Triple::x86_64 ||
TargetArch == llvm::Triple::ppc64 ||
+ TargetArch == llvm::Triple::sparcv9 ||
TargetArch == llvm::Triple::systemz ||
TargetArch == llvm::Triple::mips64 ||
TargetArch == llvm::Triple::mips64el)

View File

@ -0,0 +1,49 @@
Pull in r198923 from upstream clang trunk (by Jakob Stoklund Olesen):
Use the right dynamic linker for SPARC Linux executables.
Introduced here: http://svn.freebsd.org/changeset/base/262262
Index: tools/clang/lib/Driver/Tools.cpp
===================================================================
--- tools/clang/lib/Driver/Tools.cpp
+++ tools/clang/lib/Driver/Tools.cpp
@@ -6374,7 +6374,8 @@ static StringRef getLinuxDynamicLinker(const ArgLi
const toolchains::Linux &ToolChain) {
if (ToolChain.getTriple().getEnvironment() == llvm::Triple::Android)
return "/system/bin/linker";
- else if (ToolChain.getArch() == llvm::Triple::x86)
+ else if (ToolChain.getArch() == llvm::Triple::x86 ||
+ ToolChain.getArch() == llvm::Triple::sparc)
return "/lib/ld-linux.so.2";
else if (ToolChain.getArch() == llvm::Triple::aarch64)
return "/lib/ld-linux-aarch64.so.1";
@@ -6399,6 +6400,8 @@ static StringRef getLinuxDynamicLinker(const ArgLi
ToolChain.getArch() == llvm::Triple::ppc64le ||
ToolChain.getArch() == llvm::Triple::systemz)
return "/lib64/ld64.so.1";
+ else if (ToolChain.getArch() == llvm::Triple::sparcv9)
+ return "/lib64/ld-linux.so.2";
else
return "/lib64/ld-linux-x86-64.so.2";
}
Index: tools/clang/test/Driver/linux-ld.c
===================================================================
--- tools/clang/test/Driver/linux-ld.c
+++ tools/clang/test/Driver/linux-ld.c
@@ -389,6 +389,7 @@
// RUN: | FileCheck --check-prefix=CHECK-SPARCV8 %s
// CHECK-SPARCV8: "{{.*}}ld{{(.exe)?}}"
// CHECK-SPARCV8: "-m" "elf32_sparc"
+// CHECK-SPARCV8: "-dynamic-linker" "/lib/ld-linux.so.2"
//
// RUN: %clang %s -### -o %t.o 2>&1 \
// RUN: --target=sparcv9-linux-gnu \
@@ -395,6 +396,7 @@
// RUN: | FileCheck --check-prefix=CHECK-SPARCV9 %s
// CHECK-SPARCV9: "{{.*}}ld{{(.exe)?}}"
// CHECK-SPARCV9: "-m" "elf64_sparc"
+// CHECK-SPARCV9: "-dynamic-linker" "/lib64/ld-linux.so.2"
//
// Thoroughly exercise the Debian multiarch environment.
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \

View File

@ -0,0 +1,41 @@
Pull in r199012 from upstream clang trunk (by Jakob Stoklund Olesen):
Select the UltraSPARC instruction set when invoking the assembler.
Introduced here: http://svn.freebsd.org/changeset/base/262262
Index: tools/clang/lib/Driver/Tools.cpp
===================================================================
--- tools/clang/lib/Driver/Tools.cpp
+++ tools/clang/lib/Driver/Tools.cpp
@@ -6228,8 +6228,10 @@ void gnutools::Assemble::ConstructJob(Compilation
CmdArgs.push_back("-many");
} else if (getToolChain().getArch() == llvm::Triple::sparc) {
CmdArgs.push_back("-32");
+ CmdArgs.push_back("-Av8plusa");
} else if (getToolChain().getArch() == llvm::Triple::sparcv9) {
CmdArgs.push_back("-64");
+ CmdArgs.push_back("-Av9a");
} else if (getToolChain().getArch() == llvm::Triple::arm) {
StringRef MArch = getToolChain().getArchName();
if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a")
Index: tools/clang/test/Driver/linux-as.c
===================================================================
--- tools/clang/test/Driver/linux-as.c
+++ tools/clang/test/Driver/linux-as.c
@@ -65,6 +65,7 @@
// RUN: | FileCheck -check-prefix=CHECK-SPARCV9 %s
// CHECK-SPARCV9: as
// CHECK-SPARCV9: -64
+// CHECK-SPARCV9: -Av9a
// CHECK-SPARCV9: -o
//
// RUN: %clang -target sparc-linux -mcpu=invalid-cpu -### \
@@ -72,6 +73,7 @@
// RUN: | FileCheck -check-prefix=CHECK-SPARCV8 %s
// CHECK-SPARCV8: as
// CHECK-SPARCV8: -32
+// CHECK-SPARCV8: -Av8plusa
// CHECK-SPARCV8: -o
//
// RUN: %clang -target s390x-linux -### -no-integrated-as -c %s 2>&1 \

View File

@ -0,0 +1,81 @@
Pull in r199034 from upstream clang trunk (by Jakob Stoklund Olesen):
MIPS and SPARC assemblers both take the -KPIC flag.
Introduced here: http://svn.freebsd.org/changeset/base/262262
Index: tools/clang/lib/Driver/Tools.cpp
===================================================================
--- tools/clang/lib/Driver/Tools.cpp
+++ tools/clang/lib/Driver/Tools.cpp
@@ -6207,6 +6207,7 @@ void gnutools::Assemble::ConstructJob(Compilation
const ArgList &Args,
const char *LinkingOutput) const {
ArgStringList CmdArgs;
+ bool NeedsKPIC = false;
// Add --32/--64 to make sure we get the format we want.
// This is incomplete
@@ -6229,9 +6230,11 @@ void gnutools::Assemble::ConstructJob(Compilation
} else if (getToolChain().getArch() == llvm::Triple::sparc) {
CmdArgs.push_back("-32");
CmdArgs.push_back("-Av8plusa");
+ NeedsKPIC = true;
} else if (getToolChain().getArch() == llvm::Triple::sparcv9) {
CmdArgs.push_back("-64");
CmdArgs.push_back("-Av9a");
+ NeedsKPIC = true;
} else if (getToolChain().getArch() == llvm::Triple::arm) {
StringRef MArch = getToolChain().getArchName();
if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a")
@@ -6291,6 +6294,15 @@ void gnutools::Assemble::ConstructJob(Compilation
CmdArgs.push_back(Args.MakeArgString("-mmsa"));
}
+ NeedsKPIC = true;
+ } else if (getToolChain().getArch() == llvm::Triple::systemz) {
+ // Always pass an -march option, since our default of z10 is later
+ // than the GNU assembler's default.
+ StringRef CPUName = getSystemZTargetCPU(Args);
+ CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName));
+ }
+
+ if (NeedsKPIC) {
Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
options::OPT_fpic, options::OPT_fno_pic,
options::OPT_fPIE, options::OPT_fno_PIE,
@@ -6302,11 +6314,6 @@ void gnutools::Assemble::ConstructJob(Compilation
LastPICArg->getOption().matches(options::OPT_fpie))) {
CmdArgs.push_back("-KPIC");
}
- } else if (getToolChain().getArch() == llvm::Triple::systemz) {
- // Always pass an -march option, since our default of z10 is later
- // than the GNU assembler's default.
- StringRef CPUName = getSystemZTargetCPU(Args);
- CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName));
}
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
Index: tools/clang/test/Driver/linux-as.c
===================================================================
--- tools/clang/test/Driver/linux-as.c
+++ tools/clang/test/Driver/linux-as.c
@@ -66,8 +66,18 @@
// CHECK-SPARCV9: as
// CHECK-SPARCV9: -64
// CHECK-SPARCV9: -Av9a
+// CHECK-SPARCV9-NOT: -KPIC
// CHECK-SPARCV9: -o
//
+// RUN: %clang -target sparc64-linux -mcpu=invalid-cpu -### \
+// RUN: -no-integrated-as -fpic -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK-SPARCV9PIC %s
+// CHECK-SPARCV9PIC: as
+// CHECK-SPARCV9PIC: -64
+// CHECK-SPARCV9PIC: -Av9a
+// CHECK-SPARCV9PIC: -KPIC
+// CHECK-SPARCV9PIC: -o
+//
// RUN: %clang -target sparc-linux -mcpu=invalid-cpu -### \
// RUN: -no-integrated-as -c %s 2>&1 \
// RUN: | FileCheck -check-prefix=CHECK-SPARCV8 %s

View File

@ -0,0 +1,53 @@
Pull in r199037 from upstream clang trunk (by Jakob Stokund Olesen):
SPARC passes non-trivial C++ objects indirectly like everybody else.
Introduced here: http://svn.freebsd.org/changeset/base/262262
Index: tools/clang/lib/CodeGen/TargetInfo.cpp
===================================================================
--- tools/clang/lib/CodeGen/TargetInfo.cpp
+++ tools/clang/lib/CodeGen/TargetInfo.cpp
@@ -5349,6 +5349,11 @@ SparcV9ABIInfo::classifyType(QualType Ty, unsigned
if (!isAggregateTypeForABI(Ty))
return ABIArgInfo::getDirect();
+ // If a C++ object has either a non-trivial copy constructor or a non-trivial
+ // destructor, it is passed with an explicit indirect pointer / sret pointer.
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
+ return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
+
// This is a small aggregate type that should be passed in registers.
// Build a coercion type from the LLVM struct type.
llvm::StructType *StrTy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty));
Index: tools/clang/test/CodeGenCXX/sparcv9-abi.cpp
===================================================================
--- tools/clang/test/CodeGenCXX/sparcv9-abi.cpp
+++ tools/clang/test/CodeGenCXX/sparcv9-abi.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple sparcv9-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+
+struct pod {
+ int a, b;
+};
+
+void f0();
+void f1(struct pod);
+
+struct notpod {
+ int a, b;
+ ~notpod() { f0(); }
+};
+
+void f2(struct notpod);
+
+// CHECK-LABEL: caller
+// CHECK: call void @_Z2f13pod(i64
+// CHECK: call void @_Z2f26notpod(%struct.notpod*
+void caller()
+{
+ pod p1;
+ notpod p2;
+ f1(p1);
+ f2(p2);
+}

View File

@ -0,0 +1,35 @@
Pull in r199188 from upstream clang trunk (by Jakob Stoklund Olesen):
Puny 24-byte structs are returned by value on SPARC.
Pad these structs up so they are sret-returned even on that
architecture.
Introduced here: http://svn.freebsd.org/changeset/base/262262
Index: tools/clang/test/CodeGen/sret.c
===================================================================
--- tools/clang/test/CodeGen/sret.c
+++ tools/clang/test/CodeGen/sret.c
@@ -4,6 +4,8 @@ struct abc {
long a;
long b;
long c;
+ long d;
+ long e;
};
struct abc foo1(void);
Index: tools/clang/test/CodeGen/sret2.c
===================================================================
--- tools/clang/test/CodeGen/sret2.c
+++ tools/clang/test/CodeGen/sret2.c
@@ -4,6 +4,8 @@ struct abc {
long a;
long b;
long c;
+ long d;
+ long e;
};
struct abc foo2(){}

View File

@ -0,0 +1,37 @@
Pull in r199399 from upstream clang trunk (by Jakob Stoklund Olesen):
SPARCv9 implements long double as an IEEE quad.
Introduced here: http://svn.freebsd.org/changeset/base/262262
Index: tools/clang/test/CodeGen/sparcv9-abi.c
===================================================================
--- tools/clang/test/CodeGen/sparcv9-abi.c
+++ tools/clang/test/CodeGen/sparcv9-abi.c
@@ -18,6 +18,9 @@ long long f_int_3(long long x) { return x; }
// CHECK-LABEL: define signext i8 @f_int_4(i8 signext %x)
char f_int_4(char x) { return x; }
+// CHECK-LABEL: define fp128 @f_ld(fp128 %x)
+long double f_ld(long double x) { return x; }
+
// Small structs are passed in registers.
struct small {
int *a, *b;
Index: tools/clang/lib/Basic/Targets.cpp
===================================================================
--- tools/clang/lib/Basic/Targets.cpp
+++ tools/clang/lib/Basic/Targets.cpp
@@ -4529,6 +4529,12 @@ class SparcV9TargetInfo : public SparcTargetInfo {
UIntMaxType = UnsignedLong;
}
Int64Type = IntMaxType;
+
+ // The SPARCv8 System V ABI has long double 128-bits in size, but 64-bit
+ // aligned. The SPARCv9 SCD 2.4.1 says 16-byte aligned.
+ LongDoubleWidth = 128;
+ LongDoubleAlign = 128;
+ LongDoubleFormat = &llvm::APFloat::IEEEquad;
}
virtual void getTargetDefines(const LangOptions &Opts,

View File

@ -0,0 +1,20 @@
Pull in r200452 from upstream clang trunk (by Jakob Stoklund Olesen):
SPARCv9 supports atomic operations up to 64 bits.
Patch by Roman Divacky!
Introduced here: http://svn.freebsd.org/changeset/base/262262
Index: tools/clang/lib/Basic/Targets.cpp
===================================================================
--- tools/clang/lib/Basic/Targets.cpp
+++ tools/clang/lib/Basic/Targets.cpp
@@ -4535,6 +4535,7 @@ class SparcV9TargetInfo : public SparcTargetInfo {
LongDoubleWidth = 128;
LongDoubleAlign = 128;
LongDoubleFormat = &llvm::APFloat::IEEEquad;
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
}
virtual void getTargetDefines(const LangOptions &Opts,

View File

@ -0,0 +1,91 @@
Pull in r200453 from upstream llvm trunk (by Jakob Stoklund Olesen):
Implement SPARCv9 atomic_swap_64 with a pseudo.
The SWAP instruction only exists in a 32-bit variant, but the 64-bit
atomic swap can be implemented in terms of CASX, like the other atomic
rmw primitives.
Introduced here: http://svn.freebsd.org/changeset/base/262264
Index: lib/Target/Sparc/SparcInstr64Bit.td
===================================================================
--- lib/Target/Sparc/SparcInstr64Bit.td
+++ lib/Target/Sparc/SparcInstr64Bit.td
@@ -463,6 +463,14 @@ defm ATOMIC_LOAD_MAX : AtomicRMW<atomic_load_max_
defm ATOMIC_LOAD_UMIN : AtomicRMW<atomic_load_umin_32, atomic_load_umin_64>;
defm ATOMIC_LOAD_UMAX : AtomicRMW<atomic_load_umax_32, atomic_load_umax_64>;
+// There is no 64-bit variant of SWAP, so use a pseudo.
+let usesCustomInserter = 1, hasCtrlDep = 1, mayLoad = 1, mayStore = 1,
+ Defs = [ICC], Predicates = [Is64Bit] in
+def ATOMIC_SWAP_64 : Pseudo<(outs I64Regs:$rd),
+ (ins ptr_rc:$addr, I64Regs:$rs2), "",
+ [(set i64:$rd,
+ (atomic_swap_64 iPTR:$addr, i64:$rs2))]>;
+
// Global addresses, constant pool entries
let Predicates = [Is64Bit] in {
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -1498,7 +1498,7 @@ SparcTargetLowering::SparcTargetLowering(TargetMac
if (Subtarget->is64Bit()) {
setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i64, Legal);
- setOperationAction(ISD::ATOMIC_SWAP, MVT::i64, Expand);
+ setOperationAction(ISD::ATOMIC_SWAP, MVT::i64, Legal);
setOperationAction(ISD::ATOMIC_LOAD, MVT::i64, Custom);
setOperationAction(ISD::ATOMIC_STORE, MVT::i64, Custom);
}
@@ -2885,6 +2885,9 @@ SparcTargetLowering::EmitInstrWithCustomInserter(M
case SP::ATOMIC_LOAD_NAND_64:
return expandAtomicRMW(MI, BB, SP::ANDXrr);
+ case SP::ATOMIC_SWAP_64:
+ return expandAtomicRMW(MI, BB, 0);
+
case SP::ATOMIC_LOAD_MAX_32:
return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_G);
case SP::ATOMIC_LOAD_MAX_64:
@@ -3023,7 +3026,8 @@ SparcTargetLowering::expandAtomicRMW(MachineInstr
// Build the loop block.
unsigned ValReg = MRI.createVirtualRegister(ValueRC);
- unsigned UpdReg = MRI.createVirtualRegister(ValueRC);
+ // Opcode == 0 means try to write Rs2Reg directly (ATOMIC_SWAP).
+ unsigned UpdReg = (Opcode ? MRI.createVirtualRegister(ValueRC) : Rs2Reg);
BuildMI(LoopMBB, DL, TII.get(SP::PHI), ValReg)
.addReg(Val0Reg).addMBB(MBB)
@@ -3035,7 +3039,7 @@ SparcTargetLowering::expandAtomicRMW(MachineInstr
BuildMI(LoopMBB, DL, TII.get(SP::CMPrr)).addReg(ValReg).addReg(Rs2Reg);
BuildMI(LoopMBB, DL, TII.get(Opcode), UpdReg)
.addReg(ValReg).addReg(Rs2Reg).addImm(CondCode);
- } else {
+ } else if (Opcode) {
BuildMI(LoopMBB, DL, TII.get(Opcode), UpdReg)
.addReg(ValReg).addReg(Rs2Reg);
}
Index: test/CodeGen/SPARC/atomics.ll
===================================================================
--- test/CodeGen/SPARC/atomics.ll
+++ test/CodeGen/SPARC/atomics.ll
@@ -62,6 +62,15 @@ entry:
ret i32 %b
}
+; CHECK-LABEL: test_swap_i64
+; CHECK: casx [%o1],
+
+define i64 @test_swap_i64(i64 %a, i64* %ptr) {
+entry:
+ %b = atomicrmw xchg i64* %ptr, i64 42 monotonic
+ ret i64 %b
+}
+
; CHECK-LABEL: test_load_add_32
; CHECK: membar
; CHECK: add [[V:%[gilo][0-7]]], %o1, [[U:%[gilo][0-7]]]

View File

@ -0,0 +1,40 @@
Pull in r201718 from upstream llvm trunk (by Roman Divacky):
Expand 64bit {SHL,SHR,SRA}_PARTS on sparcv9.
Introduced here: http://svn.freebsd.org/changeset/base/262265
Index: test/CodeGen/SPARC/parts.ll
===================================================================
--- test/CodeGen/SPARC/parts.ll
+++ test/CodeGen/SPARC/parts.ll
@@ -0,0 +1,14 @@
+; RUN: llc < %s -march=sparcv9 | FileCheck %s
+
+; CHECK-LABEL: test
+; CHECK: srl %i1, 0, %o2
+; CHECK-NEXT: or %g0, %i2, %o0
+; CHECK-NEXT: call __ashlti3
+; CHECK-NEXT: or %g0, %i3, %o1
+; CHECK-NEXT: or %g0, %o0, %i0
+
+define i128 @test(i128 %a, i128 %b) {
+entry:
+ %tmp = shl i128 %b, %a
+ ret i128 %tmp
+}
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -1554,6 +1554,10 @@ SparcTargetLowering::SparcTargetLowering(TargetMac
setOperationAction(ISD::UMULO, MVT::i64, Custom);
setOperationAction(ISD::SMULO, MVT::i64, Custom);
+
+ setOperationAction(ISD::SHL_PARTS, MVT::i64, Expand);
+ setOperationAction(ISD::SRA_PARTS, MVT::i64, Expand);
+ setOperationAction(ISD::SRL_PARTS, MVT::i64, Expand);
}
// VASTART needs to be custom lowered to use the VarArgsFrameIndex.

View File

@ -0,0 +1,25 @@
Pull in r197521 from upstream clang trunk (by Roman Divacky):
Use the integrated assembler by default on FreeBSD/ppc and ppc64.
Introduced here: http://svn.freebsd.org/changeset/base/262303
Index: tools/clang/lib/Driver/ToolChains.h
===================================================================
--- tools/clang/lib/Driver/ToolChains.h
+++ tools/clang/lib/Driver/ToolChains.h
@@ -512,8 +512,13 @@ class LLVM_LIBRARY_VISIBILITY FreeBSD : public Gen
virtual void
AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const;
+ virtual bool IsIntegratedAssemblerDefault() const {
+ if (getTriple().getArch() == llvm::Triple::ppc ||
+ getTriple().getArch() == llvm::Triple::ppc64)
+ return true;
+ return Generic_ELF::IsIntegratedAssemblerDefault();
+ }
-
virtual bool UseSjLjExceptions() const;
protected:
virtual Tool *buildAssembler() const;

View File

@ -0,0 +1,49 @@
Pull in r201994 from upstream llvm trunk (by Benjamin Kramer):
SPARC: Implement TRAP lowering. Matches what GCC emits.
Introduced here: http://svn.freebsd.org/changeset/base/262415
Index: lib/Target/Sparc/SparcInstrInfo.td
===================================================================
--- lib/Target/Sparc/SparcInstrInfo.td
+++ lib/Target/Sparc/SparcInstrInfo.td
@@ -312,6 +312,9 @@ let hasSideEffects = 1, mayStore = 1 in {
[(flushw)]>;
}
+let isBarrier = 1, isTerminator = 1, rd = 0b1000, rs1 = 0, simm13 = 5 in
+ def TA5 : F3_2<0b10, 0b111010, (outs), (ins), "ta 5", [(trap)]>;
+
let rd = 0 in
def UNIMP : F2_1<0b000, (outs), (ins i32imm:$val),
"unimp $val", []>;
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -1565,6 +1565,8 @@ SparcTargetLowering::SparcTargetLowering(TargetMac
// VAARG needs to be lowered to not do unaligned accesses for doubles.
setOperationAction(ISD::VAARG , MVT::Other, Custom);
+ setOperationAction(ISD::TRAP , MVT::Other, Legal);
+
// Use the default implementation.
setOperationAction(ISD::VACOPY , MVT::Other, Expand);
setOperationAction(ISD::VAEND , MVT::Other, Expand);
Index: test/CodeGen/SPARC/trap.ll
===================================================================
--- test/CodeGen/SPARC/trap.ll
+++ test/CodeGen/SPARC/trap.ll
@@ -0,0 +1,11 @@
+; RUN: llc -mtriple=sparc-linux-gnu < %s -show-mc-encoding | FileCheck %s
+
+define void @test1() {
+ tail call void @llvm.trap()
+ unreachable
+
+; CHECK-LABEL: test1:
+; CHECK: ta 5 ! encoding: [0x91,0xd0,0x20,0x05]
+}
+
+declare void @llvm.trap()

View File

@ -0,0 +1,62 @@
Pull in r202059 from upstream clang trunk (by Roman Divacky):
Implement getDwarfEHStackPointer() and initDwarfEHRegSizeTable() for sparcv9.
Introduced here: http://svn.freebsd.org/changeset/base/262460
Index: tools/clang/lib/CodeGen/TargetInfo.cpp
===================================================================
--- tools/clang/lib/CodeGen/TargetInfo.cpp
+++ tools/clang/lib/CodeGen/TargetInfo.cpp
@@ -5435,10 +5435,51 @@ class SparcV9TargetCodeGenInfo : public TargetCode
public:
SparcV9TargetCodeGenInfo(CodeGenTypes &CGT)
: TargetCodeGenInfo(new SparcV9ABIInfo(CGT)) {}
+
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
+ return 14;
+ }
+
+ bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const;
};
} // end anonymous namespace
+bool
+SparcV9TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const {
+ // This is calculated from the LLVM and GCC tables and verified
+ // against gcc output. AFAIK all ABIs use the same encoding.
+ CodeGen::CGBuilderTy &Builder = CGF.Builder;
+
+ llvm::IntegerType *i8 = CGF.Int8Ty;
+ llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
+ llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8);
+
+ // 0-31: the 8-byte general-purpose registers
+ AssignToArrayRange(Builder, Address, Eight8, 0, 31);
+
+ // 32-63: f0-31, the 4-byte floating-point registers
+ AssignToArrayRange(Builder, Address, Four8, 32, 63);
+
+ // Y = 64
+ // PSR = 65
+ // WIM = 66
+ // TBR = 67
+ // PC = 68
+ // NPC = 69
+ // FSR = 70
+ // CSR = 71
+ AssignToArrayRange(Builder, Address, Eight8, 64, 71);
+
+ // 72-87: d0-15, the 8-byte floating-point registers
+ AssignToArrayRange(Builder, Address, Eight8, 72, 87);
+
+ return false;
+}
+
+
//===----------------------------------------------------------------------===//
// Xcore ABI Implementation
//===----------------------------------------------------------------------===//

View File

@ -0,0 +1,84 @@
Pull in r202177 from upstream clang trunk (by Roman Divacky):
Give sparcv9 the ability to set the target cpu. Change it from accepting
-march which doesnt exist on sparc gcc to -mcpu. While here adjust a
few tests to not write an unused temporary file.
Introduced here: http://svn.freebsd.org/changeset/base/262535
Index: tools/clang/lib/Basic/Targets.cpp
===================================================================
--- tools/clang/lib/Basic/Targets.cpp
+++ tools/clang/lib/Basic/Targets.cpp
@@ -4552,6 +4552,22 @@ class SparcV9TargetInfo : public SparcTargetInfo {
Builder.defineMacro("__sparcv9__");
}
}
+
+ virtual bool setCPU(const std::string &Name) {
+ bool CPUKnown = llvm::StringSwitch<bool>(Name)
+ .Case("v9", true)
+ .Case("ultrasparc", true)
+ .Case("ultrasparc3", true)
+ .Case("niagara", true)
+ .Case("niagara2", true)
+ .Case("niagara3", true)
+ .Case("niagara4", true)
+ .Default(false);
+
+ // No need to store the CPU yet. There aren't any CPU-specific
+ // macros to define.
+ return CPUKnown;
+ }
};
} // end anonymous namespace.
Index: tools/clang/lib/Driver/Tools.cpp
===================================================================
--- tools/clang/lib/Driver/Tools.cpp
+++ tools/clang/lib/Driver/Tools.cpp
@@ -1373,7 +1373,8 @@ static std::string getCPUName(const ArgList &Args,
}
case llvm::Triple::sparc:
- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
+ case llvm::Triple::sparcv9:
+ if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
return A->getValue();
return "";
Index: tools/clang/test/Driver/freebsd.c
===================================================================
--- tools/clang/test/Driver/freebsd.c
+++ tools/clang/test/Driver/freebsd.c
@@ -59,13 +59,13 @@
// CHECK-MIPSEL: "{{[^" ]*}}ld{{[^" ]*}}"
// CHECK-MIPSEL: "-dynamic-linker" "{{.*}}/libexec/ld-elf.so.1"
// CHECK-MIPSEL-NOT: "--hash-style={{gnu|both}}"
-// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: %clang %s -### 2>&1 \
// RUN: -target mips64-unknown-freebsd10.0 \
// RUN: | FileCheck --check-prefix=CHECK-MIPS64 %s
// CHECK-MIPS64: "{{[^" ]*}}ld{{[^" ]*}}"
// CHECK-MIPS64: "-dynamic-linker" "{{.*}}/libexec/ld-elf.so.1"
// CHECK-MIPS64-NOT: "--hash-style={{gnu|both}}"
-// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN: %clang %s -### 2>&1 \
// RUN: -target mips64el-unknown-freebsd10.0 \
// RUN: | FileCheck --check-prefix=CHECK-MIPS64EL %s
// CHECK-MIPS64EL: "{{[^" ]*}}ld{{[^" ]*}}"
@@ -97,12 +97,12 @@
// CHECK-NORMAL: crt1.o
// CHECK-NORMAL: crtbegin.o
-// RUN: %clang %s -### -o %t.o -target arm-unknown-freebsd10.0 2>&1 \
+// RUN: %clang %s -### -target arm-unknown-freebsd10.0 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-ARM %s
// CHECK-ARM: clang{{.*}}" "-cc1"{{.*}}" "-fsjlj-exceptions"
// CHECK-ARM: as{{.*}}" "-mfpu=softvfp"{{.*}}"-matpcs"
-// RUN: %clang %s -### -o %t.o -target arm-gnueabi-freebsd10.0 2>&1 \
+// RUN: %clang %s -### -target arm-gnueabi-freebsd10.0 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-ARM-EABI %s
// CHECK-ARM-EABI-NOT: clang{{.*}}" "-cc1"{{.*}}" "-fsjlj-exceptions"
// CHECK-ARM-EABI: as{{.*}}" "-mfpu=softvfp" "-meabi=5"

View File

@ -0,0 +1,22 @@
Pull in r202179 from upstream clang trunk (by Roman Divacky):
Pass the sparc architecture variant to the assembler.
Introduced here: http://svn.freebsd.org/changeset/base/262536
Index: tools/clang/lib/Driver/Tools.cpp
===================================================================
--- tools/clang/lib/Driver/Tools.cpp
+++ tools/clang/lib/Driver/Tools.cpp
@@ -5788,6 +5788,11 @@ void freebsd::Assemble::ConstructJob(Compilation &
}
} else if (getToolChain().getArch() == llvm::Triple::sparc ||
getToolChain().getArch() == llvm::Triple::sparcv9) {
+ if (getToolChain().getArch() == llvm::Triple::sparc)
+ CmdArgs.push_back("-Av8plusa");
+ else
+ CmdArgs.push_back("-Av9a");
+
Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
options::OPT_fpic, options::OPT_fno_pic,
options::OPT_fPIE, options::OPT_fno_PIE,

View File

@ -0,0 +1,89 @@
Pull in r202422 from upstream llvm trunk (by Roman Divacky):
Lower FNEG just like FABS to fneg[ds] and fmov[ds], thus avoiding
expensive libcall. Also, Qp_neg is not implemented on at least
FreeBSD. This is also what gcc is doing.
Introduced here: http://svn.freebsd.org/changeset/base/262582
Index: lib/Target/Sparc/SparcISelLowering.cpp
===================================================================
--- lib/Target/Sparc/SparcISelLowering.cpp
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -2643,24 +2643,16 @@ static SDValue LowerF128Store(SDValue Op, Selectio
&OutChains[0], 2);
}
-static SDValue LowerFNEG(SDValue Op, SelectionDAG &DAG,
- const SparcTargetLowering &TLI,
- bool is64Bit) {
- if (Op.getValueType() == MVT::f64)
- return LowerF64Op(Op, DAG, ISD::FNEG);
- if (Op.getValueType() == MVT::f128)
- return TLI.LowerF128Op(Op, DAG, ((is64Bit) ? "_Qp_neg" : "_Q_neg"), 1);
- return Op;
-}
+static SDValue LowerFNEGorFABS(SDValue Op, SelectionDAG &DAG, bool isV9) {
+ assert((Op.getOpcode() == ISD::FNEG || Op.getOpcode() == ISD::FABS) && "invalid");
-static SDValue LowerFABS(SDValue Op, SelectionDAG &DAG, bool isV9) {
if (Op.getValueType() == MVT::f64)
- return LowerF64Op(Op, DAG, ISD::FABS);
+ return LowerF64Op(Op, DAG, Op.getOpcode());
if (Op.getValueType() != MVT::f128)
return Op;
- // Lower fabs on f128 to fabs on f64
- // fabs f128 => fabs f64:sub_even64, fmov f64:sub_odd64
+ // Lower fabs/fneg on f128 to fabs/fneg on f64
+ // fabs/fneg f128 => fabs/fneg f64:sub_even64, fmov f64:sub_odd64
SDLoc dl(Op);
SDValue SrcReg128 = Op.getOperand(0);
@@ -2671,7 +2663,7 @@ static SDValue LowerF128Store(SDValue Op, Selectio
if (isV9)
Hi64 = DAG.getNode(Op.getOpcode(), dl, MVT::f64, Hi64);
else
- Hi64 = LowerF64Op(Hi64, DAG, ISD::FABS);
+ Hi64 = LowerF64Op(Hi64, DAG, Op.getOpcode());
SDValue DstReg128 = SDValue(DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF,
dl, MVT::f128), 0);
@@ -2792,7 +2784,6 @@ SDValue SparcTargetLowering::
LowerOperation(SDValue Op, SelectionDAG &DAG) const {
bool hasHardQuad = Subtarget->hasHardQuad();
- bool is64Bit = Subtarget->is64Bit();
bool isV9 = Subtarget->isV9();
switch (Op.getOpcode()) {
@@ -2835,8 +2826,8 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) cons
getLibcallName(RTLIB::DIV_F128), 2);
case ISD::FSQRT: return LowerF128Op(Op, DAG,
getLibcallName(RTLIB::SQRT_F128),1);
- case ISD::FNEG: return LowerFNEG(Op, DAG, *this, is64Bit);
- case ISD::FABS: return LowerFABS(Op, DAG, isV9);
+ case ISD::FABS:
+ case ISD::FNEG: return LowerFNEGorFABS(Op, DAG, isV9);
case ISD::FP_EXTEND: return LowerF128_FPEXTEND(Op, DAG, *this);
case ISD::FP_ROUND: return LowerF128_FPROUND(Op, DAG, *this);
case ISD::ADDC:
Index: test/CodeGen/SPARC/fp128.ll
===================================================================
--- test/CodeGen/SPARC/fp128.ll
+++ test/CodeGen/SPARC/fp128.ll
@@ -232,3 +232,14 @@ entry:
store i32 %3, i32* %4, align 8
ret void
}
+
+; SOFT-LABEL: f128_neg
+; SOFT: fnegs
+
+define void @f128_neg(fp128* noalias sret %scalar.result, fp128* byval %a) {
+entry:
+ %0 = load fp128* %a, align 8
+ %1 = fsub fp128 0xL00000000000000008000000000000000, %0
+ store fp128 %1, fp128* %scalar.result, align 8
+ ret void
+}

View File

@ -0,0 +1,76 @@
Pull in r196874 from upstream llvm trunk (by Andrew Trick):
Fix a crash that occurs when PWD is invalid.
MCJIT needs to be able to run in hostile environments, even when PWD
is invalid. There's no need to crash MCJIT in this case.
The obvious fix is to simply leave MCContext's CompilationDir empty
when PWD can't be determined. This way, MCJIT clients,
and other clients that link with LLVM don?\226?\128?\153t need a valid working directory.
If we do want to guarantee valid CompilationDir, that should be done
only for clients of getCompilationDir(). This is as simple as checking
for an empty string.
The only current use of getCompilationDir is EmitGenDwarfInfo, which
won?\226?\128?\153t conceivably run with an invalid working dir. However, in the
purely hypothetically and untestable case that this happens, the
AT_comp_dir will be omitted from the compilation_unit DIE.
Introduced here: http://svn.freebsd.org/changeset/base/262611
Index: include/llvm/MC/MCContext.h
===================================================================
--- include/llvm/MC/MCContext.h
+++ include/llvm/MC/MCContext.h
@@ -278,6 +278,7 @@ namespace llvm {
/// This can be overridden by clients which want to control the reported
/// compilation directory and have it be something other than the current
/// working directory.
+ /// Returns an empty string if the current directory cannot be determined.
StringRef getCompilationDir() const { return CompilationDir; }
/// \brief Set the compilation directory for DW_AT_comp_dir
Index: lib/MC/MCContext.cpp
===================================================================
--- lib/MC/MCContext.cpp
+++ lib/MC/MCContext.cpp
@@ -47,8 +47,8 @@ MCContext::MCContext(const MCAsmInfo *mai, const M
AllowTemporaryLabels(true), DwarfCompileUnitID(0), AutoReset(DoAutoReset) {
error_code EC = llvm::sys::fs::current_path(CompilationDir);
- assert(!EC && "Could not determine the current directory");
- (void)EC;
+ if (EC)
+ CompilationDir.clear();
MachOUniquingMap = 0;
ELFUniquingMap = 0;
Index: lib/MC/MCDwarf.cpp
===================================================================
--- lib/MC/MCDwarf.cpp
+++ lib/MC/MCDwarf.cpp
@@ -467,7 +467,8 @@ static void EmitGenDwarfAbbrev(MCStreamer *MCOS) {
EmitAbbrev(MCOS, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr);
EmitAbbrev(MCOS, dwarf::DW_AT_high_pc, dwarf::DW_FORM_addr);
EmitAbbrev(MCOS, dwarf::DW_AT_name, dwarf::DW_FORM_string);
- EmitAbbrev(MCOS, dwarf::DW_AT_comp_dir, dwarf::DW_FORM_string);
+ if (!context.getCompilationDir().empty())
+ EmitAbbrev(MCOS, dwarf::DW_AT_comp_dir, dwarf::DW_FORM_string);
StringRef DwarfDebugFlags = context.getDwarfDebugFlags();
if (!DwarfDebugFlags.empty())
EmitAbbrev(MCOS, dwarf::DW_AT_APPLE_flags, dwarf::DW_FORM_string);
@@ -643,8 +644,10 @@ static void EmitGenDwarfInfo(MCStreamer *MCOS,
MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
// AT_comp_dir, the working directory the assembly was done in.
- MCOS->EmitBytes(context.getCompilationDir());
- MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
+ if (!context.getCompilationDir().empty()) {
+ MCOS->EmitBytes(context.getCompilationDir());
+ MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
+ }
// AT_APPLE_flags, the command line arguments of the assembler tool.
StringRef DwarfDebugFlags = context.getDwarfDebugFlags();

View File

@ -0,0 +1,61 @@
Pull in r203007 from upstream clang trunk (by Rafael Espindola):
Don't produce an alias between destructors with different calling conventions.
Fixes pr19007.
Introduced here: http://svn.freebsd.org/changeset/base/262809
Index: tools/clang/lib/CodeGen/CGCXX.cpp
===================================================================
--- tools/clang/lib/CodeGen/CGCXX.cpp
+++ tools/clang/lib/CodeGen/CGCXX.cpp
@@ -92,7 +92,13 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(c
if (!ClassLayout.getBaseClassOffset(UniqueBase).isZero())
return true;
+ // Give up if the calling conventions don't match. We could update the call,
+ // but it is probably not worth it.
const CXXDestructorDecl *BaseD = UniqueBase->getDestructor();
+ if (BaseD->getType()->getAs<FunctionType>()->getCallConv() !=
+ D->getType()->getAs<FunctionType>()->getCallConv())
+ return true;
+
return TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Base),
GlobalDecl(BaseD, Dtor_Base),
false);
Index: tools/clang/test/CodeGenCXX/ctor-dtor-alias.cpp
===================================================================
--- tools/clang/test/CodeGenCXX/ctor-dtor-alias.cpp
+++ tools/clang/test/CodeGenCXX/ctor-dtor-alias.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 %s -triple x86_64-linux -emit-llvm -o - -mconstructor-aliases -O1 -disable-llvm-optzns | FileCheck %s
-// RUN: %clang_cc1 %s -triple x86_64-linux -emit-llvm -o - -mconstructor-aliases | FileCheck --check-prefix=NOOPT %s
+// RUN: %clang_cc1 %s -triple i686-linux -emit-llvm -o - -mconstructor-aliases -O1 -disable-llvm-optzns | FileCheck %s
+// RUN: %clang_cc1 %s -triple i686-linux -emit-llvm -o - -mconstructor-aliases | FileCheck --check-prefix=NOOPT %s
// RUN: %clang_cc1 -cc1 -triple x86_64--netbsd -emit-llvm \
// RUN: -mconstructor-aliases -O2 %s -o - | FileCheck --check-prefix=CHECK-RAUW %s
@@ -133,6 +133,22 @@ namespace test8 {
zed foo;
}
+namespace test9 {
+struct foo {
+ __attribute__((stdcall)) ~foo() {
+ }
+};
+
+struct bar : public foo {};
+
+void zed() {
+ // Test that we produce a call to bar's destructor. We used to call foo's, but
+ // it has a different calling conversion.
+ // CHECK-DAG: call void @_ZN5test93barD2Ev
+ bar ptr;
+}
+}
+
// CHECK-RAUW: @_ZTV1C = linkonce_odr unnamed_addr constant [4 x i8*] [{{[^@]*}}@_ZTI1C {{[^@]*}}@_ZN1CD2Ev {{[^@]*}}@_ZN1CD0Ev {{[^@]*}}]
// r194296 replaced C::~C with B::~B without emitting the later.

View File

@ -0,0 +1,24 @@
Pull in r203624 from upstream clang trunk (by Hans Wennborg):
Be case sensitive when determining driver mode based on argv[0] except on Windows
This narrows the impact of r188833 after Dimitry pointed out that it's good to be
able to tell the difference between 'cc' and 'CC'.
Introduced here: http://svn.freebsd.org/changeset/base/263048
Index: tools/clang/tools/driver/driver.cpp
===================================================================
--- tools/clang/tools/driver/driver.cpp
+++ tools/clang/tools/driver/driver.cpp
@@ -229,8 +229,10 @@ static void ParseProgName(SmallVectorImpl<const ch
{ "++", "--driver-mode=g++" },
};
std::string ProgName(llvm::sys::path::stem(ArgVector[0]));
+#ifdef _WIN32
std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(),
toLowercase);
+#endif
StringRef ProgNameRef(ProgName);
StringRef Prefix;

View File

@ -0,0 +1,338 @@
Pull in r196939 from upstream llvm trunk (by Reid Kleckner):
Reland "Fix miscompile of MS inline assembly with stack realignment"
This re-lands commit r196876, which was reverted in r196879.
The tests have been fixed to pass on platforms with a stack alignment
larger than 4.
Update to clang side tests will land shortly.
Introduced here: http://svn.freebsd.org/changeset/base/263312
Index: test/CodeGen/X86/inline-asm-stack-realign2.ll
===================================================================
--- test/CodeGen/X86/inline-asm-stack-realign2.ll
+++ test/CodeGen/X86/inline-asm-stack-realign2.ll
@@ -0,0 +1,15 @@
+; RUN: not llc -mtriple=i686-pc-win32 < %s 2>&1 | FileCheck %s
+
+; We don't currently support realigning the stack and adjusting the stack
+; pointer in inline asm. This can even happen in GNU asm.
+
+; CHECK: Stack realignment in presence of dynamic stack adjustments is not supported with inline assembly
+
+define i32 @foo() {
+entry:
+ %r = alloca i32, align 16
+ store i32 -1, i32* %r, align 16
+ call void asm sideeffect "push %esi\0A\09xor %esi, %esi\0A\09mov %esi, $0\0A\09pop %esi", "=*m,~{flags},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"(i32* %r)
+ %0 = load i32* %r, align 16
+ ret i32 %0
+}
Index: test/CodeGen/X86/inline-asm-stack-realign.ll
===================================================================
--- test/CodeGen/X86/inline-asm-stack-realign.ll
+++ test/CodeGen/X86/inline-asm-stack-realign.ll
@@ -0,0 +1,16 @@
+; RUN: not llc -mtriple=i686-pc-win32 < %s 2>&1 | FileCheck %s
+
+; We don't currently support realigning the stack and adjusting the stack
+; pointer in inline asm. This commonly happens in MS inline assembly using
+; push and pop.
+
+; CHECK: Stack realignment in presence of dynamic stack adjustments is not supported with inline assembly
+
+define i32 @foo() {
+entry:
+ %r = alloca i32, align 16
+ store i32 -1, i32* %r, align 16
+ call void asm sideeffect inteldialect "push esi\0A\09xor esi, esi\0A\09mov dword ptr $0, esi\0A\09pop esi", "=*m,~{flags},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"(i32* %r)
+ %0 = load i32* %r, align 16
+ ret i32 %0
+}
Index: test/CodeGen/X86/ms-inline-asm.ll
===================================================================
--- test/CodeGen/X86/ms-inline-asm.ll
+++ test/CodeGen/X86/ms-inline-asm.ll
@@ -5,7 +5,6 @@ entry:
%0 = tail call i32 asm sideeffect inteldialect "mov eax, $1\0A\09mov $0, eax", "=r,r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32 1) nounwind
ret i32 %0
; CHECK: t1
-; CHECK: movl %esp, %ebp
; CHECK: {{## InlineAsm Start|#APP}}
; CHECK: .intel_syntax
; CHECK: mov eax, ecx
@@ -19,7 +18,6 @@ entry:
call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"() nounwind
ret void
; CHECK: t2
-; CHECK: movl %esp, %ebp
; CHECK: {{## InlineAsm Start|#APP}}
; CHECK: .intel_syntax
; CHECK: mov eax, 1
@@ -34,7 +32,6 @@ entry:
call void asm sideeffect inteldialect "mov eax, DWORD PTR [$0]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %V.addr) nounwind
ret void
; CHECK: t3
-; CHECK: movl %esp, %ebp
; CHECK: {{## InlineAsm Start|#APP}}
; CHECK: .intel_syntax
; CHECK: mov eax, DWORD PTR {{[[esp]}}
@@ -56,7 +53,6 @@ entry:
%0 = load i32* %b1, align 4
ret i32 %0
; CHECK: t18
-; CHECK: movl %esp, %ebp
; CHECK: {{## InlineAsm Start|#APP}}
; CHECK: .intel_syntax
; CHECK: lea ebx, foo
@@ -76,7 +72,6 @@ entry:
call void asm sideeffect inteldialect "call $0", "r,~{dirflag},~{fpsr},~{flags}"(void ()* @t19_helper) nounwind
ret void
; CHECK-LABEL: t19:
-; CHECK: movl %esp, %ebp
; CHECK: movl ${{_?}}t19_helper, %eax
; CHECK: {{## InlineAsm Start|#APP}}
; CHECK: .intel_syntax
@@ -95,7 +90,6 @@ entry:
%0 = load i32** %res, align 4
ret i32* %0
; CHECK-LABEL: t30:
-; CHECK: movl %esp, %ebp
; CHECK: {{## InlineAsm Start|#APP}}
; CHECK: .intel_syntax
; CHECK: lea edi, dword ptr [{{_?}}results]
@@ -103,8 +97,31 @@ entry:
; CHECK: {{## InlineAsm End|#NO_APP}}
; CHECK: {{## InlineAsm Start|#APP}}
; CHECK: .intel_syntax
-; CHECK: mov dword ptr [esi], edi
+; CHECK: mov dword ptr [esp], edi
; CHECK: .att_syntax
; CHECK: {{## InlineAsm End|#NO_APP}}
-; CHECK: movl (%esi), %eax
+; CHECK: movl (%esp), %eax
}
+
+; Stack realignment plus MS inline asm that does *not* adjust the stack is no
+; longer an error.
+
+define i32 @t31() {
+entry:
+ %val = alloca i32, align 64
+ store i32 -1, i32* %val, align 64
+ call void asm sideeffect inteldialect "mov dword ptr $0, esp", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* %val) #1
+ %sp = load i32* %val, align 64
+ ret i32 %sp
+; CHECK-LABEL: t31:
+; CHECK: pushl %ebp
+; CHECK: movl %esp, %ebp
+; CHECK: andl $-64, %esp
+; CHECK: {{## InlineAsm Start|#APP}}
+; CHECK: .intel_syntax
+; CHECK: mov dword ptr [esp], esp
+; CHECK: .att_syntax
+; CHECK: {{## InlineAsm End|#NO_APP}}
+; CHECK: movl (%esp), %eax
+; CHECK: ret
+}
Index: include/llvm/CodeGen/MachineFrameInfo.h
===================================================================
--- include/llvm/CodeGen/MachineFrameInfo.h
+++ include/llvm/CodeGen/MachineFrameInfo.h
@@ -223,6 +223,10 @@ class MachineFrameInfo {
/// Whether the "realign-stack" option is on.
bool RealignOption;
+ /// True if the function includes inline assembly that adjusts the stack
+ /// pointer.
+ bool HasInlineAsmWithSPAdjust;
+
const TargetFrameLowering *getFrameLowering() const;
public:
explicit MachineFrameInfo(const TargetMachine &TM, bool RealignOpt)
@@ -451,6 +455,10 @@ class MachineFrameInfo {
bool hasCalls() const { return HasCalls; }
void setHasCalls(bool V) { HasCalls = V; }
+ /// Returns true if the function contains any stack-adjusting inline assembly.
+ bool hasInlineAsmWithSPAdjust() const { return HasInlineAsmWithSPAdjust; }
+ void setHasInlineAsmWithSPAdjust(bool B) { HasInlineAsmWithSPAdjust = B; }
+
/// getMaxCallFrameSize - Return the maximum size of a call frame that must be
/// allocated for an outgoing function call. This is only available if
/// CallFrameSetup/Destroy pseudo instructions are used by the target, and
Index: include/llvm/CodeGen/MachineFunction.h
===================================================================
--- include/llvm/CodeGen/MachineFunction.h
+++ include/llvm/CodeGen/MachineFunction.h
@@ -131,8 +131,8 @@ class MachineFunction {
/// about the control flow of such functions.
bool ExposesReturnsTwice;
- /// True if the function includes MS-style inline assembly.
- bool HasMSInlineAsm;
+ /// True if the function includes any inline assembly.
+ bool HasInlineAsm;
MachineFunction(const MachineFunction &) LLVM_DELETED_FUNCTION;
void operator=(const MachineFunction&) LLVM_DELETED_FUNCTION;
@@ -218,15 +218,14 @@ class MachineFunction {
ExposesReturnsTwice = B;
}
- /// Returns true if the function contains any MS-style inline assembly.
- bool hasMSInlineAsm() const {
- return HasMSInlineAsm;
+ /// Returns true if the function contains any inline assembly.
+ bool hasInlineAsm() const {
+ return HasInlineAsm;
}
- /// Set a flag that indicates that the function contains MS-style inline
- /// assembly.
- void setHasMSInlineAsm(bool B) {
- HasMSInlineAsm = B;
+ /// Set a flag that indicates that the function contains inline assembly.
+ void setHasInlineAsm(bool B) {
+ HasInlineAsm = B;
}
/// getInfo - Keep track of various per-function pieces of information for
Index: lib/Target/X86/X86FrameLowering.cpp
===================================================================
--- lib/Target/X86/X86FrameLowering.cpp
+++ lib/Target/X86/X86FrameLowering.cpp
@@ -50,7 +50,7 @@ bool X86FrameLowering::hasFP(const MachineFunction
return (MF.getTarget().Options.DisableFramePointerElim(MF) ||
RegInfo->needsStackRealignment(MF) ||
MFI->hasVarSizedObjects() ||
- MFI->isFrameAddressTaken() || MF.hasMSInlineAsm() ||
+ MFI->isFrameAddressTaken() || MFI->hasInlineAsmWithSPAdjust() ||
MF.getInfo<X86MachineFunctionInfo>()->getForceFramePointer() ||
MMI.callsUnwindInit() || MMI.callsEHReturn());
}
Index: lib/Target/X86/X86RegisterInfo.cpp
===================================================================
--- lib/Target/X86/X86RegisterInfo.cpp
+++ lib/Target/X86/X86RegisterInfo.cpp
@@ -347,6 +347,12 @@ BitVector X86RegisterInfo::getReservedRegs(const M
"Stack realignment in presence of dynamic allocas is not supported with"
"this calling convention.");
+ // FIXME: Do a proper analysis of the inline asm to see if it actually
+ // conflicts with the base register we chose.
+ if (MF.hasInlineAsm())
+ report_fatal_error("Stack realignment in presence of dynamic stack "
+ "adjustments is not supported with inline assembly.");
+
for (MCSubRegIterator I(getBaseRegister(), this, /*IncludeSelf=*/true);
I.isValid(); ++I)
Reserved.set(*I);
@@ -403,18 +409,15 @@ bool X86RegisterInfo::hasBasePointer(const Machine
if (!EnableBasePointer)
return false;
- // When we need stack realignment and there are dynamic allocas, we can't
- // reference off of the stack pointer, so we reserve a base pointer.
- //
- // This is also true if the function contain MS-style inline assembly. We
- // do this because if any stack changes occur in the inline assembly, e.g.,
- // "pusha", then any C local variable or C argument references in the
- // inline assembly will be wrong because the SP is not properly tracked.
- if ((needsStackRealignment(MF) && MFI->hasVarSizedObjects()) ||
- MF.hasMSInlineAsm())
- return true;
-
- return false;
+ // When we need stack realignment, we can't address the stack from the frame
+ // pointer. When we have dynamic allocas or stack-adjusting inline asm, we
+ // can't address variables from the stack pointer. MS inline asm can
+ // reference locals while also adjusting the stack pointer. When we can't
+ // use both the SP and the FP, we need a separate base pointer register.
+ bool CantUseFP = needsStackRealignment(MF);
+ bool CantUseSP =
+ MFI->hasVarSizedObjects() || MFI->hasInlineAsmWithSPAdjust();
+ return CantUseFP && CantUseSP;
}
bool X86RegisterInfo::canRealignStack(const MachineFunction &MF) const {
Index: lib/MC/MCParser/AsmParser.cpp
===================================================================
--- lib/MC/MCParser/AsmParser.cpp
+++ lib/MC/MCParser/AsmParser.cpp
@@ -4192,6 +4192,11 @@ bool AsmParser::parseMSInlineAsm(
AsmStrRewrites.push_back(AsmRewrite(AOK_Input, Start, SymName.size()));
}
}
+
+ // Consider implicit defs to be clobbers. Think of cpuid and push.
+ const uint16_t *ImpDefs = Desc.getImplicitDefs();
+ for (unsigned I = 0, E = Desc.getNumImplicitDefs(); I != E; ++I)
+ ClobberRegs.push_back(ImpDefs[I]);
}
// Set the number of Outputs and Inputs.
Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
===================================================================
--- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -851,12 +851,20 @@ void RegsForValue::AddInlineAsmOperands(unsigned C
SDValue Res = DAG.getTargetConstant(Flag, MVT::i32);
Ops.push_back(Res);
+ unsigned SP = TLI.getStackPointerRegisterToSaveRestore();
for (unsigned Value = 0, Reg = 0, e = ValueVTs.size(); Value != e; ++Value) {
unsigned NumRegs = TLI.getNumRegisters(*DAG.getContext(), ValueVTs[Value]);
MVT RegisterVT = RegVTs[Value];
for (unsigned i = 0; i != NumRegs; ++i) {
assert(Reg < Regs.size() && "Mismatch in # registers expected");
- Ops.push_back(DAG.getRegister(Regs[Reg++], RegisterVT));
+ unsigned TheReg = Regs[Reg++];
+ Ops.push_back(DAG.getRegister(TheReg, RegisterVT));
+
+ // Notice if we clobbered the stack pointer. Yes, inline asm can do this.
+ if (TheReg == SP && Code == InlineAsm::Kind_Clobber) {
+ MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI->setHasInlineAsmWithSPAdjust(true);
+ }
}
}
}
Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
===================================================================
--- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -428,7 +428,9 @@ bool SelectionDAGISel::runOnMachineFunction(Machin
SDB->init(GFI, *AA, LibInfo);
- MF->setHasMSInlineAsm(false);
+ MF->setHasInlineAsm(false);
+ MF->getFrameInfo()->setHasInlineAsmWithSPAdjust(false);
+
SelectAllBasicBlocks(Fn);
// If the first basic block in the function has live ins that need to be
@@ -511,7 +513,7 @@ bool SelectionDAGISel::runOnMachineFunction(Machin
for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); I != E;
++I) {
- if (MFI->hasCalls() && MF->hasMSInlineAsm())
+ if (MFI->hasCalls() && MF->hasInlineAsm())
break;
const MachineBasicBlock *MBB = I;
@@ -522,8 +524,8 @@ bool SelectionDAGISel::runOnMachineFunction(Machin
II->isStackAligningInlineAsm()) {
MFI->setHasCalls(true);
}
- if (II->isMSInlineAsm()) {
- MF->setHasMSInlineAsm(true);
+ if (II->isInlineAsm()) {
+ MF->setHasInlineAsm(true);
}
}
}

View File

@ -0,0 +1,78 @@
Pull in r196940 from upstream clang trunk (by Reid Kleckner):
Update clang MS inline asm tests for r196939
Introduced here: http://svn.freebsd.org/changeset/base/263312
Index: tools/clang/test/CodeGen/ms-inline-asm.cpp
===================================================================
--- tools/clang/test/CodeGen/ms-inline-asm.cpp
+++ tools/clang/test/CodeGen/ms-inline-asm.cpp
@@ -97,7 +97,7 @@ void test5() {
// CHECK: [[Y:%.*]] = alloca i32
int x, y;
__asm push y
- // CHECK: call void asm sideeffect inteldialect "push dword ptr $0", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* [[Y]])
+ // CHECK: call void asm sideeffect inteldialect "push dword ptr $0", "=*m,~{esp},~{dirflag},~{fpsr},~{flags}"(i32* [[Y]])
__asm call T5<int>::create<float>
// CHECK: call void asm sideeffect inteldialect "call $0", "r,~{dirflag},~{fpsr},~{flags}"(i32 (float)* @_ZN2T5IiE6createIfEEiT_)
__asm mov x, eax
Index: tools/clang/test/CodeGen/ms-inline-asm.c
===================================================================
--- tools/clang/test/CodeGen/ms-inline-asm.c
+++ tools/clang/test/CodeGen/ms-inline-asm.c
@@ -77,7 +77,7 @@ void t9() {
pop ebx
}
// CHECK: t9
-// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, $$0x07\0A\09pop ebx", "~{ebx},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, $$0x07\0A\09pop ebx", "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"()
}
unsigned t10(void) {
@@ -211,7 +211,7 @@ void t21() {
__asm pop ebx
}
// CHECK: t21
-// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, $$0x07\0A\09pop ebx", "~{ebx},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, $$0x07\0A\09pop ebx", "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"()
}
extern void t22_helper(int x);
@@ -227,7 +227,7 @@ void t22() {
__asm pop ebx
}
// CHECK: t22
-// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, esp", "~{ebx},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, esp", "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"()
// CHECK: call void @t22_helper
// CHECK: call void asm sideeffect inteldialect "mov esp, ebx\0A\09pop ebx", "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"()
}
@@ -268,13 +268,14 @@ void t26() {
__asm __emit 0a2h
__asm __EMIT 0a2h
__asm popad
+// FIXME: These all need to be merged into the same asm blob.
// CHECK: t26
-// CHECK: call void asm sideeffect inteldialect "pushad", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "pushad", "~{esp},~{dirflag},~{fpsr},~{flags}"()
// CHECK: call void asm sideeffect inteldialect "mov eax, $$0", "~{eax},~{dirflag},~{fpsr},~{flags}"()
// CHECK: call void asm sideeffect inteldialect ".byte 0fh", "~{dirflag},~{fpsr},~{flags}"()
// CHECK: call void asm sideeffect inteldialect ".byte 0a2h", "~{dirflag},~{fpsr},~{flags}"()
// CHECK: call void asm sideeffect inteldialect ".byte 0a2h", "~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "popad", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "popad", "~{eax},~{ebp},~{ebx},~{ecx},~{edi},~{edx},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"()
}
void t27() {
@@ -323,8 +324,8 @@ void t31() {
__asm pushad
__asm popad
// CHECK: t31
-// CHECK: call void asm sideeffect inteldialect "pushad", "~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "popad", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "pushad", "~{esp},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "popad", "~{eax},~{ebp},~{ebx},~{ecx},~{edi},~{edx},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"()
}
void t32() {

View File

@ -0,0 +1,98 @@
Pull in r196986 from upstream llvm trunk (by Reid Kleckner):
Revert the backend fatal error from r196939
The combination of inline asm, stack realignment, and dynamic allocas
turns out to be too common to reject out of hand.
ASan inserts empy inline asm fragments and uses aligned allocas.
Compiling any trivial function containing a dynamic alloca with ASan is
enough to trigger the check.
XFAIL the test cases that would be miscompiled and add one that uses the
relevant functionality.
Introduced here: http://svn.freebsd.org/changeset/base/263312
Index: lib/Target/X86/X86RegisterInfo.cpp
===================================================================
--- lib/Target/X86/X86RegisterInfo.cpp
+++ lib/Target/X86/X86RegisterInfo.cpp
@@ -347,12 +347,6 @@ BitVector X86RegisterInfo::getReservedRegs(const M
"Stack realignment in presence of dynamic allocas is not supported with"
"this calling convention.");
- // FIXME: Do a proper analysis of the inline asm to see if it actually
- // conflicts with the base register we chose.
- if (MF.hasInlineAsm())
- report_fatal_error("Stack realignment in presence of dynamic stack "
- "adjustments is not supported with inline assembly.");
-
for (MCSubRegIterator I(getBaseRegister(), this, /*IncludeSelf=*/true);
I.isValid(); ++I)
Reserved.set(*I);
Index: test/CodeGen/X86/inline-asm-stack-realign3.ll
===================================================================
--- test/CodeGen/X86/inline-asm-stack-realign3.ll
+++ test/CodeGen/X86/inline-asm-stack-realign3.ll
@@ -0,0 +1,29 @@
+; RUN: llc -march=x86 < %s | FileCheck %s
+
+declare void @bar(i32* %junk)
+
+define i32 @foo(i1 %cond) {
+entry:
+ %r = alloca i32, align 128
+ store i32 -1, i32* %r, align 128
+ br i1 %cond, label %doit, label %skip
+
+doit:
+ call void asm sideeffect "xor %ecx, %ecx\0A\09mov %ecx, $0", "=*m,~{ecx},~{flags}"(i32* %r)
+ %junk = alloca i32
+ call void @bar(i32* %junk)
+ br label %skip
+
+skip:
+ %0 = load i32* %r, align 128
+ ret i32 %0
+}
+
+; CHECK-LABEL: foo:
+; CHECK: pushl %ebp
+; CHECK: andl $-128, %esp
+; CHECK: xor %ecx, %ecx
+; CHECK-NEXT: mov %ecx, (%esi)
+; CHECK: movl (%esi), %eax
+; CHECK: popl %ebp
+; CHECK: ret
Index: test/CodeGen/X86/inline-asm-stack-realign.ll
===================================================================
--- test/CodeGen/X86/inline-asm-stack-realign.ll
+++ test/CodeGen/X86/inline-asm-stack-realign.ll
@@ -1,8 +1,8 @@
; RUN: not llc -mtriple=i686-pc-win32 < %s 2>&1 | FileCheck %s
-; We don't currently support realigning the stack and adjusting the stack
-; pointer in inline asm. This commonly happens in MS inline assembly using
-; push and pop.
+; FIXME: This is miscompiled due to our unconditional use of ESI as the base
+; pointer.
+; XFAIL:
; CHECK: Stack realignment in presence of dynamic stack adjustments is not supported with inline assembly
Index: test/CodeGen/X86/inline-asm-stack-realign2.ll
===================================================================
--- test/CodeGen/X86/inline-asm-stack-realign2.ll
+++ test/CodeGen/X86/inline-asm-stack-realign2.ll
@@ -1,7 +1,8 @@
; RUN: not llc -mtriple=i686-pc-win32 < %s 2>&1 | FileCheck %s
-; We don't currently support realigning the stack and adjusting the stack
-; pointer in inline asm. This can even happen in GNU asm.
+; FIXME: This is miscompiled due to our unconditional use of ESI as the base
+; pointer.
+; XFAIL:
; CHECK: Stack realignment in presence of dynamic stack adjustments is not supported with inline assembly

View File

@ -0,0 +1,263 @@
Pull in r202930 from upstream llvm trunk (by Hans Wennborg):
Check for dynamic allocas and inline asm that clobbers sp before building
selection dag (PR19012)
In X86SelectionDagInfo::EmitTargetCodeForMemcpy we check with MachineFrameInfo
to make sure that ESI isn't used as a base pointer register before we choose to
emit rep movs (which clobbers esi).
The problem is that MachineFrameInfo wouldn't know about dynamic allocas or
inline asm that clobbers the stack pointer until SelectionDAGBuilder has
encountered them.
This patch fixes the problem by checking for such things when building the
FunctionLoweringInfo.
Differential Revision: http://llvm-reviews.chandlerc.com/D2954
Introduced here: http://svn.freebsd.org/changeset/base/263312
Index: lib/CodeGen/MachineFunction.cpp
===================================================================
--- lib/CodeGen/MachineFunction.cpp
+++ lib/CodeGen/MachineFunction.cpp
@@ -525,13 +525,14 @@ int MachineFrameInfo::CreateSpillStackObject(uint6
/// variable sized object is created, whether or not the index returned is
/// actually used.
///
-int MachineFrameInfo::CreateVariableSizedObject(unsigned Alignment) {
+int MachineFrameInfo::CreateVariableSizedObject(unsigned Alignment,
+ const AllocaInst *Alloca) {
HasVarSizedObjects = true;
Alignment =
clampStackAlignment(!getFrameLowering()->isStackRealignable() ||
!RealignOption,
Alignment, getFrameLowering()->getStackAlignment());
- Objects.push_back(StackObject(0, Alignment, 0, false, false, true, 0));
+ Objects.push_back(StackObject(0, Alignment, 0, false, false, true, Alloca));
ensureMaxAlignment(Alignment);
return (int)Objects.size()-NumFixedObjects-1;
}
Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
===================================================================
--- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -419,7 +419,7 @@ bool SelectionDAGISel::runOnMachineFunction(Machin
SplitCriticalSideEffectEdges(const_cast<Function&>(Fn), this);
CurDAG->init(*MF, TTI, TLI);
- FuncInfo->set(Fn, *MF);
+ FuncInfo->set(Fn, *MF, CurDAG);
if (UseMBPI && OptLevel != CodeGenOpt::None)
FuncInfo->BPI = &getAnalysis<BranchProbabilityInfo>();
@@ -429,7 +429,6 @@ bool SelectionDAGISel::runOnMachineFunction(Machin
SDB->init(GFI, *AA, LibInfo);
MF->setHasInlineAsm(false);
- MF->getFrameInfo()->setHasInlineAsmWithSPAdjust(false);
SelectAllBasicBlocks(Fn);
Index: lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
===================================================================
--- lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
+++ lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
@@ -33,6 +33,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Target/TargetInstrInfo.h"
+#include "llvm/Target/TargetFrameLowering.h"
#include "llvm/Target/TargetLowering.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetRegisterInfo.h"
@@ -55,7 +56,8 @@ static bool isUsedOutsideOfDefiningBlock(const Ins
return false;
}
-void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf) {
+void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
+ SelectionDAG *DAG) {
const TargetLowering *TLI = TM.getTargetLowering();
Fn = &fn;
@@ -100,6 +102,43 @@ static bool isUsedOutsideOfDefiningBlock(const Ins
for (; BB != EB; ++BB)
for (BasicBlock::const_iterator I = BB->begin(), E = BB->end();
I != E; ++I) {
+ // Look for dynamic allocas.
+ if (const AllocaInst *AI = dyn_cast<AllocaInst>(I)) {
+ if (!AI->isStaticAlloca()) {
+ unsigned Align = std::max(
+ (unsigned)TLI->getDataLayout()->getPrefTypeAlignment(
+ AI->getAllocatedType()),
+ AI->getAlignment());
+ unsigned StackAlign = TM.getFrameLowering()->getStackAlignment();
+ if (Align <= StackAlign)
+ Align = 0;
+ // Inform the Frame Information that we have variable-sized objects.
+ MF->getFrameInfo()->CreateVariableSizedObject(Align ? Align : 1, AI);
+ }
+ }
+
+ // Look for inline asm that clobbers the SP register.
+ if (isa<CallInst>(I) || isa<InvokeInst>(I)) {
+ ImmutableCallSite CS(I);
+ if (const InlineAsm *IA = dyn_cast<InlineAsm>(CS.getCalledValue())) {
+ unsigned SP = TLI->getStackPointerRegisterToSaveRestore();
+ std::vector<TargetLowering::AsmOperandInfo> Ops =
+ TLI->ParseConstraints(CS);
+ for (size_t I = 0, E = Ops.size(); I != E; ++I) {
+ TargetLowering::AsmOperandInfo &Op = Ops[I];
+ if (Op.Type == InlineAsm::isClobber) {
+ // Clobbers don't have SDValue operands, hence SDValue().
+ TLI->ComputeConstraintToUse(Op, SDValue(), DAG);
+ std::pair<unsigned, const TargetRegisterClass*> PhysReg =
+ TLI->getRegForInlineAsmConstraint(Op.ConstraintCode,
+ Op.ConstraintVT);
+ if (PhysReg.first == SP)
+ MF->getFrameInfo()->setHasInlineAsmWithSPAdjust(true);
+ }
+ }
+ }
+ }
+
// Mark values used outside their block as exported, by allocating
// a virtual register for them.
if (isUsedOutsideOfDefiningBlock(I))
Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
===================================================================
--- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -860,10 +860,10 @@ void RegsForValue::AddInlineAsmOperands(unsigned C
unsigned TheReg = Regs[Reg++];
Ops.push_back(DAG.getRegister(TheReg, RegisterVT));
- // Notice if we clobbered the stack pointer. Yes, inline asm can do this.
if (TheReg == SP && Code == InlineAsm::Kind_Clobber) {
- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
- MFI->setHasInlineAsmWithSPAdjust(true);
+ // If we clobbered the stack pointer, MFI should know about it.
+ assert(DAG.getMachineFunction().getFrameInfo()->
+ hasInlineAsmWithSPAdjust());
}
}
}
@@ -3378,9 +3378,7 @@ void SelectionDAGBuilder::visitAlloca(const Alloca
setValue(&I, DSA);
DAG.setRoot(DSA.getValue(1));
- // Inform the Frame Information that we have just allocated a variable-sized
- // object.
- FuncInfo.MF->getFrameInfo()->CreateVariableSizedObject(Align ? Align : 1);
+ assert(FuncInfo.MF->getFrameInfo()->hasVarSizedObjects());
}
void SelectionDAGBuilder::visitLoad(const LoadInst &I) {
Index: test/CodeGen/X86/stack-align-memcpy.ll
===================================================================
--- test/CodeGen/X86/stack-align-memcpy.ll
+++ test/CodeGen/X86/stack-align-memcpy.ll
@@ -2,6 +2,9 @@
%struct.foo = type { [88 x i8] }
+declare void @bar(i8* nocapture, %struct.foo* align 4 byval) nounwind
+declare void @baz(i8*) nounwind
+
; PR15249
; We can't use rep;movsl here because it clobbers the base pointer in %esi.
define void @test1(%struct.foo* nocapture %x, i32 %y) nounwind {
@@ -15,4 +18,26 @@ define void @test1(%struct.foo* nocapture %x, i32
; CHECK-NOT: rep;movsl
}
-declare void @bar(i8* nocapture, %struct.foo* align 4 byval) nounwind
+; PR19012
+; Also don't clobber %esi if the dynamic alloca comes after the memcpy.
+define void @test2(%struct.foo* nocapture %x, i32 %y, i8* %z) nounwind {
+ call void @bar(i8* %z, %struct.foo* align 4 byval %x)
+ %dynalloc = alloca i8, i32 %y, align 1
+ call void @baz(i8* %dynalloc)
+ ret void
+
+; CHECK-LABEL: test2:
+; CHECK: movl %esp, %esi
+; CHECK-NOT: rep;movsl
+}
+
+; Check that we do use rep movs if we make the alloca static.
+define void @test3(%struct.foo* nocapture %x, i32 %y, i8* %z) nounwind {
+ call void @bar(i8* %z, %struct.foo* align 4 byval %x)
+ %statalloc = alloca i8, i32 8, align 1
+ call void @baz(i8* %statalloc)
+ ret void
+
+; CHECK-LABEL: test3:
+; CHECK: rep;movsl
+}
Index: test/CodeGen/X86/inline-asm-sp-clobber-memcpy.ll
===================================================================
--- test/CodeGen/X86/inline-asm-sp-clobber-memcpy.ll
+++ test/CodeGen/X86/inline-asm-sp-clobber-memcpy.ll
@@ -0,0 +1,17 @@
+; RUN: llc < %s -force-align-stack -mtriple i386-apple-darwin -mcpu=i486 | FileCheck %s
+
+%struct.foo = type { [88 x i8] }
+
+declare void @bar(i8* nocapture, %struct.foo* align 4 byval) nounwind
+
+; PR19012
+; Don't clobber %esi if we have inline asm that clobbers %esp.
+define void @test1(%struct.foo* nocapture %x, i32 %y, i8* %z) nounwind {
+ call void @bar(i8* %z, %struct.foo* align 4 byval %x)
+ call void asm sideeffect inteldialect "xor esp, esp", "=*m,~{flags},~{esp},~{esp},~{dirflag},~{fpsr},~{flags}"(i8* %z)
+ ret void
+
+; CHECK-LABEL: test1:
+; CHECK: movl %esp, %esi
+; CHECK-NOT: rep;movsl
+}
Index: include/llvm/CodeGen/FunctionLoweringInfo.h
===================================================================
--- include/llvm/CodeGen/FunctionLoweringInfo.h
+++ include/llvm/CodeGen/FunctionLoweringInfo.h
@@ -41,6 +41,7 @@ class MachineBasicBlock;
class MachineFunction;
class MachineModuleInfo;
class MachineRegisterInfo;
+class SelectionDAG;
class TargetLowering;
class Value;
@@ -125,7 +126,7 @@ class FunctionLoweringInfo {
/// set - Initialize this FunctionLoweringInfo with the given Function
/// and its associated MachineFunction.
///
- void set(const Function &Fn, MachineFunction &MF);
+ void set(const Function &Fn, MachineFunction &MF, SelectionDAG *DAG);
/// clear - Clear out all the function-specific state. This returns this
/// FunctionLoweringInfo to an empty state, ready to be used for a
Index: include/llvm/CodeGen/MachineFrameInfo.h
===================================================================
--- include/llvm/CodeGen/MachineFrameInfo.h
+++ include/llvm/CodeGen/MachineFrameInfo.h
@@ -244,6 +244,7 @@ class MachineFrameInfo {
LocalFrameSize = 0;
LocalFrameMaxAlign = 0;
UseLocalStackAllocationBlock = false;
+ HasInlineAsmWithSPAdjust = false;
}
/// hasStackObjects - Return true if there are any stack objects in this
@@ -529,7 +530,7 @@ class MachineFrameInfo {
/// variable sized object is created, whether or not the index returned is
/// actually used.
///
- int CreateVariableSizedObject(unsigned Alignment);
+ int CreateVariableSizedObject(unsigned Alignment, const AllocaInst *Alloca);
/// getCalleeSavedInfo - Returns a reference to call saved info vector for the
/// current function.

View File

@ -0,0 +1,60 @@
Pull in r203311 from upstream llvm trunk (by Arnold Schwaighofer):
ISel: Make VSELECT selection terminate in cases where the condition type has to
be split and the result type widened.
When the condition of a vselect has to be split it makes no sense widening the
vselect and thereby widening the condition. We end up in an endless loop of
widening (vselect result type) and splitting (condition mask type) doing this.
Instead, split both the condition and the vselect and widen the result.
I ran this over the test suite with i686 and mattr=+sse and saw no regressions.
Fixes PR18036.
Introduced here: http://svn.freebsd.org/changeset/base/263313
Index: test/CodeGen/X86/sse1.ll
===================================================================
--- test/CodeGen/X86/sse1.ll
+++ test/CodeGen/X86/sse1.ll
@@ -43,3 +43,17 @@ entry:
; CHECK-NOT: shufps $16
; CHECK: ret
}
+
+; We used to get stuck in type legalization for this example when lowering the
+; vselect. With SSE1 v4f32 is a legal type but v4i1 (or any vector integer type)
+; is not. We used to ping pong between splitting the vselect for the v4i
+; condition operand and widening the resulting vselect for the v4f32 result.
+; PR18036
+
+; CHECK-LABEL: vselect
+define <4 x float> @vselect(<4 x float>*%p, <4 x i32> %q) {
+entry:
+ %a1 = icmp eq <4 x i32> %q, zeroinitializer
+ %a14 = select <4 x i1> %a1, <4 x float> <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+0> , <4 x float> zeroinitializer
+ ret <4 x float> %a14
+}
Index: lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
===================================================================
--- lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
+++ lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
@@ -2180,6 +2180,17 @@ SDValue DAGTypeLegalizer::WidenVecRes_SELECT(SDNod
if (getTypeAction(CondVT) == TargetLowering::TypeWidenVector)
Cond1 = GetWidenedVector(Cond1);
+ // If we have to split the condition there is no point in widening the
+ // select. This would result in an cycle of widening the select ->
+ // widening the condition operand -> splitting the condition operand ->
+ // splitting the select -> widening the select. Instead split this select
+ // further and widen the resulting type.
+ if (getTypeAction(CondVT) == TargetLowering::TypeSplitVector) {
+ SDValue SplitSelect = SplitVecOp_VSELECT(N, 0);
+ SDValue Res = ModifyToType(SplitSelect, WidenVT);
+ return Res;
+ }
+
if (Cond1.getValueType() != CondWidenVT)
Cond1 = ModifyToType(Cond1, CondWidenVT);
}