summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/FileCheck/FileCheck.cpp83
-rw-r--r--utils/FileCheck/Makefile21
-rwxr-xr-xutils/GenLibDeps.pl2
-rw-r--r--utils/KillTheDoctor/KillTheDoctor.cpp4
-rw-r--r--utils/LLVMVisualizers/CMakeLists.txt7
-rw-r--r--utils/LLVMVisualizers/llvm.natvis246
-rw-r--r--utils/Makefile19
-rw-r--r--utils/Misc/mergefunctions.clang.svn.patch14
-rw-r--r--utils/PerfectShuffle/Makefile18
-rw-r--r--utils/TableGen/AsmMatcherEmitter.cpp365
-rw-r--r--utils/TableGen/AsmWriterEmitter.cpp252
-rw-r--r--utils/TableGen/AsmWriterInst.cpp19
-rw-r--r--utils/TableGen/AsmWriterInst.h29
-rw-r--r--utils/TableGen/Attributes.cpp23
-rw-r--r--utils/TableGen/CMakeLists.txt1
-rw-r--r--utils/TableGen/CodeEmitterGen.cpp9
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.cpp23
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.h4
-rw-r--r--utils/TableGen/CodeGenInstruction.cpp5
-rw-r--r--utils/TableGen/CodeGenInstruction.h7
-rw-r--r--utils/TableGen/CodeGenIntrinsics.h191
-rw-r--r--utils/TableGen/CodeGenMapTable.cpp33
-rw-r--r--utils/TableGen/CodeGenRegisters.cpp102
-rw-r--r--utils/TableGen/CodeGenRegisters.h6
-rw-r--r--utils/TableGen/CodeGenSchedule.cpp101
-rw-r--r--utils/TableGen/CodeGenSchedule.h15
-rw-r--r--utils/TableGen/CodeGenTarget.cpp64
-rw-r--r--utils/TableGen/CodeGenTarget.h15
-rw-r--r--utils/TableGen/DAGISelMatcher.cpp64
-rw-r--r--utils/TableGen/DAGISelMatcher.h125
-rw-r--r--utils/TableGen/DAGISelMatcherEmitter.cpp49
-rw-r--r--utils/TableGen/DAGISelMatcherGen.cpp16
-rw-r--r--utils/TableGen/DAGISelMatcherOpt.cpp83
-rw-r--r--utils/TableGen/DFAPacketizerEmitter.cpp27
-rw-r--r--utils/TableGen/DisassemblerEmitter.cpp13
-rw-r--r--utils/TableGen/FastISelEmitter.cpp6
-rw-r--r--utils/TableGen/FixedLenDecoderEmitter.cpp134
-rw-r--r--utils/TableGen/InstrInfoEmitter.cpp65
-rw-r--r--utils/TableGen/IntrinsicEmitter.cpp283
-rw-r--r--utils/TableGen/Makefile18
-rw-r--r--utils/TableGen/RegisterInfoEmitter.cpp116
-rw-r--r--utils/TableGen/SearchableTableEmitter.cpp320
-rw-r--r--utils/TableGen/SequenceToOffsetTable.h1
-rw-r--r--utils/TableGen/SubtargetEmitter.cpp311
-rw-r--r--utils/TableGen/TableGen.cpp10
-rw-r--r--utils/TableGen/TableGenBackends.h1
-rw-r--r--utils/TableGen/X86DisassemblerTables.cpp2
-rw-r--r--utils/TableGen/X86RecognizableInstr.cpp53
-rw-r--r--utils/TableGen/X86RecognizableInstr.h5
-rw-r--r--utils/TableGen/module.modulemap4
-rwxr-xr-xutils/abtest/abtest.py234
-rwxr-xr-xutils/abtest/mark_aarch64fns.py65
-rwxr-xr-xutils/abtest/mark_armfns.py54
-rw-r--r--utils/buildit/GNUmakefile132
-rwxr-xr-xutils/buildit/build_llvm361
-rw-r--r--utils/count/Makefile20
-rwxr-xr-xutils/extract_symbols.py496
-rwxr-xr-xutils/findoptdiff2
-rw-r--r--utils/fpcmp/Makefile16
-rw-r--r--utils/gdb-scripts/prettyprinters.py107
-rw-r--r--utils/lit/lit/Test.py20
-rw-r--r--utils/lit/lit/TestRunner.py125
-rw-r--r--utils/lit/lit/TestingConfig.py8
-rw-r--r--utils/lit/lit/formats/googletest.py6
-rwxr-xr-xutils/lit/lit/main.py5
-rw-r--r--utils/lit/lit/run.py16
-rwxr-xr-xutils/lit/tests/Inputs/googletest-upstream-format/DummySubDir/OneTest38
-rw-r--r--utils/lit/tests/Inputs/googletest-upstream-format/lit.cfg3
-rw-r--r--utils/lit/tests/Inputs/shtest-format/requires-any-missing.txt2
-rw-r--r--utils/lit/tests/Inputs/shtest-format/requires-any-present.txt2
-rw-r--r--utils/lit/tests/Inputs/shtest-output-printing/basic.txt3
-rw-r--r--utils/lit/tests/Inputs/shtest-output-printing/lit.cfg4
-rw-r--r--utils/lit/tests/googletest-upstream-format.py20
-rw-r--r--utils/lit/tests/shtest-format.py11
-rw-r--r--utils/lit/tests/shtest-output-printing.py28
-rw-r--r--utils/lit/tests/shtest-shell.py8
-rw-r--r--utils/llvm-build/llvmbuild/main.py2
-rw-r--r--utils/llvm-lit/Makefile27
-rw-r--r--utils/llvm.natvis169
-rw-r--r--utils/not/Makefile21
-rw-r--r--utils/prepare-code-coverage-artifact.py55
-rwxr-xr-xutils/release/build_llvm_package.bat8
-rwxr-xr-xutils/release/export.sh4
-rwxr-xr-xutils/release/merge.sh14
-rwxr-xr-xutils/release/tag.sh6
-rwxr-xr-xutils/release/test-release.sh26
-rw-r--r--utils/unittest/Makefile13
-rw-r--r--utils/unittest/UnitTestMain/Makefile32
-rw-r--r--utils/unittest/UnitTestMain/TestMain.cpp3
-rw-r--r--utils/unittest/googletest/Makefile42
-rw-r--r--utils/unittest/googletest/README.LLVM1
-rw-r--r--utils/unittest/googletest/include/gtest/internal/gtest-port.h5
-rwxr-xr-xutils/update_llc_test_checks.py232
-rwxr-xr-xutils/update_test_checks.py397
-rw-r--r--utils/vim/syntax/llvm.vim140
-rw-r--r--utils/yaml-bench/Makefile20
96 files changed, 3963 insertions, 2424 deletions
diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp
index f73a0fee76c82..6c9b62d5b2442 100644
--- a/utils/FileCheck/FileCheck.cpp
+++ b/utils/FileCheck/FileCheck.cpp
@@ -45,6 +45,11 @@ InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
static cl::list<std::string>
CheckPrefixes("check-prefix",
cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
+static cl::alias CheckPrefixesAlias(
+ "check-prefixes", cl::aliasopt(CheckPrefixes), cl::CommaSeparated,
+ cl::NotHidden,
+ cl::desc(
+ "Alias for -check-prefix permitting multiple comma separated values"));
static cl::opt<bool>
NoCanonicalizeWhiteSpace("strict-whitespace",
@@ -62,6 +67,12 @@ static cl::opt<bool> AllowEmptyInput(
cl::desc("Allow the input file to be empty. This is useful when making\n"
"checks that some error message does not occur, for example."));
+static cl::opt<bool> MatchFullLines(
+ "match-full-lines", cl::init(false),
+ cl::desc("Require all positive matches to cover an entire input line.\n"
+ "Allows leading and trailing whitespace if --strict-whitespace\n"
+ "is not also passed."));
+
typedef cl::list<std::string>::const_iterator prefix_iterator;
//===----------------------------------------------------------------------===//
@@ -80,7 +91,9 @@ namespace Check {
/// MatchEOF - When set, this pattern only matches the end of file. This is
/// used for trailing CHECK-NOTs.
- CheckEOF
+ CheckEOF,
+ /// CheckBadNot - Found -NOT combined with another CHECK suffix.
+ CheckBadNot
};
}
@@ -174,6 +187,8 @@ bool Pattern::ParsePattern(StringRef PatternStr,
StringRef Prefix,
SourceMgr &SM,
unsigned LineNumber) {
+ bool MatchFullLinesHere = MatchFullLines && CheckTy != Check::CheckNot;
+
this->LineNumber = LineNumber;
PatternLoc = SMLoc::getFromPointer(PatternStr.data());
@@ -191,13 +206,19 @@ bool Pattern::ParsePattern(StringRef PatternStr,
}
// Check to see if this is a fixed string, or if it has regex pieces.
- if (PatternStr.size() < 2 ||
- (PatternStr.find("{{") == StringRef::npos &&
- PatternStr.find("[[") == StringRef::npos)) {
+ if (!MatchFullLinesHere &&
+ (PatternStr.size() < 2 || (PatternStr.find("{{") == StringRef::npos &&
+ PatternStr.find("[[") == StringRef::npos))) {
FixedStr = PatternStr;
return false;
}
+ if (MatchFullLinesHere) {
+ RegExStr += '^';
+ if (!NoCanonicalizeWhiteSpace)
+ RegExStr += " *";
+ }
+
// Paren value #0 is for the fully matched string. Any new parenthesized
// values add from there.
unsigned CurParen = 1;
@@ -329,6 +350,12 @@ bool Pattern::ParsePattern(StringRef PatternStr,
PatternStr = PatternStr.substr(FixedMatchEnd);
}
+ if (MatchFullLinesHere) {
+ if (!NoCanonicalizeWhiteSpace)
+ RegExStr += " *";
+ RegExStr += '$';
+ }
+
return false;
}
@@ -598,19 +625,15 @@ struct CheckString {
/// CheckTy - Specify what kind of check this is. e.g. CHECK-NEXT: directive,
/// as opposed to a CHECK: directive.
- Check::CheckType CheckTy;
+ // Check::CheckType CheckTy;
/// DagNotStrings - These are all of the strings that are disallowed from
/// occurring between this match string and the previous one (or start of
/// file).
std::vector<Pattern> DagNotStrings;
-
- CheckString(const Pattern &P,
- StringRef S,
- SMLoc L,
- Check::CheckType Ty)
- : Pat(P), Prefix(S), Loc(L), CheckTy(Ty) {}
+ CheckString(const Pattern &P, StringRef S, SMLoc L)
+ : Pat(P), Prefix(S), Loc(L) {}
/// Check - Match check string and its "not strings" and/or "dag strings".
size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode,
@@ -677,6 +700,7 @@ static bool IsPartOfWord(char c) {
static size_t CheckTypeSize(Check::CheckType Ty) {
switch (Ty) {
case Check::CheckNone:
+ case Check::CheckBadNot:
return 0;
case Check::CheckPlain:
@@ -730,6 +754,12 @@ static Check::CheckType FindCheckType(StringRef Buffer, StringRef Prefix) {
if (Rest.startswith("LABEL:"))
return Check::CheckLabel;
+ // You can't combine -NOT with another suffix.
+ if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") ||
+ Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") ||
+ Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:"))
+ return Check::CheckBadNot;
+
return Check::CheckNone;
}
@@ -898,6 +928,14 @@ static bool ReadCheckFile(SourceMgr &SM,
// PrefixLoc is to the start of the prefix. Skip to the end.
Buffer = Buffer.drop_front(UsedPrefix.size() + CheckTypeSize(CheckTy));
+ // Complain about useful-looking but unsupported suffixes.
+ if (CheckTy == Check::CheckBadNot) {
+ SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()),
+ SourceMgr::DK_Error,
+ "unsupported -NOT combo on prefix '" + UsedPrefix + "'");
+ return true;
+ }
+
// Okay, we found the prefix, yay. Remember the rest of the line, but ignore
// leading and trailing whitespace.
Buffer = Buffer.substr(Buffer.find_first_not_of(" \t"));
@@ -942,7 +980,7 @@ static bool ReadCheckFile(SourceMgr &SM,
}
// Okay, add the string we captured to the output vector and move on.
- CheckStrings.emplace_back(P, UsedPrefix, PatternLoc, CheckTy);
+ CheckStrings.emplace_back(P, UsedPrefix, PatternLoc);
std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
DagNotMatches = ImplicitNegativeChecks;
}
@@ -951,8 +989,7 @@ static bool ReadCheckFile(SourceMgr &SM,
// prefix as a filler for the error message.
if (!DagNotMatches.empty()) {
CheckStrings.emplace_back(Pattern(Check::CheckEOF), *CheckPrefixes.begin(),
- SMLoc::getFromPointer(Buffer.data()),
- Check::CheckEOF);
+ SMLoc::getFromPointer(Buffer.data()));
std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
}
@@ -965,7 +1002,7 @@ static bool ReadCheckFile(SourceMgr &SM,
errs() << "\'" << *I << ":'";
++I;
}
- for (; I != E; ++I)
+ for (; I != E; ++I)
errs() << ", \'" << *I << ":'";
errs() << '\n';
@@ -1073,7 +1110,7 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer,
}
bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
- if (CheckTy != Check::CheckNext)
+ if (Pat.getCheckTy() != Check::CheckNext)
return false;
// Count the number of newlines between the previous match and this one.
@@ -1112,7 +1149,7 @@ bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
}
bool CheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const {
- if (CheckTy != Check::CheckSame)
+ if (Pat.getCheckTy() != Check::CheckSame)
return false;
// Count the number of newlines between the previous match and this one.
@@ -1266,8 +1303,15 @@ static void AddCheckPrefixIfNeeded() {
CheckPrefixes.push_back("CHECK");
}
+static void DumpCommandLine(int argc, char **argv) {
+ errs() << "FileCheck command line: ";
+ for (int I = 0; I < argc; I++)
+ errs() << " " << argv[I];
+ errs() << "\n";
+}
+
int main(int argc, char **argv) {
- sys::PrintStackTraceOnErrorSignal();
+ sys::PrintStackTraceOnErrorSignal(argv[0]);
PrettyStackTraceProgram X(argc, argv);
cl::ParseCommandLineOptions(argc, argv);
@@ -1299,6 +1343,7 @@ int main(int argc, char **argv) {
if (File->getBufferSize() == 0 && !AllowEmptyInput) {
errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
+ DumpCommandLine(argc, argv);
return 2;
}
@@ -1326,7 +1371,7 @@ int main(int argc, char **argv) {
CheckRegion = Buffer;
} else {
const CheckString &CheckLabelStr = CheckStrings[j];
- if (CheckLabelStr.CheckTy != Check::CheckLabel) {
+ if (CheckLabelStr.Pat.getCheckTy() != Check::CheckLabel) {
++j;
continue;
}
diff --git a/utils/FileCheck/Makefile b/utils/FileCheck/Makefile
deleted file mode 100644
index b8762365984d5..0000000000000
--- a/utils/FileCheck/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-##===- utils/FileCheck/Makefile ----------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-TOOLNAME = FileCheck
-USEDLIBS = LLVMSupport.a
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-# FIXME: Don't install this utility
-#NO_INSTALL = 1
-
-include $(LEVEL)/Makefile.common
-
diff --git a/utils/GenLibDeps.pl b/utils/GenLibDeps.pl
index 7748cabdab5b2..9b65e900c53e8 100755
--- a/utils/GenLibDeps.pl
+++ b/utils/GenLibDeps.pl
@@ -96,7 +96,6 @@ if ($PEROBJ) {
$libpath =~ s/^AsmPrinter/CodeGen\/AsmPrinter/;
$libpath =~ s/^BitReader/Bitcode\/Reader/;
$libpath =~ s/^BitWriter/Bitcode\/Writer/;
- $libpath =~ s/^CppBackend/Target\/CppBackend/;
$libpath =~ s/^MSIL/Target\/MSIL/;
$libpath =~ s/^Core/IR/;
$libpath =~ s/^Instrumentation/Transforms\/Instrumentation/;
@@ -137,7 +136,6 @@ if ($PEROBJ) {
$libpath =~ s/^AsmPrinter/CodeGen\/AsmPrinter/;
$libpath =~ s/^BitReader/Bitcode\/Reader/;
$libpath =~ s/^BitWriter/Bitcode\/Writer/;
- $libpath =~ s/^CppBackend/Target\/CppBackend/;
$libpath =~ s/^MSIL/Target\/MSIL/;
$libpath =~ s/^Core/VMCore/;
$libpath =~ s/^Instrumentation/Transforms\/Instrumentation/;
diff --git a/utils/KillTheDoctor/KillTheDoctor.cpp b/utils/KillTheDoctor/KillTheDoctor.cpp
index 6c2242aafdfe7..c9e96617f37fc 100644
--- a/utils/KillTheDoctor/KillTheDoctor.cpp
+++ b/utils/KillTheDoctor/KillTheDoctor.cpp
@@ -296,7 +296,7 @@ static StringRef ExceptionCodeToString(DWORD ExceptionCode) {
int main(int argc, char **argv) {
// Print a stack trace if we signal out.
- sys::PrintStackTraceOnErrorSignal();
+ sys::PrintStackTraceOnErrorSignal(argv[0]);
PrettyStackTraceProgram X(argc, argv);
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
@@ -337,7 +337,7 @@ int main(int argc, char **argv) {
errs() << ToolName << ": Program Image Path: " << ProgramToRun << '\n'
<< ToolName << ": Command Line: " << CommandLine << '\n';
- STARTUPINFO StartupInfo;
+ STARTUPINFOA StartupInfo;
PROCESS_INFORMATION ProcessInfo;
std::memset(&StartupInfo, 0, sizeof(StartupInfo));
StartupInfo.cb = sizeof(StartupInfo);
diff --git a/utils/LLVMVisualizers/CMakeLists.txt b/utils/LLVMVisualizers/CMakeLists.txt
new file mode 100644
index 0000000000000..9fdc8906e55ae
--- /dev/null
+++ b/utils/LLVMVisualizers/CMakeLists.txt
@@ -0,0 +1,7 @@
+# Do this by hand instead of using add_llvm_utilities(), which
+# tries to create a corresponding executable, which we don't want.
+if (LLVM_ADD_NATIVE_VISUALIZERS_TO_SOLUTION)
+ set(LLVM_VISUALIZERS llvm.natvis)
+ add_custom_target(LLVMVisualizers SOURCES ${LLVM_VISUALIZERS})
+ set_target_properties(LLVMVisualizers PROPERTIES FOLDER "Utils")
+endif()
diff --git a/utils/LLVMVisualizers/llvm.natvis b/utils/LLVMVisualizers/llvm.natvis
new file mode 100644
index 0000000000000..6d8475a1c72e1
--- /dev/null
+++ b/utils/LLVMVisualizers/llvm.natvis
@@ -0,0 +1,246 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Visual Studio Native Debugging Visualizers for LLVM
+
+For Visual Studio 2013 only, put this file into
+"%USERPROFILE%\Documents\Visual Studio 2013\Visualizers" or create a symbolic link so it updates automatically.
+
+For later versions of Visual Studio, no setup is required.
+-->
+<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
+ <!-- VS2013 -->
+ <Type Name="llvm::SmallVectorImpl&lt;*&gt;" Priority="MediumLow">
+ <DisplayString Condition="(($T1*)EndX - ($T1*)BeginX) == 0">empty</DisplayString>
+ <DisplayString Condition="(($T1*)EndX - ($T1*)BeginX) != 0">{{ size={($T1*)EndX - ($T1*)BeginX} }}</DisplayString>
+ <Expand>
+ <Item Name="[size]">($T1*)EndX - ($T1*)BeginX</Item>
+ <Item Name="[capacity]">($T1*)CapacityX - ($T1*)BeginX</Item>
+ <ArrayItems>
+ <Size>($T1*)EndX - ($T1*)BeginX</Size>
+ <ValuePointer>($T1*)BeginX</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+ <!-- VS2015 and up -->
+ <Type Name="llvm::SmallVectorImpl&lt;*&gt;">
+ <DisplayString IncludeView ="elt0" Condition="(($T1*)EndX - ($T1*)BeginX) == 0"></DisplayString>
+ <DisplayString IncludeView ="elt0">{(($T1*)BeginX)[0]}{*this,view(elt1)}</DisplayString>
+ <DisplayString IncludeView ="elt1" Condition="(($T1*)EndX - ($T1*)BeginX) == 1"></DisplayString>
+ <DisplayString IncludeView ="elt1">, {(($T1*)BeginX)[1]}{*this,view(elt2)}</DisplayString>
+ <DisplayString IncludeView ="elt2" Condition="(($T1*)EndX - ($T1*)BeginX) == 2"></DisplayString>
+ <DisplayString IncludeView ="elt2">, {(($T1*)BeginX)[2]}{*this,view(elt3)}</DisplayString>
+ <DisplayString IncludeView ="elt3" Condition="(($T1*)EndX - ($T1*)BeginX) == 3"></DisplayString>
+ <DisplayString IncludeView ="elt3">, {(($T1*)BeginX)[2]}{*this,view(elt4)}</DisplayString>
+ <DisplayString IncludeView ="elt4" Condition="(($T1*)EndX - ($T1*)BeginX) == 4"></DisplayString>
+ <DisplayString IncludeView ="elt4">, /* {(($T1*)EndX - ($T1*)BeginX) - 4} more*/ </DisplayString>
+ <DisplayString Condition="(($T1*)EndX - ($T1*)BeginX) == 0">empty</DisplayString>
+ <DisplayString Condition="(($T1*)EndX - ($T1*)BeginX) != 0">{{{*this,view(elt0)}}}</DisplayString>
+ <Expand>
+ <Item Name="[size]">($T1*)EndX - ($T1*)BeginX</Item>
+ <Item Name="[capacity]">($T1*)CapacityX - ($T1*)BeginX</Item>
+ <ArrayItems>
+ <Size>($T1*)EndX - ($T1*)BeginX</Size>
+ <ValuePointer>($T1*)BeginX</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+ <Type Name="llvm::ArrayRef&lt;*&gt;">
+ <DisplayString Condition="Length == 0">empty</DisplayString>
+ <DisplayString Condition="Length != 0">{{ size={Length} }}</DisplayString>
+ <Expand>
+ <Item Name="[size]">Length</Item>
+ <ArrayItems>
+ <Size>Length</Size>
+ <ValuePointer>Data</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+ <Type Name="llvm::SmallString&lt;*&gt;">
+ <DisplayString>{BeginX,s}</DisplayString>
+ <StringView>BeginX,s</StringView>
+ <Expand>
+ <Item Name="[size]">(char*)EndX - (char*)BeginX</Item>
+ <Item Name="[capacity]">(char*)CapacityX - (char*)BeginX</Item>
+ <ArrayItems>
+ <Size>(char*)EndX - (char*)BeginX</Size>
+ <ValuePointer>(char*)BeginX</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::StringRef">
+ <DisplayString>{Data,[Length]s}</DisplayString>
+ <StringView>Data,[Length]s</StringView>
+ <Expand>
+ <Item Name="[size]">Length</Item>
+ <ArrayItems>
+ <Size>Length</Size>
+ <ValuePointer>Data</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::PointerIntPair&lt;*,*,*,*&gt;">
+ <DisplayString>{IntMask}: {($T1)(Value &amp; PointerBitMask)} [{($T3)((Value &gt;&gt; IntShift) &amp; IntMask)}]</DisplayString>
+ <Expand>
+ <Item Name="[ptr]">($T1)(Value &amp; PointerBitMask)</Item>
+ <Item Name="[int]">($T3)((Value &gt;&gt; IntShift) &amp; IntMask)</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::PointerUnion&lt;*,*&gt;">
+ <DisplayString Condition="((Val.Value &gt;&gt; Val.IntShift) &amp; Val.IntMask) == 0">{"$T1", s8b}: {($T1)(Val.Value &amp; Val.PointerBitMask)}</DisplayString>
+ <DisplayString Condition="((Val.Value &gt;&gt; Val.IntShift) &amp; Val.IntMask) != 0">{"$T2", s8b}: {($T2)(Val.Value &amp; Val.PointerBitMask)}</DisplayString>
+ <Expand>
+ <ExpandedItem Condition="((Val.Value &gt;&gt; Val.IntShift) &amp; Val.IntMask) == 0">($T1)(Val.Value &amp; Val.PointerBitMask)</ExpandedItem>
+ <ExpandedItem Condition="((Val.Value &gt;&gt; Val.IntShift) &amp; Val.IntMask) != 0">($T2)(Val.Value &amp; Val.PointerBitMask)</ExpandedItem>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::PointerUnion3&lt;*,*,*&gt;">
+ <DisplayString Condition="(Val.Val.Value &amp; 2) != 2 &amp;&amp; (Val.Val.Value &amp; 1) != 1">{"$T1", s8b}: {($T1)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
+ <DisplayString Condition="(Val.Val.Value &amp; 2) == 2">{"$T2", s8b}: {($T2)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
+ <DisplayString Condition="(Val.Val.Value &amp; 1) == 1">{"$T3", s8b}: {($T3)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
+ <Expand>
+ <ExpandedItem Condition="(Val.Val.Value &amp; 2) != 2 &amp;&amp; (Val.Val.Value &amp; 1) != 1">($T1)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</ExpandedItem>
+ <ExpandedItem Condition="(Val.Val.Value &amp; 2) == 2">($T2)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</ExpandedItem>
+ <ExpandedItem Condition="(Val.Val.Value &amp; 1) == 1">($T3)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</ExpandedItem>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::PointerUnion4&lt;*,*,*,*&gt;">
+ <DisplayString Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 2) != 2 &amp;&amp; (Val.Val.Value &amp; 1) != 1">{"$T1", s8b}: {($T1)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
+ <DisplayString Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 2) == 2">{"$T2", s8b}: {($T2)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
+ <DisplayString Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 1) == 1">{"$T3", s8b}: {($T3)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
+ <DisplayString Condition="(Val.Val.Value &amp; 3) == 3">{"$T4", s8b}: {($T4)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
+ <Expand>
+ <ExpandedItem Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 2) != 2 &amp;&amp; (Val.Val.Value &amp; 1) != 1">($T1)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</ExpandedItem>
+ <ExpandedItem Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 2) == 2">($T2)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</ExpandedItem>
+ <ExpandedItem Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 1) == 1">($T3)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</ExpandedItem>
+ <ExpandedItem Condition="(Val.Val.Value &amp; 3) == 3">($T4)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</ExpandedItem>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::iplist&lt;*,*&gt;">
+ <DisplayString Condition="Head == 0">{{ empty }}</DisplayString>
+ <DisplayString Condition="Head != 0">{{ head={Head} }}</DisplayString>
+ <Expand>
+ <LinkedListItems>
+ <HeadPointer>Head</HeadPointer>
+ <NextPointer>Next</NextPointer>
+ <ValueNode>this</ValueNode>
+ </LinkedListItems>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::IntrusiveRefCntPtr&lt;*&gt;">
+ <DisplayString Condition="Obj == 0">empty</DisplayString>
+ <DisplayString Condition="(Obj != 0) &amp;&amp; (Obj-&gt;ref_cnt == 1)">RefPtr [1 ref] {*Obj}</DisplayString>
+ <DisplayString Condition="(Obj != 0) &amp;&amp; (Obj-&gt;ref_cnt != 1)">RefPtr [{Obj-&gt;ref_cnt} refs] {*Obj}</DisplayString>
+ <Expand>
+ <Item Condition="Obj != 0" Name="[refs]">Obj-&gt;ref_cnt</Item>
+ <ExpandedItem Condition="Obj != 0">Obj</ExpandedItem>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::SmallPtrSet&lt;*,*&gt;">
+ <DisplayString Condition="CurArray == SmallArray">{{ [Small Mode] size={NumElements}, capacity={CurArraySize} }}</DisplayString>
+ <DisplayString Condition="CurArray != SmallArray">{{ [Big Mode] size={NumElements}, capacity={CurArraySize} }}</DisplayString>
+ <Expand>
+ <Item Name="[size]">NumElements</Item>
+ <Item Name="[capacity]">CurArraySize</Item>
+ <ArrayItems>
+ <Size>CurArraySize</Size>
+ <ValuePointer>($T1*)CurArray</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::DenseMap&lt;*,*,*&gt;">
+ <DisplayString Condition="NumEntries == 0">empty</DisplayString>
+ <DisplayString Condition="NumEntries != 0">{{ size={NumEntries}, buckets={NumBuckets} }}</DisplayString>
+ <Expand>
+ <Item Name="[size]">NumEntries</Item>
+ <Item Name="[buckets]">NumBuckets</Item>
+ <ArrayItems>
+ <Size>NumBuckets</Size>
+ <ValuePointer>Buckets</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::StringMap&lt;*,*&gt;">
+ <DisplayString>{{ size={NumItems}, buckets={NumBuckets} }}</DisplayString>
+ <Expand>
+ <Item Name="[size]">NumItems</Item>
+ <Item Name="[buckets]">NumBuckets</Item>
+ <ArrayItems>
+ <Size>NumBuckets</Size>
+ <ValuePointer>(MapEntryTy**)TheTable</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::StringMapEntry&lt;*&gt;">
+ <DisplayString Condition="StrLen == 0">empty</DisplayString>
+ <DisplayString Condition="StrLen != 0">({this+1,s}, {second})</DisplayString>
+ <Expand>
+ <Item Name="[key]">this+1,s</Item>
+ <Item Name="[value]" Condition="StrLen != 0">second</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="llvm::Triple">
+ <DisplayString>{Data}</DisplayString>
+ </Type>
+
+ <Type Name="llvm::Optional&lt;*&gt;">
+ <DisplayString Condition="!hasVal">empty</DisplayString>
+ <DisplayString Condition="hasVal">{*(($T1 *)(unsigned char *)storage.buffer)}</DisplayString>
+ <Expand>
+ <Item Name="[underlying]" Condition="hasVal">*(($T1 *)(unsigned char *)storage.buffer)</Item>
+ </Expand>
+ </Type>
+
+
+ <!-- Since we're in MSVC, we can assume that the system is little endian. Therefore
+ the little and native cases just require a cast. Handle this easy case first. Use
+ a wildcard for the second template argument (the endianness), but we will use a
+ specific value of 0 later on for the big endian to give it priority for being a
+ better match. -->
+ <Type Name="llvm::support::detail::packed_endian_specific_integral&lt;*,*,1&gt;">
+ <DisplayString>{{little endian value = {*(($T1*)(unsigned char *)Value.buffer)} }}</DisplayString>
+ <Expand>
+ <Item Name="[Raw Bytes]" Condition="sizeof($T1)==1">(unsigned char *)Value.buffer,1</Item>
+ <Item Name="[Raw Bytes]" Condition="sizeof($T1)==2">(unsigned char *)Value.buffer,2</Item>
+ <Item Name="[Raw Bytes]" Condition="sizeof($T1)==4">(unsigned char *)Value.buffer,4</Item>
+ <Item Name="[Raw Bytes]" Condition="sizeof($T1)==8">(unsigned char *)Value.buffer,8</Item>
+ </Expand>
+ </Type>
+
+ <!-- Now handle the hard case of big endian. We need to do the swizzling here, but
+ we need to specialize it based on the size of the value type. -->
+ <Type Name="llvm::support::detail::packed_endian_specific_integral&lt;*,0,1&gt;">
+ <DisplayString Condition="sizeof($T1)==1">{{ big endian value = {*(unsigned char *)Value.buffer} }}</DisplayString>
+ <DisplayString Condition="sizeof($T1)==2">{{ big endian value = {(($T1)(*(unsigned char *)Value.buffer) &lt;&lt; 8)
+ | ($T1)(*((unsigned char *)Value.buffer+1))} }}</DisplayString>
+ <DisplayString Condition="sizeof($T1)==4">{{ big endian value = {(($T1)(*(unsigned char *)Value.buffer) &lt;&lt; 24)
+ | (($T1)(*((unsigned char *)Value.buffer+1)) &lt;&lt; 16)
+ | (($T1)(*((unsigned char *)Value.buffer+2)) &lt;&lt; 8)
+ | ($T1)(*((unsigned char *)Value.buffer+3))} }}</DisplayString>
+ <DisplayString Condition="sizeof($T1)==8">{{ big endian value = {(($T1)(*(unsigned char *)Value.buffer) &lt;&lt; 56)
+ | (($T1)(*((unsigned char *)Value.buffer+1)) &lt;&lt; 48)
+ | (($T1)(*((unsigned char *)Value.buffer+2)) &lt;&lt; 40)
+ | (($T1)(*((unsigned char *)Value.buffer+3)) &lt;&lt; 32)
+ | (($T1)(*((unsigned char *)Value.buffer+4)) &lt;&lt; 24)
+ | (($T1)(*((unsigned char *)Value.buffer+5)) &lt;&lt; 16)
+ | (($T1)(*((unsigned char *)Value.buffer+6)) &lt;&lt; 8)
+ | ($T1)(*((unsigned char *)Value.buffer+7))} }}</DisplayString>
+ <Expand>
+ <Item Name="[Raw Bytes]" Condition="sizeof($T1)==1">(unsigned char *)Value.buffer,1</Item>
+ <Item Name="[Raw Bytes]" Condition="sizeof($T1)==2">(unsigned char *)Value.buffer,2</Item>
+ <Item Name="[Raw Bytes]" Condition="sizeof($T1)==4">(unsigned char *)Value.buffer,4</Item>
+ <Item Name="[Raw Bytes]" Condition="sizeof($T1)==8">(unsigned char *)Value.buffer,8</Item>
+ </Expand>
+ </Type>
+</AutoVisualizer>
diff --git a/utils/Makefile b/utils/Makefile
deleted file mode 100644
index a59318de4834e..0000000000000
--- a/utils/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-##===- utils/Makefile --------------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ..
-PARALLEL_DIRS := FileCheck TableGen PerfectShuffle count fpcmp llvm-lit not \
- unittest yaml-bench
-
-EXTRA_DIST := check-each-file codegen-diff countloc.sh \
- DSAclean.py DSAextract.py emacs findsym.pl GenLibDeps.pl \
- getsrcs.sh llvmdo llvmgrep llvm-native-gcc \
- llvm-native-gxx makellvm profile.pl vim
-
-include $(LEVEL)/Makefile.common
diff --git a/utils/Misc/mergefunctions.clang.svn.patch b/utils/Misc/mergefunctions.clang.svn.patch
deleted file mode 100644
index 6e2f0f5227985..0000000000000
--- a/utils/Misc/mergefunctions.clang.svn.patch
+++ /dev/null
@@ -1,14 +0,0 @@
-Index: lib/CodeGen/BackendUtil.cpp
-===================================================================
---- lib/CodeGen/BackendUtil.cpp (revision 191330)
-+++ lib/CodeGen/BackendUtil.cpp (working copy)
-@@ -336,6 +336,9 @@
- MPM->add(createStripSymbolsPass(true));
- }
-
-+ // Force MergeFunctions pass.
-+ MPM->add(createMergeFunctionsPass());
-+
- PMBuilder.populateModulePassManager(*MPM);
- }
-
diff --git a/utils/PerfectShuffle/Makefile b/utils/PerfectShuffle/Makefile
deleted file mode 100644
index 28709fefd319b..0000000000000
--- a/utils/PerfectShuffle/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-##===- utils/PerfectShuffle/Makefile -----------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-TOOLNAME = llvm-PerfectShuffle
-NO_INSTALL = 1
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-include $(LEVEL)/Makefile.common
-
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp
index 6e9a9484dc886..76228e0b6581e 100644
--- a/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/utils/TableGen/AsmMatcherEmitter.cpp
@@ -112,10 +112,10 @@
#include "llvm/TableGen/TableGenBackend.h"
#include <cassert>
#include <cctype>
+#include <forward_list>
#include <map>
#include <set>
-#include <sstream>
-#include <forward_list>
+
using namespace llvm;
#define DEBUG_TYPE "asm-matcher-emitter"
@@ -199,6 +199,14 @@ struct ClassInfo {
/// For custom match classes: the diagnostic kind for when the predicate fails.
std::string DiagnosticType;
+
+ /// Is this operand optional and not always required.
+ bool IsOptional;
+
+ /// DefaultMethod - The name of the method that returns the default operand
+ /// for optional operand
+ std::string DefaultMethod;
+
public:
/// isRegisterClass() - Check if this is a register class.
bool isRegisterClass() const {
@@ -263,34 +271,79 @@ public:
return false;
}
- /// operator< - Compare two classes.
- // FIXME: This ordering seems to be broken. For example:
- // u64 < i64, i64 < s8, s8 < u64, forming a cycle
- // u64 is a subset of i64
- // i64 and s8 are not subsets of each other, so are ordered by name
- // s8 and u64 are not subsets of each other, so are ordered by name
+ int getTreeDepth() const {
+ int Depth = 0;
+ const ClassInfo *Root = this;
+ while (!Root->SuperClasses.empty()) {
+ Depth++;
+ Root = Root->SuperClasses.front();
+ }
+ return Depth;
+ }
+
+ const ClassInfo *findRoot() const {
+ const ClassInfo *Root = this;
+ while (!Root->SuperClasses.empty())
+ Root = Root->SuperClasses.front();
+ return Root;
+ }
+
+ /// Compare two classes. This does not produce a total ordering, but does
+ /// guarantee that subclasses are sorted before their parents, and that the
+ /// ordering is transitive.
bool operator<(const ClassInfo &RHS) const {
if (this == &RHS)
return false;
- // Unrelated classes can be ordered by kind.
- if (!isRelatedTo(RHS))
- return Kind < RHS.Kind;
-
- switch (Kind) {
- case Invalid:
- llvm_unreachable("Invalid kind!");
-
- default:
- // This class precedes the RHS if it is a proper subset of the RHS.
- if (isSubsetOf(RHS))
+ // First, enforce the ordering between the three different types of class.
+ // Tokens sort before registers, which sort before user classes.
+ if (Kind == Token) {
+ if (RHS.Kind != Token)
return true;
- if (RHS.isSubsetOf(*this))
+ assert(RHS.Kind == Token);
+ } else if (isRegisterClass()) {
+ if (RHS.Kind == Token)
return false;
+ else if (RHS.isUserClass())
+ return true;
+ assert(RHS.isRegisterClass());
+ } else if (isUserClass()) {
+ if (!RHS.isUserClass())
+ return false;
+ assert(RHS.isUserClass());
+ } else {
+ llvm_unreachable("Unknown ClassInfoKind");
+ }
- // Otherwise, order by name to ensure we have a total ordering.
- return ValueName < RHS.ValueName;
+ if (Kind == Token || isUserClass()) {
+ // Related tokens and user classes get sorted by depth in the inheritence
+ // tree (so that subclasses are before their parents).
+ if (isRelatedTo(RHS)) {
+ if (getTreeDepth() > RHS.getTreeDepth())
+ return true;
+ if (getTreeDepth() < RHS.getTreeDepth())
+ return false;
+ } else {
+ // Unrelated tokens and user classes are ordered by the name of their
+ // root nodes, so that there is a consistent ordering between
+ // unconnected trees.
+ return findRoot()->ValueName < RHS.findRoot()->ValueName;
+ }
+ } else if (isRegisterClass()) {
+ // For register sets, sort by number of registers. This guarantees that
+ // a set will always sort before all of it's strict supersets.
+ if (Registers.size() != RHS.Registers.size())
+ return Registers.size() < RHS.Registers.size();
+ } else {
+ llvm_unreachable("Unknown ClassInfoKind");
}
+
+ // FIXME: We should be able to just return false here, as we only need a
+ // partial order (we use stable sorts, so this is deterministic) and the
+ // name of a class shouldn't be significant. However, some of the backends
+ // accidentally rely on this behaviour, so it will have to stay like this
+ // until they are fixed.
+ return ValueName < RHS.ValueName;
}
};
@@ -526,8 +579,8 @@ struct MatchableInfo {
/// operator< - Compare two matchables.
bool operator<(const MatchableInfo &RHS) const {
// The primary comparator is the instruction mnemonic.
- if (Mnemonic != RHS.Mnemonic)
- return Mnemonic < RHS.Mnemonic;
+ if (int Cmp = Mnemonic.compare(RHS.Mnemonic))
+ return Cmp == -1;
if (AsmOperands.size() != RHS.AsmOperands.size())
return AsmOperands.size() < RHS.AsmOperands.size();
@@ -637,7 +690,6 @@ struct OperandMatchEntry {
}
};
-
class AsmMatcherInfo {
public:
/// Tracked Records
@@ -720,9 +772,15 @@ public:
RecordKeeper &getRecords() const {
return Records;
}
+
+ bool hasOptionalOperands() const {
+ return std::find_if(Classes.begin(), Classes.end(),
+ [](const ClassInfo& Class){ return Class.IsOptional; })
+ != Classes.end();
+ }
};
-} // End anonymous namespace
+} // end anonymous namespace
void MatchableInfo::dump() const {
errs() << TheDef->getName() << " -- " << "flattened:\"" << AsmString <<"\"\n";
@@ -833,7 +891,6 @@ extractSingletonRegisterForAsmOperand(MatchableInfo::AsmOperand &Op,
// If there is no register prefix (i.e. "%" in "%eax"), then this may
// be some random non-register token, just ignore it.
- return;
}
void MatchableInfo::initialize(const AsmMatcherInfo &Info,
@@ -1071,6 +1128,8 @@ ClassInfo *AsmMatcherInfo::getTokenClass(StringRef Token) {
Entry->RenderMethod = "<invalid>";
Entry->ParserMethod = "";
Entry->DiagnosticType = "";
+ Entry->IsOptional = false;
+ Entry->DefaultMethod = "<invalid>";
}
return Entry;
@@ -1111,7 +1170,6 @@ AsmMatcherInfo::getOperandClass(Record *Rec, int SubOpIdx) {
PrintFatalError(Rec->getLoc(), "register class has no class info!");
}
-
if (Rec->isSubClassOf("RegisterClass")) {
if (ClassInfo *CI = RegisterClassClasses[Rec])
return CI;
@@ -1206,6 +1264,8 @@ buildRegisterClasses(SmallPtrSetImpl<Record*> &SingletonRegisters) {
CI->Registers = RS;
// FIXME: diagnostic type.
CI->DiagnosticType = "";
+ CI->IsOptional = false;
+ CI->DefaultMethod = ""; // unused
RegisterSetClasses.insert(std::make_pair(RS, CI));
++Index;
}
@@ -1320,6 +1380,19 @@ void AsmMatcherInfo::buildOperandClasses() {
if (StringInit *SI = dyn_cast<StringInit>(DiagnosticType))
CI->DiagnosticType = SI->getValue();
+ Init *IsOptional = Rec->getValueInit("IsOptional");
+ if (BitInit *BI = dyn_cast<BitInit>(IsOptional))
+ CI->IsOptional = BI->getValue();
+
+ // Get or construct the default method name.
+ Init *DMName = Rec->getValueInit("DefaultMethod");
+ if (StringInit *SI = dyn_cast<StringInit>(DMName)) {
+ CI->DefaultMethod = SI->getValue();
+ } else {
+ assert(isa<UnsetInit>(DMName) && "Unexpected DefaultMethod field!");
+ CI->DefaultMethod = "default" + CI->ClassName + "Operands";
+ }
+
++Index;
}
}
@@ -1400,7 +1473,7 @@ void AsmMatcherInfo::buildInfo() {
AsmVariant->getValueAsString("BreakCharacters");
Variant.AsmVariantNo = AsmVariant->getValueAsInt("Variant");
- for (const CodeGenInstruction *CGI : Target.instructions()) {
+ for (const CodeGenInstruction *CGI : Target.getInstructionsByEnumValue()) {
// If the tblgen -match-prefix option is specified (for tblgen hackers),
// filter the set of instructions we consider.
@@ -1539,6 +1612,16 @@ void AsmMatcherInfo::buildInfo() {
// Reorder classes so that classes precede super classes.
Classes.sort();
+
+#ifndef NDEBUG
+ // Verify that the table is now sorted
+ for (auto I = Classes.begin(), E = Classes.end(); I != E; ++I) {
+ for (auto J = I; J != E; ++J) {
+ assert(!(*J < *I));
+ assert(I == J || !J->isSubsetOf(*I));
+ }
+ }
+#endif // NDEBUG
}
/// buildInstructionOperandReference - The specified operand is a reference to a
@@ -1744,10 +1827,10 @@ static unsigned getConverterOperandID(const std::string &Name,
return ID;
}
-
static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
std::vector<std::unique_ptr<MatchableInfo>> &Infos,
- bool HasMnemonicFirst, raw_ostream &OS) {
+ bool HasMnemonicFirst, bool HasOptionalOperands,
+ raw_ostream &OS) {
SmallSetVector<std::string, 16> OperandConversionKinds;
SmallSetVector<std::string, 16> InstructionConversionKinds;
std::vector<std::vector<uint8_t> > ConversionTable;
@@ -1762,24 +1845,40 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
std::string ConvertFnBody;
raw_string_ostream CvtOS(ConvertFnBody);
// Start the unified conversion function.
- CvtOS << "void " << Target.getName() << ClassName << "::\n"
- << "convertToMCInst(unsigned Kind, MCInst &Inst, "
- << "unsigned Opcode,\n"
- << " const OperandVector"
- << " &Operands) {\n"
- << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n"
- << " const uint8_t *Converter = ConversionTable[Kind];\n"
- << " Inst.setOpcode(Opcode);\n"
- << " for (const uint8_t *p = Converter; *p; p+= 2) {\n"
- << " switch (*p) {\n"
- << " default: llvm_unreachable(\"invalid conversion entry!\");\n"
- << " case CVT_Reg:\n"
- << " static_cast<" << TargetOperandClass
- << "&>(*Operands[*(p + 1)]).addRegOperands(Inst, 1);\n"
- << " break;\n"
- << " case CVT_Tied:\n"
- << " Inst.addOperand(Inst.getOperand(*(p + 1)));\n"
- << " break;\n";
+ if (HasOptionalOperands) {
+ CvtOS << "void " << Target.getName() << ClassName << "::\n"
+ << "convertToMCInst(unsigned Kind, MCInst &Inst, "
+ << "unsigned Opcode,\n"
+ << " const OperandVector &Operands,\n"
+ << " const SmallBitVector &OptionalOperandsMask) {\n";
+ } else {
+ CvtOS << "void " << Target.getName() << ClassName << "::\n"
+ << "convertToMCInst(unsigned Kind, MCInst &Inst, "
+ << "unsigned Opcode,\n"
+ << " const OperandVector &Operands) {\n";
+ }
+ CvtOS << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n";
+ CvtOS << " const uint8_t *Converter = ConversionTable[Kind];\n";
+ if (HasOptionalOperands) {
+ CvtOS << " unsigned NumDefaults = 0;\n";
+ }
+ CvtOS << " unsigned OpIdx;\n";
+ CvtOS << " Inst.setOpcode(Opcode);\n";
+ CvtOS << " for (const uint8_t *p = Converter; *p; p+= 2) {\n";
+ if (HasOptionalOperands) {
+ CvtOS << " OpIdx = *(p + 1) - NumDefaults;\n";
+ } else {
+ CvtOS << " OpIdx = *(p + 1);\n";
+ }
+ CvtOS << " switch (*p) {\n";
+ CvtOS << " default: llvm_unreachable(\"invalid conversion entry!\");\n";
+ CvtOS << " case CVT_Reg:\n";
+ CvtOS << " static_cast<" << TargetOperandClass
+ << "&>(*Operands[OpIdx]).addRegOperands(Inst, 1);\n";
+ CvtOS << " break;\n";
+ CvtOS << " case CVT_Tied:\n";
+ CvtOS << " Inst.addOperand(Inst.getOperand(OpIdx));\n";
+ CvtOS << " break;\n";
std::string OperandFnBody;
raw_string_ostream OpOS(OperandFnBody);
@@ -1873,6 +1972,11 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
// the index of its entry in the vector).
std::string Name = "CVT_" + (Op.Class->isRegisterClass() ? "Reg" :
Op.Class->RenderMethod);
+ if (Op.Class->IsOptional) {
+ // For optional operands we must also care about DefaultMethod
+ assert(HasOptionalOperands);
+ Name += "_" + Op.Class->DefaultMethod;
+ }
Name = getEnumNameForToken(Name);
bool IsNewConverter = false;
@@ -1888,11 +1992,27 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
// This is a new operand kind. Add a handler for it to the
// converter driver.
- CvtOS << " case " << Name << ":\n"
- << " static_cast<" << TargetOperandClass
- << "&>(*Operands[*(p + 1)])." << Op.Class->RenderMethod
- << "(Inst, " << OpInfo.MINumOperands << ");\n"
- << " break;\n";
+ CvtOS << " case " << Name << ":\n";
+ if (Op.Class->IsOptional) {
+ // If optional operand is not present in actual instruction then we
+ // should call its DefaultMethod before RenderMethod
+ assert(HasOptionalOperands);
+ CvtOS << " if (OptionalOperandsMask[*(p + 1) - 1]) {\n"
+ << " " << Op.Class->DefaultMethod << "()"
+ << "->" << Op.Class->RenderMethod << "(Inst, "
+ << OpInfo.MINumOperands << ");\n"
+ << " ++NumDefaults;\n"
+ << " } else {\n"
+ << " static_cast<" << TargetOperandClass
+ << "&>(*Operands[OpIdx])." << Op.Class->RenderMethod
+ << "(Inst, " << OpInfo.MINumOperands << ");\n"
+ << " }\n";
+ } else {
+ CvtOS << " static_cast<" << TargetOperandClass
+ << "&>(*Operands[OpIdx])." << Op.Class->RenderMethod
+ << "(Inst, " << OpInfo.MINumOperands << ");\n";
+ }
+ CvtOS << " break;\n";
// Add a handler for the operand number lookup.
OpOS << " case " << Name << ":\n"
@@ -2015,7 +2135,6 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName,
OS << " CVT_NUM_SIGNATURES\n";
OS << "};\n\n";
-
OS << "} // end anonymous namespace\n\n";
// Output the conversion table.
@@ -2051,6 +2170,7 @@ static void emitMatchClassEnumeration(CodeGenTarget &Target,
<< "/// instruction matching.\n";
OS << "enum MatchClassKind {\n";
OS << " InvalidMatchClass = 0,\n";
+ OS << " OptionalMatchClass = 1,\n";
for (const auto &CI : Infos) {
OS << " " << CI.Name << ", // ";
if (CI.Kind == ClassInfo::Token) {
@@ -2091,19 +2211,23 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info,
// Check the user classes. We don't care what order since we're only
// actually matching against one of them.
+ OS << " switch (Kind) {\n"
+ " default: break;\n";
for (const auto &CI : Info.Classes) {
if (!CI.isUserClass())
continue;
OS << " // '" << CI.ClassName << "' class\n";
- OS << " if (Kind == " << CI.Name << ") {\n";
+ OS << " case " << CI.Name << ":\n";
OS << " if (Operand." << CI.PredicateMethod << "())\n";
OS << " return MCTargetAsmParser::Match_Success;\n";
if (!CI.DiagnosticType.empty())
OS << " return " << Info.Target.getName() << "AsmParser::Match_"
<< CI.DiagnosticType << ";\n";
- OS << " }\n\n";
+ else
+ OS << " break;\n";
}
+ OS << " } // end switch (Kind)\n\n";
// Check for register operands, including sub-classes.
OS << " if (Operand.isReg()) {\n";
@@ -2137,6 +2261,8 @@ static void emitIsSubclass(CodeGenTarget &Target,
bool EmittedSwitch = false;
for (const auto &A : Infos) {
std::vector<StringRef> SuperClasses;
+ if (A.IsOptional)
+ SuperClasses.push_back("OptionalMatchClass");
for (const auto &B : Infos) {
if (&A != &B && A.isSubsetOf(B))
SuperClasses.push_back(B.Name);
@@ -2225,6 +2351,37 @@ static void emitMatchRegisterName(CodeGenTarget &Target, Record *AsmParser,
OS << "}\n\n";
}
+/// Emit the function to match a string to the target
+/// specific register enum.
+static void emitMatchRegisterAltName(CodeGenTarget &Target, Record *AsmParser,
+ raw_ostream &OS) {
+ // Construct the match list.
+ std::vector<StringMatcher::StringPair> Matches;
+ const auto &Regs = Target.getRegBank().getRegisters();
+ for (const CodeGenRegister &Reg : Regs) {
+
+ auto AltNames = Reg.TheDef->getValueAsListOfStrings("AltNames");
+
+ for (auto AltName : AltNames) {
+ AltName = StringRef(AltName).trim();
+
+ // don't handle empty alternative names
+ if (AltName.empty())
+ continue;
+
+ Matches.emplace_back(AltName,
+ "return " + utostr(Reg.EnumValue) + ";");
+ }
+ }
+
+ OS << "static unsigned MatchRegisterAltName(StringRef Name) {\n";
+
+ StringMatcher("Name", Matches, OS).Emit();
+
+ OS << " return 0;\n";
+ OS << "}\n\n";
+}
+
static const char *getMinimalTypeForRange(uint64_t Range) {
assert(Range <= 0xFFFFFFFFFFFFFFFFULL && "Enum too large");
if (Range > 0xFFFFFFFFULL)
@@ -2665,6 +2822,16 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
const std::unique_ptr<MatchableInfo> &b){
return *a < *b;});
+#ifndef NDEBUG
+ // Verify that the table is now sorted
+ for (auto I = Info.Matchables.begin(), E = Info.Matchables.end(); I != E;
+ ++I) {
+ for (auto J = I; J != E; ++J) {
+ assert(!(**J < **I));
+ }
+ }
+#endif // NDEBUG
+
DEBUG_WITH_TYPE("instruction_info", {
for (const auto &MI : Info.Matchables)
MI->dump();
@@ -2698,6 +2865,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
Info.buildOperandMatchInfo();
bool HasMnemonicFirst = AsmParser->getValueAsBit("HasMnemonicFirst");
+ bool HasOptionalOperands = Info.hasOptionalOperands();
// Write the output.
@@ -2707,10 +2875,16 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " // This should be included into the middle of the declaration of\n";
OS << " // your subclasses implementation of MCTargetAsmParser.\n";
OS << " uint64_t ComputeAvailableFeatures(const FeatureBitset& FB) const;\n";
- OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, "
- << "unsigned Opcode,\n"
- << " const OperandVector "
- << "&Operands);\n";
+ if (HasOptionalOperands) {
+ OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, "
+ << "unsigned Opcode,\n"
+ << " const OperandVector &Operands,\n"
+ << " const SmallBitVector &OptionalOperandsMask);\n";
+ } else {
+ OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, "
+ << "unsigned Opcode,\n"
+ << " const OperandVector &Operands);\n";
+ }
OS << " void convertToMapAndConstraints(unsigned Kind,\n ";
OS << " const OperandVector &Operands) override;\n";
if (HasMnemonicFirst)
@@ -2744,7 +2918,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
emitOperandDiagnosticTypes(Info, OS);
OS << "#endif // GET_OPERAND_DIAGNOSTIC_TYPES\n\n";
-
OS << "\n#ifdef GET_REGISTER_MATCHER\n";
OS << "#undef GET_REGISTER_MATCHER\n\n";
@@ -2756,6 +2929,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
if (AsmParser->getValueAsBit("ShouldEmitMatchRegisterName"))
emitMatchRegisterName(Target, AsmParser, OS);
+ if (AsmParser->getValueAsBit("ShouldEmitMatchRegisterAltName"))
+ emitMatchRegisterAltName(Target, AsmParser, OS);
+
OS << "#endif // GET_REGISTER_MATCHER\n\n";
OS << "\n#ifdef GET_SUBTARGET_FEATURE_NAME\n";
@@ -2775,7 +2951,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
// Generate the convertToMCInst function to convert operands into an MCInst.
// Also, generate the convertToMapAndConstraints function for MS-style inline
// assembly. The latter doesn't actually generate a MCInst.
- emitConvertFuncs(Target, ClassName, Info.Matchables, HasMnemonicFirst, OS);
+ emitConvertFuncs(Target, ClassName, Info.Matchables, HasMnemonicFirst,
+ HasOptionalOperands, OS);
// Emit the enumeration for classes which participate in matching.
emitMatchClassEnumeration(Target, Info.Classes, OS);
@@ -2792,7 +2969,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
// Emit the available features compute function.
emitComputeAvailableFeatures(Info, OS);
-
StringToOffsetTable StringTable;
size_t MaxNumOperands = 0;
@@ -2958,6 +3134,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " bool HadMatchOtherThanPredicate = false;\n";
OS << " unsigned RetCode = Match_InvalidOperand;\n";
OS << " uint64_t MissingFeatures = ~0ULL;\n";
+ if (HasOptionalOperands) {
+ OS << " SmallBitVector OptionalOperandsMask(" << MaxNumOperands << ");\n";
+ }
OS << " // Set ErrorInfo to the operand that mismatches if it is\n";
OS << " // wrong for all instances of the instruction.\n";
OS << " ErrorInfo = ~0ULL;\n";
@@ -3002,36 +3181,55 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
// Emit check that the subclasses match.
OS << " bool OperandsValid = true;\n";
- OS << " for (unsigned i = " << (HasMnemonicFirst ? "0" : "SIndex")
- << "; i != " << MaxNumOperands << "; ++i) {\n";
- OS << " auto Formal = static_cast<MatchClassKind>(it->Classes[i]);\n";
- OS << " if (i" << (HasMnemonicFirst ? "+1" : "")
- << " >= Operands.size()) {\n";
- OS << " OperandsValid = (Formal == " <<"InvalidMatchClass);\n";
- OS << " if (!OperandsValid) ErrorInfo = i"
- << (HasMnemonicFirst ? "+1" : "") << ";\n";
+ if (HasOptionalOperands) {
+ OS << " OptionalOperandsMask.reset(0, " << MaxNumOperands << ");\n";
+ }
+ OS << " for (unsigned FormalIdx = " << (HasMnemonicFirst ? "0" : "SIndex")
+ << ", ActualIdx = " << (HasMnemonicFirst ? "1" : "SIndex")
+ << "; FormalIdx != " << MaxNumOperands << "; ++FormalIdx) {\n";
+ OS << " auto Formal = "
+ << "static_cast<MatchClassKind>(it->Classes[FormalIdx]);\n";
+ OS << " if (ActualIdx >= Operands.size()) {\n";
+ OS << " OperandsValid = (Formal == " <<"InvalidMatchClass) || "
+ "isSubclass(Formal, OptionalMatchClass);\n";
+ OS << " if (!OperandsValid) ErrorInfo = ActualIdx;\n";
+ if (HasOptionalOperands) {
+ OS << " OptionalOperandsMask.set(FormalIdx, " << MaxNumOperands
+ << ");\n";
+ }
OS << " break;\n";
OS << " }\n";
- OS << " MCParsedAsmOperand &Actual = *Operands[i"
- << (HasMnemonicFirst ? "+1" : "") << "];\n";
+ OS << " MCParsedAsmOperand &Actual = *Operands[ActualIdx];\n";
OS << " unsigned Diag = validateOperandClass(Actual, Formal);\n";
- OS << " if (Diag == Match_Success)\n";
+ OS << " if (Diag == Match_Success) {\n";
+ OS << " ++ActualIdx;\n";
OS << " continue;\n";
+ OS << " }\n";
OS << " // If the generic handler indicates an invalid operand\n";
OS << " // failure, check for a special case.\n";
OS << " if (Diag == Match_InvalidOperand) {\n";
OS << " Diag = validateTargetOperandClass(Actual, Formal);\n";
- OS << " if (Diag == Match_Success)\n";
+ OS << " if (Diag == Match_Success) {\n";
+ OS << " ++ActualIdx;\n";
OS << " continue;\n";
+ OS << " }\n";
+ OS << " }\n";
+ OS << " // If current formal operand wasn't matched and it is optional\n"
+ << " // then try to match next formal operand\n";
+ OS << " if (Diag == Match_InvalidOperand "
+ << "&& isSubclass(Formal, OptionalMatchClass)) {\n";
+ if (HasOptionalOperands) {
+ OS << " OptionalOperandsMask.set(FormalIdx);\n";
+ }
+ OS << " continue;\n";
OS << " }\n";
OS << " // If this operand is broken for all of the instances of this\n";
OS << " // mnemonic, keep track of it so we can report loc info.\n";
OS << " // If we already had a match that only failed due to a\n";
OS << " // target predicate, that diagnostic is preferred.\n";
OS << " if (!HadMatchOtherThanPredicate &&\n";
- OS << " (it == MnemonicRange.first || ErrorInfo <= i"
- << (HasMnemonicFirst ? "+1" : "") << ")) {\n";
- OS << " ErrorInfo = i" << (HasMnemonicFirst ? "+1" : "") << ";\n";
+ OS << " (it == MnemonicRange.first || ErrorInfo <= ActualIdx)) {\n";
+ OS << " ErrorInfo = ActualIdx;\n";
OS << " // InvalidOperand is the default. Prefer specificity.\n";
OS << " if (Diag != Match_InvalidOperand)\n";
OS << " RetCode = Diag;\n";
@@ -3063,7 +3261,12 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " }\n\n";
OS << " // We have selected a definite instruction, convert the parsed\n"
<< " // operands into the appropriate MCInst.\n";
- OS << " convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands);\n";
+ if (HasOptionalOperands) {
+ OS << " convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands,\n"
+ << " OptionalOperandsMask);\n";
+ } else {
+ OS << " convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands);\n";
+ }
OS << "\n";
// Verify the instruction with the target-specific match predicate function.
@@ -3118,4 +3321,4 @@ void EmitAsmMatcher(RecordKeeper &RK, raw_ostream &OS) {
AsmMatcherEmitter(RK).run(OS);
}
-} // End llvm namespace
+} // end namespace llvm
diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp
index cf7cbd962865c..fc2138f7e8ea3 100644
--- a/utils/TableGen/AsmWriterEmitter.cpp
+++ b/utils/TableGen/AsmWriterEmitter.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This tablegen backend is emits an assembly printer for the current target.
+// This tablegen backend emits an assembly printer for the current target.
// Note that this is currently fairly skeletal, but will grow over time.
//
//===----------------------------------------------------------------------===//
@@ -27,6 +27,7 @@
#include <algorithm>
#include <cassert>
#include <map>
+#include <utility>
#include <vector>
using namespace llvm;
@@ -36,10 +37,8 @@ namespace {
class AsmWriterEmitter {
RecordKeeper &Records;
CodeGenTarget Target;
- std::map<const CodeGenInstruction*, AsmWriterInst*> CGIAWIMap;
- const std::vector<const CodeGenInstruction*> *NumberedInstructions;
+ ArrayRef<const CodeGenInstruction *> NumberedInstructions;
std::vector<AsmWriterInst> Instructions;
- std::vector<std::string> PrintMethods;
public:
AsmWriterEmitter(RecordKeeper &R);
@@ -50,21 +49,16 @@ private:
void EmitGetRegisterName(raw_ostream &o);
void EmitPrintAliasInstruction(raw_ostream &O);
- AsmWriterInst *getAsmWriterInstByID(unsigned ID) const {
- assert(ID < NumberedInstructions->size());
- std::map<const CodeGenInstruction*, AsmWriterInst*>::const_iterator I =
- CGIAWIMap.find(NumberedInstructions->at(ID));
- assert(I != CGIAWIMap.end() && "Didn't find inst!");
- return I->second;
- }
void FindUniqueOperandCommands(std::vector<std::string> &UOC,
- std::vector<unsigned> &InstIdxs,
- std::vector<unsigned> &InstOpsUsed) const;
+ std::vector<std::vector<unsigned>> &InstIdxs,
+ std::vector<unsigned> &InstOpsUsed,
+ bool PassSubtarget) const;
};
} // end anonymous namespace
static void PrintCases(std::vector<std::pair<std::string,
- AsmWriterOperand> > &OpsToPrint, raw_ostream &O) {
+ AsmWriterOperand> > &OpsToPrint, raw_ostream &O,
+ bool PassSubtarget) {
O << " case " << OpsToPrint.back().first << ":";
AsmWriterOperand TheOp = OpsToPrint.back().second;
OpsToPrint.pop_back();
@@ -78,7 +72,7 @@ static void PrintCases(std::vector<std::pair<std::string,
}
// Finally, emit the code.
- O << "\n " << TheOp.getCode();
+ O << "\n " << TheOp.getCode(PassSubtarget);
O << "\n break;\n";
}
@@ -86,7 +80,7 @@ static void PrintCases(std::vector<std::pair<std::string,
/// EmitInstructions - Emit the last instruction in the vector and any other
/// instructions that are suitably similar to it.
static void EmitInstructions(std::vector<AsmWriterInst> &Insts,
- raw_ostream &O) {
+ raw_ostream &O, bool PassSubtarget) {
AsmWriterInst FirstInst = Insts.back();
Insts.pop_back();
@@ -115,7 +109,7 @@ static void EmitInstructions(std::vector<AsmWriterInst> &Insts,
for (unsigned i = 0, e = FirstInst.Operands.size(); i != e; ++i) {
if (i != DifferingOperand) {
// If the operand is the same for all instructions, just print it.
- O << " " << FirstInst.Operands[i].getCode();
+ O << " " << FirstInst.Operands[i].getCode(PassSubtarget);
} else {
// If this is the operand that varies between all of the instructions,
// emit a switch for just this operand now.
@@ -133,7 +127,7 @@ static void EmitInstructions(std::vector<AsmWriterInst> &Insts,
}
std::reverse(OpsToPrint.begin(), OpsToPrint.end());
while (!OpsToPrint.empty())
- PrintCases(OpsToPrint, O);
+ PrintCases(OpsToPrint, O, PassSubtarget);
O << " }";
}
O << "\n";
@@ -143,9 +137,9 @@ static void EmitInstructions(std::vector<AsmWriterInst> &Insts,
void AsmWriterEmitter::
FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
- std::vector<unsigned> &InstIdxs,
- std::vector<unsigned> &InstOpsUsed) const {
- InstIdxs.assign(NumberedInstructions->size(), ~0U);
+ std::vector<std::vector<unsigned>> &InstIdxs,
+ std::vector<unsigned> &InstOpsUsed,
+ bool PassSubtarget) const {
// This vector parallels UniqueOperandCommands, keeping track of which
// instructions each case are used for. It is a comma separated string of
@@ -154,31 +148,27 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
InstrsForCase.resize(UniqueOperandCommands.size());
InstOpsUsed.assign(UniqueOperandCommands.size(), 0);
- for (unsigned i = 0, e = NumberedInstructions->size(); i != e; ++i) {
- const AsmWriterInst *Inst = getAsmWriterInstByID(i);
- if (!Inst)
- continue; // PHI, INLINEASM, CFI_INSTRUCTION, etc.
-
- if (Inst->Operands.empty())
+ for (size_t i = 0, e = Instructions.size(); i != e; ++i) {
+ const AsmWriterInst &Inst = Instructions[i];
+ if (Inst.Operands.empty())
continue; // Instruction already done.
- std::string Command = " " + Inst->Operands[0].getCode() + "\n";
+ std::string Command = " "+Inst.Operands[0].getCode(PassSubtarget)+"\n";
// Check to see if we already have 'Command' in UniqueOperandCommands.
// If not, add it.
- bool FoundIt = false;
- for (unsigned idx = 0, e = UniqueOperandCommands.size(); idx != e; ++idx)
- if (UniqueOperandCommands[idx] == Command) {
- InstIdxs[i] = idx;
- InstrsForCase[idx] += ", ";
- InstrsForCase[idx] += Inst->CGI->TheDef->getName();
- FoundIt = true;
- break;
- }
- if (!FoundIt) {
- InstIdxs[i] = UniqueOperandCommands.size();
+ auto I = std::find(UniqueOperandCommands.begin(),
+ UniqueOperandCommands.end(), Command);
+ if (I != UniqueOperandCommands.end()) {
+ size_t idx = I - UniqueOperandCommands.begin();
+ InstrsForCase[idx] += ", ";
+ InstrsForCase[idx] += Inst.CGI->TheDef->getName();
+ InstIdxs[idx].push_back(i);
+ } else {
UniqueOperandCommands.push_back(std::move(Command));
- InstrsForCase.push_back(Inst->CGI->TheDef->getName());
+ InstrsForCase.push_back(Inst.CGI->TheDef->getName());
+ InstIdxs.emplace_back();
+ InstIdxs.back().push_back(i);
// This command matches one operand so far.
InstOpsUsed.push_back(1);
@@ -188,45 +178,33 @@ FindUniqueOperandCommands(std::vector<std::string> &UniqueOperandCommands,
// For each entry of UniqueOperandCommands, there is a set of instructions
// that uses it. If the next command of all instructions in the set are
// identical, fold it into the command.
- for (unsigned CommandIdx = 0, e = UniqueOperandCommands.size();
+ for (size_t CommandIdx = 0, e = UniqueOperandCommands.size();
CommandIdx != e; ++CommandIdx) {
- for (unsigned Op = 1; ; ++Op) {
- // Scan for the first instruction in the set.
- std::vector<unsigned>::iterator NIT =
- std::find(InstIdxs.begin(), InstIdxs.end(), CommandIdx);
- if (NIT == InstIdxs.end()) break; // No commonality.
+ const auto &Idxs = InstIdxs[CommandIdx];
+ for (unsigned Op = 1; ; ++Op) {
+ // Find the first instruction in the set.
+ const AsmWriterInst &FirstInst = Instructions[Idxs.front()];
// If this instruction has no more operands, we isn't anything to merge
// into this command.
- const AsmWriterInst *FirstInst =
- getAsmWriterInstByID(NIT-InstIdxs.begin());
- if (!FirstInst || FirstInst->Operands.size() == Op)
+ if (FirstInst.Operands.size() == Op)
break;
// Otherwise, scan to see if all of the other instructions in this command
// set share the operand.
- bool AllSame = true;
-
- for (NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx);
- NIT != InstIdxs.end();
- NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx)) {
- // Okay, found another instruction in this command set. If the operand
- // matches, we're ok, otherwise bail out.
- const AsmWriterInst *OtherInst =
- getAsmWriterInstByID(NIT-InstIdxs.begin());
-
- if (!OtherInst || OtherInst->Operands.size() == Op ||
- OtherInst->Operands[Op] != FirstInst->Operands[Op]) {
- AllSame = false;
- break;
- }
- }
- if (!AllSame) break;
+ if (std::any_of(Idxs.begin()+1, Idxs.end(),
+ [&](unsigned Idx) {
+ const AsmWriterInst &OtherInst = Instructions[Idx];
+ return OtherInst.Operands.size() == Op ||
+ OtherInst.Operands[Op] != FirstInst.Operands[Op];
+ }))
+ break;
// Okay, everything in this command set has the same next operand. Add it
// to UniqueOperandCommands and remember that it was consumed.
- std::string Command = " " + FirstInst->Operands[Op].getCode() + "\n";
+ std::string Command = " " +
+ FirstInst.Operands[Op].getCode(PassSubtarget) + "\n";
UniqueOperandCommands[CommandIdx] += Command;
InstOpsUsed[CommandIdx]++;
@@ -277,7 +255,7 @@ static void UnescapeString(std::string &Str) {
void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
Record *AsmWriter = Target.getAsmWriter();
std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
- unsigned PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");
+ bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");
O <<
"/// printInstruction - This method is automatically generated by tablegen\n"
@@ -292,18 +270,16 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
/// OpcodeInfo - This encodes the index of the string to use for the first
/// chunk of the output as well as indices used for operand printing.
- std::vector<uint64_t> OpcodeInfo;
+ std::vector<uint64_t> OpcodeInfo(NumberedInstructions.size());
const unsigned OpcodeInfoBits = 64;
// Add all strings to the string table upfront so it can generate an optimized
// representation.
- for (const CodeGenInstruction *Inst : *NumberedInstructions) {
- AsmWriterInst *AWI = CGIAWIMap[Inst];
- if (AWI &&
- AWI->Operands[0].OperandType ==
+ for (AsmWriterInst &AWI : Instructions) {
+ if (AWI.Operands[0].OperandType ==
AsmWriterOperand::isLiteralTextOperand &&
- !AWI->Operands[0].Str.empty()) {
- std::string Str = AWI->Operands[0].Str;
+ !AWI.Operands[0].Str.empty()) {
+ std::string Str = AWI.Operands[0].Str;
UnescapeString(Str);
StringTable.add(Str);
}
@@ -312,29 +288,24 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
StringTable.layout();
unsigned MaxStringIdx = 0;
- for (const CodeGenInstruction *Inst : *NumberedInstructions) {
- AsmWriterInst *AWI = CGIAWIMap[Inst];
+ for (AsmWriterInst &AWI : Instructions) {
unsigned Idx;
- if (!AWI) {
- // Something not handled by the asmwriter printer.
- Idx = ~0U;
- } else if (AWI->Operands[0].OperandType !=
- AsmWriterOperand::isLiteralTextOperand ||
- AWI->Operands[0].Str.empty()) {
+ if (AWI.Operands[0].OperandType != AsmWriterOperand::isLiteralTextOperand ||
+ AWI.Operands[0].Str.empty()) {
// Something handled by the asmwriter printer, but with no leading string.
Idx = StringTable.get("");
} else {
- std::string Str = AWI->Operands[0].Str;
+ std::string Str = AWI.Operands[0].Str;
UnescapeString(Str);
Idx = StringTable.get(Str);
MaxStringIdx = std::max(MaxStringIdx, Idx);
// Nuke the string from the operand list. It is now handled!
- AWI->Operands.erase(AWI->Operands.begin());
+ AWI.Operands.erase(AWI.Operands.begin());
}
// Bias offset by one since we want 0 as a sentinel.
- OpcodeInfo.push_back(Idx+1);
+ OpcodeInfo[AWI.CGIIndex] = Idx+1;
}
// Figure out how many bits we used for the string index.
@@ -348,10 +319,10 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
while (1) {
std::vector<std::string> UniqueOperandCommands;
- std::vector<unsigned> InstIdxs;
+ std::vector<std::vector<unsigned>> InstIdxs;
std::vector<unsigned> NumInstOpsHandled;
FindUniqueOperandCommands(UniqueOperandCommands, InstIdxs,
- NumInstOpsHandled);
+ NumInstOpsHandled, PassSubtarget);
// If we ran out of operands to print, we're done.
if (UniqueOperandCommands.empty()) break;
@@ -368,23 +339,22 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
}
// Otherwise, we can include this in the initial lookup table. Add it in.
- for (unsigned i = 0, e = InstIdxs.size(); i != e; ++i)
- if (InstIdxs[i] != ~0U) {
- OpcodeInfo[i] |= (uint64_t)InstIdxs[i] << (OpcodeInfoBits-BitsLeft);
- }
- BitsLeft -= NumBits;
-
- // Remove the info about this operand.
- for (unsigned i = 0, e = NumberedInstructions->size(); i != e; ++i) {
- if (AsmWriterInst *Inst = getAsmWriterInstByID(i))
- if (!Inst->Operands.empty()) {
- unsigned NumOps = NumInstOpsHandled[InstIdxs[i]];
- assert(NumOps <= Inst->Operands.size() &&
+ for (size_t i = 0, e = InstIdxs.size(); i != e; ++i) {
+ unsigned NumOps = NumInstOpsHandled[i];
+ for (unsigned Idx : InstIdxs[i]) {
+ OpcodeInfo[Instructions[Idx].CGIIndex] |=
+ (uint64_t)i << (OpcodeInfoBits-BitsLeft);
+ // Remove the info about this operand from the instruction.
+ AsmWriterInst &Inst = Instructions[Idx];
+ if (!Inst.Operands.empty()) {
+ assert(NumOps <= Inst.Operands.size() &&
"Can't remove this many ops!");
- Inst->Operands.erase(Inst->Operands.begin(),
- Inst->Operands.begin()+NumOps);
+ Inst.Operands.erase(Inst.Operands.begin(),
+ Inst.Operands.begin()+NumOps);
}
+ }
}
+ BitsLeft -= NumBits;
// Remember the handlers for this set of operands.
TableDrivenOperandPrinters.push_back(std::move(UniqueOperandCommands));
@@ -411,9 +381,9 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
uint64_t Mask = (1ULL << TableSize) - 1;
O << " static const uint" << TableSize << "_t OpInfo" << Table
<< "[] = {\n";
- for (unsigned i = 0, e = NumberedInstructions->size(); i != e; ++i) {
+ for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
O << " " << ((OpcodeInfo[i] >> Shift) & Mask) << "U,\t// "
- << NumberedInstructions->at(i)->TheDef->getName() << "\n";
+ << NumberedInstructions[i]->TheDef->getName() << "\n";
}
O << " };\n\n";
// Emit string to combine the individual table lookups.
@@ -502,7 +472,7 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) {
O << " switch (MI->getOpcode()) {\n";
O << " default: llvm_unreachable(\"Unexpected opcode.\");\n";
while (!Instructions.empty())
- EmitInstructions(Instructions, O);
+ EmitInstructions(Instructions, O, PassSubtarget);
O << " }\n";
}
@@ -578,7 +548,7 @@ void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {
Record *AsmWriter = Target.getAsmWriter();
std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
const auto &Registers = Target.getRegBank().getRegisters();
- std::vector<Record*> AltNameIndices = Target.getRegAltNameIndices();
+ const std::vector<Record*> &AltNameIndices = Target.getRegAltNameIndices();
bool hasAltNames = AltNameIndices.size() > 1;
std::string Namespace =
Registers.front().TheDef->getValueAsString("Namespace");
@@ -606,7 +576,7 @@ void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {
O << " switch(AltIdx) {\n"
<< " default: llvm_unreachable(\"Invalid register alt name index!\");\n";
for (const Record *R : AltNameIndices) {
- std::string AltName(R->getName());
+ const std::string &AltName = R->getName();
std::string Prefix = !Namespace.empty() ? Namespace + "::" : "";
O << " case " << Prefix << AltName << ":\n"
<< " assert(*(AsmStrs" << AltName << "+RegAsmOffset"
@@ -631,12 +601,12 @@ namespace {
class IAPrinter {
std::vector<std::string> Conds;
std::map<StringRef, std::pair<int, int>> OpMap;
- SmallVector<Record*, 4> ReqFeatures;
std::string Result;
std::string AsmString;
public:
- IAPrinter(std::string R, std::string AS) : Result(R), AsmString(AS) {}
+ IAPrinter(std::string R, std::string AS)
+ : Result(std::move(R)), AsmString(std::move(AS)) {}
void addCond(const std::string &C) { Conds.push_back(C); }
@@ -677,7 +647,7 @@ public:
}
void print(raw_ostream &O) {
- if (Conds.empty() && ReqFeatures.empty()) {
+ if (Conds.empty()) {
O.indent(6) << "return true;\n";
return;
}
@@ -784,7 +754,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
// Emit the method that prints the alias instruction.
std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
unsigned Variant = AsmWriter->getValueAsInt("Variant");
- unsigned PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");
+ bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");
std::vector<Record*> AllInstAliases =
Records.getAllDerivedDefinitions("InstAlias");
@@ -808,6 +778,8 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
// before it can be matched to the mnemonic.
std::map<std::string, std::vector<IAPrinter>> IAPrinterMap;
+ std::vector<std::string> PrintMethods;
+
// A list of MCOperandPredicates for all operands in use, and the reverse map
std::vector<const Record*> MCOpPredicates;
DenseMap<const Record*, unsigned> MCOpPredicateMap;
@@ -825,6 +797,18 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
IAPrinter IAP(CGA.Result->getAsString(), CGA.AsmString);
+ std::string Namespace = Target.getName();
+ std::vector<Record *> ReqFeatures;
+ if (PassSubtarget) {
+ // We only consider ReqFeatures predicates if PassSubtarget
+ std::vector<Record *> RF =
+ CGA.TheDef->getValueAsListOfDefs("Predicates");
+ std::copy_if(RF.begin(), RF.end(), std::back_inserter(ReqFeatures),
+ [](Record *R) {
+ return R->getValueAsBit("AssemblerMatcherPredicate");
+ });
+ }
+
unsigned NumMIOps = 0;
for (auto &Operand : CGA.ResultOperands)
NumMIOps += Operand.getMINumOperands();
@@ -929,6 +913,27 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
}
if (CantHandle) continue;
+
+ for (auto I = ReqFeatures.cbegin(); I != ReqFeatures.cend(); I++) {
+ Record *R = *I;
+ std::string AsmCondString = R->getValueAsString("AssemblerCondString");
+
+ // AsmCondString has syntax [!]F(,[!]F)*
+ SmallVector<StringRef, 4> Ops;
+ SplitString(AsmCondString, Ops, ",");
+ assert(!Ops.empty() && "AssemblerCondString cannot be empty");
+
+ for (auto &Op : Ops) {
+ assert(!Op.empty() && "Empty operator");
+ if (Op[0] == '!')
+ Cond = "!STI.getFeatureBits()[" + Namespace + "::" +
+ Op.substr(1).str() + "]";
+ else
+ Cond = "STI.getFeatureBits()[" + Namespace + "::" + Op.str() + "]";
+ IAP.addCond(Cond);
+ }
+ }
+
IAPrinterMap[Aliases.first].push_back(std::move(IAP));
}
}
@@ -1002,13 +1007,14 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
// Code that prints the alias, replacing the operands with the ones from the
// MCInst.
O << " unsigned I = 0;\n";
- O << " while (AsmString[I] != ' ' && AsmString[I] != '\t' &&\n";
- O << " AsmString[I] != '\\0')\n";
+ O << " while (AsmString[I] != ' ' && AsmString[I] != '\\t' &&\n";
+ O << " AsmString[I] != '$' && AsmString[I] != '\\0')\n";
O << " ++I;\n";
O << " OS << '\\t' << StringRef(AsmString, I);\n";
O << " if (AsmString[I] != '\\0') {\n";
- O << " OS << '\\t';\n";
+ O << " if (AsmString[I] == ' ' || AsmString[I] == '\\t')";
+ O << " OS << '\\t';\n";
O << " do {\n";
O << " if (AsmString[I] == '$') {\n";
O << " ++I;\n";
@@ -1072,7 +1078,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
for (unsigned i = 0; i < MCOpPredicates.size(); ++i) {
Init *MCOpPred = MCOpPredicates[i]->getValueInit("MCOperandPredicate");
- if (StringInit *SI = dyn_cast<StringInit>(MCOpPred)) {
+ if (CodeInit *SI = dyn_cast<CodeInit>(MCOpPred)) {
O << " case " << i + 1 << ": {\n"
<< SI->getValue() << "\n"
<< " }\n";
@@ -1089,19 +1095,15 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
AsmWriterEmitter::AsmWriterEmitter(RecordKeeper &R) : Records(R), Target(R) {
Record *AsmWriter = Target.getAsmWriter();
unsigned Variant = AsmWriter->getValueAsInt("Variant");
- unsigned PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");
- for (const CodeGenInstruction *I : Target.instructions())
- if (!I->AsmString.empty() && I->TheDef->getName() != "PHI")
- Instructions.emplace_back(*I, Variant, PassSubtarget);
// Get the instruction numbering.
- NumberedInstructions = &Target.getInstructionsByEnumValue();
+ NumberedInstructions = Target.getInstructionsByEnumValue();
- // Compute the CodeGenInstruction -> AsmWriterInst mapping. Note that not
- // all machine instructions are necessarily being printed, so there may be
- // target instructions not in this map.
- for (AsmWriterInst &AWI : Instructions)
- CGIAWIMap.insert(std::make_pair(AWI.CGI, &AWI));
+ for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
+ const CodeGenInstruction *I = NumberedInstructions[i];
+ if (!I->AsmString.empty() && I->TheDef->getName() != "PHI")
+ Instructions.emplace_back(*I, i, Variant);
+ }
}
void AsmWriterEmitter::run(raw_ostream &O) {
diff --git a/utils/TableGen/AsmWriterInst.cpp b/utils/TableGen/AsmWriterInst.cpp
index 5b09765a2756b..2c19e5d663d66 100644
--- a/utils/TableGen/AsmWriterInst.cpp
+++ b/utils/TableGen/AsmWriterInst.cpp
@@ -26,7 +26,7 @@ static bool isIdentChar(char C) {
C == '_';
}
-std::string AsmWriterOperand::getCode() const {
+std::string AsmWriterOperand::getCode(bool PassSubtarget) const {
if (OperandType == isLiteralTextOperand) {
if (Str.size() == 1)
return "O << '" + Str + "';";
@@ -50,9 +50,9 @@ std::string AsmWriterOperand::getCode() const {
/// ParseAsmString - Parse the specified Instruction's AsmString into this
/// AsmWriterInst.
///
-AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant,
- unsigned PassSubtarget) {
- this->CGI = &CGI;
+AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex,
+ unsigned Variant)
+ : CGI(&CGI), CGIIndex(CGIIndex) {
// NOTE: Any extensions to this code need to be mirrored in the
// AsmPrinter::printInlineAsm code that executes as compile time (assuming
@@ -120,8 +120,7 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant,
while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd]))
++VarEnd;
- std::string VarName(AsmString.begin()+DollarPos+1,
- AsmString.begin()+VarEnd);
+ StringRef VarName(AsmString.data()+DollarPos+1, VarEnd-DollarPos-1);
// Modifier - Support ${foo:modifier} syntax, where "modifier" is passed
// into printOperand. Also support ${:feature}, which is passed into
@@ -143,7 +142,7 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant,
PrintFatalError("Reached end of string before terminating curly brace in '"
+ CGI.TheDef->getName() + "'");
- unsigned ModifierStart = VarEnd;
+ std::string::size_type ModifierStart = VarEnd;
while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd]))
++VarEnd;
Modifier = std::string(AsmString.begin()+ModifierStart,
@@ -163,16 +162,14 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant,
if (VarName.empty()) {
// Just a modifier, pass this into PrintSpecial.
- Operands.emplace_back("PrintSpecial", ~0U, ~0U, Modifier,
- PassSubtarget);
+ Operands.emplace_back("PrintSpecial", ~0U, Modifier);
} else {
// Otherwise, normal operand.
unsigned OpNo = CGI.Operands.getOperandNamed(VarName);
CGIOperandList::OperandInfo OpInfo = CGI.Operands[OpNo];
unsigned MIOp = OpInfo.MIOperandNo;
- Operands.emplace_back(OpInfo.PrinterMethodName, OpNo, MIOp, Modifier,
- PassSubtarget);
+ Operands.emplace_back(OpInfo.PrinterMethodName, MIOp, Modifier);
}
LastEmitted = VarEnd;
}
diff --git a/utils/TableGen/AsmWriterInst.h b/utils/TableGen/AsmWriterInst.h
index a597e6ba1a558..708f23cb5b0ef 100644
--- a/utils/TableGen/AsmWriterInst.h
+++ b/utils/TableGen/AsmWriterInst.h
@@ -35,29 +35,20 @@ namespace llvm {
isLiteralStatementOperand
} OperandType;
+ /// MiOpNo - For isMachineInstrOperand, this is the operand number of the
+ /// machine instruction.
+ unsigned MIOpNo;
+
/// Str - For isLiteralTextOperand, this IS the literal text. For
/// isMachineInstrOperand, this is the PrinterMethodName for the operand..
/// For isLiteralStatementOperand, this is the code to insert verbatim
/// into the asm writer.
std::string Str;
- /// CGIOpNo - For isMachineInstrOperand, this is the index of the operand in
- /// the CodeGenInstruction.
- unsigned CGIOpNo;
-
- /// MiOpNo - For isMachineInstrOperand, this is the operand number of the
- /// machine instruction.
- unsigned MIOpNo;
-
/// MiModifier - For isMachineInstrOperand, this is the modifier string for
/// an operand, specified with syntax like ${opname:modifier}.
std::string MiModifier;
- // PassSubtarget - Pass MCSubtargetInfo to the print method if this is
- // equal to 1.
- // FIXME: Remove after all ports are updated.
- unsigned PassSubtarget;
-
// To make VS STL happy
AsmWriterOperand(OpType op = isLiteralTextOperand):OperandType(op) {}
@@ -66,13 +57,10 @@ namespace llvm {
: OperandType(op), Str(LitStr) {}
AsmWriterOperand(const std::string &Printer,
- unsigned _CGIOpNo,
unsigned _MIOpNo,
const std::string &Modifier,
- unsigned PassSubtarget,
OpType op = isMachineInstrOperand)
- : OperandType(op), Str(Printer), CGIOpNo(_CGIOpNo), MIOpNo(_MIOpNo),
- MiModifier(Modifier), PassSubtarget(PassSubtarget) {}
+ : OperandType(op), MIOpNo(_MIOpNo), Str(Printer), MiModifier(Modifier) {}
bool operator!=(const AsmWriterOperand &Other) const {
if (OperandType != Other.OperandType || Str != Other.Str) return true;
@@ -85,16 +73,17 @@ namespace llvm {
}
/// getCode - Return the code that prints this operand.
- std::string getCode() const;
+ std::string getCode(bool PassSubtarget) const;
};
class AsmWriterInst {
public:
std::vector<AsmWriterOperand> Operands;
const CodeGenInstruction *CGI;
+ unsigned CGIIndex;
- AsmWriterInst(const CodeGenInstruction &CGI,
- unsigned Variant, unsigned PassSubtarget);
+ AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex,
+ unsigned Variant);
/// MatchesAllButOneOp - If this instruction is exactly identical to the
/// specified instruction except for one differing operand, return the
diff --git a/utils/TableGen/Attributes.cpp b/utils/TableGen/Attributes.cpp
index 7b001bf14de58..58dbe5767adab 100644
--- a/utils/TableGen/Attributes.cpp
+++ b/utils/TableGen/Attributes.cpp
@@ -27,6 +27,7 @@ public:
private:
void emitTargetIndependentEnums(raw_ostream &OS);
+ void emitConversionFn(raw_ostream &OS);
void emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr);
void printEnumAttrClasses(raw_ostream &OS,
@@ -52,6 +53,27 @@ void Attributes::emitTargetIndependentEnums(raw_ostream &OS) {
OS << "#endif\n";
}
+void Attributes::emitConversionFn(raw_ostream &OS) {
+ OS << "#ifdef GET_ATTR_KIND_FROM_NAME\n";
+ OS << "#undef GET_ATTR_KIND_FROM_NAME\n";
+
+ std::vector<Record*> Attrs =
+ Records.getAllDerivedDefinitions("EnumAttr");
+
+ OS << "static Attribute::AttrKind getAttrKindFromName(StringRef AttrName) {\n";
+ OS << " return StringSwitch<Attribute::AttrKind>(AttrName)\n";
+
+ for (auto A : Attrs) {
+ OS << " .Case(\"" << A->getValueAsString("AttrString");
+ OS << "\", Attribute::" << A->getName() << ")\n";
+ }
+
+ OS << " .Default(Attribute::None);\n";
+ OS << "}\n\n";
+
+ OS << "#endif\n";
+}
+
void Attributes::emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr) {
OS << "#ifdef GET_ATTR_COMPAT_FUNC\n";
OS << "#undef GET_ATTR_COMPAT_FUNC\n";
@@ -144,6 +166,7 @@ void Attributes::printStrBoolAttrClasses(raw_ostream &OS,
void Attributes::emit(raw_ostream &OS) {
emitTargetIndependentEnums(OS);
+ emitConversionFn(OS);
emitFnAttrCompatCheck(OS, false);
}
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
index eef1540424dd1..e8fe30f5ac704 100644
--- a/utils/TableGen/CMakeLists.txt
+++ b/utils/TableGen/CMakeLists.txt
@@ -27,6 +27,7 @@ add_tablegen(llvm-tblgen LLVM
OptParserEmitter.cpp
PseudoLoweringEmitter.cpp
RegisterInfoEmitter.cpp
+ SearchableTableEmitter.cpp
SubtargetEmitter.cpp
TableGen.cpp
X86DisassemblerTables.cpp
diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp
index 46fcdf5e96ffd..400913e327459 100644
--- a/utils/TableGen/CodeEmitterGen.cpp
+++ b/utils/TableGen/CodeEmitterGen.cpp
@@ -15,7 +15,6 @@
#include "CodeGenTarget.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
@@ -227,7 +226,7 @@ void CodeEmitterGen::run(raw_ostream &o) {
// For little-endian instruction bit encodings, reverse the bit order
Target.reverseBitsForLittleEndianEncoding();
- const std::vector<const CodeGenInstruction*> &NumberedInstructions =
+ ArrayRef<const CodeGenInstruction*> NumberedInstructions =
Target.getInstructionsByEnumValue();
// Emit function declaration
@@ -238,11 +237,7 @@ void CodeEmitterGen::run(raw_ostream &o) {
// Emit instruction base values
o << " static const uint64_t InstBits[] = {\n";
- for (std::vector<const CodeGenInstruction*>::const_iterator
- IN = NumberedInstructions.begin(),
- EN = NumberedInstructions.end();
- IN != EN; ++IN) {
- const CodeGenInstruction *CGI = *IN;
+ for (const CodeGenInstruction *CGI : NumberedInstructions) {
Record *R = CGI->TheDef;
if (R->getValueAsString("Namespace") == "TargetOpcode" ||
diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp
index 3ebe51e05121d..307a95373c9d0 100644
--- a/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -2392,8 +2392,8 @@ void TreePattern::dump() const { print(errs()); }
CodeGenDAGPatterns::CodeGenDAGPatterns(RecordKeeper &R) :
Records(R), Target(R) {
- Intrinsics = LoadIntrinsics(Records, false);
- TgtIntrinsics = LoadIntrinsics(Records, true);
+ Intrinsics = CodeGenIntrinsicTable(Records, false);
+ TgtIntrinsics = CodeGenIntrinsicTable(Records, true);
ParseNodeInfo();
ParseNodeTransforms();
ParseComplexPatterns();
@@ -2816,14 +2816,14 @@ public:
if (const CodeGenIntrinsic *IntInfo = N->getIntrinsicInfo(CDP)) {
// If this is an intrinsic, analyze it.
- if (IntInfo->ModRef >= CodeGenIntrinsic::ReadArgMem)
+ if (IntInfo->ModRef & CodeGenIntrinsic::MR_Ref)
mayLoad = true;// These may load memory.
- if (IntInfo->ModRef >= CodeGenIntrinsic::ReadWriteArgMem)
+ if (IntInfo->ModRef & CodeGenIntrinsic::MR_Mod)
mayStore = true;// Intrinsics that can write to memory are 'mayStore'.
if (IntInfo->ModRef >= CodeGenIntrinsic::ReadWriteMem)
- // WriteMem intrinsics can have other strange effects.
+ // ReadWriteMem intrinsics can have other strange effects.
hasSideEffects = true;
}
}
@@ -2974,9 +2974,16 @@ const DAGInstruction &CodeGenDAGPatterns::parseInstructionPattern(
// fill in the InstResults map.
for (unsigned j = 0, e = I->getNumTrees(); j != e; ++j) {
TreePatternNode *Pat = I->getTree(j);
- if (Pat->getNumTypes() != 0)
+ if (Pat->getNumTypes() != 0) {
+ std::string Types;
+ for (unsigned k = 0, ke = Pat->getNumTypes(); k != ke; ++k) {
+ if (k > 0)
+ Types += ", ";
+ Types += Pat->getExtType(k).getName();
+ }
I->error("Top-level forms in instruction pattern should have"
- " void types");
+ " void types, has types " + Types);
+ }
// Find inputs and outputs, and verify the structure of the uses/defs.
FindPatternInputsAndOutputs(I, Pat, InstInputs, InstResults,
@@ -3249,7 +3256,7 @@ void CodeGenDAGPatterns::AddPatternToMatch(TreePattern *Pattern,
void CodeGenDAGPatterns::InferInstructionFlags() {
- const std::vector<const CodeGenInstruction*> &Instructions =
+ ArrayRef<const CodeGenInstruction*> Instructions =
Target.getInstructionsByEnumValue();
// First try to infer flags from the primary instruction pattern, if any.
diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h
index 76c9cefea50fd..819c4b8492cb2 100644
--- a/utils/TableGen/CodeGenDAGPatterns.h
+++ b/utils/TableGen/CodeGenDAGPatterns.h
@@ -716,8 +716,8 @@ public:
class CodeGenDAGPatterns {
RecordKeeper &Records;
CodeGenTarget Target;
- std::vector<CodeGenIntrinsic> Intrinsics;
- std::vector<CodeGenIntrinsic> TgtIntrinsics;
+ CodeGenIntrinsicTable Intrinsics;
+ CodeGenIntrinsicTable TgtIntrinsics;
std::map<Record*, SDNodeInfo, LessRecordByID> SDNodes;
std::map<Record*, std::pair<Record*, std::string>, LessRecordByID> SDNodeXForms;
diff --git a/utils/TableGen/CodeGenInstruction.cpp b/utils/TableGen/CodeGenInstruction.cpp
index 366e8ec7fac15..ec802363030e7 100644
--- a/utils/TableGen/CodeGenInstruction.cpp
+++ b/utils/TableGen/CodeGenInstruction.cpp
@@ -49,7 +49,9 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
unsigned MIOperandNo = 0;
std::set<std::string> OperandNames;
- for (unsigned i = 0, e = InDI->getNumArgs()+OutDI->getNumArgs(); i != e; ++i){
+ unsigned e = InDI->getNumArgs() + OutDI->getNumArgs();
+ OperandList.reserve(e);
+ for (unsigned i = 0; i != e; ++i){
Init *ArgInit;
std::string ArgName;
if (i < NumDefs) {
@@ -322,6 +324,7 @@ CodeGenInstruction::CodeGenInstruction(Record *R)
isExtractSubreg = R->getValueAsBit("isExtractSubreg");
isInsertSubreg = R->getValueAsBit("isInsertSubreg");
isConvergent = R->getValueAsBit("isConvergent");
+ hasNoSchedulingInfo = R->getValueAsBit("hasNoSchedulingInfo");
bool Unset;
mayLoad = R->getValueAsBitOrUnset("mayLoad", Unset);
diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h
index 8f01abd5403cf..8e5a03d7b7439 100644
--- a/utils/TableGen/CodeGenInstruction.h
+++ b/utils/TableGen/CodeGenInstruction.h
@@ -14,7 +14,6 @@
#ifndef LLVM_UTILS_TABLEGEN_CODEGENINSTRUCTION_H
#define LLVM_UTILS_TABLEGEN_CODEGENINSTRUCTION_H
-#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/Support/SMLoc.h"
@@ -23,10 +22,10 @@
#include <vector>
namespace llvm {
+template <typename T> class ArrayRef;
class Record;
class DagInit;
class CodeGenTarget;
- class StringRef;
class CGIOperandList {
public:
@@ -257,6 +256,7 @@ namespace llvm {
bool isExtractSubreg : 1;
bool isInsertSubreg : 1;
bool isConvergent : 1;
+ bool hasNoSchedulingInfo : 1;
std::string DeprecatedReason;
bool HasComplexDeprecationPredicate;
@@ -316,7 +316,8 @@ namespace llvm {
K_Reg
} Kind;
- ResultOperand(std::string N, Record *r) : Name(N), R(r), Kind(K_Record) {}
+ ResultOperand(std::string N, Record *r)
+ : Name(std::move(N)), R(r), Kind(K_Record) {}
ResultOperand(int64_t I) : Imm(I), Kind(K_Imm) {}
ResultOperand(Record *r) : R(r), Kind(K_Reg) {}
diff --git a/utils/TableGen/CodeGenIntrinsics.h b/utils/TableGen/CodeGenIntrinsics.h
index 7bdb7e1bc537c..ea3ec67d62edd 100644
--- a/utils/TableGen/CodeGenIntrinsics.h
+++ b/utils/TableGen/CodeGenIntrinsics.h
@@ -19,85 +19,122 @@
#include <vector>
namespace llvm {
- class Record;
- class RecordKeeper;
- class CodeGenTarget;
-
- struct CodeGenIntrinsic {
- Record *TheDef; // The actual record defining this intrinsic.
- std::string Name; // The name of the LLVM function "llvm.bswap.i32"
- std::string EnumName; // The name of the enum "bswap_i32"
- std::string GCCBuiltinName;// Name of the corresponding GCC builtin, or "".
- std::string MSBuiltinName; // Name of the corresponding MS builtin, or "".
- std::string TargetPrefix; // Target prefix, e.g. "ppc" for t-s intrinsics.
-
- /// IntrinsicSignature - This structure holds the return values and
- /// parameter values of an intrinsic. If the number of return values is > 1,
- /// then the intrinsic implicitly returns a first-class aggregate. The
- /// numbering of the types starts at 0 with the first return value and
- /// continues from there through the parameter list. This is useful for
- /// "matching" types.
- struct IntrinsicSignature {
- /// RetVTs - The MVT::SimpleValueType for each return type. Note that this
- /// list is only populated when in the context of a target .td file. When
- /// building Intrinsics.td, this isn't available, because we don't know
- /// the target pointer size.
- std::vector<MVT::SimpleValueType> RetVTs;
-
- /// RetTypeDefs - The records for each return type.
- std::vector<Record*> RetTypeDefs;
-
- /// ParamVTs - The MVT::SimpleValueType for each parameter type. Note that
- /// this list is only populated when in the context of a target .td file.
- /// When building Intrinsics.td, this isn't available, because we don't
- /// know the target pointer size.
- std::vector<MVT::SimpleValueType> ParamVTs;
-
- /// ParamTypeDefs - The records for each parameter type.
- std::vector<Record*> ParamTypeDefs;
- };
-
- IntrinsicSignature IS;
-
- // Memory mod/ref behavior of this intrinsic.
- enum ModRefKind {
- NoMem, ReadArgMem, ReadMem, ReadWriteArgMem, ReadWriteMem
- };
- ModRefKind ModRef;
-
- /// This is set to true if the intrinsic is overloaded by its argument
- /// types.
- bool isOverloaded;
-
- /// isCommutative - True if the intrinsic is commutative.
- bool isCommutative;
-
- /// canThrow - True if the intrinsic can throw.
- bool canThrow;
-
- /// isNoDuplicate - True if the intrinsic is marked as noduplicate.
- bool isNoDuplicate;
-
- /// isNoReturn - True if the intrinsic is no-return.
- bool isNoReturn;
-
- /// isConvergent - True if the intrinsic is marked as convergent.
- bool isConvergent;
-
- enum ArgAttribute {
- NoCapture,
- ReadOnly,
- ReadNone
- };
- std::vector<std::pair<unsigned, ArgAttribute> > ArgumentAttributes;
-
- CodeGenIntrinsic(Record *R);
+class Record;
+class RecordKeeper;
+class CodeGenTarget;
+
+struct CodeGenIntrinsic {
+ Record *TheDef; // The actual record defining this intrinsic.
+ std::string Name; // The name of the LLVM function "llvm.bswap.i32"
+ std::string EnumName; // The name of the enum "bswap_i32"
+ std::string GCCBuiltinName; // Name of the corresponding GCC builtin, or "".
+ std::string MSBuiltinName; // Name of the corresponding MS builtin, or "".
+ std::string TargetPrefix; // Target prefix, e.g. "ppc" for t-s intrinsics.
+
+ /// This structure holds the return values and parameter values of an
+ /// intrinsic. If the number of return values is > 1, then the intrinsic
+ /// implicitly returns a first-class aggregate. The numbering of the types
+ /// starts at 0 with the first return value and continues from there through
+ /// the parameter list. This is useful for "matching" types.
+ struct IntrinsicSignature {
+ /// The MVT::SimpleValueType for each return type. Note that this list is
+ /// only populated when in the context of a target .td file. When building
+ /// Intrinsics.td, this isn't available, because we don't know the target
+ /// pointer size.
+ std::vector<MVT::SimpleValueType> RetVTs;
+
+ /// The records for each return type.
+ std::vector<Record *> RetTypeDefs;
+
+ /// The MVT::SimpleValueType for each parameter type. Note that this list is
+ /// only populated when in the context of a target .td file. When building
+ /// Intrinsics.td, this isn't available, because we don't know the target
+ /// pointer size.
+ std::vector<MVT::SimpleValueType> ParamVTs;
+
+ /// The records for each parameter type.
+ std::vector<Record *> ParamTypeDefs;
};
- /// LoadIntrinsics - Read all of the intrinsics defined in the specified
- /// .td file.
- std::vector<CodeGenIntrinsic> LoadIntrinsics(const RecordKeeper &RC,
- bool TargetOnly);
+ IntrinsicSignature IS;
+
+ /// Bit flags describing the type (ref/mod) and location of memory
+ /// accesses that may be performed by the intrinsics. Analogous to
+ /// \c FunctionModRefBehaviour.
+ enum ModRefBits {
+ /// The intrinsic may access memory anywhere, i.e. it is not restricted
+ /// to access through pointer arguments.
+ MR_Anywhere = 1,
+
+ /// The intrinsic may read memory.
+ MR_Ref = 2,
+
+ /// The intrinsic may write memory.
+ MR_Mod = 4,
+
+ /// The intrinsic may both read and write memory.
+ MR_ModRef = MR_Ref | MR_Mod,
+ };
+
+ /// Memory mod/ref behavior of this intrinsic, corresponding to intrinsic
+ /// properties (IntrReadMem, IntrArgMemOnly, etc.).
+ enum ModRefBehavior {
+ NoMem = 0,
+ ReadArgMem = MR_Ref,
+ ReadMem = MR_Ref | MR_Anywhere,
+ WriteArgMem = MR_Mod,
+ WriteMem = MR_Mod | MR_Anywhere,
+ ReadWriteArgMem = MR_ModRef,
+ ReadWriteMem = MR_ModRef | MR_Anywhere,
+ };
+ ModRefBehavior ModRef;
+
+ /// This is set to true if the intrinsic is overloaded by its argument
+ /// types.
+ bool isOverloaded;
+
+ /// True if the intrinsic is commutative.
+ bool isCommutative;
+
+ /// True if the intrinsic can throw.
+ bool canThrow;
+
+ /// True if the intrinsic is marked as noduplicate.
+ bool isNoDuplicate;
+
+ /// True if the intrinsic is no-return.
+ bool isNoReturn;
+
+ /// True if the intrinsic is marked as convergent.
+ bool isConvergent;
+
+ enum ArgAttribute { NoCapture, Returned, ReadOnly, WriteOnly, ReadNone };
+ std::vector<std::pair<unsigned, ArgAttribute>> ArgumentAttributes;
+
+ CodeGenIntrinsic(Record *R);
+};
+
+class CodeGenIntrinsicTable {
+ std::vector<CodeGenIntrinsic> Intrinsics;
+
+public:
+ struct TargetSet {
+ std::string Name;
+ size_t Offset;
+ size_t Count;
+ };
+ std::vector<TargetSet> Targets;
+
+ explicit CodeGenIntrinsicTable(const RecordKeeper &RC, bool TargetOnly);
+ CodeGenIntrinsicTable() = default;
+
+ bool empty() const { return Intrinsics.empty(); }
+ size_t size() const { return Intrinsics.size(); }
+ CodeGenIntrinsic &operator[](size_t Pos) { return Intrinsics[Pos]; }
+ const CodeGenIntrinsic &operator[](size_t Pos) const {
+ return Intrinsics[Pos];
+ }
+};
}
#endif
diff --git a/utils/TableGen/CodeGenMapTable.cpp b/utils/TableGen/CodeGenMapTable.cpp
index f66dd082709ba..527f530da479a 100644
--- a/utils/TableGen/CodeGenMapTable.cpp
+++ b/utils/TableGen/CodeGenMapTable.cpp
@@ -337,10 +337,20 @@ Record *MapTableEmitter::getInstrForColumn(Record *KeyInstr,
}
if (MatchFound) {
- if (MatchInstr) // Already had a match
+ if (MatchInstr) {
+ // Already had a match
// Error if multiple matches are found for a column.
+ std::string KeyValueStr;
+ for (Init *Value : KeyValue) {
+ if (!KeyValueStr.empty())
+ KeyValueStr += ", ";
+ KeyValueStr += Value->getAsString();
+ }
+
PrintFatalError("Multiple matches found for `" + KeyInstr->getName() +
- "', for the relation `" + InstrMapDesc.getName());
+ "', for the relation `" + InstrMapDesc.getName() + "', row fields [" +
+ KeyValueStr + "], column `" + CurValueCol->getAsString() + "'");
+ }
MatchInstr = CurInstr;
}
}
@@ -355,7 +365,7 @@ Record *MapTableEmitter::getInstrForColumn(Record *KeyInstr,
unsigned MapTableEmitter::emitBinSearchTable(raw_ostream &OS) {
- const std::vector<const CodeGenInstruction*> &NumberedInstructions =
+ ArrayRef<const CodeGenInstruction*> NumberedInstructions =
Target.getInstructionsByEnumValue();
std::string TargetName = Target.getName();
const std::vector<ListInit*> &ValueCols = InstrMapDesc.getValueCols();
@@ -499,8 +509,7 @@ static void emitEnums(raw_ostream &OS, RecordKeeper &Records) {
// Iterate over all InstrMapping records and create a map between column
// fields and their possible values across all records.
- for (unsigned i = 0, e = InstrMapVec.size(); i < e; i++) {
- Record *CurMap = InstrMapVec[i];
+ for (Record *CurMap : InstrMapVec) {
ListInit *ColFields;
ColFields = CurMap->getValueAsListInit("ColFields");
ListInit *List = CurMap->getValueAsListInit("ValueCols");
@@ -524,10 +533,8 @@ static void emitEnums(raw_ostream &OS, RecordKeeper &Records) {
}
}
- for (std::map<std::string, std::vector<Init*> >::iterator
- II = ColFieldValueMap.begin(), IE = ColFieldValueMap.end();
- II != IE; II++) {
- std::vector<Init*> FieldValues = (*II).second;
+ for (auto &Entry : ColFieldValueMap) {
+ std::vector<Init*> FieldValues = Entry.second;
// Delete duplicate entries from ColFieldValueMap
for (unsigned i = 0; i < FieldValues.size() - 1; i++) {
@@ -540,9 +547,9 @@ static void emitEnums(raw_ostream &OS, RecordKeeper &Records) {
}
// Emit enumerated values for the column fields.
- OS << "enum " << (*II).first << " {\n";
+ OS << "enum " << Entry.first << " {\n";
for (unsigned i = 0, endFV = FieldValues.size(); i < endFV; i++) {
- OS << "\t" << (*II).first << "_" << FieldValues[i]->getAsUnquotedString();
+ OS << "\t" << Entry.first << "_" << FieldValues[i]->getAsUnquotedString();
if (i != endFV - 1)
OS << ",\n";
else
@@ -577,8 +584,8 @@ void EmitMapTable(RecordKeeper &Records, raw_ostream &OS) {
// Iterate over all instruction mapping records and construct relationship
// maps based on the information specified there.
//
- for (unsigned i = 0, e = InstrMapVec.size(); i < e; i++) {
- MapTableEmitter IMap(Target, Records, InstrMapVec[i]);
+ for (Record *CurMap : InstrMapVec) {
+ MapTableEmitter IMap(Target, Records, CurMap);
// Build RowInstrMap to group instructions based on their values for
// RowFields. In the process, also collect key instructions into
diff --git a/utils/TableGen/CodeGenRegisters.cpp b/utils/TableGen/CodeGenRegisters.cpp
index ca316e96a21ad..626144fbe855a 100644
--- a/utils/TableGen/CodeGenRegisters.cpp
+++ b/utils/TableGen/CodeGenRegisters.cpp
@@ -587,10 +587,9 @@ struct TupleExpander : SetTheory::Expander {
Elts.insert(NewReg);
// Copy Proto super-classes.
- ArrayRef<Record *> Supers = Proto->getSuperClasses();
- ArrayRef<SMRange> Ranges = Proto->getSuperClassRanges();
- for (unsigned i = 0, e = Supers.size(); i != e; ++i)
- NewReg->addSuperClass(Supers[i], Ranges[i]);
+ ArrayRef<std::pair<Record *, SMRange>> Supers = Proto->getSuperClasses();
+ for (const auto &SuperPair : Supers)
+ NewReg->addSuperClass(SuperPair.first, SuperPair.second);
// Copy Proto fields.
for (unsigned i = 0, e = Proto->getValues().size(); i != e; ++i) {
@@ -1193,45 +1192,57 @@ void CodeGenRegBank::computeSubRegLaneMasks() {
for (const auto &Idx : SubRegIndices) {
const auto &Composites = Idx.getComposites();
auto &LaneTransforms = Idx.CompositionLaneMaskTransform;
- // Go through all leaf subregisters and find the ones that compose with Idx.
- // These make out all possible valid bits in the lane mask we want to
- // transform. Looking only at the leafs ensure that only a single bit in
- // the mask is set.
- unsigned NextBit = 0;
- for (auto &Idx2 : SubRegIndices) {
- // Skip non-leaf subregisters.
- if (!Idx2.getComposites().empty())
- continue;
- // Replicate the behaviour from the lane mask generation loop above.
- unsigned SrcBit = NextBit;
- unsigned SrcMask = 1u << SrcBit;
- if (NextBit < 31)
- ++NextBit;
- assert(Idx2.LaneMask == SrcMask);
-
- // Get the composed subregister if there is any.
- auto C = Composites.find(&Idx2);
- if (C == Composites.end())
- continue;
- const CodeGenSubRegIndex *Composite = C->second;
- // The Composed subreg should be a leaf subreg too
- assert(Composite->getComposites().empty());
-
- // Create Mask+Rotate operation and merge with existing ops if possible.
- unsigned DstBit = Log2_32(Composite->LaneMask);
- int Shift = DstBit - SrcBit;
- uint8_t RotateLeft = Shift >= 0 ? (uint8_t)Shift : 32+Shift;
- for (auto &I : LaneTransforms) {
- if (I.RotateLeft == RotateLeft) {
- I.Mask |= SrcMask;
- SrcMask = 0;
+
+ if (Composites.empty()) {
+ // Moving from a class with no subregisters we just had a single lane:
+ // The subregister must be a leaf subregister and only occupies 1 bit.
+ // Move the bit from the class without subregisters into that position.
+ unsigned DstBit = Log2_32(Idx.LaneMask);
+ assert(Idx.LaneMask == 1u << DstBit && "Must be a leaf subregister");
+ MaskRolPair MaskRol = { 1, (uint8_t)DstBit };
+ LaneTransforms.push_back(MaskRol);
+ } else {
+ // Go through all leaf subregisters and find the ones that compose with
+ // Idx. These make out all possible valid bits in the lane mask we want to
+ // transform. Looking only at the leafs ensure that only a single bit in
+ // the mask is set.
+ unsigned NextBit = 0;
+ for (auto &Idx2 : SubRegIndices) {
+ // Skip non-leaf subregisters.
+ if (!Idx2.getComposites().empty())
+ continue;
+ // Replicate the behaviour from the lane mask generation loop above.
+ unsigned SrcBit = NextBit;
+ unsigned SrcMask = 1u << SrcBit;
+ if (NextBit < 31)
+ ++NextBit;
+ assert(Idx2.LaneMask == SrcMask);
+
+ // Get the composed subregister if there is any.
+ auto C = Composites.find(&Idx2);
+ if (C == Composites.end())
+ continue;
+ const CodeGenSubRegIndex *Composite = C->second;
+ // The Composed subreg should be a leaf subreg too
+ assert(Composite->getComposites().empty());
+
+ // Create Mask+Rotate operation and merge with existing ops if possible.
+ unsigned DstBit = Log2_32(Composite->LaneMask);
+ int Shift = DstBit - SrcBit;
+ uint8_t RotateLeft = Shift >= 0 ? (uint8_t)Shift : 32+Shift;
+ for (auto &I : LaneTransforms) {
+ if (I.RotateLeft == RotateLeft) {
+ I.Mask |= SrcMask;
+ SrcMask = 0;
+ }
+ }
+ if (SrcMask != 0) {
+ MaskRolPair MaskRol = { SrcMask, RotateLeft };
+ LaneTransforms.push_back(MaskRol);
}
- }
- if (SrcMask != 0) {
- MaskRolPair MaskRol = { SrcMask, RotateLeft };
- LaneTransforms.push_back(MaskRol);
}
}
+
// Optimize if the transformation consists of one step only: Set mask to
// 0xffffffff (including some irrelevant invalid bits) so that it should
// merge with more entries later while compressing the table.
@@ -1268,10 +1279,10 @@ void CodeGenRegBank::computeSubRegLaneMasks() {
LaneMask |= SubRegIndex.LaneMask;
}
- // For classes without any subregisters set LaneMask to ~0u instead of 0.
+ // For classes without any subregisters set LaneMask to 1 instead of 0.
// This makes it easier for client code to handle classes uniformly.
if (LaneMask == 0)
- LaneMask = ~0u;
+ LaneMask = 1;
RegClass.LaneMask = LaneMask;
}
@@ -1818,11 +1829,14 @@ void CodeGenRegBank::computeDerivedInfo() {
computeRegUnitLaneMasks();
- // Compute register class HasDisjunctSubRegs flag.
+ // Compute register class HasDisjunctSubRegs/CoveredBySubRegs flag.
for (CodeGenRegisterClass &RC : RegClasses) {
RC.HasDisjunctSubRegs = false;
- for (const CodeGenRegister *Reg : RC.getMembers())
+ RC.CoveredBySubRegs = true;
+ for (const CodeGenRegister *Reg : RC.getMembers()) {
RC.HasDisjunctSubRegs |= Reg->HasDisjunctSubRegs;
+ RC.CoveredBySubRegs &= Reg->CoveredBySubRegs;
+ }
}
// Get the weight of each set.
diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h
index dc441436537db..b8d47aa4ff82d 100644
--- a/utils/TableGen/CodeGenRegisters.h
+++ b/utils/TableGen/CodeGenRegisters.h
@@ -19,22 +19,21 @@
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SparseBitVector.h"
#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/SetTheory.h"
#include <cstdlib>
+#include <deque>
#include <list>
#include <map>
-#include <set>
#include <string>
#include <vector>
-#include <deque>
namespace llvm {
class CodeGenRegBank;
+ template <typename T, typename Vector, typename Set> class SetVector;
/// Used to encode a step in a register lane mask transformation.
/// Mask the bits specified in Mask, then rotate them Rol bits to the left
@@ -311,6 +310,7 @@ namespace llvm {
unsigned LaneMask;
/// True if there are at least 2 subregisters which do not interfere.
bool HasDisjunctSubRegs;
+ bool CoveredBySubRegs;
// Return the Record that defined this class, or NULL if the class was
// created by TableGen.
diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp
index c98f62345342d..d1b141e3160f5 100644
--- a/utils/TableGen/CodeGenSchedule.cpp
+++ b/utils/TableGen/CodeGenSchedule.cpp
@@ -68,7 +68,7 @@ struct InstRegexOp : public SetTheory::Operator {
}
RegexList.push_back(Regex(pat));
}
- for (const CodeGenInstruction *Inst : Target.instructions()) {
+ for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
for (auto &R : RegexList) {
if (R.match(Inst->TheDef->getName()))
Elts.insert(Inst->TheDef);
@@ -120,12 +120,18 @@ CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK,
// (For per-operand resources mapped to itinerary classes).
collectProcItinRW();
+ // Find UnsupportedFeatures records for each processor.
+ // (For per-operand resources mapped to itinerary classes).
+ collectProcUnsupportedFeatures();
+
// Infer new SchedClasses from SchedVariant.
inferSchedClasses();
// Populate each CodeGenProcModel's WriteResDefs, ReadAdvanceDefs, and
// ProcResourceDefs.
collectProcResources();
+
+ checkCompleteness();
}
/// Gather all processor models.
@@ -204,7 +210,7 @@ void CodeGenSchedModels::collectSchedRW() {
// Find all SchedReadWrites referenced by instruction defs.
RecVec SWDefs, SRDefs;
- for (const CodeGenInstruction *Inst : Target.instructions()) {
+ for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
Record *SchedDef = Inst->TheDef;
if (SchedDef->isValueUnset("SchedRW"))
continue;
@@ -498,7 +504,7 @@ void CodeGenSchedModels::collectSchedClasses() {
// Create a SchedClass for each unique combination of itinerary class and
// SchedRW list.
- for (const CodeGenInstruction *Inst : Target.instructions()) {
+ for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
Record *ItinDef = Inst->TheDef->getValueAsDef("Itinerary");
IdxVec Writes, Reads;
if (!Inst->TheDef->isValueUnset("SchedRW"))
@@ -523,11 +529,12 @@ void CodeGenSchedModels::collectSchedClasses() {
if (!EnableDump)
return;
- for (const CodeGenInstruction *Inst : Target.instructions()) {
+ for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
std::string InstName = Inst->TheDef->getName();
unsigned SCIdx = InstrClassMap.lookup(Inst->TheDef);
if (!SCIdx) {
- dbgs() << "No machine model for " << Inst->TheDef->getName() << '\n';
+ if (!Inst->hasNoSchedulingInfo)
+ dbgs() << "No machine model for " << Inst->TheDef->getName() << '\n';
continue;
}
CodeGenSchedClass &SC = getSchedClass(SCIdx);
@@ -826,6 +833,15 @@ void CodeGenSchedModels::collectProcItinRW() {
}
}
+// Gather the unsupported features for processor models.
+void CodeGenSchedModels::collectProcUnsupportedFeatures() {
+ for (CodeGenProcModel &ProcModel : ProcModels) {
+ for (Record *Pred : ProcModel.ModelDef->getValueAsListOfDefs("UnsupportedFeatures")) {
+ ProcModel.UnsupportedFeaturesDefs.push_back(Pred);
+ }
+ }
+}
+
/// Infer new classes from existing classes. In the process, this may create new
/// SchedWrites from sequences of existing SchedWrites.
void CodeGenSchedModels::inferSchedClasses() {
@@ -1426,6 +1442,9 @@ void CodeGenSchedModels::verifyProcResourceGroups(CodeGenProcModel &PM) {
// Collect and sort WriteRes, ReadAdvance, and ProcResources.
void CodeGenSchedModels::collectProcResources() {
+ ProcResourceDefs = Records.getAllDerivedDefinitions("ProcResourceUnits");
+ ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup");
+
// Add any subtarget-specific SchedReadWrites that are directly associated
// with processor resources. Refer to the parent SchedClass's ProcIndices to
// determine which processors they apply to.
@@ -1520,6 +1539,63 @@ void CodeGenSchedModels::collectProcResources() {
dbgs() << '\n');
verifyProcResourceGroups(PM);
}
+
+ ProcResourceDefs.clear();
+ ProcResGroups.clear();
+}
+
+void CodeGenSchedModels::checkCompleteness() {
+ bool Complete = true;
+ bool HadCompleteModel = false;
+ for (const CodeGenProcModel &ProcModel : procModels()) {
+ if (!ProcModel.ModelDef->getValueAsBit("CompleteModel"))
+ continue;
+ for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
+ if (Inst->hasNoSchedulingInfo)
+ continue;
+ if (ProcModel.isUnsupported(*Inst))
+ continue;
+ unsigned SCIdx = getSchedClassIdx(*Inst);
+ if (!SCIdx) {
+ if (Inst->TheDef->isValueUnset("SchedRW") && !HadCompleteModel) {
+ PrintError("No schedule information for instruction '"
+ + Inst->TheDef->getName() + "'");
+ Complete = false;
+ }
+ continue;
+ }
+
+ const CodeGenSchedClass &SC = getSchedClass(SCIdx);
+ if (!SC.Writes.empty())
+ continue;
+ if (SC.ItinClassDef != nullptr)
+ continue;
+
+ const RecVec &InstRWs = SC.InstRWs;
+ auto I = std::find_if(InstRWs.begin(), InstRWs.end(),
+ [&ProcModel] (const Record *R) {
+ return R->getValueAsDef("SchedModel") ==
+ ProcModel.ModelDef;
+ });
+ if (I == InstRWs.end()) {
+ PrintError("'" + ProcModel.ModelName + "' lacks information for '" +
+ Inst->TheDef->getName() + "'");
+ Complete = false;
+ }
+ }
+ HadCompleteModel = true;
+ }
+ if (!Complete) {
+ errs() << "\n\nIncomplete schedule models found.\n"
+ << "- Consider setting 'CompleteModel = 0' while developing new models.\n"
+ << "- Pseudo instructions can be marked with 'hasNoSchedulingInfo = 1'.\n"
+ << "- Instructions should usually have Sched<[...]> as a superclass, "
+ "you may temporarily use an empty list.\n"
+ << "- Instructions related to unsupported features can be excluded with "
+ "list<Predicate> UnsupportedFeatures = [HasA,..,HasY]; in the "
+ "processor model.\n\n";
+ PrintFatalError("Incomplete schedule model");
+ }
}
// Collect itinerary class resources for each processor.
@@ -1600,8 +1676,8 @@ Record *CodeGenSchedModels::findProcResUnits(Record *ProcResKind,
return ProcResKind;
Record *ProcUnitDef = nullptr;
- RecVec ProcResourceDefs =
- Records.getAllDerivedDefinitions("ProcResourceUnits");
+ assert(!ProcResourceDefs.empty());
+ assert(!ProcResGroups.empty());
for (RecIter RI = ProcResourceDefs.begin(), RE = ProcResourceDefs.end();
RI != RE; ++RI) {
@@ -1616,7 +1692,6 @@ Record *CodeGenSchedModels::findProcResUnits(Record *ProcResKind,
ProcUnitDef = *RI;
}
}
- RecVec ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup");
for (RecIter RI = ProcResGroups.begin(), RE = ProcResGroups.end();
RI != RE; ++RI) {
@@ -1699,6 +1774,16 @@ unsigned CodeGenProcModel::getProcResourceIdx(Record *PRDef) const {
return 1 + (PRPos - ProcResourceDefs.begin());
}
+bool CodeGenProcModel::isUnsupported(const CodeGenInstruction &Inst) const {
+ for (const Record *TheDef : UnsupportedFeaturesDefs) {
+ for (const Record *PredDef : Inst.TheDef->getValueAsListOfDefs("Predicates")) {
+ if (TheDef->getName() == PredDef->getName())
+ return true;
+ }
+ }
+ return false;
+}
+
#ifndef NDEBUG
void CodeGenProcModel::dump() const {
dbgs() << Index << ": " << ModelName << " "
diff --git a/utils/TableGen/CodeGenSchedule.h b/utils/TableGen/CodeGenSchedule.h
index f5c50c992a928..755ffd25b0cbc 100644
--- a/utils/TableGen/CodeGenSchedule.h
+++ b/utils/TableGen/CodeGenSchedule.h
@@ -189,6 +189,10 @@ struct CodeGenProcModel {
// This list is empty if no ItinRW refers to this Processor.
RecVec ItinRWDefs;
+ // List of unsupported feature.
+ // This list is empty if the Processor has no UnsupportedFeatures.
+ RecVec UnsupportedFeaturesDefs;
+
// All read/write resources associated with this processor.
RecVec WriteResDefs;
RecVec ReadAdvanceDefs;
@@ -211,6 +215,8 @@ struct CodeGenProcModel {
unsigned getProcResourceIdx(Record *PRDef) const;
+ bool isUnsupported(const CodeGenInstruction &Inst) const;
+
#ifndef NDEBUG
void dump() const;
#endif
@@ -241,6 +247,9 @@ class CodeGenSchedModels {
// Any inferred SchedClass has an index greater than NumInstrSchedClassses.
unsigned NumInstrSchedClasses;
+ RecVec ProcResourceDefs;
+ RecVec ProcResGroups;
+
// Map each instruction to its unique SchedClass index considering the
// combination of it's itinerary class, SchedRW list, and InstRW records.
typedef DenseMap<Record*, unsigned> InstClassMapTy;
@@ -300,6 +309,7 @@ public:
typedef std::vector<CodeGenProcModel>::const_iterator ProcIter;
ProcIter procModelBegin() const { return ProcModels.begin(); }
ProcIter procModelEnd() const { return ProcModels.end(); }
+ ArrayRef<CodeGenProcModel> procModels() const { return ProcModels; }
// Return true if any processors have itineraries.
bool hasItineraries() const;
@@ -353,6 +363,7 @@ public:
typedef std::vector<CodeGenSchedClass>::const_iterator SchedClassIter;
SchedClassIter schedClassBegin() const { return SchedClasses.begin(); }
SchedClassIter schedClassEnd() const { return SchedClasses.end(); }
+ ArrayRef<CodeGenSchedClass> schedClasses() const { return SchedClasses; }
unsigned numInstrSchedClasses() const { return NumInstrSchedClasses; }
@@ -397,8 +408,12 @@ private:
void collectProcItinRW();
+ void collectProcUnsupportedFeatures();
+
void inferSchedClasses();
+ void checkCompleteness();
+
void inferFromRW(ArrayRef<unsigned> OperWrites, ArrayRef<unsigned> OperReads,
unsigned FromClassIdx, ArrayRef<unsigned> ProcIndices);
void inferFromItinClass(Record *ItinClassDef, unsigned FromClassIdx);
diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp
index aaad4225ace88..245b9eeeed858 100644
--- a/utils/TableGen/CodeGenTarget.cpp
+++ b/utils/TableGen/CodeGenTarget.cpp
@@ -39,7 +39,7 @@ MVT::SimpleValueType llvm::getValueType(Record *Rec) {
return (MVT::SimpleValueType)Rec->getValueAsInt("Value");
}
-std::string llvm::getName(MVT::SimpleValueType T) {
+StringRef llvm::getName(MVT::SimpleValueType T) {
switch (T) {
case MVT::Other: return "UNKNOWN";
case MVT::iPTR: return "TLI.getPointerTy()";
@@ -48,7 +48,7 @@ std::string llvm::getName(MVT::SimpleValueType T) {
}
}
-std::string llvm::getEnumName(MVT::SimpleValueType T) {
+StringRef llvm::getEnumName(MVT::SimpleValueType T) {
switch (T) {
case MVT::Other: return "MVT::Other";
case MVT::i1: return "MVT::i1";
@@ -162,7 +162,7 @@ const std::string &CodeGenTarget::getName() const {
}
std::string CodeGenTarget::getInstNamespace() const {
- for (const CodeGenInstruction *Inst : instructions()) {
+ for (const CodeGenInstruction *Inst : getInstructionsByEnumValue()) {
// Make sure not to pick up "TargetOpcode" by accidentally getting
// the namespace off the PHI instruction or something.
if (Inst->Namespace != "TargetOpcode")
@@ -300,14 +300,9 @@ GetInstByName(const char *Name,
/// \brief Return all of the instructions defined by the target, ordered by
/// their enum value.
void CodeGenTarget::ComputeInstrsByEnum() const {
- // The ordering here must match the ordering in TargetOpcodes.h.
static const char *const FixedInstrs[] = {
- "PHI", "INLINEASM", "CFI_INSTRUCTION", "EH_LABEL",
- "GC_LABEL", "KILL", "EXTRACT_SUBREG", "INSERT_SUBREG",
- "IMPLICIT_DEF", "SUBREG_TO_REG", "COPY_TO_REGCLASS", "DBG_VALUE",
- "REG_SEQUENCE", "COPY", "BUNDLE", "LIFETIME_START",
- "LIFETIME_END", "STACKMAP", "PATCHPOINT", "LOAD_STACK_GUARD",
- "STATEPOINT", "LOCAL_ESCAPE", "FAULTING_LOAD_OP",
+#define HANDLE_TARGET_OPCODE(OPC, NUM) #OPC,
+#include "llvm/Target/TargetOpcodes.def"
nullptr};
const auto &Insts = getInstructions();
for (const char *const *p = FixedInstrs; *p; ++p) {
@@ -357,9 +352,9 @@ void CodeGenTarget::reverseBitsForLittleEndianEncoding() {
BitsInit *BI = R->getValueAsBitsInit("Inst");
unsigned numBits = BI->getNumBits();
-
+
SmallVector<Init *, 16> NewBits(numBits);
-
+
for (unsigned bit = 0, end = numBits / 2; bit != end; ++bit) {
unsigned bitSwapIdx = numBits - bit - 1;
Init *OrigBit = BI->getBit(bit);
@@ -431,18 +426,29 @@ ComplexPattern::ComplexPattern(Record *R) {
// CodeGenIntrinsic Implementation
//===----------------------------------------------------------------------===//
-std::vector<CodeGenIntrinsic> llvm::LoadIntrinsics(const RecordKeeper &RC,
- bool TargetOnly) {
- std::vector<Record*> I = RC.getAllDerivedDefinitions("Intrinsic");
+CodeGenIntrinsicTable::CodeGenIntrinsicTable(const RecordKeeper &RC,
+ bool TargetOnly) {
+ std::vector<Record*> Defs = RC.getAllDerivedDefinitions("Intrinsic");
- std::vector<CodeGenIntrinsic> Result;
+ Intrinsics.reserve(Defs.size());
- for (unsigned i = 0, e = I.size(); i != e; ++i) {
- bool isTarget = I[i]->getValueAsBit("isTarget");
+ for (unsigned I = 0, e = Defs.size(); I != e; ++I) {
+ bool isTarget = Defs[I]->getValueAsBit("isTarget");
if (isTarget == TargetOnly)
- Result.push_back(CodeGenIntrinsic(I[i]));
+ Intrinsics.push_back(CodeGenIntrinsic(Defs[I]));
}
- return Result;
+ std::sort(Intrinsics.begin(), Intrinsics.end(),
+ [](const CodeGenIntrinsic &LHS, const CodeGenIntrinsic &RHS) {
+ return std::tie(LHS.TargetPrefix, LHS.Name) <
+ std::tie(RHS.TargetPrefix, RHS.Name);
+ });
+ Targets.push_back({"", 0, 0});
+ for (size_t I = 0, E = Intrinsics.size(); I < E; ++I)
+ if (Intrinsics[I].TargetPrefix != Targets.back().Name) {
+ Targets.back().Count = I - Targets.back().Offset;
+ Targets.push_back({Intrinsics[I].TargetPrefix, I, 0});
+ }
+ Targets.back().Count = Intrinsics.size() - Targets.back().Offset;
}
CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
@@ -565,7 +571,7 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
}
// Parse the intrinsic properties.
- ListInit *PropList = R->getValueAsListInit("Properties");
+ ListInit *PropList = R->getValueAsListInit("IntrProperties");
for (unsigned i = 0, e = PropList->size(); i != e; ++i) {
Record *Property = PropList->getElementAsRecord(i);
assert(Property->isSubClassOf("IntrinsicProperty") &&
@@ -573,12 +579,12 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
if (Property->getName() == "IntrNoMem")
ModRef = NoMem;
- else if (Property->getName() == "IntrReadArgMem")
- ModRef = ReadArgMem;
else if (Property->getName() == "IntrReadMem")
- ModRef = ReadMem;
- else if (Property->getName() == "IntrReadWriteArgMem")
- ModRef = ReadWriteArgMem;
+ ModRef = ModRefBehavior(ModRef & ~MR_Mod);
+ else if (Property->getName() == "IntrWriteMem")
+ ModRef = ModRefBehavior(ModRef & ~MR_Ref);
+ else if (Property->getName() == "IntrArgMemOnly")
+ ModRef = ModRefBehavior(ModRef & ~MR_Anywhere);
else if (Property->getName() == "Commutative")
isCommutative = true;
else if (Property->getName() == "Throws")
@@ -592,9 +598,15 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) {
else if (Property->isSubClassOf("NoCapture")) {
unsigned ArgNo = Property->getValueAsInt("ArgNo");
ArgumentAttributes.push_back(std::make_pair(ArgNo, NoCapture));
+ } else if (Property->isSubClassOf("Returned")) {
+ unsigned ArgNo = Property->getValueAsInt("ArgNo");
+ ArgumentAttributes.push_back(std::make_pair(ArgNo, Returned));
} else if (Property->isSubClassOf("ReadOnly")) {
unsigned ArgNo = Property->getValueAsInt("ArgNo");
ArgumentAttributes.push_back(std::make_pair(ArgNo, ReadOnly));
+ } else if (Property->isSubClassOf("WriteOnly")) {
+ unsigned ArgNo = Property->getValueAsInt("ArgNo");
+ ArgumentAttributes.push_back(std::make_pair(ArgNo, WriteOnly));
} else if (Property->isSubClassOf("ReadNone")) {
unsigned ArgNo = Property->getValueAsInt("ArgNo");
ArgumentAttributes.push_back(std::make_pair(ArgNo, ReadNone));
diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h
index cf4a0bbe5bd9e..85a8c1b188785 100644
--- a/utils/TableGen/CodeGenTarget.h
+++ b/utils/TableGen/CodeGenTarget.h
@@ -52,8 +52,8 @@ enum SDNP {
/// record corresponds to.
MVT::SimpleValueType getValueType(Record *Rec);
-std::string getName(MVT::SimpleValueType T);
-std::string getEnumName(MVT::SimpleValueType T);
+StringRef getName(MVT::SimpleValueType T);
+StringRef getEnumName(MVT::SimpleValueType T);
/// getQualifiedName - Return the name of the specified record, with a
/// namespace qualifier if the record contains one.
@@ -139,9 +139,7 @@ public:
/// supported by the target (i.e. there are registers that directly hold it).
bool isLegalValueType(MVT::SimpleValueType VT) const {
ArrayRef<MVT::SimpleValueType> LegalVTs = getLegalValueTypes();
- for (unsigned i = 0, e = LegalVTs.size(); i != e; ++i)
- if (LegalVTs[i] == VT) return true;
- return false;
+ return std::find(LegalVTs.begin(), LegalVTs.end(), VT) != LegalVTs.end();
}
CodeGenSchedModels &getSchedModels() const;
@@ -163,18 +161,15 @@ public:
/// getInstructionsByEnumValue - Return all of the instructions defined by the
/// target, ordered by their enum value.
- const std::vector<const CodeGenInstruction*> &
+ ArrayRef<const CodeGenInstruction *>
getInstructionsByEnumValue() const {
if (InstrsByEnum.empty()) ComputeInstrsByEnum();
return InstrsByEnum;
}
- typedef std::vector<const CodeGenInstruction*>::const_iterator inst_iterator;
+ typedef ArrayRef<const CodeGenInstruction *>::const_iterator inst_iterator;
inst_iterator inst_begin() const{return getInstructionsByEnumValue().begin();}
inst_iterator inst_end() const { return getInstructionsByEnumValue().end(); }
- iterator_range<inst_iterator> instructions() const {
- return make_range(inst_begin(), inst_end());
- }
/// isLittleEndianEncoding - are instruction bit patterns defined as [0..n]?
diff --git a/utils/TableGen/DAGISelMatcher.cpp b/utils/TableGen/DAGISelMatcher.cpp
index 9c4079906a383..6ac3958e0f430 100644
--- a/utils/TableGen/DAGISelMatcher.cpp
+++ b/utils/TableGen/DAGISelMatcher.cpp
@@ -225,12 +225,14 @@ void CheckFoldableChainNodeMatcher::printImpl(raw_ostream &OS,
}
void EmitIntegerMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
- OS.indent(indent) << "EmitInteger " << Val << " VT=" << VT << '\n';
+ OS.indent(indent) << "EmitInteger " << Val << " VT=" << getEnumName(VT)
+ << '\n';
}
void EmitStringIntegerMatcher::
printImpl(raw_ostream &OS, unsigned indent) const {
- OS.indent(indent) << "EmitStringInteger " << Val << " VT=" << VT << '\n';
+ OS.indent(indent) << "EmitStringInteger " << Val << " VT=" << getEnumName(VT)
+ << '\n';
}
void EmitRegisterMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
@@ -239,7 +241,7 @@ void EmitRegisterMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
OS << Reg->getName();
else
OS << "zero_reg";
- OS << " VT=" << VT << '\n';
+ OS << " VT=" << getEnumName(VT) << '\n';
}
void EmitConvertToTargetMatcher::
@@ -275,54 +277,12 @@ void EmitNodeMatcherCommon::printImpl(raw_ostream &OS, unsigned indent) const {
OS << ")\n";
}
-void MarkGlueResultsMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
- OS.indent(indent) << "MarkGlueResults <todo: args>\n";
-}
-
void CompleteMatchMatcher::printImpl(raw_ostream &OS, unsigned indent) const {
OS.indent(indent) << "CompleteMatch <todo args>\n";
OS.indent(indent) << "Src = " << *Pattern.getSrcPattern() << "\n";
OS.indent(indent) << "Dst = " << *Pattern.getDstPattern() << "\n";
}
-// getHashImpl Implementation.
-
-unsigned CheckPatternPredicateMatcher::getHashImpl() const {
- return HashString(Predicate);
-}
-
-unsigned CheckPredicateMatcher::getHashImpl() const {
- return HashString(getPredicate().getFnName());
-}
-
-unsigned CheckOpcodeMatcher::getHashImpl() const {
- return HashString(Opcode.getEnumName());
-}
-
-unsigned CheckCondCodeMatcher::getHashImpl() const {
- return HashString(CondCodeName);
-}
-
-unsigned CheckValueTypeMatcher::getHashImpl() const {
- return HashString(TypeName);
-}
-
-unsigned EmitStringIntegerMatcher::getHashImpl() const {
- return HashString(Val) ^ VT;
-}
-
-template<typename It>
-static unsigned HashUnsigneds(It I, It E) {
- unsigned Result = 0;
- for (; I != E; ++I)
- Result = (Result<<3) ^ *I;
- return Result;
-}
-
-unsigned EmitMergeInputChainsMatcher::getHashImpl() const {
- return HashUnsigneds(ChainNodes.begin(), ChainNodes.end());
-}
-
bool CheckOpcodeMatcher::isEqualImpl(const Matcher *M) const {
// Note: pointer equality isn't enough here, we have to check the enum names
// to ensure that the nodes are for the same opcode.
@@ -339,24 +299,10 @@ bool EmitNodeMatcherCommon::isEqualImpl(const Matcher *m) const {
M->NumFixedArityOperands == NumFixedArityOperands;
}
-unsigned EmitNodeMatcherCommon::getHashImpl() const {
- return (HashString(OpcodeName) << 4) | Operands.size();
-}
-
-
void EmitNodeMatcher::anchor() { }
void MorphNodeToMatcher::anchor() { }
-unsigned MarkGlueResultsMatcher::getHashImpl() const {
- return HashUnsigneds(GlueResultNodes.begin(), GlueResultNodes.end());
-}
-
-unsigned CompleteMatchMatcher::getHashImpl() const {
- return HashUnsigneds(Results.begin(), Results.end()) ^
- ((unsigned)(intptr_t)&Pattern << 8);
-}
-
// isContradictoryImpl Implementations.
static bool TypesAreContradictory(MVT::SimpleValueType T1,
diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h
index a8a6ba5c32e15..6bda9ca5f96fa 100644
--- a/utils/TableGen/DAGISelMatcher.h
+++ b/utils/TableGen/DAGISelMatcher.h
@@ -82,7 +82,6 @@ public:
EmitCopyToReg, // Emit a copytoreg into a physreg.
EmitNode, // Create a DAG node
EmitNodeXForm, // Run a SDNodeXForm
- MarkGlueResults, // Indicate which interior nodes have glue results.
CompleteMatch, // Finish a match and update the results.
MorphNodeTo // Build a node, finish a match and update results.
};
@@ -107,17 +106,6 @@ public:
return isEqualImpl(M);
}
- unsigned getHash() const {
- // Clear the high bit so we don't conflict with tombstones etc.
- return ((getHashImpl() << 4) ^ getKind()) & (~0U>>1);
- }
-
- /// isSafeToReorderWithPatternPredicate - Return true if it is safe to sink a
- /// PatternPredicate node past this one.
- virtual bool isSafeToReorderWithPatternPredicate() const {
- return false;
- }
-
/// isSimplePredicateNode - Return true if this is a simple predicate that
/// operates on the node or its children without potential side effects or a
/// change of the current node.
@@ -181,7 +169,6 @@ public:
protected:
virtual void printImpl(raw_ostream &OS, unsigned indent) const = 0;
virtual bool isEqualImpl(const Matcher *M) const = 0;
- virtual unsigned getHashImpl() const = 0;
virtual bool isContradictoryImpl(const Matcher *M) const { return false; }
};
@@ -228,7 +215,6 @@ public:
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override { return false; }
- unsigned getHashImpl() const override { return 12312; }
};
/// RecordMatcher - Save the current node in the operand list.
@@ -251,11 +237,9 @@ public:
return N->getKind() == RecordNode;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override { return true; }
- unsigned getHashImpl() const override { return 0; }
};
/// RecordChildMatcher - Save a numbered child of the current node, or fail
@@ -285,14 +269,11 @@ public:
return N->getKind() == RecordChild;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override {
return cast<RecordChildMatcher>(M)->getChildNo() == getChildNo();
}
- unsigned getHashImpl() const override { return getChildNo(); }
};
/// RecordMemRefMatcher - Save the current node's memref.
@@ -304,12 +285,9 @@ public:
return N->getKind() == RecordMemRef;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override { return true; }
- unsigned getHashImpl() const override { return 0; }
};
@@ -323,12 +301,9 @@ public:
return N->getKind() == CaptureGlueInput;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override { return true; }
- unsigned getHashImpl() const override { return 0; }
};
/// MoveChildMatcher - This tells the interpreter to move into the
@@ -344,14 +319,11 @@ public:
return N->getKind() == MoveChild;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override {
return cast<MoveChildMatcher>(M)->getChildNo() == getChildNo();
}
- unsigned getHashImpl() const override { return getChildNo(); }
};
/// MoveParentMatcher - This tells the interpreter to move to the parent
@@ -364,12 +336,9 @@ public:
return N->getKind() == MoveParent;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override { return true; }
- unsigned getHashImpl() const override { return 0; }
};
/// CheckSameMatcher - This checks to see if this node is exactly the same
@@ -387,14 +356,11 @@ public:
return N->getKind() == CheckSame;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override {
return cast<CheckSameMatcher>(M)->getMatchNumber() == getMatchNumber();
}
- unsigned getHashImpl() const override { return getMatchNumber(); }
};
/// CheckChildSameMatcher - This checks to see if child node is exactly the same
@@ -414,15 +380,12 @@ public:
return N->getKind() == CheckChildSame;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override {
return cast<CheckChildSameMatcher>(M)->ChildNo == ChildNo &&
cast<CheckChildSameMatcher>(M)->MatchNumber == MatchNumber;
}
- unsigned getHashImpl() const override { return (MatchNumber << 2) | ChildNo; }
};
/// CheckPatternPredicateMatcher - This checks the target-specific predicate
@@ -440,14 +403,11 @@ public:
return N->getKind() == CheckPatternPredicate;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override {
return cast<CheckPatternPredicateMatcher>(M)->getPredicate() == Predicate;
}
- unsigned getHashImpl() const override;
};
/// CheckPredicateMatcher - This checks the target-specific predicate to
@@ -463,15 +423,11 @@ public:
return N->getKind() == CheckPredicate;
}
- // TODO: Ok?
- //virtual bool isSafeToReorderWithPatternPredicate() const { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override {
return cast<CheckPredicateMatcher>(M)->Pred == Pred;
}
- unsigned getHashImpl() const override;
};
@@ -489,12 +445,9 @@ public:
return N->getKind() == CheckOpcode;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override;
- unsigned getHashImpl() const override;
bool isContradictoryImpl(const Matcher *M) const override;
};
@@ -522,7 +475,6 @@ public:
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override { return false; }
- unsigned getHashImpl() const override { return 4123; }
};
/// CheckTypeMatcher - This checks to see if the current node has the
@@ -541,14 +493,11 @@ public:
return N->getKind() == CheckType;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override {
return cast<CheckTypeMatcher>(M)->Type == Type;
}
- unsigned getHashImpl() const override { return Type; }
bool isContradictoryImpl(const Matcher *M) const override;
};
@@ -576,7 +525,6 @@ public:
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override { return false; }
- unsigned getHashImpl() const override { return 4123; }
};
@@ -596,15 +544,12 @@ public:
return N->getKind() == CheckChildType;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override {
return cast<CheckChildTypeMatcher>(M)->ChildNo == ChildNo &&
cast<CheckChildTypeMatcher>(M)->Type == Type;
}
- unsigned getHashImpl() const override { return (Type << 3) | ChildNo; }
bool isContradictoryImpl(const Matcher *M) const override;
};
@@ -623,14 +568,11 @@ public:
return N->getKind() == CheckInteger;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override {
return cast<CheckIntegerMatcher>(M)->Value == Value;
}
- unsigned getHashImpl() const override { return Value; }
bool isContradictoryImpl(const Matcher *M) const override;
};
@@ -650,15 +592,12 @@ public:
return N->getKind() == CheckChildInteger;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override {
return cast<CheckChildIntegerMatcher>(M)->ChildNo == ChildNo &&
cast<CheckChildIntegerMatcher>(M)->Value == Value;
}
- unsigned getHashImpl() const override { return (Value << 3) | ChildNo; }
bool isContradictoryImpl(const Matcher *M) const override;
};
@@ -676,14 +615,11 @@ public:
return N->getKind() == CheckCondCode;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override {
return cast<CheckCondCodeMatcher>(M)->CondCodeName == CondCodeName;
}
- unsigned getHashImpl() const override;
};
/// CheckValueTypeMatcher - This checks to see if the current node is a
@@ -700,14 +636,11 @@ public:
return N->getKind() == CheckValueType;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override {
return cast<CheckValueTypeMatcher>(M)->TypeName == TypeName;
}
- unsigned getHashImpl() const override;
bool isContradictoryImpl(const Matcher *M) const override;
};
@@ -744,18 +677,12 @@ public:
return N->getKind() == CheckComplexPat;
}
- // Not safe to move a pattern predicate past a complex pattern.
- bool isSafeToReorderWithPatternPredicate() const override { return false; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override {
return &cast<CheckComplexPatMatcher>(M)->Pattern == &Pattern &&
cast<CheckComplexPatMatcher>(M)->MatchNumber == MatchNumber;
}
- unsigned getHashImpl() const override {
- return (unsigned)(intptr_t)&Pattern ^ MatchNumber;
- }
};
/// CheckAndImmMatcher - This checks to see if the current node is an 'and'
@@ -772,14 +699,11 @@ public:
return N->getKind() == CheckAndImm;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override {
return cast<CheckAndImmMatcher>(M)->Value == Value;
}
- unsigned getHashImpl() const override { return Value; }
};
/// CheckOrImmMatcher - This checks to see if the current node is an 'and'
@@ -796,14 +720,11 @@ public:
return N->getKind() == CheckOrImm;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override {
return cast<CheckOrImmMatcher>(M)->Value == Value;
}
- unsigned getHashImpl() const override { return Value; }
};
/// CheckFoldableChainNodeMatcher - This checks to see if the current node
@@ -817,12 +738,9 @@ public:
return N->getKind() == CheckFoldableChainNode;
}
- bool isSafeToReorderWithPatternPredicate() const override { return true; }
-
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override { return true; }
- unsigned getHashImpl() const override { return 0; }
};
/// EmitIntegerMatcher - This creates a new TargetConstant.
@@ -846,7 +764,6 @@ private:
return cast<EmitIntegerMatcher>(M)->Val == Val &&
cast<EmitIntegerMatcher>(M)->VT == VT;
}
- unsigned getHashImpl() const override { return (Val << 4) | VT; }
};
/// EmitStringIntegerMatcher - A target constant whose value is represented
@@ -871,7 +788,6 @@ private:
return cast<EmitStringIntegerMatcher>(M)->Val == Val &&
cast<EmitStringIntegerMatcher>(M)->VT == VT;
}
- unsigned getHashImpl() const override;
};
/// EmitRegisterMatcher - This creates a new TargetConstant.
@@ -897,9 +813,6 @@ private:
return cast<EmitRegisterMatcher>(M)->Reg == Reg &&
cast<EmitRegisterMatcher>(M)->VT == VT;
}
- unsigned getHashImpl() const override {
- return ((unsigned)(intptr_t)Reg) << 4 | VT;
- }
};
/// EmitConvertToTargetMatcher - Emit an operation that reads a specified
@@ -922,7 +835,6 @@ private:
bool isEqualImpl(const Matcher *M) const override {
return cast<EmitConvertToTargetMatcher>(M)->Slot == Slot;
}
- unsigned getHashImpl() const override { return Slot; }
};
/// EmitMergeInputChainsMatcher - Emit a node that merges a list of input
@@ -951,7 +863,6 @@ private:
bool isEqualImpl(const Matcher *M) const override {
return cast<EmitMergeInputChainsMatcher>(M)->ChainNodes == ChainNodes;
}
- unsigned getHashImpl() const override;
};
/// EmitCopyToRegMatcher - Emit a CopyToReg node from a value to a physreg,
@@ -977,9 +888,6 @@ private:
return cast<EmitCopyToRegMatcher>(M)->SrcSlot == SrcSlot &&
cast<EmitCopyToRegMatcher>(M)->DestPhysReg == DestPhysReg;
}
- unsigned getHashImpl() const override {
- return SrcSlot ^ ((unsigned)(intptr_t)DestPhysReg << 4);
- }
};
@@ -1006,9 +914,6 @@ private:
return cast<EmitNodeXFormMatcher>(M)->Slot == Slot &&
cast<EmitNodeXFormMatcher>(M)->NodeXForm == NodeXForm;
}
- unsigned getHashImpl() const override {
- return Slot ^ ((unsigned)(intptr_t)NodeXForm << 4);
- }
};
/// EmitNodeMatcherCommon - Common class shared between EmitNode and
@@ -1066,7 +971,6 @@ public:
private:
void printImpl(raw_ostream &OS, unsigned indent) const override;
bool isEqualImpl(const Matcher *M) const override;
- unsigned getHashImpl() const override;
};
/// EmitNodeMatcher - This signals a successful match and generates a node.
@@ -1116,34 +1020,6 @@ public:
}
};
-/// MarkGlueResultsMatcher - This node indicates which non-root nodes in the
-/// pattern produce glue. This allows CompleteMatchMatcher to update them
-/// with the output glue of the resultant code.
-class MarkGlueResultsMatcher : public Matcher {
- SmallVector<unsigned, 3> GlueResultNodes;
-public:
- MarkGlueResultsMatcher(ArrayRef<unsigned> nodes)
- : Matcher(MarkGlueResults), GlueResultNodes(nodes.begin(), nodes.end()) {}
-
- unsigned getNumNodes() const { return GlueResultNodes.size(); }
-
- unsigned getNode(unsigned i) const {
- assert(i < GlueResultNodes.size());
- return GlueResultNodes[i];
- }
-
- static inline bool classof(const Matcher *N) {
- return N->getKind() == MarkGlueResults;
- }
-
-private:
- void printImpl(raw_ostream &OS, unsigned indent) const override;
- bool isEqualImpl(const Matcher *M) const override {
- return cast<MarkGlueResultsMatcher>(M)->GlueResultNodes == GlueResultNodes;
- }
- unsigned getHashImpl() const override;
-};
-
/// CompleteMatchMatcher - Complete a match by replacing the results of the
/// pattern with the newly generated nodes. This also prints a comment
/// indicating the source and dest patterns.
@@ -1170,7 +1046,6 @@ private:
return cast<CompleteMatchMatcher>(M)->Results == Results &&
&cast<CompleteMatchMatcher>(M)->Pattern == &Pattern;
}
- unsigned getHashImpl() const override;
};
} // end namespace llvm
diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp
index 26f53dca63618..d30fc5131cbaf 100644
--- a/utils/TableGen/DAGISelMatcherEmitter.cpp
+++ b/utils/TableGen/DAGISelMatcherEmitter.cpp
@@ -247,9 +247,16 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
OS << "OPC_CaptureGlueInput,\n";
return 1;
- case Matcher::MoveChild:
- OS << "OPC_MoveChild, " << cast<MoveChildMatcher>(N)->getChildNo() << ",\n";
- return 2;
+ case Matcher::MoveChild: {
+ const auto *MCM = cast<MoveChildMatcher>(N);
+
+ OS << "OPC_MoveChild";
+ // Handle the specialized forms.
+ if (MCM->getChildNo() >= 8)
+ OS << ", ";
+ OS << MCM->getChildNo() << ",\n";
+ return (MCM->getChildNo() >= 8) ? 2 : 1;
+ }
case Matcher::MoveParent:
OS << "OPC_MoveParent,\n";
@@ -500,8 +507,8 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
const EmitMergeInputChainsMatcher *MN =
cast<EmitMergeInputChainsMatcher>(N);
- // Handle the specialized forms OPC_EmitMergeInputChains1_0 and 1_1.
- if (MN->getNumNodes() == 1 && MN->getNode(0) < 2) {
+ // Handle the specialized forms OPC_EmitMergeInputChains1_0, 1_1, and 1_2.
+ if (MN->getNumNodes() == 1 && MN->getNode(0) < 3) {
OS << "OPC_EmitMergeInputChains1_" << MN->getNode(0) << ",\n";
return 1;
}
@@ -532,6 +539,10 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
case Matcher::MorphNodeTo: {
const EmitNodeMatcherCommon *EN = cast<EmitNodeMatcherCommon>(N);
OS << (isa<EmitNodeMatcher>(EN) ? "OPC_EmitNode" : "OPC_MorphNodeTo");
+ bool CompressVTs = EN->getNumVTs() < 3;
+ if (CompressVTs)
+ OS << EN->getNumVTs();
+
OS << ", TARGET_VAL(" << EN->getOpcodeName() << "), 0";
if (EN->hasChain()) OS << "|OPFL_Chain";
@@ -542,10 +553,13 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
OS << "|OPFL_Variadic" << EN->getNumFixedArityOperands();
OS << ",\n";
- OS.PadToColumn(Indent*2+4) << EN->getNumVTs();
- if (!OmitComments)
- OS << "/*#VTs*/";
- OS << ", ";
+ OS.PadToColumn(Indent*2+4);
+ if (!CompressVTs) {
+ OS << EN->getNumVTs();
+ if (!OmitComments)
+ OS << "/*#VTs*/";
+ OS << ", ";
+ }
for (unsigned i = 0, e = EN->getNumVTs(); i != e; ++i)
OS << getEnumName(EN->getVT(i)) << ", ";
@@ -579,16 +593,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
} else
OS << '\n';
- return 6+EN->getNumVTs()+NumOperandBytes;
- }
- case Matcher::MarkGlueResults: {
- const MarkGlueResultsMatcher *CFR = cast<MarkGlueResultsMatcher>(N);
- OS << "OPC_MarkGlueResults, " << CFR->getNumNodes() << ", ";
- unsigned NumOperandBytes = 0;
- for (unsigned i = 0, e = CFR->getNumNodes(); i != e; ++i)
- NumOperandBytes += EmitVBRValue(CFR->getNode(i), OS);
- OS << '\n';
- return 2+NumOperandBytes;
+ return 5 + !CompressVTs + EN->getNumVTs() + NumOperandBytes;
}
case Matcher::CompleteMatch: {
const CompleteMatchMatcher *CM = cast<CompleteMatchMatcher>(N);
@@ -807,7 +812,6 @@ void MatcherTableEmitter::EmitHistogram(const Matcher *M,
case Matcher::EmitNode: OS << "OPC_EmitNode"; break;
case Matcher::MorphNodeTo: OS << "OPC_MorphNodeTo"; break;
case Matcher::EmitNodeXForm: OS << "OPC_EmitNodeXForm"; break;
- case Matcher::MarkGlueResults: OS << "OPC_MarkGlueResults"; break;
case Matcher::CompleteMatch: OS << "OPC_CompleteMatch"; break;
}
@@ -837,8 +841,9 @@ void llvm::EmitMatcherTable(const Matcher *TheMatcher,
MatcherEmitter.EmitHistogram(TheMatcher, OS);
OS << " #undef TARGET_VAL\n";
- OS << " return SelectCodeCommon(N, MatcherTable,sizeof(MatcherTable));\n}\n";
- OS << '\n';
+ OS << " SelectCodeCommon(N, MatcherTable,sizeof(MatcherTable));\n";
+ OS << " return nullptr;\n";
+ OS << "}\n";
// Next up, emit the function for node and pattern predicates:
MatcherEmitter.EmitPredicateFunctions(OS);
diff --git a/utils/TableGen/DAGISelMatcherGen.cpp b/utils/TableGen/DAGISelMatcherGen.cpp
index 9663b71d6620d..4110e9725b5a8 100644
--- a/utils/TableGen/DAGISelMatcherGen.cpp
+++ b/utils/TableGen/DAGISelMatcherGen.cpp
@@ -10,7 +10,6 @@
#include "DAGISelMatcher.h"
#include "CodeGenDAGPatterns.h"
#include "CodeGenRegisters.h"
-#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/TableGen/Error.h"
@@ -76,10 +75,6 @@ namespace {
/// array of all of the recorded input nodes that have chains.
SmallVector<unsigned, 2> MatchedChainNodes;
- /// MatchedGlueResultNodes - This maintains the position in the recorded
- /// nodes array of all of the recorded input nodes that have glue results.
- SmallVector<unsigned, 2> MatchedGlueResultNodes;
-
/// MatchedComplexPatterns - This maintains a list of all of the
/// ComplexPatterns that we need to check. The second element of each pair
/// is the recorded operand number of the input node.
@@ -121,7 +116,7 @@ namespace {
/// If this is the first time a node with unique identifier Name has been
/// seen, record it. Otherwise, emit a check to make sure this is the same
/// node. Returns true if this is the first encounter.
- bool recordUniqueNode(std::string Name);
+ bool recordUniqueNode(const std::string &Name);
// Result Code Generation.
unsigned getNamedArgumentSlot(StringRef Name) {
@@ -426,8 +421,6 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
AddMatcher(new RecordMatcher("'" + N->getOperator()->getName() +
"' glue output node",
NextRecordedOperandNo));
- // Remember all of the nodes with output glue our pattern will match.
- MatchedGlueResultNodes.push_back(NextRecordedOperandNo++);
}
// If this node is known to have an input glue or if it *might* have an input
@@ -445,7 +438,7 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N,
}
}
-bool MatcherGen::recordUniqueNode(std::string Name) {
+bool MatcherGen::recordUniqueNode(const std::string &Name) {
unsigned &VarMapEntry = VariableMap[Name];
if (VarMapEntry == 0) {
// If it is a named node, we must emit a 'Record' opcode.
@@ -989,11 +982,6 @@ void MatcherGen::EmitResultCode() {
assert(Ops.size() >= NumSrcResults && "Didn't provide enough results");
Ops.resize(NumSrcResults);
- // If the matched pattern covers nodes which define a glue result, emit a node
- // that tells the matcher about them so that it can update their results.
- if (!MatchedGlueResultNodes.empty())
- AddMatcher(new MarkGlueResultsMatcher(MatchedGlueResultNodes));
-
AddMatcher(new CompleteMatchMatcher(Ops, Pattern));
}
diff --git a/utils/TableGen/DAGISelMatcherOpt.cpp b/utils/TableGen/DAGISelMatcherOpt.cpp
index c9ee371e3e2fe..ad385fac04389 100644
--- a/utils/TableGen/DAGISelMatcherOpt.cpp
+++ b/utils/TableGen/DAGISelMatcherOpt.cpp
@@ -13,7 +13,6 @@
#include "DAGISelMatcher.h"
#include "CodeGenDAGPatterns.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -79,24 +78,6 @@ static void ContractNodes(std::unique_ptr<Matcher> &MatcherPtr,
return ContractNodes(MatcherPtr, CGP);
}
- // Turn EmitNode->MarkFlagResults->CompleteMatch into
- // MarkFlagResults->EmitNode->CompleteMatch when we can to encourage
- // MorphNodeTo formation. This is safe because MarkFlagResults never refers
- // to the root of the pattern.
- if (isa<EmitNodeMatcher>(N) && isa<MarkGlueResultsMatcher>(N->getNext()) &&
- isa<CompleteMatchMatcher>(N->getNext()->getNext())) {
- // Unlink the two nodes from the list.
- Matcher *EmitNode = MatcherPtr.release();
- Matcher *MFR = EmitNode->takeNext();
- Matcher *Tail = MFR->takeNext();
-
- // Relink them.
- MatcherPtr.reset(MFR);
- MFR->setNext(EmitNode);
- EmitNode->setNext(Tail);
- return ContractNodes(MatcherPtr, CGP);
- }
-
// Turn EmitNode->CompleteMatch into MorphNodeTo if we can.
if (EmitNodeMatcher *EN = dyn_cast<EmitNodeMatcher>(N))
if (CompleteMatchMatcher *CM =
@@ -177,59 +158,6 @@ static void ContractNodes(std::unique_ptr<Matcher> &MatcherPtr,
}
}
-/// SinkPatternPredicates - Pattern predicates can be checked at any level of
-/// the matching tree. The generator dumps them at the top level of the pattern
-/// though, which prevents factoring from being able to see past them. This
-/// optimization sinks them as far down into the pattern as possible.
-///
-/// Conceptually, we'd like to sink these predicates all the way to the last
-/// matcher predicate in the series. However, it turns out that some
-/// ComplexPatterns have side effects on the graph, so we really don't want to
-/// run a complex pattern if the pattern predicate will fail. For this
-/// reason, we refuse to sink the pattern predicate past a ComplexPattern.
-///
-static void SinkPatternPredicates(std::unique_ptr<Matcher> &MatcherPtr) {
- // Recursively scan for a PatternPredicate.
- // If we reached the end of the chain, we're done.
- Matcher *N = MatcherPtr.get();
- if (!N) return;
-
- // Walk down all members of a scope node.
- if (ScopeMatcher *Scope = dyn_cast<ScopeMatcher>(N)) {
- for (unsigned i = 0, e = Scope->getNumChildren(); i != e; ++i) {
- std::unique_ptr<Matcher> Child(Scope->takeChild(i));
- SinkPatternPredicates(Child);
- Scope->resetChild(i, Child.release());
- }
- return;
- }
-
- // If this node isn't a CheckPatternPredicateMatcher we keep scanning until
- // we find one.
- CheckPatternPredicateMatcher *CPPM =dyn_cast<CheckPatternPredicateMatcher>(N);
- if (!CPPM)
- return SinkPatternPredicates(N->getNextPtr());
-
- // Ok, we found one, lets try to sink it. Check if we can sink it past the
- // next node in the chain. If not, we won't be able to change anything and
- // might as well bail.
- if (!CPPM->getNext()->isSafeToReorderWithPatternPredicate())
- return;
-
- // Okay, we know we can sink it past at least one node. Unlink it from the
- // chain and scan for the new insertion point.
- MatcherPtr.release(); // Don't delete CPPM.
- MatcherPtr.reset(CPPM->takeNext());
-
- N = MatcherPtr.get();
- while (N->getNext()->isSafeToReorderWithPatternPredicate())
- N = N->getNext();
-
- // At this point, we want to insert CPPM after N.
- CPPM->setNext(N->takeNext());
- N->setNext(CPPM);
-}
-
/// FindNodeWithKind - Scan a series of matchers looking for a matcher with a
/// specified kind. Return null if we didn't find one otherwise return the
/// matcher.
@@ -264,8 +192,7 @@ static void FactorNodes(std::unique_ptr<Matcher> &MatcherPtr) {
return FactorNodes(N->getNextPtr());
// Okay, pull together the children of the scope node into a vector so we can
- // inspect it more easily. While we're at it, bucket them up by the hash
- // code of their first predicate.
+ // inspect it more easily.
SmallVector<Matcher*, 32> OptionsToMatch;
for (unsigned i = 0, e = Scope->getNumChildren(); i != e; ++i) {
@@ -456,7 +383,8 @@ static void FactorNodes(std::unique_ptr<Matcher> &MatcherPtr) {
CheckOpcodeMatcher *COM = cast<CheckOpcodeMatcher>(NewOptionsToMatch[i]);
assert(Opcodes.insert(COM->getOpcode().getEnumName()).second &&
"Duplicate opcodes not factored?");
- Cases.push_back(std::make_pair(&COM->getOpcode(), COM->getNext()));
+ Cases.push_back(std::make_pair(&COM->getOpcode(), COM->takeNext()));
+ delete COM;
}
MatcherPtr.reset(new SwitchOpcodeMatcher(Cases));
@@ -486,7 +414,9 @@ static void FactorNodes(std::unique_ptr<Matcher> &MatcherPtr) {
}
Matcher *Entries[2] = { PrevMatcher, MatcherWithoutCTM };
- Cases[Entry-1].second = new ScopeMatcher(Entries);
+ std::unique_ptr<Matcher> Case(new ScopeMatcher(Entries));
+ FactorNodes(Case);
+ Cases[Entry-1].second = Case.release();
continue;
}
@@ -515,6 +445,5 @@ void
llvm::OptimizeMatcher(std::unique_ptr<Matcher> &MatcherPtr,
const CodeGenDAGPatterns &CGP) {
ContractNodes(MatcherPtr, CGP);
- SinkPatternPredicates(MatcherPtr);
FactorNodes(MatcherPtr);
}
diff --git a/utils/TableGen/DFAPacketizerEmitter.cpp b/utils/TableGen/DFAPacketizerEmitter.cpp
index 77afff7ab5c23..e31caaf3c98c6 100644
--- a/utils/TableGen/DFAPacketizerEmitter.cpp
+++ b/utils/TableGen/DFAPacketizerEmitter.cpp
@@ -1,4 +1,4 @@
-//===- DFAPacketizerEmitter.cpp - Packetization DFA for a VLIW machine-----===//
+//===- DFAPacketizerEmitter.cpp - Packetization DFA for a VLIW machine ----===//
//
// The LLVM Compiler Infrastructure
//
@@ -24,10 +24,10 @@
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include "llvm/Support/Debug.h"
-#include <list>
#include <map>
#include <string>
#include <queue>
+
using namespace llvm;
// --------------------------------------------------------------------
@@ -73,7 +73,8 @@ namespace {
InsnInput = addDFAFuncUnits(InsnInput, U);
return InsnInput;
}
-}
+} // end anonymous namespace
+
// --------------------------------------------------------------------
#ifndef NDEBUG
@@ -149,7 +150,7 @@ public:
void run(raw_ostream &OS);
};
-} // End anonymous namespace.
+} // end anonymous namespace
//
//
@@ -234,7 +235,7 @@ class State {
//
bool hasTransition(std::vector<unsigned> InsnClass) const;
};
-} // End anonymous namespace.
+} // end anonymous namespace
//
// class DFA: deterministic finite automaton for processor resource tracking.
@@ -262,7 +263,7 @@ public:
int numInsnClasses = 0,
int maxResources = 0, int numCombos = 0, int maxStages = 0);
};
-} // End anonymous namespace.
+} // end anonymous namespace
#ifndef NDEBUG
// To enable debugging, run llvm-tblgen with: "-debug-only dfa-emitter".
@@ -305,7 +306,7 @@ void dbgsIndent(unsigned indent) {
DEBUG(dbgs() << " ");
}
}
-#endif
+#endif // NDEBUG
//
// Constructors and destructors for State and DFA
@@ -454,7 +455,6 @@ void State::AddInsnClassStages(std::vector<unsigned> &InsnClass,
}
}
-
//
// canMaybeAddInsnClass - Quickly verifies if an instruction of type InsnClass
// may be a valid transition from this state i.e., can an instruction of type
@@ -505,7 +505,6 @@ bool State::canMaybeAddInsnClass(std::vector<unsigned> &InsnClass,
return false;
}
-
const State &DFA::newState() {
auto IterPair = states.insert(State());
assert(IterPair.second && "State already exists");
@@ -518,7 +517,6 @@ DFAPacketizerEmitter::DFAPacketizerEmitter(RecordKeeper &R):
TargetName(CodeGenTarget(R).getName()),
allInsnClasses(), Records(R) {}
-
//
// writeTableAndAPI - Print out a table representing the DFA and the
// associated API to create a DFA packetizer.
@@ -626,7 +624,6 @@ void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName,
OS << "};\n";
OS << "} // namespace\n";
-
//
// Emit DFA Packetizer tables if the target is a VLIW machine.
//
@@ -640,7 +637,6 @@ void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName,
OS << "} // End llvm namespace \n";
}
-
//
// collectAllFuncUnits - Construct a map of function unit names to bits.
//
@@ -713,7 +709,7 @@ int DFAPacketizerEmitter::collectAllComboFuncs(
Record *ComboFunc = FuncData->getValueAsDef("TheComboFunc");
const std::vector<Record*> &FuncList =
FuncData->getValueAsListOfDefs("FuncList");
- std::string ComboFuncName = ComboFunc->getName();
+ const std::string &ComboFuncName = ComboFunc->getName();
unsigned ComboBit = FUNameToBitsMap[ComboFuncName];
unsigned ComboResources = ComboBit;
DEBUG(dbgs() << " combo: " << ComboFuncName
@@ -735,7 +731,6 @@ int DFAPacketizerEmitter::collectAllComboFuncs(
return numCombos;
}
-
//
// collectOneInsnClass - Populate allInsnClasses with one instruction class
//
@@ -940,7 +935,7 @@ void DFAPacketizerEmitter::run(raw_ostream &OS) {
//
if (!current->hasTransition(InsnClass) &&
current->canMaybeAddInsnClass(InsnClass, ComboBitToBitsMap)) {
- const State *NewState = NULL;
+ const State *NewState = nullptr;
current->AddInsnClass(InsnClass, ComboBitToBitsMap, NewStateResources);
if (NewStateResources.size() == 0) {
DEBUG(dbgs() << " Skipped - no new states generated\n");
@@ -994,4 +989,4 @@ void EmitDFAPacketizer(RecordKeeper &RK, raw_ostream &OS) {
DFAPacketizerEmitter(RK).run(OS);
}
-} // End llvm namespace
+} // end namespaec llvm
diff --git a/utils/TableGen/DisassemblerEmitter.cpp b/utils/TableGen/DisassemblerEmitter.cpp
index e8595271bccef..44815b05f274f 100644
--- a/utils/TableGen/DisassemblerEmitter.cpp
+++ b/utils/TableGen/DisassemblerEmitter.cpp
@@ -96,12 +96,11 @@ using namespace llvm::X86Disassembler;
namespace llvm {
extern void EmitFixedLenDecoder(RecordKeeper &RK, raw_ostream &OS,
- std::string PredicateNamespace,
- std::string GPrefix,
- std::string GPostfix,
- std::string ROK,
- std::string RFail,
- std::string L);
+ const std::string &PredicateNamespace,
+ const std::string &GPrefix,
+ const std::string &GPostfix,
+ const std::string &ROK,
+ const std::string &RFail, const std::string &L);
void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) {
CodeGenTarget Target(Records);
@@ -111,7 +110,7 @@ void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) {
if (Target.getName() == "X86") {
DisassemblerTables Tables;
- const std::vector<const CodeGenInstruction*> &numberedInstructions =
+ ArrayRef<const CodeGenInstruction*> numberedInstructions =
Target.getInstructionsByEnumValue();
for (unsigned i = 0, e = numberedInstructions.size(); i != e; ++i)
diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp
index 748c923477838..debb12c4f5110 100644
--- a/utils/TableGen/FastISelEmitter.cpp
+++ b/utils/TableGen/FastISelEmitter.cpp
@@ -18,13 +18,13 @@
//===----------------------------------------------------------------------===//
#include "CodeGenDAGPatterns.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
+#include <utility>
using namespace llvm;
@@ -417,9 +417,7 @@ static std::string getLegalCName(std::string OpName) {
return OpName;
}
-FastISelMap::FastISelMap(std::string instns)
- : InstNS(instns) {
-}
+FastISelMap::FastISelMap(std::string instns) : InstNS(std::move(instns)) {}
static std::string PhyRegForNode(TreePatternNode *Op,
const CodeGenTarget &Target) {
diff --git a/utils/TableGen/FixedLenDecoderEmitter.cpp b/utils/TableGen/FixedLenDecoderEmitter.cpp
index 8ca4a1bf54040..0506400b90f65 100644
--- a/utils/TableGen/FixedLenDecoderEmitter.cpp
+++ b/utils/TableGen/FixedLenDecoderEmitter.cpp
@@ -28,6 +28,7 @@
#include "llvm/TableGen/Record.h"
#include <map>
#include <string>
+#include <utility>
#include <vector>
using namespace llvm;
@@ -47,7 +48,7 @@ struct OperandInfo {
bool HasCompleteDecoder;
OperandInfo(std::string D, bool HCD)
- : Decoder(D), HasCompleteDecoder(HCD) { }
+ : Decoder(std::move(D)), HasCompleteDecoder(HCD) {}
void addField(unsigned Base, unsigned Width, unsigned Offset) {
Fields.push_back(EncodingField(Base, Width, Offset));
@@ -78,22 +79,21 @@ struct DecoderTableInfo {
namespace {
class FixedLenDecoderEmitter {
- const std::vector<const CodeGenInstruction*> *NumberedInstructions;
+ ArrayRef<const CodeGenInstruction *> NumberedInstructions;
public:
// Defaults preserved here for documentation, even though they aren't
// strictly necessary given the way that this is currently being called.
- FixedLenDecoderEmitter(RecordKeeper &R,
- std::string PredicateNamespace,
- std::string GPrefix = "if (",
+ FixedLenDecoderEmitter(RecordKeeper &R, std::string PredicateNamespace,
+ std::string GPrefix = "if (",
std::string GPostfix = " == MCDisassembler::Fail)",
- std::string ROK = "MCDisassembler::Success",
- std::string RFail = "MCDisassembler::Fail",
- std::string L = "") :
- Target(R),
- PredicateNamespace(PredicateNamespace),
- GuardPrefix(GPrefix), GuardPostfix(GPostfix),
- ReturnOK(ROK), ReturnFail(RFail), Locals(L) {}
+ std::string ROK = "MCDisassembler::Success",
+ std::string RFail = "MCDisassembler::Fail",
+ std::string L = "")
+ : Target(R), PredicateNamespace(std::move(PredicateNamespace)),
+ GuardPrefix(std::move(GPrefix)), GuardPostfix(std::move(GPostfix)),
+ ReturnOK(std::move(ROK)), ReturnFail(std::move(RFail)),
+ Locals(std::move(L)) {}
// Emit the decoder state machine table.
void emitTable(formatted_raw_ostream &o, DecoderTable &Table,
@@ -306,7 +306,7 @@ protected:
friend class Filter;
// Vector of codegen instructions to choose our filter.
- const std::vector<const CodeGenInstruction*> &AllInstructions;
+ ArrayRef<const CodeGenInstruction *> AllInstructions;
// Vector of uid's for this filter chooser to work on.
const std::vector<unsigned> &Opcodes;
@@ -337,7 +337,7 @@ protected:
void operator=(const FilterChooser &) = delete;
public:
- FilterChooser(const std::vector<const CodeGenInstruction*> &Insts,
+ FilterChooser(ArrayRef<const CodeGenInstruction *> Insts,
const std::vector<unsigned> &IDs,
const std::map<unsigned, std::vector<OperandInfo> > &Ops,
unsigned BW,
@@ -348,7 +348,7 @@ public:
doFilter();
}
- FilterChooser(const std::vector<const CodeGenInstruction*> &Insts,
+ FilterChooser(ArrayRef<const CodeGenInstruction *> Insts,
const std::vector<unsigned> &IDs,
const std::map<unsigned, std::vector<OperandInfo> > &Ops,
const std::vector<bit_value_t> &ParentFilterBitValues,
@@ -410,9 +410,6 @@ protected:
return Filters[BestIndex];
}
- // Called from Filter::recurse() when singleton exists. For debug purpose.
- void SingletonExists(unsigned Opc) const;
-
bool PositionFiltered(unsigned i) const {
return ValueSet(FilterBitValues[i]);
}
@@ -559,7 +556,6 @@ void Filter::recurse() {
// No need to recurse for a singleton filtered instruction.
// See also Filter::emit*().
if (getNumFiltered() == 1) {
- //Owner->SingletonExists(LastOpcFiltered);
assert(FilterChooserMap.size() == 1);
return;
}
@@ -732,15 +728,15 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS,
OS.indent(Indentation) << "MCD::OPC_FilterValue, ";
// The filter value is ULEB128 encoded.
while (*I >= 128)
- OS << utostr(*I++) << ", ";
- OS << utostr(*I++) << ", ";
+ OS << (unsigned)*I++ << ", ";
+ OS << (unsigned)*I++ << ", ";
// 16-bit numtoskip value.
uint8_t Byte = *I++;
uint32_t NumToSkip = Byte;
- OS << utostr(Byte) << ", ";
+ OS << (unsigned)Byte << ", ";
Byte = *I++;
- OS << utostr(Byte) << ", ";
+ OS << (unsigned)Byte << ", ";
NumToSkip |= Byte << 8;
OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n";
break;
@@ -753,14 +749,14 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS,
<< Len << ", ";// << Val << ", " << NumToSkip << ",\n";
// ULEB128 encoded field value.
for (; *I >= 128; ++I)
- OS << utostr(*I) << ", ";
- OS << utostr(*I++) << ", ";
+ OS << (unsigned)*I << ", ";
+ OS << (unsigned)*I++ << ", ";
// 16-bit numtoskip value.
uint8_t Byte = *I++;
uint32_t NumToSkip = Byte;
- OS << utostr(Byte) << ", ";
+ OS << (unsigned)Byte << ", ";
Byte = *I++;
- OS << utostr(Byte) << ", ";
+ OS << (unsigned)Byte << ", ";
NumToSkip |= Byte << 8;
OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n";
break;
@@ -769,15 +765,15 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS,
++I;
OS.indent(Indentation) << "MCD::OPC_CheckPredicate, ";
for (; *I >= 128; ++I)
- OS << utostr(*I) << ", ";
- OS << utostr(*I++) << ", ";
+ OS << (unsigned)*I << ", ";
+ OS << (unsigned)*I++ << ", ";
// 16-bit numtoskip value.
uint8_t Byte = *I++;
uint32_t NumToSkip = Byte;
- OS << utostr(Byte) << ", ";
+ OS << (unsigned)Byte << ", ";
Byte = *I++;
- OS << utostr(Byte) << ", ";
+ OS << (unsigned)Byte << ", ";
NumToSkip |= Byte << 8;
OS << "// Skip to: " << ((I - Table.begin()) + NumToSkip) << "\n";
break;
@@ -796,17 +792,17 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS,
OS.indent(Indentation) << "MCD::OPC_" << (IsTry ? "Try" : "")
<< "Decode, ";
for (p = Buffer; *p >= 128; ++p)
- OS << utostr(*p) << ", ";
- OS << utostr(*p) << ", ";
+ OS << (unsigned)*p << ", ";
+ OS << (unsigned)*p << ", ";
// Decoder index.
for (; *I >= 128; ++I)
- OS << utostr(*I) << ", ";
- OS << utostr(*I++) << ", ";
+ OS << (unsigned)*I << ", ";
+ OS << (unsigned)*I++ << ", ";
if (!IsTry) {
OS << "// Opcode: "
- << NumberedInstructions->at(Opc)->TheDef->getName() << "\n";
+ << NumberedInstructions[Opc]->TheDef->getName() << "\n";
break;
}
@@ -815,13 +811,13 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS,
// 16-bit numtoskip value.
uint8_t Byte = *I++;
uint32_t NumToSkip = Byte;
- OS << utostr(Byte) << ", ";
+ OS << (unsigned)Byte << ", ";
Byte = *I++;
- OS << utostr(Byte) << ", ";
+ OS << (unsigned)Byte << ", ";
NumToSkip |= Byte << 8;
OS << "// Opcode: "
- << NumberedInstructions->at(Opc)->TheDef->getName()
+ << NumberedInstructions[Opc]->TheDef->getName()
<< ", skip to: " << ((I - Table.begin()) + NumToSkip) << "\n";
break;
}
@@ -832,22 +828,28 @@ void FixedLenDecoderEmitter::emitTable(formatted_raw_ostream &OS,
uint64_t Value = 0;
unsigned Shift = 0;
do {
- OS << ", " << utostr(*I);
+ OS << ", " << (unsigned)*I;
Value += (*I & 0x7f) << Shift;
Shift += 7;
} while (*I++ >= 128);
- if (Value > 127)
- OS << " /* 0x" << utohexstr(Value) << " */";
+ if (Value > 127) {
+ OS << " /* 0x";
+ OS.write_hex(Value);
+ OS << " */";
+ }
// Negative mask
Value = 0;
Shift = 0;
do {
- OS << ", " << utostr(*I);
+ OS << ", " << (unsigned)*I;
Value += (*I & 0x7f) << Shift;
Shift += 7;
} while (*I++ >= 128);
- if (Value > 127)
- OS << " /* 0x" << utohexstr(Value) << " */";
+ if (Value > 127) {
+ OS << " /* 0x";
+ OS.write_hex(Value);
+ OS << " */";
+ }
OS << ",\n";
break;
}
@@ -971,30 +973,6 @@ void FilterChooser::dumpStack(raw_ostream &o, const char *prefix) const {
}
}
-// Called from Filter::recurse() when singleton exists. For debug purpose.
-void FilterChooser::SingletonExists(unsigned Opc) const {
- insn_t Insn0;
- insnWithID(Insn0, Opc);
-
- errs() << "Singleton exists: " << nameWithID(Opc)
- << " with its decoding dominating ";
- for (unsigned i = 0; i < Opcodes.size(); ++i) {
- if (Opcodes[i] == Opc) continue;
- errs() << nameWithID(Opcodes[i]) << ' ';
- }
- errs() << '\n';
-
- dumpStack(errs(), "\t\t");
- for (unsigned i = 0; i < Opcodes.size(); ++i) {
- const std::string &Name = nameWithID(Opcodes[i]);
-
- errs() << '\t' << Name << " ";
- dumpBits(errs(),
- getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst"));
- errs() << '\n';
- }
-}
-
// Calculates the island(s) needed to decode the instruction.
// This returns a list of undecoded bits of an instructions, for example,
// Inst{20} = 1 && Inst{3-0} == 0b1111 represents two islands of yet-to-be
@@ -2250,13 +2228,13 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) {
Target.reverseBitsForLittleEndianEncoding();
// Parameterize the decoders based on namespace and instruction width.
- NumberedInstructions = &Target.getInstructionsByEnumValue();
+ NumberedInstructions = Target.getInstructionsByEnumValue();
std::map<std::pair<std::string, unsigned>,
std::vector<unsigned> > OpcMap;
std::map<unsigned, std::vector<OperandInfo> > Operands;
- for (unsigned i = 0; i < NumberedInstructions->size(); ++i) {
- const CodeGenInstruction *Inst = NumberedInstructions->at(i);
+ for (unsigned i = 0; i < NumberedInstructions.size(); ++i) {
+ const CodeGenInstruction *Inst = NumberedInstructions[i];
const Record *Def = Inst->TheDef;
unsigned Size = Def->getValueAsInt("Size");
if (Def->getValueAsString("Namespace") == "TargetOpcode" ||
@@ -2277,7 +2255,7 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) {
DecoderTableInfo TableInfo;
for (const auto &Opc : OpcMap) {
// Emit the decoder for this namespace+width combination.
- FilterChooser FC(*NumberedInstructions, Opc.second, Operands,
+ FilterChooser FC(NumberedInstructions, Opc.second, Operands,
8*Opc.first.second, this);
// The decode table is cleared for each top level decoder function. The
@@ -2318,12 +2296,10 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) {
namespace llvm {
void EmitFixedLenDecoder(RecordKeeper &RK, raw_ostream &OS,
- std::string PredicateNamespace,
- std::string GPrefix,
- std::string GPostfix,
- std::string ROK,
- std::string RFail,
- std::string L) {
+ const std::string &PredicateNamespace,
+ const std::string &GPrefix,
+ const std::string &GPostfix, const std::string &ROK,
+ const std::string &RFail, const std::string &L) {
FixedLenDecoderEmitter(RK, PredicateNamespace, GPrefix, GPostfix,
ROK, RFail, L).run(OS);
}
diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp
index a6583399fa209..02461cc0508dd 100644
--- a/utils/TableGen/InstrInfoEmitter.cpp
+++ b/utils/TableGen/InstrInfoEmitter.cpp
@@ -59,12 +59,12 @@ private:
raw_ostream &OS);
void emitOperandTypesEnum(raw_ostream &OS, const CodeGenTarget &Target);
void initOperandMapData(
- const std::vector<const CodeGenInstruction *> &NumberedInstructions,
+ ArrayRef<const CodeGenInstruction *> NumberedInstructions,
const std::string &Namespace,
std::map<std::string, unsigned> &Operands,
OpNameMapTy &OperandMap);
void emitOperandNameMappings(raw_ostream &OS, const CodeGenTarget &Target,
- const std::vector<const CodeGenInstruction*> &NumberedInstructions);
+ ArrayRef<const CodeGenInstruction*> NumberedInstructions);
// Operand information.
void EmitOperandInfo(raw_ostream &OS, OperandInfoMapTy &OperandInfoIDs);
@@ -75,8 +75,8 @@ private:
static void PrintDefList(const std::vector<Record*> &Uses,
unsigned Num, raw_ostream &OS) {
OS << "static const MCPhysReg ImplicitList" << Num << "[] = { ";
- for (unsigned i = 0, e = Uses.size(); i != e; ++i)
- OS << getQualifiedName(Uses[i]) << ", ";
+ for (Record *U : Uses)
+ OS << getQualifiedName(U) << ", ";
OS << "0 };\n";
}
@@ -177,7 +177,7 @@ void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
OS << "\n";
const CodeGenTarget &Target = CDP.getTargetInfo();
- for (const CodeGenInstruction *Inst : Target.instructions()) {
+ for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) {
std::vector<std::string> OperandInfo = GetOperandInfo(*Inst);
unsigned &N = OperandInfoIDs[OperandInfo];
if (N != 0) continue;
@@ -198,7 +198,7 @@ void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
/// each instructions. This is used to generate the OperandMap table as
/// well as the getNamedOperandIdx() function.
void InstrInfoEmitter::initOperandMapData(
- const std::vector<const CodeGenInstruction *> &NumberedInstructions,
+ ArrayRef<const CodeGenInstruction *> NumberedInstructions,
const std::string &Namespace,
std::map<std::string, unsigned> &Operands,
OpNameMapTy &OperandMap) {
@@ -234,7 +234,7 @@ void InstrInfoEmitter::initOperandMapData(
/// OpName enum
void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS,
const CodeGenTarget &Target,
- const std::vector<const CodeGenInstruction*> &NumberedInstructions) {
+ ArrayRef<const CodeGenInstruction*> NumberedInstructions) {
const std::string &Namespace = Target.getInstNamespace();
std::string OpNameNS = "OpName";
@@ -249,7 +249,7 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS,
OS << "#undef GET_INSTRINFO_OPERAND_ENUM\n";
OS << "namespace llvm {\n";
OS << "namespace " << Namespace << " {\n";
- OS << "namespace " << OpNameNS << " { \n";
+ OS << "namespace " << OpNameNS << " {\n";
OS << "enum {\n";
for (const auto &Op : Operands)
OS << " " << Op.first << " = " << Op.second << ",\n";
@@ -259,7 +259,7 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS,
OS << "} // end namespace OpName\n";
OS << "} // end namespace " << Namespace << "\n";
OS << "} // end namespace llvm\n";
- OS << "#endif //GET_INSTRINFO_OPERAND_ENUM\n";
+ OS << "#endif //GET_INSTRINFO_OPERAND_ENUM\n\n";
OS << "#ifdef GET_INSTRINFO_NAMED_OPS\n";
OS << "#undef GET_INSTRINFO_NAMED_OPS\n";
@@ -299,7 +299,7 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS,
OS << "}\n";
OS << "} // end namespace " << Namespace << "\n";
OS << "} // end namespace llvm\n";
- OS << "#endif //GET_INSTRINFO_NAMED_OPS\n";
+ OS << "#endif //GET_INSTRINFO_NAMED_OPS\n\n";
}
@@ -312,11 +312,11 @@ void InstrInfoEmitter::emitOperandTypesEnum(raw_ostream &OS,
const std::string &Namespace = Target.getInstNamespace();
std::vector<Record *> Operands = Records.getAllDerivedDefinitions("Operand");
- OS << "\n#ifdef GET_INSTRINFO_OPERAND_TYPES_ENUM\n";
+ OS << "#ifdef GET_INSTRINFO_OPERAND_TYPES_ENUM\n";
OS << "#undef GET_INSTRINFO_OPERAND_TYPES_ENUM\n";
OS << "namespace llvm {\n";
OS << "namespace " << Namespace << " {\n";
- OS << "namespace OpTypes { \n";
+ OS << "namespace OpTypes {\n";
OS << "enum OperandType {\n";
unsigned EnumVal = 0;
@@ -330,7 +330,7 @@ void InstrInfoEmitter::emitOperandTypesEnum(raw_ostream &OS,
OS << "} // end namespace OpTypes\n";
OS << "} // end namespace " << Namespace << "\n";
OS << "} // end namespace llvm\n";
- OS << "#endif // GET_INSTRINFO_OPERAND_TYPES_ENUM\n";
+ OS << "#endif // GET_INSTRINFO_OPERAND_TYPES_ENUM\n\n";
}
//===----------------------------------------------------------------------===//
@@ -339,12 +339,10 @@ void InstrInfoEmitter::emitOperandTypesEnum(raw_ostream &OS,
// run - Emit the main instruction description records for the target...
void InstrInfoEmitter::run(raw_ostream &OS) {
- emitSourceFileHeader("Target Instruction Enum Values", OS);
+ emitSourceFileHeader("Target Instruction Enum Values and Descriptors", OS);
emitEnums(OS);
- emitSourceFileHeader("Target Instruction Descriptors", OS);
-
- OS << "\n#ifdef GET_INSTRINFO_MC_DESC\n";
+ OS << "#ifdef GET_INSTRINFO_MC_DESC\n";
OS << "#undef GET_INSTRINFO_MC_DESC\n";
OS << "namespace llvm {\n\n";
@@ -358,7 +356,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
unsigned ListNumber = 0;
// Emit all of the instruction's implicit uses and defs.
- for (const CodeGenInstruction *II : Target.instructions()) {
+ for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) {
Record *Inst = II->TheDef;
std::vector<Record*> Uses = Inst->getValueAsListOfDefs("Uses");
if (!Uses.empty()) {
@@ -380,7 +378,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
// Emit all of the MCInstrDesc records in their ENUM ordering.
//
OS << "\nextern const MCInstrDesc " << TargetName << "Insts[] = {\n";
- const std::vector<const CodeGenInstruction*> &NumberedInstructions =
+ ArrayRef<const CodeGenInstruction*> NumberedInstructions =
Target.getInstructionsByEnumValue();
SequenceToOffsetTable<std::string> InstrNames;
@@ -418,26 +416,26 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
<< TargetName << "InstrNameIndices, " << TargetName << "InstrNameData, "
<< NumberedInstructions.size() << ");\n}\n\n";
- OS << "} // end llvm namespace \n";
+ OS << "} // end llvm namespace\n";
OS << "#endif // GET_INSTRINFO_MC_DESC\n\n";
// Create a TargetInstrInfo subclass to hide the MC layer initialization.
- OS << "\n#ifdef GET_INSTRINFO_HEADER\n";
+ OS << "#ifdef GET_INSTRINFO_HEADER\n";
OS << "#undef GET_INSTRINFO_HEADER\n";
std::string ClassName = TargetName + "GenInstrInfo";
OS << "namespace llvm {\n";
OS << "struct " << ClassName << " : public TargetInstrInfo {\n"
<< " explicit " << ClassName
- << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1, int CatchRetOpcode = -1);\n"
+ << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1, int CatchRetOpcode = -1, int ReturnOpcode = -1);\n"
<< " ~" << ClassName << "() override {}\n"
<< "};\n";
- OS << "} // end llvm namespace \n";
+ OS << "} // end llvm namespace\n";
OS << "#endif // GET_INSTRINFO_HEADER\n\n";
- OS << "\n#ifdef GET_INSTRINFO_CTOR_DTOR\n";
+ OS << "#ifdef GET_INSTRINFO_CTOR_DTOR\n";
OS << "#undef GET_INSTRINFO_CTOR_DTOR\n";
OS << "namespace llvm {\n";
@@ -445,12 +443,12 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
OS << "extern const unsigned " << TargetName << "InstrNameIndices[];\n";
OS << "extern const char " << TargetName << "InstrNameData[];\n";
OS << ClassName << "::" << ClassName
- << "(int CFSetupOpcode, int CFDestroyOpcode, int CatchRetOpcode)\n"
- << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode) {\n"
+ << "(int CFSetupOpcode, int CFDestroyOpcode, int CatchRetOpcode, int ReturnOpcode)\n"
+ << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode, ReturnOpcode) {\n"
<< " InitMCInstrInfo(" << TargetName << "Insts, " << TargetName
<< "InstrNameIndices, " << TargetName << "InstrNameData, "
<< NumberedInstructions.size() << ");\n}\n";
- OS << "} // end llvm namespace \n";
+ OS << "} // end llvm namespace\n";
OS << "#endif // GET_INSTRINFO_CTOR_DTOR\n\n";
@@ -564,7 +562,7 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
// emitEnums - Print out enum values for all of the instructions.
void InstrInfoEmitter::emitEnums(raw_ostream &OS) {
- OS << "\n#ifdef GET_INSTRINFO_ENUM\n";
+ OS << "#ifdef GET_INSTRINFO_ENUM\n";
OS << "#undef GET_INSTRINFO_ENUM\n";
OS << "namespace llvm {\n\n";
@@ -577,26 +575,23 @@ void InstrInfoEmitter::emitEnums(raw_ostream &OS) {
if (Namespace.empty())
PrintFatalError("No instructions defined!");
- const std::vector<const CodeGenInstruction*> &NumberedInstructions =
- Target.getInstructionsByEnumValue();
-
OS << "namespace " << Namespace << " {\n";
OS << " enum {\n";
unsigned Num = 0;
- for (const CodeGenInstruction *Inst : NumberedInstructions)
+ for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue())
OS << " " << Inst->TheDef->getName() << "\t= " << Num++ << ",\n";
- OS << " INSTRUCTION_LIST_END = " << NumberedInstructions.size() << "\n";
+ OS << " INSTRUCTION_LIST_END = " << Num << "\n";
OS << " };\n\n";
OS << "namespace Sched {\n";
OS << " enum {\n";
Num = 0;
for (const auto &Class : SchedModels.explicit_classes())
OS << " " << Class.Name << "\t= " << Num++ << ",\n";
- OS << " SCHED_LIST_END = " << SchedModels.numInstrSchedClasses() << "\n";
+ OS << " SCHED_LIST_END = " << Num << "\n";
OS << " };\n";
OS << "} // end Sched namespace\n";
OS << "} // end " << Namespace << " namespace\n";
- OS << "} // end llvm namespace \n";
+ OS << "} // end llvm namespace\n";
OS << "#endif // GET_INSTRINFO_ENUM\n\n";
}
diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp
index 42a6a152f55ec..a676159e494b9 100644
--- a/utils/TableGen/IntrinsicEmitter.cpp
+++ b/utils/TableGen/IntrinsicEmitter.cpp
@@ -20,6 +20,7 @@
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/StringMatcher.h"
#include "llvm/TableGen/TableGenBackend.h"
+#include "llvm/TableGen/StringToOffsetTable.h"
#include <algorithm>
using namespace llvm;
@@ -37,23 +38,16 @@ public:
void EmitPrefix(raw_ostream &OS);
- void EmitEnumInfo(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS);
-
- void EmitFnNameRecognizer(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS);
- void EmitIntrinsicToNameTable(const std::vector<CodeGenIntrinsic> &Ints,
+ void EmitEnumInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);
+ void EmitTargetInfo(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);
+ void EmitIntrinsicToNameTable(const CodeGenIntrinsicTable &Ints,
raw_ostream &OS);
- void EmitIntrinsicToOverloadTable(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS);
- void EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS);
- void EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS);
- void EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
+ void EmitIntrinsicToOverloadTable(const CodeGenIntrinsicTable &Ints,
raw_ostream &OS);
- void EmitIntrinsicToMSBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS);
+ void EmitGenerator(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);
+ void EmitAttributes(const CodeGenIntrinsicTable &Ints, raw_ostream &OS);
+ void EmitIntrinsicToBuiltinMap(const CodeGenIntrinsicTable &Ints, bool IsGCC,
+ raw_ostream &OS);
void EmitSuffix(raw_ostream &OS);
};
} // End anonymous namespace
@@ -65,7 +59,7 @@ public:
void IntrinsicEmitter::run(raw_ostream &OS) {
emitSourceFileHeader("Intrinsic Function Source Fragment", OS);
- std::vector<CodeGenIntrinsic> Ints = LoadIntrinsics(Records, TargetOnly);
+ CodeGenIntrinsicTable Ints(Records, TargetOnly);
if (TargetOnly && !Ints.empty())
TargetPrefix = Ints[0].TargetPrefix;
@@ -75,26 +69,29 @@ void IntrinsicEmitter::run(raw_ostream &OS) {
// Emit the enum information.
EmitEnumInfo(Ints, OS);
+ // Emit the target metadata.
+ EmitTargetInfo(Ints, OS);
+
// Emit the intrinsic ID -> name table.
EmitIntrinsicToNameTable(Ints, OS);
// Emit the intrinsic ID -> overload table.
EmitIntrinsicToOverloadTable(Ints, OS);
- // Emit the function name recognizer.
- EmitFnNameRecognizer(Ints, OS);
-
// Emit the intrinsic declaration generator.
EmitGenerator(Ints, OS);
// Emit the intrinsic parameter attributes.
EmitAttributes(Ints, OS);
- // Emit code to translate GCC builtins into LLVM intrinsics.
- EmitIntrinsicToGCCBuiltinMap(Ints, OS);
+ // Individual targets don't need GCC builtin name mappings.
+ if (!TargetOnly) {
+ // Emit code to translate GCC builtins into LLVM intrinsics.
+ EmitIntrinsicToBuiltinMap(Ints, true, OS);
- // Emit code to translate MS builtins into LLVM intrinsics.
- EmitIntrinsicToMSBuiltinMap(Ints, OS);
+ // Emit code to translate MS builtins into LLVM intrinsics.
+ EmitIntrinsicToBuiltinMap(Ints, false, OS);
+ }
EmitSuffix(OS);
}
@@ -117,7 +114,7 @@ void IntrinsicEmitter::EmitSuffix(raw_ostream &OS) {
"#endif\n\n";
}
-void IntrinsicEmitter::EmitEnumInfo(const std::vector<CodeGenIntrinsic> &Ints,
+void IntrinsicEmitter::EmitEnumInfo(const CodeGenIntrinsicTable &Ints,
raw_ostream &OS) {
OS << "// Enum values for Intrinsics.h\n";
OS << "#ifdef GET_INTRINSIC_ENUM_VALUES\n";
@@ -131,64 +128,25 @@ void IntrinsicEmitter::EmitEnumInfo(const std::vector<CodeGenIntrinsic> &Ints,
OS << "#endif\n\n";
}
-void IntrinsicEmitter::
-EmitFnNameRecognizer(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS) {
- // Build a 'first character of function name' -> intrinsic # mapping.
- std::map<char, std::vector<unsigned> > IntMapping;
- for (unsigned i = 0, e = Ints.size(); i != e; ++i)
- IntMapping[Ints[i].Name[5]].push_back(i);
-
- OS << "// Function name -> enum value recognizer code.\n";
- OS << "#ifdef GET_FUNCTION_RECOGNIZER\n";
- OS << " StringRef NameR(Name+6, Len-6); // Skip over 'llvm.'\n";
- OS << " switch (Name[5]) { // Dispatch on first letter.\n";
- OS << " default: break;\n";
- // Emit the intrinsic matching stuff by first letter.
- for (std::map<char, std::vector<unsigned> >::iterator I = IntMapping.begin(),
- E = IntMapping.end(); I != E; ++I) {
- OS << " case '" << I->first << "':\n";
- std::vector<unsigned> &IntList = I->second;
-
- // Sort in reverse order of intrinsic name so "abc.def" appears after
- // "abd.def.ghi" in the overridden name matcher
- std::sort(IntList.begin(), IntList.end(), [&](unsigned i, unsigned j) {
- return Ints[i].Name > Ints[j].Name;
- });
-
- // Emit all the overloaded intrinsics first, build a table of the
- // non-overloaded ones.
- std::vector<StringMatcher::StringPair> MatchTable;
-
- for (unsigned i = 0, e = IntList.size(); i != e; ++i) {
- unsigned IntNo = IntList[i];
- std::string Result = "return " + TargetPrefix + "Intrinsic::" +
- Ints[IntNo].EnumName + ";";
-
- if (!Ints[IntNo].isOverloaded) {
- MatchTable.push_back(std::make_pair(Ints[IntNo].Name.substr(6),Result));
- continue;
- }
-
- // For overloaded intrinsics, only the prefix needs to match
- std::string TheStr = Ints[IntNo].Name.substr(6);
- TheStr += '.'; // Require "bswap." instead of bswap.
- OS << " if (NameR.startswith(\"" << TheStr << "\")) "
- << Result << '\n';
- }
-
- // Emit the matcher logic for the fixed length strings.
- StringMatcher("NameR", MatchTable, OS).Emit(1);
- OS << " break; // end of '" << I->first << "' case.\n";
- }
-
- OS << " }\n";
+void IntrinsicEmitter::EmitTargetInfo(const CodeGenIntrinsicTable &Ints,
+ raw_ostream &OS) {
+ OS << "// Target mapping\n";
+ OS << "#ifdef GET_INTRINSIC_TARGET_DATA\n";
+ OS << "struct IntrinsicTargetInfo {\n"
+ << " StringRef Name;\n"
+ << " size_t Offset;\n"
+ << " size_t Count;\n"
+ << "};\n";
+ OS << "static const IntrinsicTargetInfo TargetInfos[] = {\n";
+ for (auto Target : Ints.Targets)
+ OS << " {\"" << Target.Name << "\", " << Target.Offset << ", "
+ << Target.Count << "},\n";
+ OS << "};\n";
OS << "#endif\n\n";
}
-void IntrinsicEmitter::
-EmitIntrinsicToNameTable(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS) {
+void IntrinsicEmitter::EmitIntrinsicToNameTable(
+ const CodeGenIntrinsicTable &Ints, raw_ostream &OS) {
OS << "// Intrinsic ID to name table\n";
OS << "#ifdef GET_INTRINSIC_NAME_TABLE\n";
OS << " // Note that entry #0 is the invalid intrinsic!\n";
@@ -197,9 +155,8 @@ EmitIntrinsicToNameTable(const std::vector<CodeGenIntrinsic> &Ints,
OS << "#endif\n\n";
}
-void IntrinsicEmitter::
-EmitIntrinsicToOverloadTable(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS) {
+void IntrinsicEmitter::EmitIntrinsicToOverloadTable(
+ const CodeGenIntrinsicTable &Ints, raw_ostream &OS) {
OS << "// Intrinsic ID to overload bitset\n";
OS << "#ifdef GET_INTRINSIC_OVERLOAD_TABLE\n";
OS << "static const uint8_t OTable[] = {\n";
@@ -421,7 +378,7 @@ static void printIITEntry(raw_ostream &OS, unsigned char X) {
OS << (unsigned)X;
}
-void IntrinsicEmitter::EmitGenerator(const std::vector<CodeGenIntrinsic> &Ints,
+void IntrinsicEmitter::EmitGenerator(const CodeGenIntrinsicTable &Ints,
raw_ostream &OS) {
// If we can compute a 32-bit fixed encoding for this intrinsic, do so and
// capture it in this vector, otherwise store a ~0U.
@@ -520,8 +477,8 @@ struct AttributeComparator {
return R->isConvergent;
// Try to order by readonly/readnone attribute.
- CodeGenIntrinsic::ModRefKind LK = L->ModRef;
- CodeGenIntrinsic::ModRefKind RK = R->ModRef;
+ CodeGenIntrinsic::ModRefBehavior LK = L->ModRef;
+ CodeGenIntrinsic::ModRefBehavior RK = R->ModRef;
if (LK != RK) return (LK > RK);
// Order by argument attributes.
@@ -532,8 +489,8 @@ struct AttributeComparator {
} // End anonymous namespace
/// EmitAttributes - This emits the Intrinsic::getAttributes method.
-void IntrinsicEmitter::
-EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
+void IntrinsicEmitter::EmitAttributes(const CodeGenIntrinsicTable &Ints,
+ raw_ostream &OS) {
OS << "// Add parameter attributes that are not common to all intrinsics.\n";
OS << "#ifdef GET_INTRINSIC_ATTRIBUTES\n";
if (TargetOnly)
@@ -606,12 +563,24 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
OS << "Attribute::NoCapture";
addComma = true;
break;
+ case CodeGenIntrinsic::Returned:
+ if (addComma)
+ OS << ",";
+ OS << "Attribute::Returned";
+ addComma = true;
+ break;
case CodeGenIntrinsic::ReadOnly:
if (addComma)
OS << ",";
OS << "Attribute::ReadOnly";
addComma = true;
break;
+ case CodeGenIntrinsic::WriteOnly:
+ if (addComma)
+ OS << ",";
+ OS << "Attribute::WriteOnly";
+ addComma = true;
+ break;
case CodeGenIntrinsic::ReadNone:
if (addComma)
OS << ",";
@@ -674,6 +643,17 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
OS << ",";
OS << "Attribute::ReadOnly";
break;
+ case CodeGenIntrinsic::WriteArgMem:
+ if (addComma)
+ OS << ",";
+ OS << "Attribute::WriteOnly,";
+ OS << "Attribute::ArgMemOnly";
+ break;
+ case CodeGenIntrinsic::WriteMem:
+ if (addComma)
+ OS << ",";
+ OS << "Attribute::WriteOnly";
+ break;
case CodeGenIntrinsic::ReadWriteArgMem:
if (addComma)
OS << ",";
@@ -704,56 +684,57 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
OS << "#endif // GET_INTRINSIC_ATTRIBUTES\n\n";
}
-/// EmitTargetBuiltins - All of the builtins in the specified map are for the
-/// same target, and we already checked it.
-static void EmitTargetBuiltins(const std::map<std::string, std::string> &BIM,
- const std::string &TargetPrefix,
- raw_ostream &OS) {
-
- std::vector<StringMatcher::StringPair> Results;
-
- for (std::map<std::string, std::string>::const_iterator I = BIM.begin(),
- E = BIM.end(); I != E; ++I) {
- std::string ResultCode =
- "return " + TargetPrefix + "Intrinsic::" + I->second + ";";
- Results.emplace_back(I->first, ResultCode);
- }
-
- StringMatcher("BuiltinName", Results, OS).Emit();
-}
-
-
-void IntrinsicEmitter::
-EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS) {
- typedef std::map<std::string, std::map<std::string, std::string> > BIMTy;
+void IntrinsicEmitter::EmitIntrinsicToBuiltinMap(
+ const CodeGenIntrinsicTable &Ints, bool IsGCC, raw_ostream &OS) {
+ StringRef CompilerName = (IsGCC ? "GCC" : "MS");
+ typedef std::map<std::string, std::map<std::string, std::string>> BIMTy;
BIMTy BuiltinMap;
+ StringToOffsetTable Table;
for (unsigned i = 0, e = Ints.size(); i != e; ++i) {
- if (!Ints[i].GCCBuiltinName.empty()) {
+ const std::string &BuiltinName =
+ IsGCC ? Ints[i].GCCBuiltinName : Ints[i].MSBuiltinName;
+ if (!BuiltinName.empty()) {
// Get the map for this target prefix.
- std::map<std::string, std::string> &BIM =BuiltinMap[Ints[i].TargetPrefix];
+ std::map<std::string, std::string> &BIM =
+ BuiltinMap[Ints[i].TargetPrefix];
- if (!BIM.insert(std::make_pair(Ints[i].GCCBuiltinName,
- Ints[i].EnumName)).second)
+ if (!BIM.insert(std::make_pair(BuiltinName, Ints[i].EnumName)).second)
PrintFatalError("Intrinsic '" + Ints[i].TheDef->getName() +
- "': duplicate GCC builtin name!");
+ "': duplicate " + CompilerName + " builtin name!");
+ Table.GetOrAddStringOffset(BuiltinName);
}
}
- OS << "// Get the LLVM intrinsic that corresponds to a GCC builtin.\n";
- OS << "// This is used by the C front-end. The GCC builtin name is passed\n";
+ OS << "// Get the LLVM intrinsic that corresponds to a builtin.\n";
+ OS << "// This is used by the C front-end. The builtin name is passed\n";
OS << "// in as BuiltinName, and a target prefix (e.g. 'ppc') is passed\n";
OS << "// in as TargetPrefix. The result is assigned to 'IntrinsicID'.\n";
- OS << "#ifdef GET_LLVM_INTRINSIC_FOR_GCC_BUILTIN\n";
+ OS << "#ifdef GET_LLVM_INTRINSIC_FOR_" << CompilerName << "_BUILTIN\n";
if (TargetOnly) {
OS << "static " << TargetPrefix << "Intrinsic::ID "
- << "getIntrinsicForGCCBuiltin(const char "
+ << "getIntrinsicFor" << CompilerName << "Builtin(const char "
<< "*TargetPrefixStr, const char *BuiltinNameStr) {\n";
} else {
- OS << "Intrinsic::ID Intrinsic::getIntrinsicForGCCBuiltin(const char "
+ OS << "Intrinsic::ID Intrinsic::getIntrinsicFor" << CompilerName
+ << "Builtin(const char "
<< "*TargetPrefixStr, const char *BuiltinNameStr) {\n";
}
+ OS << " static const char BuiltinNames[] = {\n";
+ Table.EmitCharArray(OS);
+ OS << " };\n\n";
+
+ OS << " struct BuiltinEntry {\n";
+ OS << " Intrinsic::ID IntrinID;\n";
+ OS << " unsigned StrTabOffset;\n";
+ OS << " const char *getName() const {\n";
+ OS << " return &BuiltinNames[StrTabOffset];\n";
+ OS << " }\n";
+ OS << " bool operator<(const char *RHS) const {\n";
+ OS << " return strcmp(getName(), RHS) < 0;\n";
+ OS << " }\n";
+ OS << " };\n";
+
OS << " StringRef BuiltinName(BuiltinNameStr);\n";
OS << " StringRef TargetPrefix(TargetPrefixStr);\n\n";
@@ -768,7 +749,18 @@ EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
OS << "{\n";
// Emit the comparisons for this target prefix.
- EmitTargetBuiltins(I->second, TargetPrefix, OS);
+ OS << " static const BuiltinEntry " << I->first << "Names[] = {\n";
+ for (const auto &P : I->second) {
+ OS << " {Intrinsic::" << P.second << ", "
+ << Table.GetOrAddStringOffset(P.first) << "}, // " << P.first << "\n";
+ }
+ OS << " };\n";
+ OS << " auto I = std::lower_bound(std::begin(" << I->first << "Names),\n";
+ OS << " std::end(" << I->first << "Names),\n";
+ OS << " BuiltinNameStr);\n";
+ OS << " if (I != std::end(" << I->first << "Names) &&\n";
+ OS << " strcmp(I->getName(), BuiltinNameStr) == 0)\n";
+ OS << " return I->IntrinID;\n";
OS << " }\n";
}
OS << " return ";
@@ -779,55 +771,6 @@ EmitIntrinsicToGCCBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
OS << "#endif\n\n";
}
-void IntrinsicEmitter::
-EmitIntrinsicToMSBuiltinMap(const std::vector<CodeGenIntrinsic> &Ints,
- raw_ostream &OS) {
- std::map<std::string, std::map<std::string, std::string>> TargetBuiltins;
-
- for (const auto &Intrinsic : Ints) {
- if (Intrinsic.MSBuiltinName.empty())
- continue;
-
- auto &Builtins = TargetBuiltins[Intrinsic.TargetPrefix];
- if (!Builtins.insert(std::make_pair(Intrinsic.MSBuiltinName,
- Intrinsic.EnumName)).second)
- PrintFatalError("Intrinsic '" + Intrinsic.TheDef->getName() + "': "
- "duplicate MS builtin name!");
- }
-
- OS << "// Get the LLVM intrinsic that corresponds to a MS builtin.\n"
- "// This is used by the C front-end. The MS builtin name is passed\n"
- "// in as a BuiltinName, and a target prefix (e.g. 'arm') is passed\n"
- "// in as a TargetPrefix. The result is assigned to 'IntrinsicID'.\n"
- "#ifdef GET_LLVM_INTRINSIC_FOR_MS_BUILTIN\n";
-
- OS << (TargetOnly ? "static " + TargetPrefix : "") << "Intrinsic::ID "
- << (TargetOnly ? "" : "Intrinsic::")
- << "getIntrinsicForMSBuiltin(const char *TP, const char *BN) {\n";
- OS << " StringRef BuiltinName(BN);\n"
- " StringRef TargetPrefix(TP);\n"
- "\n";
-
- for (const auto &Builtins : TargetBuiltins) {
- OS << " ";
- if (Builtins.first.empty())
- OS << "/* Target Independent Builtins */ ";
- else
- OS << "if (TargetPrefix == \"" << Builtins.first << "\") ";
- OS << "{\n";
- EmitTargetBuiltins(Builtins.second, TargetPrefix, OS);
- OS << "}";
- }
-
- OS << " return ";
- if (!TargetPrefix.empty())
- OS << "(" << TargetPrefix << "Intrinsic::ID)";
- OS << "Intrinsic::not_intrinsic;\n";
- OS << "}\n";
-
- OS << "#endif\n\n";
-}
-
void llvm::EmitIntrinsics(RecordKeeper &RK, raw_ostream &OS, bool TargetOnly) {
IntrinsicEmitter(RK, TargetOnly).run(OS);
}
diff --git a/utils/TableGen/Makefile b/utils/TableGen/Makefile
deleted file mode 100644
index 9bfd94b7576bd..0000000000000
--- a/utils/TableGen/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-##===- utils/TableGen/Makefile -----------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-TOOLNAME = llvm-tblgen
-USEDLIBS = LLVMTableGen.a LLVMSupport.a
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-include $(LEVEL)/Makefile.common
-
diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp
index b727df75626f2..9bb988f30f18a 100644
--- a/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/utils/TableGen/RegisterInfoEmitter.cpp
@@ -16,22 +16,38 @@
#include "CodeGenRegisters.h"
#include "CodeGenTarget.h"
#include "SequenceToOffsetTable.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/SparseBitVector.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/CodeGen/MachineValueType.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/SetTheory.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <deque>
+#include <iterator>
#include <set>
+#include <string>
#include <vector>
+
using namespace llvm;
namespace {
+
class RegisterInfoEmitter {
RecordKeeper &Records;
+
public:
RegisterInfoEmitter(RecordKeeper &R) : Records(R) {}
@@ -65,7 +81,8 @@ private:
void emitComposeSubRegIndexLaneMask(raw_ostream &OS, CodeGenRegBank &RegBank,
const std::string &ClassName);
};
-} // End anonymous namespace
+
+} // end anonymous namespace
// runEnums - Print out enum values for all of the registers.
void RegisterInfoEmitter::runEnums(raw_ostream &OS,
@@ -81,7 +98,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS,
emitSourceFileHeader("Target Register Enum Values", OS);
OS << "\n#ifdef GET_REGINFO_ENUM\n";
- OS << "#undef GET_REGINFO_ENUM\n";
+ OS << "#undef GET_REGINFO_ENUM\n\n";
OS << "namespace llvm {\n\n";
@@ -100,7 +117,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS,
OS << " NUM_TARGET_REGS \t// " << Registers.size()+1 << "\n";
OS << "};\n";
if (!Namespace.empty())
- OS << "}\n";
+ OS << "} // end namespace " << Namespace << "\n";
const auto &RegisterClasses = Bank.getRegClasses();
if (!RegisterClasses.empty()) {
@@ -109,7 +126,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS,
assert(RegisterClasses.size() <= 0xffff &&
"Too many register classes to fit in tables");
- OS << "\n// Register classes\n";
+ OS << "\n// Register classes\n\n";
if (!Namespace.empty())
OS << "namespace " << Namespace << " {\n";
OS << "enum {\n";
@@ -118,14 +135,14 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS,
<< " = " << RC.EnumValue << ",\n";
OS << "\n };\n";
if (!Namespace.empty())
- OS << "}\n";
+ OS << "} // end namespace " << Namespace << "\n\n";
}
const std::vector<Record*> &RegAltNameIndices = Target.getRegAltNameIndices();
// If the only definition is the default NoRegAltName, we don't need to
// emit anything.
if (RegAltNameIndices.size() > 1) {
- OS << "\n// Register alternate name indices\n";
+ OS << "\n// Register alternate name indices\n\n";
if (!Namespace.empty())
OS << "namespace " << Namespace << " {\n";
OS << "enum {\n";
@@ -134,12 +151,12 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS,
OS << " NUM_TARGET_REG_ALT_NAMES = " << RegAltNameIndices.size() << "\n";
OS << "};\n";
if (!Namespace.empty())
- OS << "}\n";
+ OS << "} // end namespace " << Namespace << "\n\n";
}
auto &SubRegIndices = Bank.getSubRegIndices();
if (!SubRegIndices.empty()) {
- OS << "\n// Subregister indices\n";
+ OS << "\n// Subregister indices\n\n";
std::string Namespace = SubRegIndices.front().getNamespace();
if (!Namespace.empty())
OS << "namespace " << Namespace << " {\n";
@@ -149,10 +166,10 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS,
OS << " " << Idx.getName() << ",\t// " << ++i << "\n";
OS << " NUM_TARGET_SUBREGS\n};\n";
if (!Namespace.empty())
- OS << "}\n";
+ OS << "} // end namespace " << Namespace << "\n\n";
}
- OS << "} // End llvm namespace\n";
+ OS << "} // end namespace llvm\n\n";
OS << "#endif // GET_REGINFO_ENUM\n\n";
}
@@ -728,15 +745,11 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS,
SubReg2SequenceIndexMap.push_back(Found);
}
- OS << "unsigned " << ClName
- << "::composeSubRegIndexLaneMaskImpl(unsigned IdxA, unsigned LaneMask)"
- " const {\n";
-
OS << " struct MaskRolOp {\n"
" unsigned Mask;\n"
" uint8_t RotateLeft;\n"
" };\n"
- " static const MaskRolOp Seqs[] = {\n";
+ " static const MaskRolOp LaneMaskComposeSequences[] = {\n";
unsigned Idx = 0;
for (size_t s = 0, se = Sequences.size(); s != se; ++s) {
OS << " ";
@@ -756,24 +769,43 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS,
for (size_t i = 0, e = SubRegIndices.size(); i != e; ++i) {
OS << " ";
unsigned Idx = SubReg2SequenceIndexMap[i];
- OS << format("&Seqs[%u]", Idx);
+ OS << format("&LaneMaskComposeSequences[%u]", Idx);
if (i+1 != e)
OS << ",";
OS << " // to " << SubRegIndices[i].getName() << "\n";
}
OS << " };\n\n";
- OS << " --IdxA; assert(IdxA < " << SubRegIndices.size()
+ OS << "LaneBitmask " << ClName
+ << "::composeSubRegIndexLaneMaskImpl(unsigned IdxA, LaneBitmask LaneMask)"
+ " const {\n"
+ " --IdxA; assert(IdxA < " << SubRegIndices.size()
<< " && \"Subregister index out of bounds\");\n"
- " unsigned Result = 0;\n"
+ " LaneBitmask Result = 0;\n"
" for (const MaskRolOp *Ops = CompositeSequences[IdxA]; Ops->Mask != 0; ++Ops)"
" {\n"
- " unsigned Masked = LaneMask & Ops->Mask;\n"
+ " LaneBitmask Masked = LaneMask & Ops->Mask;\n"
" Result |= (Masked << Ops->RotateLeft) & 0xFFFFFFFF;\n"
" Result |= (Masked >> ((32 - Ops->RotateLeft) & 0x1F));\n"
" }\n"
" return Result;\n"
- "}\n";
+ "}\n\n";
+
+ OS << "LaneBitmask " << ClName
+ << "::reverseComposeSubRegIndexLaneMaskImpl(unsigned IdxA, "
+ " LaneBitmask LaneMask) const {\n"
+ " LaneMask &= getSubRegIndexLaneMask(IdxA);\n"
+ " --IdxA; assert(IdxA < " << SubRegIndices.size()
+ << " && \"Subregister index out of bounds\");\n"
+ " LaneBitmask Result = 0;\n"
+ " for (const MaskRolOp *Ops = CompositeSequences[IdxA]; Ops->Mask != 0; ++Ops)"
+ " {\n"
+ " LaneBitmask Rotated = (LaneMask >> Ops->RotateLeft) |\n"
+ " ((LaneMask << ((32 - Ops->RotateLeft) & 0x1F)) & 0xFFFFFFFF);\n"
+ " Result |= Rotated & Ops->Mask;\n"
+ " }\n"
+ " return Result;\n"
+ "}\n\n";
}
//
@@ -785,7 +817,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
emitSourceFileHeader("MC Register Information", OS);
OS << "\n#ifdef GET_REGINFO_MC_DESC\n";
- OS << "#undef GET_REGINFO_MC_DESC\n";
+ OS << "#undef GET_REGINFO_MC_DESC\n\n";
const auto &Regs = RegBank.getRegisters();
@@ -958,7 +990,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
ArrayRef<Record*> Order = RC.getOrder();
// Give the register class a legal C name if it's anonymous.
- std::string Name = RC.getName();
+ const std::string &Name = RC.getName();
RegClassStrings.add(Name);
@@ -984,7 +1016,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
OS << "\n };\n\n";
}
- OS << "}\n\n";
+ OS << "} // end anonymous namespace\n\n";
RegClassStrings.layout();
OS << "extern const char " << TargetName << "RegClassStrings[] = {\n";
@@ -1008,7 +1040,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
<< RC.SpillSize/8 << ", "
<< RC.SpillAlignment/8 << ", "
<< RC.CopyCost << ", "
- << RC.Allocatable << " },\n";
+ << ( RC.Allocatable ? "true" : "false" ) << " },\n";
}
OS << "};\n\n";
@@ -1051,7 +1083,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target,
OS << "}\n\n";
- OS << "} // End llvm namespace\n";
+ OS << "} // end namespace llvm\n\n";
OS << "#endif // GET_REGINFO_MC_DESC\n\n";
}
@@ -1061,7 +1093,7 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
emitSourceFileHeader("Register Information Header Fragment", OS);
OS << "\n#ifdef GET_REGINFO_HEADER\n";
- OS << "#undef GET_REGINFO_HEADER\n";
+ OS << "#undef GET_REGINFO_HEADER\n\n";
const std::string &TargetName = Target.getName();
std::string ClassName = TargetName + "GenRegisterInfo";
@@ -1078,8 +1110,10 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
if (!RegBank.getSubRegIndices().empty()) {
OS << " unsigned composeSubRegIndicesImpl"
<< "(unsigned, unsigned) const override;\n"
- << " unsigned composeSubRegIndexLaneMaskImpl"
- << "(unsigned, unsigned) const override;\n"
+ << " LaneBitmask composeSubRegIndexLaneMaskImpl"
+ << "(unsigned, LaneBitmask) const override;\n"
+ << " LaneBitmask reverseComposeSubRegIndexLaneMaskImpl"
+ << "(unsigned, LaneBitmask) const override;\n"
<< " const TargetRegisterClass *getSubClassWithSubReg"
<< "(const TargetRegisterClass*, unsigned) const override;\n";
}
@@ -1113,9 +1147,9 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target,
// Output the extern for the instance.
OS << " extern const TargetRegisterClass " << Name << "RegClass;\n";
}
- OS << "} // end of namespace " << TargetName << "\n\n";
+ OS << "} // end namespace " << RegisterClasses.front().Namespace << "\n\n";
}
- OS << "} // End llvm namespace\n";
+ OS << "} // end namespace llvm\n\n";
OS << "#endif // GET_REGINFO_HEADER\n\n";
}
@@ -1128,7 +1162,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
emitSourceFileHeader("Target Register and Register Classes Information", OS);
OS << "\n#ifdef GET_REGINFO_TARGET_DESC\n";
- OS << "#undef GET_REGINFO_TARGET_DESC\n";
+ OS << "#undef GET_REGINFO_TARGET_DESC\n\n";
OS << "namespace llvm {\n\n";
@@ -1294,7 +1328,9 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
<< format("0x%08x,\n ", RC.LaneMask)
<< (unsigned)RC.AllocationPriority << ",\n "
<< (RC.HasDisjunctSubRegs?"true":"false")
- << ", /* HasDisjunctSubRegs */\n ";
+ << ", /* HasDisjunctSubRegs */\n "
+ << (RC.CoveredBySubRegs?"true":"false")
+ << ", /* CoveredBySubRegs */\n ";
if (RC.getSuperClasses().empty())
OS << "NullRegClasses,\n ";
else
@@ -1306,7 +1342,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
OS << " };\n\n";
}
- OS << "}\n";
+ OS << "} // end namespace " << RegisterClasses.front().Namespace << "\n";
}
OS << "\nnamespace {\n";
@@ -1314,19 +1350,20 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
for (const auto &RC : RegisterClasses)
OS << " &" << RC.getQualifiedName() << "RegClass,\n";
OS << " };\n";
- OS << "}\n"; // End of anonymous namespace...
+ OS << "} // end anonymous namespace\n";
// Emit extra information about registers.
const std::string &TargetName = Target.getName();
OS << "\nstatic const TargetRegisterInfoDesc "
<< TargetName << "RegInfoDesc[] = { // Extra Descriptors\n";
- OS << " { 0, 0 },\n";
+ OS << " { 0, false },\n";
const auto &Regs = RegBank.getRegisters();
for (const auto &Reg : Regs) {
OS << " { ";
OS << Reg.CostPerUse << ", "
- << int(AllocatableRegs.count(Reg.TheDef)) << " },\n";
+ << ( AllocatableRegs.count(Reg.TheDef) != 0 ? "true" : "false" )
+ << " },\n";
}
OS << "};\n"; // End of register descriptors...
@@ -1414,7 +1451,6 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
OS << "}\n\n";
-
// Emit CalleeSavedRegs information.
std::vector<Record*> CSRSets =
Records.getAllDerivedDefinitions("CalleeSavedRegs");
@@ -1482,7 +1518,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target,
<< " MF.getSubtarget().getFrameLowering());\n"
<< "}\n\n";
- OS << "} // End llvm namespace\n";
+ OS << "} // end namespace llvm\n\n";
OS << "#endif // GET_REGINFO_TARGET_DESC\n\n";
}
@@ -1503,4 +1539,4 @@ void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS) {
RegisterInfoEmitter(RK).run(OS);
}
-} // End llvm namespace
+} // end namespace llvm
diff --git a/utils/TableGen/SearchableTableEmitter.cpp b/utils/TableGen/SearchableTableEmitter.cpp
new file mode 100644
index 0000000000000..8c1b8804d1741
--- /dev/null
+++ b/utils/TableGen/SearchableTableEmitter.cpp
@@ -0,0 +1,320 @@
+//===- SearchableTableEmitter.cpp - Generate efficiently searchable tables -==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits a generic array initialized by specified fields,
+// together with companion index tables and lookup functions (binary search,
+// currently).
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+#include <algorithm>
+#include <sstream>
+#include <string>
+#include <vector>
+using namespace llvm;
+
+#define DEBUG_TYPE "searchable-table-emitter"
+
+namespace {
+
+class SearchableTableEmitter {
+ RecordKeeper &Records;
+
+public:
+ SearchableTableEmitter(RecordKeeper &R) : Records(R) {}
+
+ void run(raw_ostream &OS);
+
+private:
+ typedef std::pair<Init *, int> SearchTableEntry;
+
+ int getAsInt(BitsInit *B) {
+ return cast<IntInit>(B->convertInitializerTo(IntRecTy::get()))->getValue();
+ }
+ int getInt(Record *R, StringRef Field) {
+ return getAsInt(R->getValueAsBitsInit(Field));
+ }
+
+ std::string primaryRepresentation(Init *I) {
+ if (StringInit *SI = dyn_cast<StringInit>(I))
+ return SI->getAsString();
+ else if (BitsInit *BI = dyn_cast<BitsInit>(I))
+ return "0x" + utohexstr(getAsInt(BI));
+ else if (BitInit *BI = dyn_cast<BitInit>(I))
+ return BI->getValue() ? "true" : "false";
+ else if (CodeInit *CI = dyn_cast<CodeInit>(I)) {
+ return CI->getValue();
+ }
+ PrintFatalError(SMLoc(),
+ "invalid field type, expected: string, bits, bit or code");
+ }
+
+ std::string searchRepresentation(Init *I) {
+ std::string PrimaryRep = primaryRepresentation(I);
+ if (!isa<StringInit>(I))
+ return PrimaryRep;
+ return StringRef(PrimaryRep).upper();
+ }
+
+ std::string searchableFieldType(Init *I) {
+ if (isa<StringInit>(I))
+ return "const char *";
+ else if (BitsInit *BI = dyn_cast<BitsInit>(I)) {
+ unsigned NumBits = BI->getNumBits();
+ if (NumBits <= 8)
+ NumBits = 8;
+ else if (NumBits <= 16)
+ NumBits = 16;
+ else if (NumBits <= 32)
+ NumBits = 32;
+ else if (NumBits <= 64)
+ NumBits = 64;
+ else
+ PrintFatalError(SMLoc(), "bitfield too large to search");
+ return "uint" + utostr(NumBits) + "_t";
+ }
+ PrintFatalError(SMLoc(), "Unknown type to search by");
+ }
+
+ void emitMapping(Record *MappingDesc, raw_ostream &OS);
+ void emitMappingEnum(std::vector<Record *> &Items, Record *InstanceClass,
+ raw_ostream &OS);
+ void
+ emitPrimaryTable(StringRef Name, std::vector<std::string> &FieldNames,
+ std::vector<std::string> &SearchFieldNames,
+ std::vector<std::vector<SearchTableEntry>> &SearchTables,
+ std::vector<Record *> &Items, raw_ostream &OS);
+ void emitSearchTable(StringRef Name, StringRef Field,
+ std::vector<SearchTableEntry> &SearchTable,
+ raw_ostream &OS);
+ void emitLookupDeclaration(StringRef Name, StringRef Field, Init *I,
+ raw_ostream &OS);
+ void emitLookupFunction(StringRef Name, StringRef Field, Init *I,
+ raw_ostream &OS);
+};
+
+} // End anonymous namespace.
+
+/// Emit an enum providing symbolic access to some preferred field from
+/// C++.
+void SearchableTableEmitter::emitMappingEnum(std::vector<Record *> &Items,
+ Record *InstanceClass,
+ raw_ostream &OS) {
+ std::string EnumNameField = InstanceClass->getValueAsString("EnumNameField");
+ std::string EnumValueField;
+ if (!InstanceClass->isValueUnset("EnumValueField"))
+ EnumValueField = InstanceClass->getValueAsString("EnumValueField");
+
+ OS << "enum " << InstanceClass->getName() << "Values {\n";
+ for (auto Item : Items) {
+ OS << " " << Item->getValueAsString(EnumNameField);
+ if (EnumValueField != StringRef())
+ OS << " = " << getInt(Item, EnumValueField);
+ OS << ",\n";
+ }
+ OS << "};\n\n";
+}
+
+void SearchableTableEmitter::emitPrimaryTable(
+ StringRef Name, std::vector<std::string> &FieldNames,
+ std::vector<std::string> &SearchFieldNames,
+ std::vector<std::vector<SearchTableEntry>> &SearchTables,
+ std::vector<Record *> &Items, raw_ostream &OS) {
+ OS << "const " << Name << " " << Name << "sList[] = {\n";
+
+ for (auto Item : Items) {
+ OS << " { ";
+ for (unsigned i = 0; i < FieldNames.size(); ++i) {
+ OS << primaryRepresentation(Item->getValueInit(FieldNames[i]));
+ if (i != FieldNames.size() - 1)
+ OS << ", ";
+ }
+ OS << "},\n";
+ }
+ OS << "};\n\n";
+}
+
+void SearchableTableEmitter::emitSearchTable(
+ StringRef Name, StringRef Field, std::vector<SearchTableEntry> &SearchTable,
+ raw_ostream &OS) {
+ OS << "const std::pair<" << searchableFieldType(SearchTable[0].first)
+ << ", int> " << Name << "sBy" << Field << "[] = {\n";
+
+ if (isa<BitsInit>(SearchTable[0].first)) {
+ std::stable_sort(SearchTable.begin(), SearchTable.end(),
+ [this](const SearchTableEntry &LHS,
+ const SearchTableEntry &RHS) {
+ return getAsInt(cast<BitsInit>(LHS.first)) <
+ getAsInt(cast<BitsInit>(RHS.first));
+ });
+ } else {
+ std::stable_sort(SearchTable.begin(), SearchTable.end(),
+ [this](const SearchTableEntry &LHS,
+ const SearchTableEntry &RHS) {
+ return searchRepresentation(LHS.first) <
+ searchRepresentation(RHS.first);
+ });
+ }
+
+ for (auto Entry : SearchTable) {
+ OS << " { " << searchRepresentation(Entry.first) << ", " << Entry.second
+ << " },\n";
+ }
+ OS << "};\n\n";
+}
+
+void SearchableTableEmitter::emitLookupFunction(StringRef Name, StringRef Field,
+ Init *I, raw_ostream &OS) {
+ bool IsIntegral = isa<BitsInit>(I);
+ std::string FieldType = searchableFieldType(I);
+ std::string PairType = "std::pair<" + FieldType + ", int>";
+
+ // const SysRegs *lookupSysRegByName(const char *Name) {
+ OS << "const " << Name << " *"
+ << "lookup" << Name << "By" << Field;
+ OS << "(" << (IsIntegral ? FieldType : "StringRef") << " " << Field
+ << ") {\n";
+
+ if (IsIntegral) {
+ OS << " auto CanonicalVal = " << Field << ";\n";
+ OS << " " << PairType << " Val = {CanonicalVal, 0};\n";
+ } else {
+ // Make sure the result is null terminated because it's going via "char *".
+ OS << " std::string CanonicalVal = " << Field << ".upper();\n";
+ OS << " " << PairType << " Val = {CanonicalVal.data(), 0};\n";
+ }
+
+ OS << " ArrayRef<" << PairType << "> Table(" << Name << "sBy" << Field
+ << ");\n";
+ OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Val";
+
+ if (IsIntegral)
+ OS << ");\n";
+ else {
+ OS << ",\n ";
+ OS << "[](const " << PairType << " &LHS, const " << PairType
+ << " &RHS) {\n";
+ OS << " return StringRef(LHS.first) < StringRef(RHS.first);\n";
+ OS << " });\n\n";
+ }
+
+ OS << " if (Idx == Table.end() || CanonicalVal != Idx->first)\n";
+ OS << " return nullptr;\n";
+
+ OS << " return &" << Name << "sList[Idx->second];\n";
+ OS << "}\n\n";
+}
+
+void SearchableTableEmitter::emitLookupDeclaration(StringRef Name,
+ StringRef Field, Init *I,
+ raw_ostream &OS) {
+ bool IsIntegral = isa<BitsInit>(I);
+ std::string FieldType = searchableFieldType(I);
+ OS << "const " << Name << " *"
+ << "lookup" << Name << "By" << Field;
+ OS << "(" << (IsIntegral ? FieldType : "StringRef") << " " << Field
+ << ");\n\n";
+}
+
+void SearchableTableEmitter::emitMapping(Record *InstanceClass,
+ raw_ostream &OS) {
+ const std::string &TableName = InstanceClass->getName();
+ std::vector<Record *> Items = Records.getAllDerivedDefinitions(TableName);
+
+ // Gather all the records we're going to need for this particular mapping.
+ std::vector<std::vector<SearchTableEntry>> SearchTables;
+ std::vector<std::string> SearchFieldNames;
+
+ std::vector<std::string> FieldNames;
+ for (const RecordVal &Field : InstanceClass->getValues()) {
+ std::string FieldName = Field.getName();
+
+ // Skip uninteresting fields: either built-in, special to us, or injected
+ // template parameters (if they contain a ':').
+ if (FieldName.find(':') != std::string::npos || FieldName == "NAME" ||
+ FieldName == "SearchableFields" || FieldName == "EnumNameField" ||
+ FieldName == "EnumValueField")
+ continue;
+
+ FieldNames.push_back(FieldName);
+ }
+
+ for (auto *Field : *InstanceClass->getValueAsListInit("SearchableFields")) {
+ SearchTables.emplace_back();
+ SearchFieldNames.push_back(Field->getAsUnquotedString());
+ }
+
+ int Idx = 0;
+ for (Record *Item : Items) {
+ for (unsigned i = 0; i < SearchFieldNames.size(); ++i) {
+ Init *SearchVal = Item->getValueInit(SearchFieldNames[i]);
+ SearchTables[i].emplace_back(SearchVal, Idx);
+ }
+ ++Idx;
+ }
+
+ OS << "#ifdef GET_" << StringRef(TableName).upper() << "_DECL\n";
+ OS << "#undef GET_" << StringRef(TableName).upper() << "_DECL\n";
+
+ // Next emit the enum containing the top-level names for use in C++ code if
+ // requested
+ if (!InstanceClass->isValueUnset("EnumNameField")) {
+ emitMappingEnum(Items, InstanceClass, OS);
+ }
+
+ // And the declarations for the functions that will perform lookup.
+ for (unsigned i = 0; i < SearchFieldNames.size(); ++i)
+ emitLookupDeclaration(TableName, SearchFieldNames[i],
+ SearchTables[i][0].first, OS);
+
+ OS << "#endif\n\n";
+
+ OS << "#ifdef GET_" << StringRef(TableName).upper() << "_IMPL\n";
+ OS << "#undef GET_" << StringRef(TableName).upper() << "_IMPL\n";
+
+ // The primary data table contains all the fields defined for this map.
+ emitPrimaryTable(TableName, FieldNames, SearchFieldNames, SearchTables, Items,
+ OS);
+
+ // Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary
+ // search can be performed by "Thing".
+ for (unsigned i = 0; i < SearchTables.size(); ++i) {
+ emitSearchTable(TableName, SearchFieldNames[i], SearchTables[i], OS);
+ emitLookupFunction(TableName, SearchFieldNames[i], SearchTables[i][0].first,
+ OS);
+ }
+
+ OS << "#endif\n";
+}
+
+void SearchableTableEmitter::run(raw_ostream &OS) {
+ // Tables are defined to be the direct descendents of "SearchableEntry".
+ Record *SearchableTable = Records.getClass("SearchableTable");
+ for (auto &NameRec : Records.getClasses()) {
+ Record *Class = NameRec.second.get();
+ if (Class->getSuperClasses().size() != 1 ||
+ !Class->isSubClassOf(SearchableTable))
+ continue;
+ emitMapping(Class, OS);
+ }
+}
+
+namespace llvm {
+
+void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS) {
+ SearchableTableEmitter(RK).run(OS);
+}
+
+} // End llvm namespace.
diff --git a/utils/TableGen/SequenceToOffsetTable.h b/utils/TableGen/SequenceToOffsetTable.h
index 66506ea0638f0..e026b1c9fbf02 100644
--- a/utils/TableGen/SequenceToOffsetTable.h
+++ b/utils/TableGen/SequenceToOffsetTable.h
@@ -22,7 +22,6 @@
#include <cctype>
#include <functional>
#include <map>
-#include <vector>
namespace llvm {
diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp
index d056de003e189..228882177bdf6 100644
--- a/utils/TableGen/SubtargetEmitter.cpp
+++ b/utils/TableGen/SubtargetEmitter.cpp
@@ -13,16 +13,20 @@
#include "CodeGenTarget.h"
#include "CodeGenSchedule.h"
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/MC/MCInstrItineraries.h"
+#include "llvm/MC/MCSchedule.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <algorithm>
+#include <cassert>
+#include <cstdint>
#include <map>
#include <string>
#include <vector>
@@ -32,6 +36,7 @@ using namespace llvm;
#define DEBUG_TYPE "subtarget-emitter"
namespace {
+
class SubtargetEmitter {
// Each processor has a SchedClassDesc table with an entry for each SchedClass.
// The SchedClassDesc table indexes into a global write resource table, write
@@ -64,7 +69,7 @@ class SubtargetEmitter {
CodeGenSchedModels &SchedModels;
std::string Target;
- void Enumeration(raw_ostream &OS, const char *ClassName);
+ void Enumeration(raw_ostream &OS);
unsigned FeatureKeyValues(raw_ostream &OS);
unsigned CPUKeyValues(raw_ostream &OS);
void FormItineraryStageString(const std::string &Names,
@@ -96,7 +101,7 @@ class SubtargetEmitter {
void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS);
void EmitProcessorModels(raw_ostream &OS);
void EmitProcessorLookup(raw_ostream &OS);
- void EmitSchedModelHelpers(std::string ClassName, raw_ostream &OS);
+ void EmitSchedModelHelpers(const std::string &ClassName, raw_ostream &OS);
void EmitSchedModel(raw_ostream &OS);
void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures,
unsigned NumProcs);
@@ -107,15 +112,16 @@ public:
void run(raw_ostream &o);
};
+
} // end anonymous namespace
//
// Enumeration - Emit the specified class as an enumeration.
//
-void SubtargetEmitter::Enumeration(raw_ostream &OS,
- const char *ClassName) {
+void SubtargetEmitter::Enumeration(raw_ostream &OS) {
// Get all records of class and sort
- std::vector<Record*> DefList = Records.getAllDerivedDefinitions(ClassName);
+ std::vector<Record*> DefList =
+ Records.getAllDerivedDefinitions("SubtargetFeature");
std::sort(DefList.begin(), DefList.end(), LessRecord());
unsigned N = DefList.size();
@@ -126,8 +132,8 @@ void SubtargetEmitter::Enumeration(raw_ostream &OS,
OS << "namespace " << Target << " {\n";
- // Open enumeration. Use a 64-bit underlying type.
- OS << "enum : uint64_t {\n";
+ // Open enumeration.
+ OS << "enum {\n";
// For each record
for (unsigned i = 0; i < N;) {
@@ -142,7 +148,8 @@ void SubtargetEmitter::Enumeration(raw_ostream &OS,
}
// Close enumeration and namespace
- OS << "};\n}\n";
+ OS << "};\n";
+ OS << "} // end namespace " << Target << "\n";
}
//
@@ -357,17 +364,16 @@ EmitStageAndOperandCycleData(raw_ostream &OS,
SmallPtrSet<Record*, 8> ItinsDefSet;
// Emit functional units for all the itineraries.
- for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
- PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
+ for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {
- if (!ItinsDefSet.insert(PI->ItinsDef).second)
+ if (!ItinsDefSet.insert(ProcModel.ItinsDef).second)
continue;
- std::vector<Record*> FUs = PI->ItinsDef->getValueAsListOfDefs("FU");
+ std::vector<Record*> FUs = ProcModel.ItinsDef->getValueAsListOfDefs("FU");
if (FUs.empty())
continue;
- const std::string &Name = PI->ItinsDef->getName();
+ const std::string &Name = ProcModel.ItinsDef->getName();
OS << "\n// Functional units for \"" << Name << "\"\n"
<< "namespace " << Name << "FU {\n";
@@ -375,9 +381,9 @@ EmitStageAndOperandCycleData(raw_ostream &OS,
OS << " const unsigned " << FUs[j]->getName()
<< " = 1 << " << j << ";\n";
- OS << "}\n";
+ OS << "} // end namespace " << Name << "FU\n";
- std::vector<Record*> BPs = PI->ItinsDef->getValueAsListOfDefs("BP");
+ std::vector<Record*> BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP");
if (!BPs.empty()) {
OS << "\n// Pipeline forwarding pathes for itineraries \"" << Name
<< "\"\n" << "namespace " << Name << "Bypass {\n";
@@ -387,7 +393,7 @@ EmitStageAndOperandCycleData(raw_ostream &OS,
OS << " const unsigned " << BPs[j]->getName()
<< " = 1 << " << j << ";\n";
- OS << "}\n";
+ OS << "} // end namespace " << Name << "Bypass\n";
}
}
@@ -411,10 +417,7 @@ EmitStageAndOperandCycleData(raw_ostream &OS,
// object with computed offsets to the ProcItinLists result.
unsigned StageCount = 1, OperandCycleCount = 1;
std::map<std::string, unsigned> ItinStageMap, ItinOperandMap;
- for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
- PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
- const CodeGenProcModel &ProcModel = *PI;
-
+ for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {
// Add process itinerary to the list.
ProcItinLists.resize(ProcItinLists.size()+1);
@@ -612,9 +615,8 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel,
int BufferSize = PRDef->getValueAsInt("BufferSize");
if (PRDef->isSubClassOf("ProcResGroup")) {
RecVec ResUnits = PRDef->getValueAsListOfDefs("Resources");
- for (RecIter RUI = ResUnits.begin(), RUE = ResUnits.end();
- RUI != RUE; ++RUI) {
- NumUnits += (*RUI)->getValueAsInt("NumUnits");
+ for (Record *RU : ResUnits) {
+ NumUnits += RU->getValueAsInt("NumUnits");
}
}
else {
@@ -652,10 +654,9 @@ Record *SubtargetEmitter::FindWriteResources(
return SchedWrite.TheDef;
Record *AliasDef = nullptr;
- for (RecIter AI = SchedWrite.Aliases.begin(), AE = SchedWrite.Aliases.end();
- AI != AE; ++AI) {
+ for (Record *A : SchedWrite.Aliases) {
const CodeGenSchedRW &AliasRW =
- SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW"));
+ SchedModels.getSchedRW(A->getValueAsDef("AliasRW"));
if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) {
Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");
if (&SchedModels.getProcModel(ModelDef) != &ProcModel)
@@ -672,18 +673,17 @@ Record *SubtargetEmitter::FindWriteResources(
// Check this processor's list of write resources.
Record *ResDef = nullptr;
- for (RecIter WRI = ProcModel.WriteResDefs.begin(),
- WRE = ProcModel.WriteResDefs.end(); WRI != WRE; ++WRI) {
- if (!(*WRI)->isSubClassOf("WriteRes"))
+ for (Record *WR : ProcModel.WriteResDefs) {
+ if (!WR->isSubClassOf("WriteRes"))
continue;
- if (AliasDef == (*WRI)->getValueAsDef("WriteType")
- || SchedWrite.TheDef == (*WRI)->getValueAsDef("WriteType")) {
+ if (AliasDef == WR->getValueAsDef("WriteType")
+ || SchedWrite.TheDef == WR->getValueAsDef("WriteType")) {
if (ResDef) {
- PrintFatalError((*WRI)->getLoc(), "Resources are defined for both "
+ PrintFatalError(WR->getLoc(), "Resources are defined for both "
"SchedWrite and its alias on processor " +
ProcModel.ModelName);
}
- ResDef = *WRI;
+ ResDef = WR;
}
}
// TODO: If ProcModel has a base model (previous generation processor),
@@ -706,10 +706,9 @@ Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead,
// Check this processor's list of aliases for SchedRead.
Record *AliasDef = nullptr;
- for (RecIter AI = SchedRead.Aliases.begin(), AE = SchedRead.Aliases.end();
- AI != AE; ++AI) {
+ for (Record *A : SchedRead.Aliases) {
const CodeGenSchedRW &AliasRW =
- SchedModels.getSchedRW((*AI)->getValueAsDef("AliasRW"));
+ SchedModels.getSchedRW(A->getValueAsDef("AliasRW"));
if (AliasRW.TheDef->getValueInit("SchedModel")->isComplete()) {
Record *ModelDef = AliasRW.TheDef->getValueAsDef("SchedModel");
if (&SchedModels.getProcModel(ModelDef) != &ProcModel)
@@ -726,18 +725,17 @@ Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead,
// Check this processor's ReadAdvanceList.
Record *ResDef = nullptr;
- for (RecIter RAI = ProcModel.ReadAdvanceDefs.begin(),
- RAE = ProcModel.ReadAdvanceDefs.end(); RAI != RAE; ++RAI) {
- if (!(*RAI)->isSubClassOf("ReadAdvance"))
+ for (Record *RA : ProcModel.ReadAdvanceDefs) {
+ if (!RA->isSubClassOf("ReadAdvance"))
continue;
- if (AliasDef == (*RAI)->getValueAsDef("ReadType")
- || SchedRead.TheDef == (*RAI)->getValueAsDef("ReadType")) {
+ if (AliasDef == RA->getValueAsDef("ReadType")
+ || SchedRead.TheDef == RA->getValueAsDef("ReadType")) {
if (ResDef) {
- PrintFatalError((*RAI)->getLoc(), "Resources are defined for both "
+ PrintFatalError(RA->getLoc(), "Resources are defined for both "
"SchedRead and its alias on processor " +
ProcModel.ModelName);
}
- ResDef = *RAI;
+ ResDef = RA;
}
}
// TODO: If ProcModel has a base model (previous generation processor),
@@ -779,12 +777,10 @@ void SubtargetEmitter::ExpandProcResources(RecVec &PRVec,
SubDef = SuperDef;
}
}
- for (RecIter PRI = PM.ProcResourceDefs.begin(),
- PRE = PM.ProcResourceDefs.end();
- PRI != PRE; ++PRI) {
- if (*PRI == PRDef || !(*PRI)->isSubClassOf("ProcResGroup"))
+ for (Record *PR : PM.ProcResourceDefs) {
+ if (PR == PRDef || !PR->isSubClassOf("ProcResGroup"))
continue;
- RecVec SuperResources = (*PRI)->getValueAsListOfDefs("Resources");
+ RecVec SuperResources = PR->getValueAsListOfDefs("Resources");
RecIter SubI = SubResources.begin(), SubE = SubResources.end();
for( ; SubI != SubE; ++SubI) {
if (std::find(SuperResources.begin(), SuperResources.end(), *SubI)
@@ -793,7 +789,7 @@ void SubtargetEmitter::ExpandProcResources(RecVec &PRVec,
}
}
if (SubI == SubE) {
- PRVec.push_back(*PRI);
+ PRVec.push_back(PR);
Cycles.push_back(Cycles[i]);
}
}
@@ -809,9 +805,8 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
return;
std::vector<MCSchedClassDesc> &SCTab = SchedTables.ProcSchedClasses.back();
- for (CodeGenSchedModels::SchedClassIter SCI = SchedModels.schedClassBegin(),
- SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) {
- DEBUG(SCI->dump(&SchedModels));
+ for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) {
+ DEBUG(SC.dump(&SchedModels));
SCTab.resize(SCTab.size() + 1);
MCSchedClassDesc &SCDesc = SCTab.back();
@@ -826,7 +821,7 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
// A Variant SchedClass has no resources of its own.
bool HasVariants = false;
for (std::vector<CodeGenSchedTransition>::const_iterator
- TI = SCI->Transitions.begin(), TE = SCI->Transitions.end();
+ TI = SC.Transitions.begin(), TE = SC.Transitions.end();
TI != TE; ++TI) {
if (TI->ProcIndices[0] == 0) {
HasVariants = true;
@@ -847,24 +842,23 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
// Determine if the SchedClass is actually reachable on this processor. If
// not don't try to locate the processor resources, it will fail.
// If ProcIndices contains 0, this class applies to all processors.
- assert(!SCI->ProcIndices.empty() && "expect at least one procidx");
- if (SCI->ProcIndices[0] != 0) {
- IdxIter PIPos = std::find(SCI->ProcIndices.begin(),
- SCI->ProcIndices.end(), ProcModel.Index);
- if (PIPos == SCI->ProcIndices.end())
+ assert(!SC.ProcIndices.empty() && "expect at least one procidx");
+ if (SC.ProcIndices[0] != 0) {
+ IdxIter PIPos = std::find(SC.ProcIndices.begin(),
+ SC.ProcIndices.end(), ProcModel.Index);
+ if (PIPos == SC.ProcIndices.end())
continue;
}
- IdxVec Writes = SCI->Writes;
- IdxVec Reads = SCI->Reads;
- if (!SCI->InstRWs.empty()) {
+ IdxVec Writes = SC.Writes;
+ IdxVec Reads = SC.Reads;
+ if (!SC.InstRWs.empty()) {
// This class has a default ReadWrite list which can be overriden by
// InstRW definitions.
Record *RWDef = nullptr;
- for (RecIter RWI = SCI->InstRWs.begin(), RWE = SCI->InstRWs.end();
- RWI != RWE; ++RWI) {
- Record *RWModelDef = (*RWI)->getValueAsDef("SchedModel");
+ for (Record *RW : SC.InstRWs) {
+ Record *RWModelDef = RW->getValueAsDef("SchedModel");
if (&ProcModel == &SchedModels.getProcModel(RWModelDef)) {
- RWDef = *RWI;
+ RWDef = RW;
break;
}
}
@@ -877,19 +871,18 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
}
if (Writes.empty()) {
// Check this processor's itinerary class resources.
- for (RecIter II = ProcModel.ItinRWDefs.begin(),
- IE = ProcModel.ItinRWDefs.end(); II != IE; ++II) {
- RecVec Matched = (*II)->getValueAsListOfDefs("MatchedItinClasses");
- if (std::find(Matched.begin(), Matched.end(), SCI->ItinClassDef)
+ for (Record *I : ProcModel.ItinRWDefs) {
+ RecVec Matched = I->getValueAsListOfDefs("MatchedItinClasses");
+ if (std::find(Matched.begin(), Matched.end(), SC.ItinClassDef)
!= Matched.end()) {
- SchedModels.findRWs((*II)->getValueAsListOfDefs("OperandReadWrites"),
+ SchedModels.findRWs(I->getValueAsListOfDefs("OperandReadWrites"),
Writes, Reads);
break;
}
}
if (Writes.empty()) {
DEBUG(dbgs() << ProcModel.ModelName
- << " does not have resources for class " << SCI->Name << '\n');
+ << " does not have resources for class " << SC.Name << '\n');
}
}
// Sum resources across all operand writes.
@@ -897,9 +890,9 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
std::vector<MCWriteLatencyEntry> WriteLatencies;
std::vector<std::string> WriterNames;
std::vector<MCReadAdvanceEntry> ReadAdvanceEntries;
- for (IdxIter WI = Writes.begin(), WE = Writes.end(); WI != WE; ++WI) {
+ for (unsigned W : Writes) {
IdxVec WriteSeq;
- SchedModels.expandRWSeqForProc(*WI, WriteSeq, /*IsRead=*/false,
+ SchedModels.expandRWSeqForProc(W, WriteSeq, /*IsRead=*/false,
ProcModel);
// For each operand, create a latency entry.
@@ -915,11 +908,10 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
}
WLEntry.WriteResourceID = WriteID;
- for (IdxIter WSI = WriteSeq.begin(), WSE = WriteSeq.end();
- WSI != WSE; ++WSI) {
+ for (unsigned WS : WriteSeq) {
Record *WriteRes =
- FindWriteResources(SchedModels.getSchedWrite(*WSI), ProcModel);
+ FindWriteResources(SchedModels.getSchedWrite(WS), ProcModel);
// Mark the parent class as invalid for unsupported write types.
if (WriteRes->getValueAsBit("Unsupported")) {
@@ -981,16 +973,15 @@ void SubtargetEmitter::GenSchedClassTables(const CodeGenProcModel &ProcModel,
if (ValidWrites.empty())
WriteIDs.push_back(0);
else {
- for (RecIter VWI = ValidWrites.begin(), VWE = ValidWrites.end();
- VWI != VWE; ++VWI) {
- WriteIDs.push_back(SchedModels.getSchedRWIdx(*VWI, /*IsRead=*/false));
+ for (Record *VW : ValidWrites) {
+ WriteIDs.push_back(SchedModels.getSchedRWIdx(VW, /*IsRead=*/false));
}
}
std::sort(WriteIDs.begin(), WriteIDs.end());
- for(IdxIter WI = WriteIDs.begin(), WE = WriteIDs.end(); WI != WE; ++WI) {
+ for(unsigned W : WriteIDs) {
MCReadAdvanceEntry RAEntry;
RAEntry.UseIdx = UseIdx;
- RAEntry.WriteResourceID = *WI;
+ RAEntry.WriteResourceID = W;
RAEntry.Cycles = ReadAdvance->getValueAsInt("Cycles");
ReadAdvanceEntries.push_back(RAEntry);
}
@@ -1130,7 +1121,7 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
&& "invalid class not first");
OS << " {DBGFIELD(\"InvalidSchedClass\") "
<< MCSchedClassDesc::InvalidNumMicroOps
- << ", 0, 0, 0, 0, 0, 0, 0, 0},\n";
+ << ", false, false, 0, 0, 0, 0, 0, 0},\n";
for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) {
MCSchedClassDesc &MCDesc = SCTab[SCIdx];
@@ -1139,7 +1130,8 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
if (SchedClass.Name.size() < 18)
OS.indent(18 - SchedClass.Name.size());
OS << MCDesc.NumMicroOps
- << ", " << MCDesc.BeginGroup << ", " << MCDesc.EndGroup
+ << ", " << ( MCDesc.BeginGroup ? "true" : "false" )
+ << ", " << ( MCDesc.EndGroup ? "true" : "false" )
<< ", " << format("%2d", MCDesc.WriteProcResIdx)
<< ", " << MCDesc.NumWriteProcResEntries
<< ", " << format("%2d", MCDesc.WriteLatencyIdx)
@@ -1156,45 +1148,48 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables,
void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
// For each processor model.
- for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
- PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
+ for (const CodeGenProcModel &PM : SchedModels.procModels()) {
// Emit processor resource table.
- if (PI->hasInstrSchedModel())
- EmitProcessorResources(*PI, OS);
- else if(!PI->ProcResourceDefs.empty())
- PrintFatalError(PI->ModelDef->getLoc(), "SchedMachineModel defines "
+ if (PM.hasInstrSchedModel())
+ EmitProcessorResources(PM, OS);
+ else if(!PM.ProcResourceDefs.empty())
+ PrintFatalError(PM.ModelDef->getLoc(), "SchedMachineModel defines "
"ProcResources without defining WriteRes SchedWriteRes");
// Begin processor itinerary properties
OS << "\n";
- OS << "static const llvm::MCSchedModel " << PI->ModelName << " = {\n";
- EmitProcessorProp(OS, PI->ModelDef, "IssueWidth", ',');
- EmitProcessorProp(OS, PI->ModelDef, "MicroOpBufferSize", ',');
- EmitProcessorProp(OS, PI->ModelDef, "LoopMicroOpBufferSize", ',');
- EmitProcessorProp(OS, PI->ModelDef, "LoadLatency", ',');
- EmitProcessorProp(OS, PI->ModelDef, "HighLatency", ',');
- EmitProcessorProp(OS, PI->ModelDef, "MispredictPenalty", ',');
-
- OS << " " << (bool)(PI->ModelDef ?
- PI->ModelDef->getValueAsBit("PostRAScheduler") : 0)
- << ", // " << "PostRAScheduler\n";
-
- OS << " " << (bool)(PI->ModelDef ?
- PI->ModelDef->getValueAsBit("CompleteModel") : 0)
- << ", // " << "CompleteModel\n";
-
- OS << " " << PI->Index << ", // Processor ID\n";
- if (PI->hasInstrSchedModel())
- OS << " " << PI->ModelName << "ProcResources" << ",\n"
- << " " << PI->ModelName << "SchedClasses" << ",\n"
- << " " << PI->ProcResourceDefs.size()+1 << ",\n"
+ OS << "static const llvm::MCSchedModel " << PM.ModelName << " = {\n";
+ EmitProcessorProp(OS, PM.ModelDef, "IssueWidth", ',');
+ EmitProcessorProp(OS, PM.ModelDef, "MicroOpBufferSize", ',');
+ EmitProcessorProp(OS, PM.ModelDef, "LoopMicroOpBufferSize", ',');
+ EmitProcessorProp(OS, PM.ModelDef, "LoadLatency", ',');
+ EmitProcessorProp(OS, PM.ModelDef, "HighLatency", ',');
+ EmitProcessorProp(OS, PM.ModelDef, "MispredictPenalty", ',');
+
+ bool PostRAScheduler =
+ (PM.ModelDef ? PM.ModelDef->getValueAsBit("PostRAScheduler") : false);
+
+ OS << " " << (PostRAScheduler ? "true" : "false") << ", // "
+ << "PostRAScheduler\n";
+
+ bool CompleteModel =
+ (PM.ModelDef ? PM.ModelDef->getValueAsBit("CompleteModel") : false);
+
+ OS << " " << (CompleteModel ? "true" : "false") << ", // "
+ << "CompleteModel\n";
+
+ OS << " " << PM.Index << ", // Processor ID\n";
+ if (PM.hasInstrSchedModel())
+ OS << " " << PM.ModelName << "ProcResources" << ",\n"
+ << " " << PM.ModelName << "SchedClasses" << ",\n"
+ << " " << PM.ProcResourceDefs.size()+1 << ",\n"
<< " " << (SchedModels.schedClassEnd()
- SchedModels.schedClassBegin()) << ",\n";
else
OS << " nullptr, nullptr, 0, 0,"
<< " // No instruction-level machine model.\n";
- if (PI->hasItineraries())
- OS << " " << PI->ItinsDef->getName() << "};\n";
+ if (PM.hasItineraries())
+ OS << " " << PM.ItinsDef->getName() << "};\n";
else
OS << " nullptr}; // No Itinerary\n";
}
@@ -1260,9 +1255,8 @@ void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) {
<< "// Data tables for the new per-operand machine model.\n";
SchedClassTables SchedTables;
- for (CodeGenSchedModels::ProcIter PI = SchedModels.procModelBegin(),
- PE = SchedModels.procModelEnd(); PI != PE; ++PI) {
- GenSchedClassTables(*PI, SchedTables);
+ for (const CodeGenProcModel &ProcModel : SchedModels.procModels()) {
+ GenSchedClassTables(ProcModel, SchedTables);
}
EmitSchedClassTables(SchedTables, OS);
@@ -1274,7 +1268,7 @@ void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) {
OS << "#undef DBGFIELD";
}
-void SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName,
+void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName,
raw_ostream &OS) {
OS << "unsigned " << ClassName
<< "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI,"
@@ -1282,60 +1276,52 @@ void SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName,
std::vector<Record*> Prologs = Records.getAllDerivedDefinitions("PredicateProlog");
std::sort(Prologs.begin(), Prologs.end(), LessRecord());
- for (std::vector<Record*>::const_iterator
- PI = Prologs.begin(), PE = Prologs.end(); PI != PE; ++PI) {
- OS << (*PI)->getValueAsString("Code") << '\n';
+ for (Record *P : Prologs) {
+ OS << P->getValueAsString("Code") << '\n';
}
IdxVec VariantClasses;
- for (CodeGenSchedModels::SchedClassIter SCI = SchedModels.schedClassBegin(),
- SCE = SchedModels.schedClassEnd(); SCI != SCE; ++SCI) {
- if (SCI->Transitions.empty())
+ for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) {
+ if (SC.Transitions.empty())
continue;
- VariantClasses.push_back(SCI->Index);
+ VariantClasses.push_back(SC.Index);
}
if (!VariantClasses.empty()) {
OS << " switch (SchedClass) {\n";
- for (IdxIter VCI = VariantClasses.begin(), VCE = VariantClasses.end();
- VCI != VCE; ++VCI) {
- const CodeGenSchedClass &SC = SchedModels.getSchedClass(*VCI);
- OS << " case " << *VCI << ": // " << SC.Name << '\n';
+ for (unsigned VC : VariantClasses) {
+ const CodeGenSchedClass &SC = SchedModels.getSchedClass(VC);
+ OS << " case " << VC << ": // " << SC.Name << '\n';
IdxVec ProcIndices;
- for (std::vector<CodeGenSchedTransition>::const_iterator
- TI = SC.Transitions.begin(), TE = SC.Transitions.end();
- TI != TE; ++TI) {
+ for (const CodeGenSchedTransition &T : SC.Transitions) {
IdxVec PI;
- std::set_union(TI->ProcIndices.begin(), TI->ProcIndices.end(),
+ std::set_union(T.ProcIndices.begin(), T.ProcIndices.end(),
ProcIndices.begin(), ProcIndices.end(),
std::back_inserter(PI));
ProcIndices.swap(PI);
}
- for (IdxIter PI = ProcIndices.begin(), PE = ProcIndices.end();
- PI != PE; ++PI) {
+ for (unsigned PI : ProcIndices) {
OS << " ";
- if (*PI != 0)
- OS << "if (SchedModel->getProcessorID() == " << *PI << ") ";
- OS << "{ // " << (SchedModels.procModelBegin() + *PI)->ModelName
+ if (PI != 0)
+ OS << "if (SchedModel->getProcessorID() == " << PI << ") ";
+ OS << "{ // " << (SchedModels.procModelBegin() + PI)->ModelName
<< '\n';
- for (std::vector<CodeGenSchedTransition>::const_iterator
- TI = SC.Transitions.begin(), TE = SC.Transitions.end();
- TI != TE; ++TI) {
- if (*PI != 0 && !std::count(TI->ProcIndices.begin(),
- TI->ProcIndices.end(), *PI)) {
+ for (const CodeGenSchedTransition &T : SC.Transitions) {
+ if (PI != 0 && !std::count(T.ProcIndices.begin(),
+ T.ProcIndices.end(), PI)) {
continue;
}
OS << " if (";
- for (RecIter RI = TI->PredTerm.begin(), RE = TI->PredTerm.end();
+ for (RecIter RI = T.PredTerm.begin(), RE = T.PredTerm.end();
RI != RE; ++RI) {
- if (RI != TI->PredTerm.begin())
+ if (RI != T.PredTerm.begin())
OS << "\n && ";
OS << "(" << (*RI)->getValueAsString("Predicate") << ")";
}
OS << ")\n"
- << " return " << TI->ToClassIdx << "; // "
- << SchedModels.getSchedClass(TI->ToClassIdx).Name << '\n';
+ << " return " << T.ToClassIdx << "; // "
+ << SchedModels.getSchedClass(T.ToClassIdx).Name << '\n';
}
OS << " }\n";
- if (*PI == 0)
+ if (PI == 0)
break;
}
if (SC.isInferred())
@@ -1375,9 +1361,8 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS,
OS << " InitMCProcessorInfo(CPU, FS);\n"
<< " const FeatureBitset& Bits = getFeatureBits();\n";
- for (unsigned i = 0; i < Features.size(); i++) {
+ for (Record *R : Features) {
// Next record
- Record *R = Features[i];
const std::string &Instance = R->getName();
const std::string &Value = R->getValueAsString("Value");
const std::string &Attribute = R->getValueAsString("Attribute");
@@ -1403,15 +1388,15 @@ void SubtargetEmitter::run(raw_ostream &OS) {
emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS);
OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n";
- OS << "#undef GET_SUBTARGETINFO_ENUM\n";
+ OS << "#undef GET_SUBTARGETINFO_ENUM\n\n";
OS << "namespace llvm {\n";
- Enumeration(OS, "SubtargetFeature");
- OS << "} // end llvm namespace\n";
+ Enumeration(OS);
+ OS << "} // end namespace llvm\n\n";
OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n";
OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n";
- OS << "#undef GET_SUBTARGETINFO_MC_DESC\n";
+ OS << "#undef GET_SUBTARGETINFO_MC_DESC\n\n";
OS << "namespace llvm {\n";
#if 0
@@ -1424,7 +1409,7 @@ void SubtargetEmitter::run(raw_ostream &OS) {
EmitSchedModel(OS);
OS << "\n";
#if 0
- OS << "}\n";
+ OS << "} // end anonymous namespace\n\n";
#endif
// MCInstrInfo initialization routine.
@@ -1454,22 +1439,22 @@ void SubtargetEmitter::run(raw_ostream &OS) {
OS << "0, 0, 0";
OS << ");\n}\n\n";
- OS << "} // end llvm namespace\n";
+ OS << "} // end namespace llvm\n\n";
OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n";
OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n";
- OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n";
+ OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n\n";
OS << "#include \"llvm/Support/Debug.h\"\n";
- OS << "#include \"llvm/Support/raw_ostream.h\"\n";
+ OS << "#include \"llvm/Support/raw_ostream.h\"\n\n";
ParseFeaturesFunction(OS, NumFeatures, NumProcs);
OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n";
// Create a TargetSubtargetInfo subclass to hide the MC layer initialization.
OS << "\n#ifdef GET_SUBTARGETINFO_HEADER\n";
- OS << "#undef GET_SUBTARGETINFO_HEADER\n";
+ OS << "#undef GET_SUBTARGETINFO_HEADER\n\n";
std::string ClassName = Target + "GenSubtargetInfo";
OS << "namespace llvm {\n";
@@ -1484,14 +1469,14 @@ void SubtargetEmitter::run(raw_ostream &OS) {
<< " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)"
<< " const;\n"
<< "};\n";
- OS << "} // end llvm namespace\n";
+ OS << "} // end namespace llvm\n\n";
OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n";
OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n";
- OS << "#undef GET_SUBTARGETINFO_CTOR\n";
+ OS << "#undef GET_SUBTARGETINFO_CTOR\n\n";
- OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n";
+ OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n\n";
OS << "namespace llvm {\n";
OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n";
OS << "extern const llvm::SubtargetFeatureKV " << Target << "SubTypeKV[];\n";
@@ -1536,7 +1521,7 @@ void SubtargetEmitter::run(raw_ostream &OS) {
EmitSchedModelHelpers(ClassName, OS);
- OS << "} // end llvm namespace\n";
+ OS << "} // end namespace llvm\n\n";
OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n";
}
@@ -1548,4 +1533,4 @@ void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS) {
SubtargetEmitter(RK, CGTarget).run(OS);
}
-} // end llvm namespace
+} // end namespace llvm
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index bcc594d69a1d9..24dbe5d3a2801 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -43,7 +43,8 @@ enum ActionType {
PrintSets,
GenOptParserDefs,
GenCTags,
- GenAttributes
+ GenAttributes,
+ GenSearchableTables,
};
namespace {
@@ -89,6 +90,8 @@ namespace {
"Generate ctags-compatible index"),
clEnumValN(GenAttributes, "gen-attrs",
"Generate attributes"),
+ clEnumValN(GenSearchableTables, "gen-searchable-tables",
+ "Generate generic binary-searchable table"),
clEnumValEnd));
cl::opt<std::string>
@@ -172,6 +175,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenAttributes:
EmitAttributes(Records, OS);
break;
+ case GenSearchableTables:
+ EmitSearchableTables(Records, OS);
+ break;
}
return false;
@@ -179,7 +185,7 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
}
int main(int argc, char **argv) {
- sys::PrintStackTraceOnErrorSignal();
+ sys::PrintStackTraceOnErrorSignal(argv[0]);
PrettyStackTraceProgram X(argc, argv);
cl::ParseCommandLineOptions(argc, argv);
diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h
index d9dd3d157697b..51e017fe65942 100644
--- a/utils/TableGen/TableGenBackends.h
+++ b/utils/TableGen/TableGenBackends.h
@@ -79,6 +79,7 @@ void EmitMapTable(RecordKeeper &RK, raw_ostream &OS);
void EmitOptParser(RecordKeeper &RK, raw_ostream &OS);
void EmitCTags(RecordKeeper &RK, raw_ostream &OS);
void EmitAttributes(RecordKeeper &RK, raw_ostream &OS);
+void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS);
} // End llvm namespace
diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp
index ad36dc427a562..5b710e4461507 100644
--- a/utils/TableGen/X86DisassemblerTables.cpp
+++ b/utils/TableGen/X86DisassemblerTables.cpp
@@ -285,7 +285,7 @@ static inline bool inheritsFrom(InstructionContext child,
return false;
case IC_EVEX_L_W_K:
case IC_EVEX_L_W_B:
- case IC_EVEX_L_W_K_B:
+ case IC_EVEX_L_W_K_B:
case IC_EVEX_L_W_XS_K:
case IC_EVEX_L_W_XS_B:
case IC_EVEX_L_W_XS_K_B:
diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp
index 8a5ae12f67fb2..ca937d09726d5 100644
--- a/utils/TableGen/X86RecognizableInstr.cpp
+++ b/utils/TableGen/X86RecognizableInstr.cpp
@@ -225,7 +225,6 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables,
CD8_Scale = byteFromRec(Rec, "CD8_Scale");
Name = Rec->getName();
- AsmString = Rec->getValueAsString("AsmString");
Operands = &insn.Operands.OperandList;
@@ -477,7 +476,7 @@ void RecognizableInstr::adjustOperandEncoding(OperandEncoding &encoding) {
void RecognizableInstr::handleOperand(bool optional, unsigned &operandIndex,
unsigned &physicalOperandIndex,
- unsigned &numPhysicalOperands,
+ unsigned numPhysicalOperands,
const unsigned *operandMapping,
OperandEncoding (*encodingFromString)
(const std::string&,
@@ -562,6 +561,7 @@ void RecognizableInstr::emitInstructionSpecifier() {
// physicalOperandIndex should always be < numPhysicalOperands
unsigned physicalOperandIndex = 0;
+#ifndef NDEBUG
// Given the set of prefix bits, how many additional operands does the
// instruction have?
unsigned additionalOperands = 0;
@@ -569,6 +569,7 @@ void RecognizableInstr::emitInstructionSpecifier() {
++additionalOperands;
if (HasEVEX_K)
++additionalOperands;
+#endif
switch (Form) {
default: llvm_unreachable("Unhandled form");
@@ -584,11 +585,9 @@ void RecognizableInstr::emitInstructionSpecifier() {
return;
case X86Local::RawFrm:
// Operand 1 (optional) is an address or immediate.
- // Operand 2 (optional) is an immediate.
- assert(numPhysicalOperands <= 2 &&
+ assert(numPhysicalOperands <= 1 &&
"Unexpected number of operands for RawFrm");
HANDLE_OPTIONAL(relocation)
- HANDLE_OPTIONAL(immediate)
break;
case X86Local::RawFrmMemOffs:
// Operand 1 is an address.
@@ -800,8 +799,8 @@ void RecognizableInstr::emitInstructionSpecifier() {
case X86Local::MRM_F1: case X86Local::MRM_F2: case X86Local::MRM_F3:
case X86Local::MRM_F4: case X86Local::MRM_F5: case X86Local::MRM_F6:
case X86Local::MRM_F7: case X86Local::MRM_F9: case X86Local::MRM_FA:
- case X86Local::MRM_FB: case X86Local::MRM_FC: case X86Local::MRM_FD:
- case X86Local::MRM_FE: case X86Local::MRM_FF:
+ case X86Local::MRM_FB: case X86Local::MRM_FC: case X86Local::MRM_FD:
+ case X86Local::MRM_FE: case X86Local::MRM_FF:
// Ignored.
break;
}
@@ -1024,19 +1023,19 @@ OperandType RecognizableInstr::typeFromString(const std::string &s,
TYPE("VK32WM", TYPE_VK32)
TYPE("VK64", TYPE_VK64)
TYPE("VK64WM", TYPE_VK64)
- TYPE("GR16_NOAX", TYPE_Rv)
TYPE("GR32_NOAX", TYPE_Rv)
- TYPE("GR64_NOAX", TYPE_R64)
- TYPE("vx32mem", TYPE_M32)
- TYPE("vx32xmem", TYPE_M32)
- TYPE("vy32mem", TYPE_M32)
- TYPE("vy32xmem", TYPE_M32)
- TYPE("vz32mem", TYPE_M32)
TYPE("vx64mem", TYPE_M64)
+ TYPE("vx128mem", TYPE_M128)
+ TYPE("vx256mem", TYPE_M256)
+ TYPE("vy128mem", TYPE_M128)
+ TYPE("vy256mem", TYPE_M256)
TYPE("vx64xmem", TYPE_M64)
- TYPE("vy64mem", TYPE_M64)
- TYPE("vy64xmem", TYPE_M64)
- TYPE("vz64mem", TYPE_M64)
+ TYPE("vx128xmem", TYPE_M128)
+ TYPE("vx256xmem", TYPE_M256)
+ TYPE("vy128xmem", TYPE_M128)
+ TYPE("vy256xmem", TYPE_M256)
+ TYPE("vy512mem", TYPE_M512)
+ TYPE("vz512mem", TYPE_M512)
TYPE("BNDR", TYPE_BNDR)
errs() << "Unhandled type string " << s << "\n";
llvm_unreachable("Unhandled type string");
@@ -1220,16 +1219,18 @@ RecognizableInstr::memoryEncodingFromString(const std::string &s,
ENCODING("opaque48mem", ENCODING_RM)
ENCODING("opaque80mem", ENCODING_RM)
ENCODING("opaque512mem", ENCODING_RM)
- ENCODING("vx32mem", ENCODING_RM)
- ENCODING("vx32xmem", ENCODING_RM)
- ENCODING("vy32mem", ENCODING_RM)
- ENCODING("vy32xmem", ENCODING_RM)
- ENCODING("vz32mem", ENCODING_RM)
ENCODING("vx64mem", ENCODING_RM)
+ ENCODING("vx128mem", ENCODING_RM)
+ ENCODING("vx256mem", ENCODING_RM)
+ ENCODING("vy128mem", ENCODING_RM)
+ ENCODING("vy256mem", ENCODING_RM)
ENCODING("vx64xmem", ENCODING_RM)
- ENCODING("vy64mem", ENCODING_RM)
- ENCODING("vy64xmem", ENCODING_RM)
- ENCODING("vz64mem", ENCODING_RM)
+ ENCODING("vx128xmem", ENCODING_RM)
+ ENCODING("vx256xmem", ENCODING_RM)
+ ENCODING("vy128xmem", ENCODING_RM)
+ ENCODING("vy256xmem", ENCODING_RM)
+ ENCODING("vy512mem", ENCODING_RM)
+ ENCODING("vz512mem", ENCODING_RM)
errs() << "Unhandled memory encoding " << s << "\n";
llvm_unreachable("Unhandled memory encoding");
}
@@ -1288,9 +1289,7 @@ RecognizableInstr::opcodeModifierEncodingFromString(const std::string &s,
ENCODING("GR64", ENCODING_RO)
ENCODING("GR16", ENCODING_Rv)
ENCODING("GR8", ENCODING_RB)
- ENCODING("GR16_NOAX", ENCODING_Rv)
ENCODING("GR32_NOAX", ENCODING_Rv)
- ENCODING("GR64_NOAX", ENCODING_RO)
errs() << "Unhandled opcode modifier encoding " << s << "\n";
llvm_unreachable("Unhandled opcode modifier encoding");
}
diff --git a/utils/TableGen/X86RecognizableInstr.h b/utils/TableGen/X86RecognizableInstr.h
index 28e10535508d7..f6f50065f7049 100644
--- a/utils/TableGen/X86RecognizableInstr.h
+++ b/utils/TableGen/X86RecognizableInstr.h
@@ -19,7 +19,6 @@
#include "CodeGenTarget.h"
#include "X86DisassemblerTables.h"
-#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/TableGen/Record.h"
@@ -87,8 +86,6 @@ private:
/// The instruction name as listed in the tables
std::string Name;
- /// The AT&T AsmString for the instruction
- std::string AsmString;
/// Indicates whether the instruction should be emitted into the decode
/// tables; regardless, it will be emitted into the instruction info table
@@ -179,7 +176,7 @@ private:
void handleOperand(bool optional,
unsigned &operandIndex,
unsigned &physicalOperandIndex,
- unsigned &numPhysicalOperands,
+ unsigned numPhysicalOperands,
const unsigned *operandMapping,
OperandEncoding (*encodingFromString)
(const std::string&,
diff --git a/utils/TableGen/module.modulemap b/utils/TableGen/module.modulemap
deleted file mode 100644
index 8871bbfd4a2f7..0000000000000
--- a/utils/TableGen/module.modulemap
+++ /dev/null
@@ -1,4 +0,0 @@
-module TableGen {
- umbrella "."
- module * { export * }
-}
diff --git a/utils/abtest/abtest.py b/utils/abtest/abtest.py
new file mode 100755
index 0000000000000..ad6a3e0ea8d22
--- /dev/null
+++ b/utils/abtest/abtest.py
@@ -0,0 +1,234 @@
+#!/usr/bin/env python
+#
+# Given a previous good compile narrow down miscompiles.
+# Expects two directories named "before" and "after" each containing a set of
+# assembly or object files where the "after" version is assumed to be broken.
+# You also have to provide a script called "link_test". It is called with a list
+# of files which should be linked together and result tested. "link_test" should
+# returns with exitcode 0 if the linking and testing succeeded.
+#
+# abtest.py operates by taking all files from the "before" directory and
+# in each step replacing one of them with a file from the "bad" directory.
+#
+# Additionally you can perform the same steps with a single .s file. In this
+# mode functions are identified by "# -- Begin FunctionName" and
+# "# -- End FunctionName" markers. The abtest.py then takes all functions from
+# the file in the "before" directory and replaces one function with the
+# corresponding function from the "bad" file in each step.
+#
+# Example usage to identify miscompiled files:
+# 1. Create a link_test script, make it executable. Simple Example:
+# clang "$@" -o /tmp/test && /tmp/test || echo "PROBLEM"
+# 2. Run the script to figure out which files are miscompiled:
+# > ./abtest.py
+# somefile.s: ok
+# someotherfile.s: skipped: same content
+# anotherfile.s: failed: './link_test' exitcode != 0
+# ...
+# Example usage to identify miscompiled functions inside a file:
+# 3. First you have to mark begin and end of the functions.
+# The script comes with some examples called mark_xxx.py.
+# Unfortunately this is very specific to your environment and it is likely
+# that you have to write a custom version for your environment.
+# > for i in before/*.s after/*.s; do mark_xxx.py $i; done
+# 4. Run the tests on a single file (assuming before/file.s and
+# after/file.s exist)
+# > ./abtest.py file.s
+# funcname1 [0/XX]: ok
+# funcname2 [1/XX]: ok
+# funcname3 [2/XX]: skipped: same content
+# funcname4 [3/XX]: failed: './link_test' exitcode != 0
+# ...
+from fnmatch import filter
+from sys import stderr
+import argparse
+import filecmp
+import os
+import subprocess
+import sys
+
+LINKTEST="./link_test"
+ESCAPE="\033[%sm"
+BOLD=ESCAPE % "1"
+RED=ESCAPE % "31"
+NORMAL=ESCAPE % "0"
+FAILED=RED+"failed"+NORMAL
+
+def find(dir, file_filter=None):
+ files = [walkdir[0]+"/"+file for walkdir in os.walk(dir) for file in walkdir[2]]
+ if file_filter != None:
+ files = filter(files, file_filter)
+ return files
+
+def error(message):
+ stderr.write("Error: %s\n" % (message,))
+
+def warn(message):
+ stderr.write("Warning: %s\n" % (message,))
+
+def extract_functions(file):
+ functions = []
+ in_function = None
+ for line in open(file):
+ if line.startswith("# -- Begin "):
+ if in_function != None:
+ warn("Missing end of function %s" % (in_function,))
+ funcname = line[12:-1]
+ in_function = funcname
+ text = line
+ elif line.startswith("# -- End "):
+ function_name = line[10:-1]
+ if in_function != function_name:
+ warn("End %s does not match begin %s" % (function_name, in_function))
+ else:
+ text += line
+ functions.append( (in_function, text) )
+ in_function = None
+ elif in_function != None:
+ text += line
+ return functions
+
+def replace_function(file, function, replacement, dest):
+ out = open(dest, "w")
+ skip = False
+ found = False
+ in_function = None
+ for line in open(file):
+ if line.startswith("# -- Begin "):
+ if in_function != None:
+ warn("Missing end of function %s" % (in_function,))
+ funcname = line[12:-1]
+ in_function = funcname
+ if in_function == function:
+ out.write(replacement)
+ skip = True
+ elif line.startswith("# -- End "):
+ function_name = line[10:-1]
+ if in_function != function_name:
+ warn("End %s does not match begin %s" % (function_name, in_function))
+ in_function = None
+ if skip:
+ skip = False
+ continue
+ if not skip:
+ out.write(line)
+
+def announce_test(name):
+ stderr.write("%s%s%s: " % (BOLD, name, NORMAL))
+ stderr.flush()
+
+def announce_result(result, info):
+ stderr.write(result)
+ if info != "":
+ stderr.write(": %s" % info)
+ stderr.write("\n")
+ stderr.flush()
+
+def testrun(files):
+ linkline="%s %s" % (LINKTEST, " ".join(files),)
+ res = subprocess.call(linkline, shell=True)
+ if res != 0:
+ announce_result(FAILED, "'%s' exitcode != 0" % LINKTEST)
+ return False
+ else:
+ announce_result("ok", "")
+ return True
+
+def check_files():
+ """Check files mode"""
+ for i in range(0, len(NO_PREFIX)):
+ f = NO_PREFIX[i]
+ b=baddir+"/"+f
+ if b not in BAD_FILES:
+ warn("There is no corresponding file to '%s' in %s" \
+ % (gooddir+"/"+f, baddir))
+ continue
+
+ announce_test(f + " [%s/%s]" % (i+1, len(NO_PREFIX)))
+
+ # combine files (everything from good except f)
+ testfiles=[]
+ skip=False
+ for c in NO_PREFIX:
+ badfile = baddir+"/"+c
+ goodfile = gooddir+"/"+c
+ if c == f:
+ testfiles.append(badfile)
+ if filecmp.cmp(goodfile, badfile):
+ announce_result("skipped", "same content")
+ skip = True
+ break
+ else:
+ testfiles.append(goodfile)
+ if skip:
+ continue
+ testrun(testfiles)
+
+def check_functions_in_file(base, goodfile, badfile):
+ functions = extract_functions(goodfile)
+ if len(functions) == 0:
+ warn("Couldn't find any function in %s, missing annotations?" % (goodfile,))
+ return
+ badfunctions = dict(extract_functions(badfile))
+ if len(functions) == 0:
+ warn("Couldn't find any function in %s, missing annotations?" % (badfile,))
+ return
+
+ COMBINED="/tmp/combined.s"
+ i = 0
+ for (func,func_text) in functions:
+ announce_test(func + " [%s/%s]" % (i+1, len(functions)))
+ i+=1
+ if func not in badfunctions:
+ warn("Function '%s' missing from bad file" % func)
+ continue
+ if badfunctions[func] == func_text:
+ announce_result("skipped", "same content")
+ continue
+ replace_function(goodfile, func, badfunctions[func], COMBINED)
+ testfiles=[]
+ for c in NO_PREFIX:
+ if c == base:
+ testfiles.append(COMBINED)
+ continue
+ testfiles.append(gooddir + "/" + c)
+
+ testrun(testfiles)
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--a', dest='dir_a', default='before')
+parser.add_argument('--b', dest='dir_b', default='after')
+parser.add_argument('--insane', help='Skip sanity check', action='store_true')
+parser.add_argument('file', metavar='file', nargs='?')
+config = parser.parse_args()
+
+gooddir=config.dir_a
+baddir=config.dir_b
+
+BAD_FILES=find(baddir, "*")
+GOOD_FILES=find(gooddir, "*")
+NO_PREFIX=sorted([x[len(gooddir)+1:] for x in GOOD_FILES])
+
+# "Checking whether build environment is sane ..."
+if not config.insane:
+ announce_test("sanity check")
+ if not os.access(LINKTEST, os.X_OK):
+ error("Expect '%s' to be present and executable" % (LINKTEST,))
+ exit(1)
+
+ res = testrun(GOOD_FILES)
+ if not res:
+ # "build environment is grinning and holding a spatula. Guess not."
+ linkline="%s %s" % (LINKTEST, " ".join(GOOD_FILES),)
+ stderr.write("\n%s\n\n" % linkline)
+ stderr.write("Returned with exitcode != 0\n")
+ sys.exit(1)
+
+if config.file is not None:
+ # File exchange mode
+ goodfile = gooddir+"/"+config.file
+ badfile = baddir+"/"+config.file
+ check_functions_in_file(config.file, goodfile, badfile)
+else:
+ # Function exchange mode
+ check_files()
diff --git a/utils/abtest/mark_aarch64fns.py b/utils/abtest/mark_aarch64fns.py
new file mode 100755
index 0000000000000..652014792849b
--- /dev/null
+++ b/utils/abtest/mark_aarch64fns.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+#
+# Mark functions in an arm assembly file. This is done by surrounding the
+# function with "# -- Begin Name" and "# -- End Name"
+# (This script is designed for aarch64 ios assembly syntax)
+import sys
+import re
+
+inp = open(sys.argv[1], "r").readlines()
+
+# First pass
+linenum = 0
+INVALID=-100
+last_align = INVALID
+last_code = INVALID
+last_globl = INVALID
+last_globl_name = None
+begin = INVALID
+in_text_section = False
+begins = dict()
+for line in inp:
+ linenum += 1
+ if re.search(r'.section\s+__TEXT,__text,regular,pure_instructions', line):
+ in_text_section = True
+ continue
+ elif ".section" in line:
+ in_text_section = False
+ continue
+
+ if not in_text_section:
+ continue
+
+ if ".align" in line:
+ last_align = linenum
+ gl = re.search(r'.globl\s+(\w+)', line)
+ if gl:
+ last_globl_name = gl.group(1)
+ last_globl = linenum
+ m = re.search(r'^(\w+):', line)
+ if m and begin == INVALID:
+ labelname = m.group(1)
+ if last_globl+2 == linenum and last_globl_name == labelname:
+ begin = last_globl
+ funcname = labelname
+ if line == "\n" and begin != INVALID:
+ end = linenum
+ triple = (funcname, begin, end)
+ begins[begin] = triple
+ begin = INVALID
+
+# Second pass: Mark
+out = open(sys.argv[1], "w")
+in_func = None
+linenum = 0
+for line in inp:
+ linenum += 1
+ if in_func is not None and linenum == end:
+ out.write("# -- End %s\n" % in_func)
+ in_func = None
+
+ triple = begins.get(linenum)
+ if triple is not None:
+ in_func, begin, end = triple
+ out.write("# -- Begin %s\n" % in_func)
+ out.write(line)
diff --git a/utils/abtest/mark_armfns.py b/utils/abtest/mark_armfns.py
new file mode 100755
index 0000000000000..0edf42e8a83c4
--- /dev/null
+++ b/utils/abtest/mark_armfns.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+#
+# Mark functions in an arm assembly file. This is done by surrounding the
+# function with "# -- Begin Name" and "# -- End Name"
+# (This script is designed for arm ios assembly syntax)
+import sys
+import re
+
+inp = open(sys.argv[1], "r").readlines()
+
+# First pass
+linenum = 0
+INVALID=-100
+last_align = INVALID
+last_code = INVALID
+last_globl = INVALID
+begin = INVALID
+begins = dict()
+for line in inp:
+ linenum += 1
+ if ".align" in line:
+ last_align = linenum
+ if ".code" in line:
+ last_code = linenum
+ if ".globl" in line:
+ last_globl = linenum
+ m = re.search(r'.thumb_func\s+(\w+)', line)
+ if m:
+ funcname = m.group(1)
+ if last_code == last_align+1 and (linenum - last_code) < 4:
+ begin = last_align
+ if last_globl+1 == last_align:
+ begin = last_globl
+ if line == "\n" and begin != INVALID:
+ end = linenum
+ triple = (funcname, begin, end)
+ begins[begin] = triple
+ begin = INVALID
+
+# Second pass: Mark
+out = open(sys.argv[1], "w")
+in_func = None
+linenum = 0
+for line in inp:
+ linenum += 1
+ if in_func is not None and linenum == end:
+ out.write("# -- End %s\n" % in_func)
+ in_func = None
+
+ triple = begins.get(linenum)
+ if triple is not None:
+ in_func, begin, end = triple
+ out.write("# -- Begin %s\n" % in_func)
+ out.write(line)
diff --git a/utils/buildit/GNUmakefile b/utils/buildit/GNUmakefile
deleted file mode 100644
index fc5578a68464e..0000000000000
--- a/utils/buildit/GNUmakefile
+++ /dev/null
@@ -1,132 +0,0 @@
-# LLVM LOCAL file build machinery
-# LLVM Compiler Makefile for use by buildit.
-#
-# This makefile is intended only for use with B&I buildit. For "normal" builds
-# use the conventional top-level makefile.
-#
-# You can specify TARGETS=ppc (or i386) on the buildit command line to limit the
-# build to just one target. The default is for ppc and i386. The compiler
-# targeted at this host gets built anyway, but not installed unless it's listed
-# in TARGETS.
-
-# Include the set of standard Apple makefile definitions.
-ifndef CoreOSMakefiles
-CoreOSMakefiles = $(MAKEFILEPATH)/CoreOS
-endif
-include $(CoreOSMakefiles)/Standard/Standard.make
-
-# Enable Apple extensions to (gnu)make.
-USE_APPLE_PB_SUPPORT = all
-
-RC_ARCHS := ppc i386
-HOSTS = $(RC_ARCHS)
-targets = echo $(RC_ARCHS)
-TARGETS := $(shell $(targets))
-
-SRCROOT = .
-
-SRC = $(shell cd $(SRCROOT) && pwd | sed s,/private,,)
-OBJROOT = $(SRC)/obj
-SYMROOT = $(OBJROOT)/../sym
-DSTROOT = $(OBJROOT)/../dst
-
-#######################################################################
-
-PREFIX = /usr/local
-
-# Unless assertions are forced on in the GMAKE command line, disable them.
-ifndef ENABLE_ASSERTIONS
-ENABLE_ASSERTIONS := no
-endif
-
-# Default is optimized build.
-ifeq ($(LLVM_DEBUG),1)
-LLVM_OPTIMIZED := no
-else
-LLVM_OPTIMIZED := yes
-endif
-
-# Default to do a native build, not a cross-build for an ARM host or simulator.
-ARM_HOSTED_BUILD := no
-IOS_SIM_BUILD := no
-
-ifndef RC_ProjectSourceVersion
-RC_ProjectSourceVersion = 9999
-endif
-
-ifndef RC_ProjectSourceSubversion
-RC_ProjectSourceSubversion = 0
-endif
-
-# NOTE : Always put version numbers at the end because they are optional.
-install: $(OBJROOT) $(SYMROOT) $(DSTROOT)
- cd $(OBJROOT) && \
- $(SRC)/utils/buildit/build_llvm "$(RC_ARCHS)" "$(TARGETS)" \
- $(SRC) $(PREFIX) $(DSTROOT) $(SYMROOT) \
- $(ENABLE_ASSERTIONS) $(LLVM_OPTIMIZED) \
- $(ARM_HOSTED_BUILD) $(IOS_SIM_BUILD) \
- $(RC_ProjectSourceVersion) $(RC_ProjectSourceSubversion)
-
-EmbeddedHosted:
- $(MAKE) ARM_HOSTED_BUILD=yes PREFIX=/usr/local install
-
-# When building for the iOS simulator, MACOSX_DEPLOYMENT_TARGET is not set
-# by default, but it needs to be set when building tools that run on the host
-# (e.g., tblgen), so set it here.
-EmbeddedSim:
- export MACOSX_DEPLOYMENT_TARGET=`sw_vers -productVersion`; \
- $(MAKE) IOS_SIM_BUILD=yes PREFIX=$(SDKROOT)/usr/local install
-
-Embedded:
- ARM_PLATFORM=`xcodebuild -version -sdk iphoneos PlatformPath` && \
- $(MAKE) DSTROOT=$(DSTROOT)$$ARM_PLATFORM/Developer install
-
-# installhdrs does nothing, because the headers aren't useful until
-# the compiler is installed.
-installhdrs:
-
-# We build and install in one shell script.
-build:
-
-installsrc:
- @echo
- @echo ++++++++++++++++++++++
- @echo + Installing sources +
- @echo ++++++++++++++++++++++
- @echo
- if [ $(SRCROOT) != . ]; then \
- $(PAX) -rw . $(SRCROOT); \
- fi
- find -d "$(SRCROOT)" \( -type d -a -name .svn -o \
- -type f -a -name .DS_Store -o \
- -name \*~ -o -name .\#\* \) \
- -exec rm -rf {} \;
- rm -rf "$(SRCROOT)/test"
-
-#######################################################################
-
-clean:
- @echo
- @echo ++++++++++++
- @echo + Cleaning +
- @echo ++++++++++++
- @echo
- @if [ -d $(OBJROOT) -a "$(OBJROOT)" != / ]; then \
- echo '*** DELETING ' $(OBJROOT); \
- rm -rf $(OBJROOT); \
- fi
- @if [ -d $(SYMROOT) -a "$(SYMROOT)" != / ]; then \
- echo '*** DELETING ' $(SYMROOT); \
- rm -rf $(SYMROOT); \
- fi
- @if [ -d $(DSTROOT) -a "$(DSTROOT)" != / ]; then \
- echo '*** DELETING ' $(DSTROOT); \
- rm -rf $(DSTROOT); \
- fi
-
-#######################################################################
-
-$(OBJROOT) $(SYMROOT) $(DSTROOT):
- mkdir -p $@
-
-.PHONY: install installsrc clean EmbeddedHosted EmbeddedSim Embedded
diff --git a/utils/buildit/build_llvm b/utils/buildit/build_llvm
deleted file mode 100755
index bc609e909a92b..0000000000000
--- a/utils/buildit/build_llvm
+++ /dev/null
@@ -1,361 +0,0 @@
-#!/bin/sh
-# LLVM LOCAL file B&I
-
-set -x
-
-# Build LLVM the "Apple way".
-# Parameters:
-
-# The first parameter is a space-separated list of the architectures the
-# compilers will run on. For instance, "ppc i386". If the current machine
-# isn't in the list, it will (effectively) be added.
-HOSTS="$1"
-
-# The second parameter is a space-separated list of the architectures the
-# compilers will generate code for. If the current machine isn't in the list, a
-# compiler for it will get built anyway, but won't be installed.
-# FIXME: The list of targets is currently hard-coded and TARGETS is not used.
-TARGETS="$2"
-
-# The third parameter is the path to the compiler sources. There should be a
-# shell script named 'configure' in this directory. This script makes a copy...
-ORIG_SRC_DIR="$3"
-
-# The fourth parameter is the location where the LLVM will be installed. You can
-# move it once it's built, so this mostly controls the layout of $DEST_DIR.
-DEST_ROOT="$4"
-
-# The fifth parameter is the place where the compiler will be copied once it's
-# built.
-DEST_DIR="$5"
-
-# The sixth parameter is a directory in which to place information (like
-# unstripped executables and generated source files) helpful in debugging the
-# resulting compiler.
-SYM_DIR="$6"
-
-# The seventh parameter is a yes/no that indicates whether assertions should be
-# enabled in the LLVM libs/tools.
-LLVM_ASSERTIONS="$7"
-
-# The eighth parameter is a yes/no that indicates whether this is an optimized
-# build.
-LLVM_OPTIMIZED="$8"
-
-# A yes/no parameter that controls whether to cross-build for an ARM host.
-ARM_HOSTED_BUILD="$9"
-
-# A yes/no parameter that controls whether to cross-build for the iOS simulator
-IOS_SIM_BUILD="${10}"
-
-# The version number of the submission, e.g. 1007.
-LLVM_SUBMIT_VERSION="${11}"
-
-# The subversion number of the submission, e.g. 03.
-LLVM_SUBMIT_SUBVERSION="${12}"
-
-# The current working directory is where the build will happen. It may already
-# contain a partial result of an interrupted build, in which case this script
-# will continue where it left off.
-DIR=`pwd`
-
-DARWIN_VERS=`uname -r | sed 's/\..*//'`
-echo DARWIN_VERS = $DARWIN_VERS
-
-################################################################################
-# Run the build.
-
-# Create the source tree we'll actually use to build, deleting
-# tcl since it doesn't actually build properly in a cross environment
-# and we don't really need it.
-SRC_DIR=$DIR/src
-rm -rf $SRC_DIR || exit 1
-mkdir $SRC_DIR || exit 1
-ln -s $ORIG_SRC_DIR/* $SRC_DIR/ || exit 1
-# We can't use the top-level Makefile as-is. Remove the soft link:
-rm $SRC_DIR/Makefile || exit 1
-# Now create our own by editing the top-level Makefile, deleting every line marked "Apple-style":
-sed -e '/[Aa]pple-style/d' -e '/include.*GNUmakefile/d' $ORIG_SRC_DIR/Makefile > $SRC_DIR/Makefile || exit 1
-
-SUBVERSION=`echo $RC_ProjectSourceVersion | sed -e 's/.*\.\([0-9]*\).*/\1/'`
-if [ "x$SUBVERSION" != "x$RC_ProjectSourceVersion" ]; then
- LLVM_SUBMIT_SUBVERSION=`printf "%02d" $SUBVERSION`
- RC_ProjectSourceVersion=`echo $RC_ProjectSourceVersion | sed -e 's/\..*//'`
- LLVM_SUBMIT_VERSION=$RC_ProjectSourceVersion
-fi
-if [ "x$LLVM_SUBMIT_SUBVERSION" = "x00" -o "x$LLVM_SUBMIT_SUBVERSION" = "x0" ]; then
- LLVM_VERSION="$LLVM_SUBMIT_VERSION"
-else
- LLVM_VERSION="$LLVM_SUBMIT_VERSION-$LLVM_SUBMIT_SUBVERSION"
-fi
-
-SDKROOT_PATH=`xcodebuild -version -sdk $SDKROOT Path`
-
-# Figure out how many make processes to run.
-SYSCTL=`sysctl -n hw.activecpu`
-# sysctl -n hw.* does not work when invoked via B&I chroot /BuildRoot.
-# Builders can default to 2, since even if they are single processor,
-# nothing else is running on the machine.
-if [ -z "$SYSCTL" ]; then
- SYSCTL=2
-fi
-JOBS_FLAG="-j $SYSCTL"
-
-COMMON_CONFIGURE_OPTS="\
- --prefix=$DEST_DIR$DEST_ROOT \
- --enable-assertions=$LLVM_ASSERTIONS \
- --enable-optimized=$LLVM_OPTIMIZED \
- --disable-bindings \
- --disable-zlib \
- --enable-terminfo=no"
-
-COMMON_MAKEFLAGS="\
- UNIVERSAL=1 \
- UNIVERSAL_SDK_PATH=$SDKROOT_PATH \
- NO_RUNTIME_LIBS=1 \
- DISABLE_EDIS=1 \
- REQUIRES_RTTI=1 \
- DEBUG_SYMBOLS=1 \
- LLVM_SUBMIT_VERSION=$LLVM_SUBMIT_VERSION \
- LLVM_SUBMIT_SUBVERSION=$LLVM_SUBMIT_SUBVERSION \
- VERBOSE=1"
-
-# Build the LLVM tree universal.
-mkdir -p $DIR/obj-llvm || exit 1
-cd $DIR/obj-llvm || exit 1
-
-if [ "$ARM_HOSTED_BUILD" = yes ]; then
- # The cross-tools' build process expects to find an existing cross toolchain
- # under names like 'arm-apple-darwin$DARWIN_VERS-as'; so make them.
- rm -rf $DIR/bin || exit 1
- mkdir $DIR/bin || exit 1
- for prog in ar nm ranlib strip lipo ld as ; do
- P=$DIR/bin/arm-apple-darwin$DARWIN_VERS-${prog}
- T=`xcrun -sdk $SDKROOT -find ${prog}`
- ln -s $T $DIR/bin/$prog
- echo '#!/bin/sh' > $P || exit 1
- echo 'exec '$T' "$@"' >> $P || exit 1
- chmod a+x $P || exit 1
- done
- # Set up the links for clang.
- for prog in clang clang++ ; do
- P=$DIR/bin/arm-apple-darwin$DARWIN_VERS-${prog}
- T=`xcrun -sdk $SDKROOT -find ${prog}`
- ln -s $T $DIR/bin/$prog
- echo '#!/bin/sh' > $P || exit 1
- echo 'exec '$T' -arch armv7 -isysroot '${SDKROOT_PATH}' "$@"' >> $P || exit 1
- chmod a+x $P || exit 1
- done
-
- PATH=$DIR/bin:$PATH
-
- unset SDKROOT && \
- $SRC_DIR/configure $COMMON_CONFIGURE_OPTS \
- --enable-targets=arm,arm64 \
- --host=arm-apple-darwin10 \
- --target=arm-apple-darwin10 \
- --build=i686-apple-darwin10 \
- --program-prefix="" \
- || exit 1
-
- if [ -n "$IPHONEOS_DEPLOYMENT_TARGET" ]; then
- COMMON_MAKEFLAGS="$COMMON_MAKEFLAGS \
- DEPLOYMENT_TARGET=-mios-version-min=$IPHONEOS_DEPLOYMENT_TARGET"
- fi
-
- make $JOBS_FLAG $COMMON_MAKEFLAGS SDKROOT= UNIVERSAL_ARCH="$HOSTS" \
- CXXFLAGS="-DLLVM_VERSION_INFO='\" Apple Build #$LLVM_VERSION\"'"
- if [ $? != 0 ] ; then
- echo "error: LLVM 'make' failed!"
- exit 1
- fi
-
-else
-# not $ARM_HOSTED_BUILD
-
- if [ "$IOS_SIM_BUILD" = yes ]; then
- export CC=`xcrun -sdk iphonesimulator -find clang`
- export CXX=`xcrun -sdk iphonesimulator -find clang++`
-
- # Use a non-standard "darwin_sim" host triple to trigger a cross-build.
- configure_opts="--enable-targets=x86 --host=i686-apple-darwin_sim \
- --build=i686-apple-darwin10"
- if [ -n "$IPHONEOS_DEPLOYMENT_TARGET" ]; then
- COMMON_MAKEFLAGS="$COMMON_MAKEFLAGS \
- DEPLOYMENT_TARGET=-mios-simulator-version-min=$IPHONEOS_DEPLOYMENT_TARGET"
- fi
- else
- export CC=`xcrun -sdk macosx -find clang`
- export CXX=`xcrun -sdk macosx -find clang++`
-
- configure_opts="--enable-targets=arm,arm64,x86"
- if [ -n "$MACOSX_DEPLOYMENT_TARGET" ]; then
- COMMON_MAKEFLAGS="$COMMON_MAKEFLAGS \
- DEPLOYMENT_TARGET=-mmacosx-version-min=$MACOSX_DEPLOYMENT_TARGET"
- fi
- fi
-
- if [ $SDKROOT_PATH ]; then
- CPPFLAGS="$CPPFLAGS -isysroot $SDKROOT_PATH"
- fi
- for host in $HOSTS; do :; done
- CPPFLAGS="$CPPFLAGS -arch $host"
-
- $SRC_DIR/configure $COMMON_CONFIGURE_OPTS $configure_opts \
- --program-prefix="" \
- CPPFLAGS="$CPPFLAGS" \
- || exit 1
-
- make $JOBS_FLAG $COMMON_MAKEFLAGS UNIVERSAL_ARCH="$HOSTS" \
- CXXFLAGS="-DLLVM_VERSION_INFO='\" Apple Build #$LLVM_VERSION\"'"
- if [ $? != 0 ] ; then
- echo "error: LLVM 'make' failed!"
- exit 1
- fi
-fi
-
-################################################################################
-# Construct the actual destination root, by copying stuff from $DIR/dst-* to
-# $DEST_DIR, with occasional 'lipo' commands.
-
-cd $DEST_DIR || exit 1
-
-# Clean out DEST_DIR in case -noclean was passed to buildit.
-rm -rf * || exit 1
-
-cd $DIR/obj-llvm || exit 1
-
-# Install the tree into the destination directory.
-make $JOBS_FLAG $COMMON_MAKEFLAGS UNIVERSAL_ARCH="$HOSTS" install
-if ! test $? == 0 ; then
- echo "error: LLVM 'make install' failed!"
- exit 1
-fi
-
-# Install Version.h
-LLVM_MINOR_VERSION=`echo $LLVM_SUBMIT_SUBVERSION | sed -e 's,0*\([1-9][0-9]*\),\1,'`
-if [ "x$LLVM_MINOR_VERSION" = "x" ]; then
- LLVM_MINOR_VERSION=0
-fi
-RC_ProjectSourceSubversion=`printf "%d" $LLVM_MINOR_VERSION`
-echo "#define LLVM_VERSION ${RC_ProjectSourceVersion}" > $DEST_DIR$DEST_ROOT/include/llvm/Version.h
-echo "#define LLVM_MINOR_VERSION ${RC_ProjectSourceSubversion}" >> $DEST_DIR$DEST_ROOT/include/llvm/Version.h
-
-# Run unifdef to preprocess the installed headers to reflect whether this
-# was a debug or release build.
-for file in `find $DEST_DIR$DEST_ROOT/include -type f -print`; do
- if [ "$LLVM_ASSERTIONS" = yes ]; then
- unifdef -UNDEBUG -D_DEBUG -o $file $file
- else
- unifdef -DNDEBUG -U_DEBUG -ULLVM_ENABLE_DUMP -o $file $file
- fi
-done
-
-# Find the right version of strip to use.
-STRIP=strip
-if [ -n "$SDKROOT" ]; then
- STRIP=`xcrun -sdk $SDKROOT -find strip`
-fi
-
-if [ "x$LLVM_DEBUG" != "x1" ]; then
- # Strip local symbols from llvm libraries.
- #
- # Use '-l' to strip i386 modules. N.B. that flag doesn't work with kext or
- # PPC objects!
- $STRIP -Sl $DEST_DIR$DEST_ROOT/lib/*.[oa]
- for f in `ls $DEST_DIR$DEST_ROOT/lib/*.so`; do
- $STRIP -Sxl $f
- done
-fi
-
-# Remove .dir files
-cd $DEST_DIR$DEST_ROOT
-rm -f bin/.dir etc/llvm/.dir lib/.dir
-
-# The Hello dylib is an example of how to build a pass.
-# The BugpointPasses module is only used to test bugpoint.
-# These unversioned dylibs cause verification failures, so do not install them.
-# (The wildcards are used to match a "lib" prefix if it is present.)
-rm $DEST_DIR$DEST_ROOT/lib/*LLVMHello.dylib
-rm $DEST_DIR$DEST_ROOT/lib/*BugpointPasses.dylib
-
-# Compress manpages
-MDIR=$DEST_DIR$DEST_ROOT/share/man/man1
-gzip -f $MDIR/*
-
-################################################################################
-# Create SYM_DIR with information required for debugging.
-
-# Figure out how many make processes to run.
-SYSCTL=`sysctl -n hw.activecpu`
-
-# hw.activecpu only available in 10.2.6 and later
-if [ -z "$SYSCTL" ]; then
- SYSCTL=`sysctl -n hw.ncpu`
-fi
-
-# sysctl -n hw.* does not work when invoked via B&I chroot /BuildRoot. Builders
-# can default to 2, since even if they are single processor, nothing else is
-# running on the machine.
-if [ -z "$SYSCTL" ]; then
- SYSCTL=2
-fi
-
-cd $SYM_DIR || exit 1
-
-# Clean out SYM_DIR in case -noclean was passed to buildit.
-rm -rf * || exit 1
-
-# Generate .dSYM files
-DSYMUTIL=`xcrun -find dsymutil`
-find $DEST_DIR -perm -0111 -type f \
- ! \( -name '*.la' -o -name gccas -o -name gccld -o -name llvm-config -o -name '*.a' \) \
- -print | xargs -n 1 -P ${SYSCTL} ${DSYMUTIL}
-
-# Save .dSYM files and .a archives
-cd $DEST_DIR || exit 1
-find . \( -path \*.dSYM/\* -or -name \*.a \) -print \
- | cpio -pdml $SYM_DIR || exit 1
-
-# Save source files.
-mkdir $SYM_DIR/src || exit 1
-cd $DIR || exit 1
-find obj-* -name \*.\[chy\] -o -name \*.cpp -print \
- | cpio -pdml $SYM_DIR/src || exit 1
-
-################################################################################
-# Remove libLTO.dylib and lto.h. Those are installed by clang.
-
-cd $DEST_DIR$DEST_ROOT
-rm -f lib/libLTO.dylib
-rm -f lib/libLTO.a lib/libLTO.la
-find $DEST_DIR$DEST_ROOT -name lto.h -delete
-
-################################################################################
-# Remove debugging information from DEST_DIR.
-
-cd $DIR || exit 1
-
-find $DEST_DIR -name \*.a -print | xargs ranlib || exit 1
-find $DEST_DIR -name \*.dSYM -print | xargs rm -r || exit 1
-
-# Strip debugging information from files
-#
-# Use '-l' to strip i386 modules. N.B. that flag doesn't work with kext or
-# PPC objects!
-find $DEST_DIR -perm -0111 -type f \
- ! \( -name '*.la' -o -name gccas -o -name gccld -o -name llvm-config \) \
- -print | xargs -n 1 -P ${SYSCTL} $STRIP -arch all -Sl
-
-chgrp -h -R wheel $DEST_DIR
-chgrp -R wheel $DEST_DIR
-
-################################################################################
-# Remove the docs directory
-
-rm -rf $DEST_DIR$DEST_ROOT/docs
-
-################################################################################
-# w00t! Done!
-
-exit 0
diff --git a/utils/count/Makefile b/utils/count/Makefile
deleted file mode 100644
index 2a955e66679f0..0000000000000
--- a/utils/count/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-##===- utils/count/Makefile --------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-TOOLNAME = count
-USEDLIBS =
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-# FIXME: Don't install this utility
-#NO_INSTALL = 1
-
-include $(LEVEL)/Makefile.common
diff --git a/utils/extract_symbols.py b/utils/extract_symbols.py
new file mode 100755
index 0000000000000..9f467a7d0556b
--- /dev/null
+++ b/utils/extract_symbols.py
@@ -0,0 +1,496 @@
+#!/usr/bin/env python
+
+"""A tool for extracting a list of symbols to export
+
+When exporting symbols from a dll or exe we either need to mark the symbols in
+the source code as __declspec(dllexport) or supply a list of symbols to the
+linker. This program automates the latter by inspecting the symbol tables of a
+list of link inputs and deciding which of those symbols need to be exported.
+
+We can't just export all the defined symbols, as there's a limit of 65535
+exported symbols and in clang we go way over that, particularly in a debug
+build. Therefore a large part of the work is pruning symbols either which can't
+be imported, or which we think are things that have definitions in public header
+files (i.e. template instantiations) and we would get defined in the thing
+importing these symbols anyway.
+"""
+
+from __future__ import print_function
+import sys
+import re
+import os
+import subprocess
+import multiprocessing
+import argparse
+
+# Define functions which extract a list of symbols from a library using several
+# different tools. We use subprocess.Popen and yield a symbol at a time instead
+# of using subprocess.check_output and returning a list as, especially on
+# Windows, waiting for the entire output to be ready can take a significant
+# amount of time.
+
+def dumpbin_get_symbols(lib):
+ process = subprocess.Popen(['dumpbin','/symbols',lib], bufsize=1,
+ stdout=subprocess.PIPE, stdin=subprocess.PIPE,
+ universal_newlines=True)
+ process.stdin.close()
+ for line in process.stdout:
+ # Look for external symbols that are defined in some section
+ match = re.match("^.+SECT.+External\s+\|\s+(\S+).*$", line)
+ if match:
+ yield match.group(1)
+ process.wait()
+
+def nm_get_symbols(lib):
+ process = subprocess.Popen(['nm',lib], bufsize=1,
+ stdout=subprocess.PIPE, stdin=subprocess.PIPE,
+ universal_newlines=True)
+ process.stdin.close()
+ for line in process.stdout:
+ # Look for external symbols that are defined in some section
+ match = re.match("^\S+\s+[BDGRSTVW]\s+(\S+)$", line)
+ if match:
+ yield match.group(1)
+ process.wait()
+
+def readobj_get_symbols(lib):
+ process = subprocess.Popen(['llvm-readobj','-symbols',lib], bufsize=1,
+ stdout=subprocess.PIPE, stdin=subprocess.PIPE,
+ universal_newlines=True)
+ process.stdin.close()
+ for line in process.stdout:
+ # When looking through the output of llvm-readobj we expect to see Name,
+ # Section, then StorageClass, so record Name and Section when we see
+ # them and decide if this is a defined external symbol when we see
+ # StorageClass.
+ match = re.search('Name: (\S+)', line)
+ if match:
+ name = match.group(1)
+ match = re.search('Section: (\S+)', line)
+ if match:
+ section = match.group(1)
+ match = re.search('StorageClass: (\S+)', line)
+ if match:
+ storageclass = match.group(1)
+ if section != 'IMAGE_SYM_ABSOLUTE' and \
+ section != 'IMAGE_SYM_UNDEFINED' and \
+ storageclass == 'External':
+ yield name
+ process.wait()
+
+# Define functions which determine if the target is 32-bit Windows (as that's
+# where calling convention name decoration happens).
+
+def dumpbin_is_32bit_windows(lib):
+ # dumpbin /headers can output a huge amount of data (>100MB in a debug
+ # build) so we read only up to the 'machine' line then close the output.
+ process = subprocess.Popen(['dumpbin','/headers',lib], bufsize=1,
+ stdout=subprocess.PIPE, stdin=subprocess.PIPE,
+ universal_newlines=True)
+ process.stdin.close()
+ retval = False
+ for line in process.stdout:
+ match = re.match('.+machine \((\S+)\)', line)
+ if match:
+ retval = (match.group(1) == 'x86')
+ break
+ process.stdout.close()
+ process.wait()
+ return retval
+
+def objdump_is_32bit_windows(lib):
+ output = subprocess.check_output(['objdump','-f',lib],
+ universal_newlines=True)
+ for line in output:
+ match = re.match('.+file format (\S+)', line)
+ if match:
+ return (match.group(1) == 'pe-i386')
+ return False
+
+def readobj_is_32bit_windows(lib):
+ output = subprocess.check_output(['llvm-readobj','-file-headers',lib],
+ universal_newlines=True)
+ for line in output:
+ match = re.match('Format: (\S+)', line)
+ if match:
+ return (match.group(1) == 'COFF-i386')
+ return False
+
+# MSVC mangles names to ?<identifier_mangling>@<type_mangling>. By examining the
+# identifier/type mangling we can decide which symbols could possibly be
+# required and which we can discard.
+def should_keep_microsoft_symbol(symbol, calling_convention_decoration):
+ # Keep unmangled (i.e. extern "C") names
+ if not '?' in symbol:
+ if calling_convention_decoration:
+ # Remove calling convention decoration from names
+ match = re.match('[_@]([^@]+)', symbol)
+ if match:
+ return match.group(1)
+ return symbol
+ # Function template instantiations start with ?$, discard them as it's
+ # assumed that the definition is public
+ elif symbol.startswith('??$'):
+ return None
+ # Deleting destructors start with ?_G or ?_E and can be discarded because
+ # link.exe gives you a warning telling you they can't be exported if you
+ # don't
+ elif symbol.startswith('??_G') or symbol.startswith('??_E'):
+ return None
+ # Constructors (?0) and destructors (?1) of templates (?$) are assumed to be
+ # defined in headers and not required to be kept
+ elif symbol.startswith('??0?$') or symbol.startswith('??1?$'):
+ return None
+ # An anonymous namespace is mangled as ?A(maybe hex number)@. Any symbol
+ # that mentions an anonymous namespace can be discarded, as the anonymous
+ # namespace doesn't exist outside of that translation unit.
+ elif re.search('\?A(0x\w+)?@', symbol):
+ return None
+ # Keep mangled llvm:: and clang:: function symbols. How we detect these is a
+ # bit of a mess and imprecise, but that avoids having to completely demangle
+ # the symbol name. The outermost namespace is at the end of the identifier
+ # mangling, and the identifier mangling is followed by the type mangling, so
+ # we look for (llvm|clang)@@ followed by something that looks like a
+ # function type mangling. To spot a function type we use (this is derived
+ # from clang/lib/AST/MicrosoftMangle.cpp):
+ # <function-type> ::= <function-class> <this-cvr-qualifiers>
+ # <calling-convention> <return-type>
+ # <argument-list> <throw-spec>
+ # <function-class> ::= [A-Z]
+ # <this-cvr-qualifiers> ::= [A-Z0-9_]*
+ # <calling-convention> ::= [A-JQ]
+ # <return-type> ::= .+
+ # <argument-list> ::= X (void)
+ # ::= .+@ (list of types)
+ # ::= .*Z (list of types, varargs)
+ # <throw-spec> ::= exceptions are not allowed
+ elif re.search('(llvm|clang)@@[A-Z][A-Z0-9_]*[A-JQ].+(X|.+@|.*Z)$', symbol):
+ return symbol
+ return None
+
+# Itanium manglings are of the form _Z<identifier_mangling><type_mangling>. We
+# demangle the identifier mangling to identify symbols that can be safely
+# discarded.
+def should_keep_itanium_symbol(symbol, calling_convention_decoration):
+ # Start by removing any calling convention decoration (which we expect to
+ # see on all symbols, even mangled C++ symbols)
+ if calling_convention_decoration and symbol.startswith('_'):
+ symbol = symbol[1:]
+ # Keep unmangled names
+ if not symbol.startswith('_') and not symbol.startswith('.'):
+ return symbol
+ # Discard manglings that aren't nested names
+ match = re.match('_Z(T[VTIS])?(N.+)', symbol)
+ if not match:
+ return None
+ # Demangle the name. If the name is too complex then we don't need to keep
+ # it, but it the demangling fails then keep the symbol just in case.
+ try:
+ names, _ = parse_itanium_nested_name(match.group(2))
+ except TooComplexName:
+ return None
+ if not names:
+ return symbol
+ # Constructors and destructors of templates classes are assumed to be
+ # defined in headers and not required to be kept
+ if re.match('[CD][123]', names[-1][0]) and names[-2][1]:
+ return None
+ # Discard function template instantiations as it's assumed that the
+ # definition is public
+ elif names[-1][1]:
+ return None
+ # Keep llvm:: and clang:: names
+ elif names[0][0] == '4llvm' or names[0][0] == '5clang':
+ return symbol
+ # Discard everything else
+ else:
+ return None
+
+# Certain kinds of complex manglings we assume cannot be part of a public
+# interface, and we handle them by raising an exception.
+class TooComplexName(Exception):
+ pass
+
+# Parse an itanium mangled name from the start of a string and return a
+# (name, rest of string) pair.
+def parse_itanium_name(arg):
+ # Check for a normal name
+ match = re.match('(\d+)(.+)', arg)
+ if match:
+ n = int(match.group(1))
+ name = match.group(1)+match.group(2)[:n]
+ rest = match.group(2)[n:]
+ return name, rest
+ # Check for constructor/destructor names
+ match = re.match('([CD][123])(.+)', arg)
+ if match:
+ return match.group(1), match.group(2)
+ # Assume that a sequence of characters that doesn't end a nesting is an
+ # operator (this is very imprecise, but appears to be good enough)
+ match = re.match('([^E]+)(.+)', arg)
+ if match:
+ return match.group(1), match.group(2)
+ # Anything else: we can't handle it
+ return None, arg
+
+# Parse an itanium mangled template argument list from the start of a string
+# and throw it away, returning the rest of the string.
+def skip_itanium_template(arg):
+ # A template argument list starts with I
+ assert arg.startswith('I'), arg
+ tmp = arg[1:]
+ while tmp:
+ # Check for names
+ match = re.match('(\d+)(.+)', tmp)
+ if match:
+ n = int(match.group(1))
+ tmp = match.group(2)[n:]
+ continue
+ # Check for substitutions
+ match = re.match('S[A-Z0-9]*_(.+)', tmp)
+ if match:
+ tmp = match.group(1)
+ # Start of a template
+ elif tmp.startswith('I'):
+ tmp = skip_itanium_template(tmp)
+ # Start of a nested name
+ elif tmp.startswith('N'):
+ _, tmp = parse_itanium_nested_name(tmp)
+ # Start of an expression: assume that it's too complicated
+ elif tmp.startswith('L') or tmp.startswith('X'):
+ raise TooComplexName
+ # End of the template
+ elif tmp.startswith('E'):
+ return tmp[1:]
+ # Something else: probably a type, skip it
+ else:
+ tmp = tmp[1:]
+ return None
+
+# Parse an itanium mangled nested name and transform it into a list of pairs of
+# (name, is_template), returning (list, rest of string).
+def parse_itanium_nested_name(arg):
+ # A nested name starts with N
+ assert arg.startswith('N'), arg
+ ret = []
+
+ # Skip past the N, and possibly a substitution
+ match = re.match('NS[A-Z0-9]*_(.+)', arg)
+ if match:
+ tmp = match.group(1)
+ else:
+ tmp = arg[1:]
+
+ # Skip past CV-qualifiers and ref qualifiers
+ match = re.match('[rVKRO]*(.+)', tmp);
+ if match:
+ tmp = match.group(1)
+
+ # Repeatedly parse names from the string until we reach the end of the
+ # nested name
+ while tmp:
+ # An E ends the nested name
+ if tmp.startswith('E'):
+ return ret, tmp[1:]
+ # Parse a name
+ name_part, tmp = parse_itanium_name(tmp)
+ if not name_part:
+ # If we failed then we don't know how to demangle this
+ return None, None
+ is_template = False
+ # If this name is a template record that, then skip the template
+ # arguments
+ if tmp.startswith('I'):
+ tmp = skip_itanium_template(tmp)
+ is_template = True
+ # Add the name to the list
+ ret.append((name_part, is_template))
+
+ # If we get here then something went wrong
+ return None, None
+
+def extract_symbols(arg):
+ get_symbols, should_keep_symbol, calling_convention_decoration, lib = arg
+ symbols = dict()
+ for symbol in get_symbols(lib):
+ symbol = should_keep_symbol(symbol, calling_convention_decoration)
+ if symbol:
+ symbols[symbol] = 1 + symbols.setdefault(symbol,0)
+ return symbols
+
+if __name__ == '__main__':
+ tool_exes = ['dumpbin','nm','objdump','llvm-readobj']
+ parser = argparse.ArgumentParser(
+ description='Extract symbols to export from libraries')
+ parser.add_argument('--mangling', choices=['itanium','microsoft'],
+ required=True, help='expected symbol mangling scheme')
+ parser.add_argument('--tools', choices=tool_exes, nargs='*',
+ help='tools to use to extract symbols and determine the'
+ ' target')
+ parser.add_argument('libs', metavar='lib', type=str, nargs='+',
+ help='libraries to extract symbols from')
+ parser.add_argument('-o', metavar='file', type=str, help='output to file')
+ args = parser.parse_args()
+
+ # Determine the function to use to get the list of symbols from the inputs,
+ # and the function to use to determine if the target is 32-bit windows.
+ tools = { 'dumpbin' : (dumpbin_get_symbols, dumpbin_is_32bit_windows),
+ 'nm' : (nm_get_symbols, None),
+ 'objdump' : (None, objdump_is_32bit_windows),
+ 'llvm-readobj' : (readobj_get_symbols, readobj_is_32bit_windows) }
+ get_symbols = None
+ is_32bit_windows = None
+ # If we have a tools argument then use that for the list of tools to check
+ if args.tools:
+ tool_exes = args.tools
+ # Find a tool to use by trying each in turn until we find one that exists
+ # (subprocess.call will throw OSError when the program does not exist)
+ get_symbols = None
+ for exe in tool_exes:
+ try:
+ # Close std streams as we don't want any output and we don't
+ # want the process to wait for something on stdin.
+ p = subprocess.Popen([exe], stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE,
+ universal_newlines=True)
+ p.stdout.close()
+ p.stderr.close()
+ p.stdin.close()
+ p.wait()
+ # Keep going until we have a tool to use for both get_symbols and
+ # is_32bit_windows
+ if not get_symbols:
+ get_symbols = tools[exe][0]
+ if not is_32bit_windows:
+ is_32bit_windows = tools[exe][1]
+ if get_symbols and is_32bit_windows:
+ break
+ except OSError:
+ continue
+ if not get_symbols:
+ print("Couldn't find a program to read symbols with", file=sys.stderr)
+ exit(1)
+ if not is_32bit_windows:
+ print("Couldn't find a program to determing the target", file=sys.stderr)
+ exit(1)
+
+ # How we determine which symbols to keep and which to discard depends on
+ # the mangling scheme
+ if args.mangling == 'microsoft':
+ should_keep_symbol = should_keep_microsoft_symbol
+ else:
+ should_keep_symbol = should_keep_itanium_symbol
+
+ # Get the list of libraries to extract symbols from
+ libs = list()
+ for lib in args.libs:
+ # When invoked by cmake the arguments are the cmake target names of the
+ # libraries, so we need to add .lib/.a to the end and maybe lib to the
+ # start to get the filename. Also allow objects.
+ suffixes = ['.lib','.a','.obj','.o']
+ if not any([lib.endswith(s) for s in suffixes]):
+ for s in suffixes:
+ if os.path.exists(lib+s):
+ lib = lib+s
+ break
+ if os.path.exists('lib'+lib+s):
+ lib = 'lib'+lib+s
+ break
+ if not any([lib.endswith(s) for s in suffixes]):
+ print("Don't know what to do with argument "+lib, file=sys.stderr)
+ exit(1)
+ libs.append(lib)
+
+ # Check if calling convention decoration is used by inspecting the first
+ # library in the list
+ calling_convention_decoration = is_32bit_windows(libs[0])
+
+ # Extract symbols from libraries in parallel. This is a huge time saver when
+ # doing a debug build, as there are hundreds of thousands of symbols in each
+ # library.
+ pool = multiprocessing.Pool()
+ try:
+ # Only one argument can be passed to the mapping function, and we can't
+ # use a lambda or local function definition as that doesn't work on
+ # windows, so create a list of tuples which duplicates the arguments
+ # that are the same in all calls.
+ vals = [(get_symbols, should_keep_symbol, calling_convention_decoration, x) for x in libs]
+ # Do an async map then wait for the result to make sure that
+ # KeyboardInterrupt gets caught correctly (see
+ # http://bugs.python.org/issue8296)
+ result = pool.map_async(extract_symbols, vals)
+ pool.close()
+ libs_symbols = result.get(3600)
+ except KeyboardInterrupt:
+ # On Ctrl-C terminate everything and exit
+ pool.terminate()
+ pool.join()
+ exit(1)
+
+ # Merge everything into a single dict
+ symbols = dict()
+ for this_lib_symbols in libs_symbols:
+ for k,v in list(this_lib_symbols.items()):
+ symbols[k] = v + symbols.setdefault(k,0)
+
+ # Count instances of member functions of template classes, and map the
+ # symbol name to the function+class. We do this under the assumption that if
+ # a member function of a template class is instantiated many times it's
+ # probably declared in a public header file.
+ template_function_count = dict()
+ template_function_mapping = dict()
+ template_function_count[""] = 0
+ for k in symbols:
+ name = None
+ if args.mangling == 'microsoft':
+ # Member functions of templates start with
+ # ?<fn_name>@?$<class_name>@, so we map to <fn_name>@?$<class_name>.
+ # As manglings go from the innermost scope to the outermost scope
+ # this means:
+ # * When we have a function member of a subclass of a template
+ # class then <fn_name> will actually contain the mangling of
+ # both the subclass and the function member. This is fine.
+ # * When we have a function member of a template subclass of a
+ # (possibly template) class then it's the innermost template
+ # subclass that becomes <class_name>. This should be OK so long
+ # as we don't have multiple classes with a template subclass of
+ # the same name.
+ match = re.search("^\?(\??\w+\@\?\$\w+)\@", k)
+ if match:
+ name = match.group(1)
+ else:
+ # Find member functions of templates by demangling the name and
+ # checking if the second-to-last name in the list is a template.
+ match = re.match('_Z(T[VTIS])?(N.+)', k)
+ if match:
+ try:
+ names, _ = parse_itanium_nested_name(match.group(2))
+ if names and names[-2][1]:
+ name = ''.join([x for x,_ in names])
+ except TooComplexName:
+ # Manglings that are too complex should already have been
+ # filtered out, but if we happen to somehow see one here
+ # just leave it as-is.
+ pass
+ if name:
+ old_count = template_function_count.setdefault(name,0)
+ template_function_count[name] = old_count + 1
+ template_function_mapping[k] = name
+ else:
+ template_function_mapping[k] = ""
+
+ # Print symbols which both:
+ # * Appear in exactly one input, as symbols defined in multiple
+ # objects/libraries are assumed to have public definitions.
+ # * Aren't instances of member functions of templates which have been
+ # instantiated 100 times or more, which are assumed to have public
+ # definitions. (100 is an arbitrary guess here.)
+ if args.o:
+ outfile = open(args.o,'w')
+ else:
+ outfile = sys.stdout
+ for k,v in list(symbols.items()):
+ template_count = template_function_count[template_function_mapping[k]]
+ if v == 1 and template_count < 100:
+ print(k, file=outfile)
diff --git a/utils/findoptdiff b/utils/findoptdiff
index 7a2eab05d71a5..9a8803184384e 100755
--- a/utils/findoptdiff
+++ b/utils/findoptdiff
@@ -70,7 +70,7 @@ dis2="$llvm2/Debug/bin/llvm-dis"
opt1="$llvm1/Debug/bin/opt"
opt2="$llvm2/Debug/bin/opt"
-all_switches="-verify -lowersetjmp -simplifycfg -mem2reg -globalopt -globaldce -ipconstprop -deadargelim -instcombine -simplifycfg -prune-eh -inline -simplify-libcalls -argpromotion -tailduplicate -simplifycfg -scalarrepl -instcombine -predsimplify -condprop -tailcallelim -simplifycfg -reassociate -licm -loop-unswitch -instcombine -indvars -loop-unroll -instcombine -load-vn -gcse -sccp -instcombine -condprop -dse -dce -simplifycfg -deadtypeelim -constmerge -internalize -ipsccp -globalopt -constmerge -deadargelim -inline -prune-eh -globalopt -globaldce -argpromotion -instcombine -predsimplify -scalarrepl -globalsmodref-aa -licm -load-vn -gcse -dse -instcombine -simplifycfg -verify"
+all_switches="-verify -lowersetjmp -simplifycfg -mem2reg -globalopt -globaldce -ipconstprop -deadargelim -instcombine -simplifycfg -prune-eh -inline -simplify-libcalls -argpromotion -tailduplicate -simplifycfg -sroa -instcombine -predsimplify -condprop -tailcallelim -simplifycfg -reassociate -licm -loop-unswitch -instcombine -indvars -loop-unroll -instcombine -load-vn -gcse -sccp -instcombine -condprop -dse -dce -simplifycfg -deadtypeelim -constmerge -internalize -ipsccp -globalopt -constmerge -deadargelim -inline -prune-eh -globalopt -globaldce -argpromotion -instcombine -predsimplify -sroa -globalsmodref-aa -licm -load-vn -gcse -dse -instcombine -simplifycfg -verify"
#counter=0
function tryit {
diff --git a/utils/fpcmp/Makefile b/utils/fpcmp/Makefile
deleted file mode 100644
index 81db3b9c3f6ee..0000000000000
--- a/utils/fpcmp/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-##===- utils/fpcmp/Makefile --------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-TOOLNAME = fpcmp
-USEDLIBS = LLVMSupport.a
-NO_INSTALL = 1
-
-include $(LEVEL)/Makefile.common
-
diff --git a/utils/gdb-scripts/prettyprinters.py b/utils/gdb-scripts/prettyprinters.py
new file mode 100644
index 0000000000000..0dbc7af3e46ef
--- /dev/null
+++ b/utils/gdb-scripts/prettyprinters.py
@@ -0,0 +1,107 @@
+import gdb.printing
+class SmallStringPrinter:
+ """Print an llvm::SmallString object."""
+
+ def __init__(self, val):
+ self.val = val
+
+ def to_string(self):
+ begin = self.val['BeginX']
+ end = self.val['EndX']
+ return begin.cast(gdb.lookup_type("char").pointer()).string(length = end - begin)
+
+ def display_hint (self):
+ return 'string'
+
+class StringRefPrinter:
+ """Print an llvm::StringRef object."""
+
+ def __init__(self, val):
+ self.val = val
+
+ def to_string(self):
+ return self.val['Data'].string(length = self.val['Length'])
+
+ def display_hint (self):
+ return 'string'
+
+class SmallVectorPrinter:
+ """Print an llvm::SmallVector object."""
+
+ class _iterator:
+ def __init__(self, begin, end):
+ self.cur = begin
+ self.end = end
+ self.count = 0
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ if self.cur == self.end:
+ raise StopIteration
+ count = self.count
+ self.count = self.count + 1
+ cur = self.cur
+ self.cur = self.cur + 1
+ return '[%d]' % count, cur.dereference()
+
+ def __init__(self, val):
+ self.val = val
+
+ def children(self):
+ t = self.val.type.template_argument(0).pointer()
+ begin = self.val['BeginX'].cast(t)
+ end = self.val['EndX'].cast(t)
+ return self._iterator(begin, end)
+
+ def to_string(self):
+ t = self.val.type.template_argument(0).pointer()
+ begin = self.val['BeginX'].cast(t)
+ end = self.val['EndX'].cast(t)
+ capacity = self.val['CapacityX'].cast(t)
+ return 'llvm::SmallVector of length %d, capacity %d' % (end - begin, capacity - begin)
+
+ def display_hint (self):
+ return 'array'
+
+class ArrayRefPrinter:
+ """Print an llvm::ArrayRef object."""
+
+ class _iterator:
+ def __init__(self, begin, end):
+ self.cur = begin
+ self.end = end
+ self.count = 0
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ if self.cur == self.end:
+ raise StopIteration
+ count = self.count
+ self.count = self.count + 1
+ cur = self.cur
+ self.cur = self.cur + 1
+ return '[%d]' % count, cur.dereference()
+
+ def __init__(self, val):
+ self.val = val
+
+ def children(self):
+ data = self.val['Data']
+ return self._iterator(data, data + self.val['Length'])
+
+ def to_string(self):
+ return 'llvm::ArrayRef of length %d' % (self.val['Length'])
+
+ def display_hint (self):
+ return 'array'
+
+pp = gdb.printing.RegexpCollectionPrettyPrinter("LLVMSupport")
+pp.add_printer('llvm::SmallString', '^llvm::SmallString<.*>$', SmallStringPrinter)
+pp.add_printer('llvm::StringRef', '^llvm::StringRef$', StringRefPrinter)
+pp.add_printer('llvm::SmallVectorImpl', '^llvm::SmallVector(Impl)?<.*>$', SmallVectorPrinter)
+pp.add_printer('llvm::ArrayRef', '^llvm::(Const)?ArrayRef<.*>$', ArrayRefPrinter)
+gdb.printing.register_pretty_printer(gdb.current_objfile(), pp)
diff --git a/utils/lit/lit/Test.py b/utils/lit/lit/Test.py
index ef0e7bfc2a37d..9c9c47d63217a 100644
--- a/utils/lit/lit/Test.py
+++ b/utils/lit/lit/Test.py
@@ -102,11 +102,18 @@ class JSONMetricValue(MetricValue):
def toMetricValue(value):
if isinstance(value, MetricValue):
return value
- elif isinstance(value, int) or isinstance(value, long):
+ elif isinstance(value, int):
return IntMetricValue(value)
elif isinstance(value, float):
return RealMetricValue(value)
else:
+ # 'long' is only present in python2
+ try:
+ if isinstance(value, long):
+ return IntMetricValue(value)
+ except NameError:
+ pass
+
# Try to create a JSONMetricValue and let the constructor throw
# if value is not a valid type.
return JSONMetricValue(value)
@@ -230,11 +237,20 @@ class Test:
return True
# If this is a part of the target triple, it fails.
- if item in self.suite.config.target_triple:
+ if item and item in self.suite.config.target_triple:
return True
return False
+ def isEarlyTest(self):
+ """
+ isEarlyTest() -> bool
+
+ Check whether this test should be executed early in a particular run.
+ This can be used for test suites with long running tests to maximize
+ parallelism or where it is desirable to surface their failures early.
+ """
+ return self.suite.config.is_early
def getJUnitXML(self):
test_name = self.path_in_suite[-1]
diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py
index 1af82e1584456..24d687280c43f 100644
--- a/utils/lit/lit/TestRunner.py
+++ b/utils/lit/lit/TestRunner.py
@@ -110,6 +110,18 @@ class TimeoutHelper(object):
self._procs = [] # Python2 doesn't have list.clear()
self._doneKillPass = True
+class ShellCommandResult(object):
+ """Captures the result of an individual command."""
+
+ def __init__(self, command, stdout, stderr, exitCode, timeoutReached,
+ outputFiles = []):
+ self.command = command
+ self.stdout = stdout
+ self.stderr = stderr
+ self.exitCode = exitCode
+ self.timeoutReached = timeoutReached
+ self.outputFiles = list(outputFiles)
+
def executeShCmd(cmd, shenv, results, timeout=0):
"""
Wrapper around _executeShCmd that handles
@@ -243,8 +255,13 @@ def _executeShCmd(cmd, shenv, results, timeoutHelper):
result = subprocess.PIPE
else:
if r[2] is None:
+ redir_filename = None
if kAvoidDevNull and r[0] == '/dev/null':
r[2] = tempfile.TemporaryFile(mode=r[1])
+ elif kIsWindows and r[0] == '/dev/tty':
+ # Simulate /dev/tty on Windows.
+ # "CON" is a special filename for the console.
+ r[2] = open("CON", r[1])
else:
# Make sure relative paths are relative to the cwd.
redir_filename = os.path.join(cmd_shenv.cwd, r[0])
@@ -254,7 +271,7 @@ def _executeShCmd(cmd, shenv, results, timeoutHelper):
# FIXME: Actually, this is probably an instance of PR6753.
if r[1] == 'a':
r[2].seek(0, 2)
- opened_files.append(r[2])
+ opened_files.append(tuple(r) + (redir_filename,))
result = r[2]
final_redirects.append(result)
@@ -328,7 +345,7 @@ def _executeShCmd(cmd, shenv, results, timeoutHelper):
# need to release any handles we may have on the temporary files (important
# on Win32, for example). Since we have already spawned the subprocess, our
# handles have already been transferred so we do not need them anymore.
- for f in opened_files:
+ for (name, mode, f, path) in opened_files:
f.close()
# FIXME: There is probably still deadlock potential here. Yawn.
@@ -365,15 +382,36 @@ def _executeShCmd(cmd, shenv, results, timeoutHelper):
# Ensure the resulting output is always of string type.
try:
- out = to_string(out.decode('utf-8'))
+ if out is None:
+ out = ''
+ else:
+ out = to_string(out.decode('utf-8', errors='replace'))
except:
out = str(out)
try:
- err = to_string(err.decode('utf-8'))
+ if err is None:
+ err = ''
+ else:
+ err = to_string(err.decode('utf-8', errors='replace'))
except:
err = str(err)
- results.append((cmd.commands[i], out, err, res, timeoutHelper.timeoutReached()))
+ # Gather the redirected output files for failed commands.
+ output_files = []
+ if res != 0:
+ for (name, mode, f, path) in sorted(opened_files):
+ if path is not None and mode in ('w', 'a'):
+ try:
+ with open(path, 'rb') as f:
+ data = f.read()
+ except:
+ data = None
+ if data != None:
+ output_files.append((name, path, data))
+
+ results.append(ShellCommandResult(
+ cmd.commands[i], out, err, res, timeoutHelper.timeoutReached(),
+ output_files))
if cmd.pipe_err:
# Python treats the exit code as a signed char.
if exitCode is None:
@@ -418,16 +456,49 @@ def executeScriptInternal(test, litConfig, tmpBase, commands, cwd):
except InternalShellError:
e = sys.exc_info()[1]
exitCode = 127
- results.append((e.command, '', e.message, exitCode, False))
+ results.append(
+ ShellCommandResult(e.command, '', e.message, exitCode, False))
out = err = ''
- for i,(cmd, cmd_out, cmd_err, res, timeoutReached) in enumerate(results):
- out += 'Command %d: %s\n' % (i, ' '.join('"%s"' % s for s in cmd.args))
- out += 'Command %d Result: %r\n' % (i, res)
+ for i,result in enumerate(results):
+ # Write the command line run.
+ out += '$ %s\n' % (' '.join('"%s"' % s
+ for s in result.command.args),)
+
+ # If nothing interesting happened, move on.
+ if litConfig.maxIndividualTestTime == 0 and \
+ result.exitCode == 0 and \
+ not result.stdout.strip() and not result.stderr.strip():
+ continue
+
+ # Otherwise, something failed or was printed, show it.
+
+ # Add the command output, if redirected.
+ for (name, path, data) in result.outputFiles:
+ if data.strip():
+ out += "# redirected output from %r:\n" % (name,)
+ data = to_string(data.decode('utf-8', errors='replace'))
+ if len(data) > 1024:
+ out += data[:1024] + "\n...\n"
+ out += "note: data was truncated\n"
+ else:
+ out += data
+ out += "\n"
+
+ if result.stdout.strip():
+ out += '# command output:\n%s\n' % (result.stdout,)
+ if result.stderr.strip():
+ out += '# command stderr:\n%s\n' % (result.stderr,)
+ if not result.stdout.strip() and not result.stderr.strip():
+ out += "note: command had no output on stdout or stderr\n"
+
+ # Show the error conditions:
+ if result.exitCode != 0:
+ out += "error: command failed with exit status: %d\n" % (
+ result.exitCode,)
if litConfig.maxIndividualTestTime > 0:
- out += 'Command %d Reached Timeout: %s\n\n' % (i, str(timeoutReached))
- out += 'Command %d Output:\n%s\n\n' % (i, cmd_out)
- out += 'Command %d Stderr:\n%s\n\n' % (i, cmd_err)
+ out += 'error: command reached timeout: %s\n' % (
+ i, str(result.timeoutReached))
return out, err, exitCode, timeoutInfo
@@ -564,6 +635,24 @@ def getDefaultSubstitutions(test, tmpDir, tmpBase, normalize_slashes=False):
('%/t', tmpBase.replace('\\', '/') + '.tmp'),
('%/T', tmpDir.replace('\\', '/')),
])
+
+ # "%:[STpst]" are paths without colons.
+ if kIsWindows:
+ substitutions.extend([
+ ('%:s', re.sub(r'^(.):', r'\1', sourcepath)),
+ ('%:S', re.sub(r'^(.):', r'\1', sourcedir)),
+ ('%:p', re.sub(r'^(.):', r'\1', sourcedir)),
+ ('%:t', re.sub(r'^(.):', r'\1', tmpBase) + '.tmp'),
+ ('%:T', re.sub(r'^(.):', r'\1', tmpDir)),
+ ])
+ else:
+ substitutions.extend([
+ ('%:s', sourcepath),
+ ('%:S', sourcedir),
+ ('%:p', sourcedir),
+ ('%:t', tmpBase + '.tmp'),
+ ('%:T', tmpDir),
+ ])
return substitutions
def applySubstitutions(script, substitutions):
@@ -594,8 +683,10 @@ def parseIntegratedTestScript(test, require_script=True):
sourcepath = test.getSourcePath()
script = []
requires = []
+ requires_any = []
unsupported = []
- keywords = ['RUN:', 'XFAIL:', 'REQUIRES:', 'UNSUPPORTED:', 'END.']
+ keywords = ['RUN:', 'XFAIL:', 'REQUIRES:', 'REQUIRES-ANY:',
+ 'UNSUPPORTED:', 'END.']
for line_number, command_type, ln in \
parseIntegratedTestScriptCommands(sourcepath, keywords):
if command_type == 'RUN':
@@ -620,6 +711,8 @@ def parseIntegratedTestScript(test, require_script=True):
test.xfails.extend([s.strip() for s in ln.split(',')])
elif command_type == 'REQUIRES':
requires.extend([s.strip() for s in ln.split(',')])
+ elif command_type == 'REQUIRES-ANY':
+ requires_any.extend([s.strip() for s in ln.split(',')])
elif command_type == 'UNSUPPORTED':
unsupported.extend([s.strip() for s in ln.split(',')])
elif command_type == 'END':
@@ -646,6 +739,12 @@ def parseIntegratedTestScript(test, require_script=True):
msg = ', '.join(missing_required_features)
return lit.Test.Result(Test.UNSUPPORTED,
"Test requires the following features: %s" % msg)
+ requires_any_features = [f for f in requires_any
+ if f in test.config.available_features]
+ if requires_any and not requires_any_features:
+ msg = ' ,'.join(requires_any)
+ return lit.Test.Result(Test.UNSUPPORTED,
+ "Test requires any of the following features: %s" % msg)
unsupported_features = [f for f in unsupported
if f in test.config.available_features]
if unsupported_features:
diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py
index 7441b94b9f087..1e39a000c90d8 100644
--- a/utils/lit/lit/TestingConfig.py
+++ b/utils/lit/lit/TestingConfig.py
@@ -24,7 +24,8 @@ class TestingConfig:
pass_vars = ['LIBRARY_PATH', 'LD_LIBRARY_PATH', 'SYSTEMROOT', 'TERM',
'LD_PRELOAD', 'ASAN_OPTIONS', 'UBSAN_OPTIONS',
- 'LSAN_OPTIONS', 'ADB', 'ANDROID_SERIAL']
+ 'LSAN_OPTIONS', 'ADB', 'ANDROID_SERIAL',
+ 'SANITIZER_IGNORE_CVE_2016_2143']
for var in pass_vars:
val = os.environ.get(var, '')
# Check for empty string as some variables such as LD_PRELOAD cannot be empty
@@ -118,7 +119,8 @@ class TestingConfig:
def __init__(self, parent, name, suffixes, test_format,
environment, substitutions, unsupported,
test_exec_root, test_source_root, excludes,
- available_features, pipefail, limit_to_features = []):
+ available_features, pipefail, limit_to_features = [],
+ is_early = False):
self.parent = parent
self.name = str(name)
self.suffixes = set(suffixes)
@@ -135,6 +137,8 @@ class TestingConfig:
# require one of the features in this list if this list is non-empty.
# Configurations can set this list to restrict the set of tests to run.
self.limit_to_features = set(limit_to_features)
+ # Whether the suite should be tested early in a given run.
+ self.is_early = bool(is_early)
def finish(self, litConfig):
"""finish() - Finish this config object, after loading is complete."""
diff --git a/utils/lit/lit/formats/googletest.py b/utils/lit/lit/formats/googletest.py
index 5b19d4e638f94..f0250a3f96dd1 100644
--- a/utils/lit/lit/formats/googletest.py
+++ b/utils/lit/lit/formats/googletest.py
@@ -43,6 +43,12 @@ class GoogleTest(TestFormat):
if not ln.strip():
continue
+ if 'Running main() from gtest_main.cc' in ln:
+ # Upstream googletest prints this to stdout prior to running
+ # tests. LLVM removed that print statement in r61540, but we
+ # handle it here in case upstream googletest is being used.
+ continue
+
prefix = ''
index = 0
while ln[index*2:index*2+2] == ' ':
diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py
index 4df2571da998b..50927e2cbf022 100755
--- a/utils/lit/lit/main.py
+++ b/utils/lit/lit/main.py
@@ -336,6 +336,9 @@ def main(builtinParameters = {}):
print(' %s - %d tests' %(ts.name, len(ts_tests)))
print(' Source Root: %s' % ts.source_root)
print(' Exec Root : %s' % ts.exec_root)
+ if ts.config.available_features:
+ print(' Available Features : %s' % ' '.join(
+ sorted(ts.config.available_features)))
# Show the tests, if requested.
if opts.showTests:
@@ -367,7 +370,7 @@ def main(builtinParameters = {}):
elif opts.incremental:
sort_by_incremental_cache(run)
else:
- run.tests.sort(key = lambda result_test: result_test.getFullName())
+ run.tests.sort(key = lambda t: (not t.isEarlyTest(), t.getFullName()))
# Finally limit the number of tests, if desired.
if opts.maxTests is not None:
diff --git a/utils/lit/lit/run.py b/utils/lit/lit/run.py
index 27c414d6dd65e..bbf644ef7dbeb 100644
--- a/utils/lit/lit/run.py
+++ b/utils/lit/lit/run.py
@@ -44,11 +44,13 @@ class LockedValue(object):
value = property(_get_value, _set_value)
class TestProvider(object):
- def __init__(self, tests, num_jobs, queue_impl, canceled_flag):
+ def __init__(self, queue_impl, canceled_flag):
self.canceled_flag = canceled_flag
# Create a shared queue to provide the test indices.
self.queue = queue_impl()
+
+ def queue_tests(self, tests, num_jobs):
for i in range(len(tests)):
self.queue.put(i)
for i in range(num_jobs):
@@ -229,7 +231,15 @@ class Run(object):
consumer = ThreadResultsConsumer(display)
# Create the test provider.
- provider = TestProvider(self.tests, jobs, queue_impl, canceled_flag)
+ provider = TestProvider(queue_impl, canceled_flag)
+
+ # Queue the tests outside the main thread because we can't guarantee
+ # that we can put() all the tests without blocking:
+ # https://docs.python.org/2/library/multiprocessing.html
+ # e.g: On Mac OS X, we will hang if we put 2^15 elements in the queue
+ # without taking any out.
+ queuer = task_impl(target=provider.queue_tests, args=(self.tests, jobs))
+ queuer.start()
# Install a console-control signal handler on Windows.
if win32api is not None:
@@ -252,6 +262,8 @@ class Run(object):
# Otherwise, execute the tests in parallel
self._execute_tests_in_parallel(task_impl, provider, consumer, jobs)
+ queuer.join()
+
# Cancel the timeout handler.
if max_time is not None:
timeout_timer.cancel()
diff --git a/utils/lit/tests/Inputs/googletest-upstream-format/DummySubDir/OneTest b/utils/lit/tests/Inputs/googletest-upstream-format/DummySubDir/OneTest
new file mode 100755
index 0000000000000..d7bc5968f2611
--- /dev/null
+++ b/utils/lit/tests/Inputs/googletest-upstream-format/DummySubDir/OneTest
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+import sys
+
+if len(sys.argv) != 2:
+ raise ValueError("unexpected number of args")
+
+if sys.argv[1] == "--gtest_list_tests":
+ print("""\
+Running main() from gtest_main.cc
+FirstTest.
+ subTestA
+ subTestB
+ParameterizedTest/0.
+ subTest
+ParameterizedTest/1.
+ subTest""")
+ sys.exit(0)
+elif not sys.argv[1].startswith("--gtest_filter="):
+ raise ValueError("unexpected argument: %r" % (sys.argv[1]))
+
+test_name = sys.argv[1].split('=',1)[1]
+print('Running main() from gtest_main.cc')
+if test_name == 'FirstTest.subTestA':
+ print('I am subTest A, I PASS')
+ print('[ PASSED ] 1 test.')
+ sys.exit(0)
+elif test_name == 'FirstTest.subTestB':
+ print('I am subTest B, I FAIL')
+ print('And I have two lines of output')
+ sys.exit(1)
+elif test_name in ('ParameterizedTest/0.subTest',
+ 'ParameterizedTest/1.subTest'):
+ print('I am a parameterized test, I also PASS')
+ print('[ PASSED ] 1 test.')
+ sys.exit(0)
+else:
+ raise SystemExit("error: invalid test name: %r" % (test_name,))
diff --git a/utils/lit/tests/Inputs/googletest-upstream-format/lit.cfg b/utils/lit/tests/Inputs/googletest-upstream-format/lit.cfg
new file mode 100644
index 0000000000000..9fb5d2b0247be
--- /dev/null
+++ b/utils/lit/tests/Inputs/googletest-upstream-format/lit.cfg
@@ -0,0 +1,3 @@
+import lit.formats
+config.name = 'googletest-upstream-format'
+config.test_format = lit.formats.GoogleTest('DummySubDir', 'Test')
diff --git a/utils/lit/tests/Inputs/shtest-format/requires-any-missing.txt b/utils/lit/tests/Inputs/shtest-format/requires-any-missing.txt
new file mode 100644
index 0000000000000..c977ee90c9e55
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/requires-any-missing.txt
@@ -0,0 +1,2 @@
+RUN: true
+REQUIRES-ANY: a-missing-feature, a-missing-feature-2
diff --git a/utils/lit/tests/Inputs/shtest-format/requires-any-present.txt b/utils/lit/tests/Inputs/shtest-format/requires-any-present.txt
new file mode 100644
index 0000000000000..f3be518b25827
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-format/requires-any-present.txt
@@ -0,0 +1,2 @@
+RUN: true
+REQUIRES-ANY: a-missing-feature, a-present-feature
diff --git a/utils/lit/tests/Inputs/shtest-output-printing/basic.txt b/utils/lit/tests/Inputs/shtest-output-printing/basic.txt
new file mode 100644
index 0000000000000..4899c7e63db45
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-output-printing/basic.txt
@@ -0,0 +1,3 @@
+# RUN: true
+# RUN: echo hi
+# RUN: wc missing-file &> %t.out
diff --git a/utils/lit/tests/Inputs/shtest-output-printing/lit.cfg b/utils/lit/tests/Inputs/shtest-output-printing/lit.cfg
new file mode 100644
index 0000000000000..4fe698d73368e
--- /dev/null
+++ b/utils/lit/tests/Inputs/shtest-output-printing/lit.cfg
@@ -0,0 +1,4 @@
+import lit.formats
+config.name = 'shtest-output-printing'
+config.suffixes = ['.txt']
+config.test_format = lit.formats.ShTest(execute_external=False)
diff --git a/utils/lit/tests/googletest-upstream-format.py b/utils/lit/tests/googletest-upstream-format.py
new file mode 100644
index 0000000000000..1fc7c7c4a5ad2
--- /dev/null
+++ b/utils/lit/tests/googletest-upstream-format.py
@@ -0,0 +1,20 @@
+# Check the various features of the GoogleTest format.
+#
+# RUN: not %{lit} -j 1 -v %{inputs}/googletest-upstream-format > %t.out
+# RUN: FileCheck < %t.out %s
+#
+# END.
+
+# CHECK: -- Testing:
+# CHECK: PASS: googletest-upstream-format :: DummySubDir/OneTest/FirstTest.subTestA
+# CHECK: FAIL: googletest-upstream-format :: DummySubDir/OneTest/FirstTest.subTestB
+# CHECK-NEXT: *** TEST 'googletest-upstream-format :: DummySubDir/OneTest/FirstTest.subTestB' FAILED ***
+# CHECK-NEXT: Running main() from gtest_main.cc
+# CHECK-NEXT: I am subTest B, I FAIL
+# CHECK-NEXT: And I have two lines of output
+# CHECK: ***
+# CHECK: PASS: googletest-upstream-format :: DummySubDir/OneTest/ParameterizedTest/0.subTest
+# CHECK: PASS: googletest-upstream-format :: DummySubDir/OneTest/ParameterizedTest/1.subTest
+# CHECK: Failing Tests (1)
+# CHECK: Expected Passes : 3
+# CHECK: Unexpected Failures: 1
diff --git a/utils/lit/tests/shtest-format.py b/utils/lit/tests/shtest-format.py
index 751f0d7080306..20884f8c4854d 100644
--- a/utils/lit/tests/shtest-format.py
+++ b/utils/lit/tests/shtest-format.py
@@ -39,14 +39,15 @@
#
# CHECK: Command Output (stdout):
# CHECK-NEXT: --
-# CHECK-NEXT: Command 0: "printf"
-# CHECK-NEXT: Command 0 Result: 0
-# CHECK-NEXT: Command 0 Output:
+# CHECK-NEXT: $ "printf"
+# CHECK-NEXT: # command output:
# CHECK-NEXT: line 1: failed test output on stdout
# CHECK-NEXT: line 2: failed test output on stdout
# CHECK: UNRESOLVED: shtest-format :: no-test-line.txt
# CHECK: PASS: shtest-format :: pass.txt
+# CHECK: UNSUPPORTED: shtest-format :: requires-any-missing.txt
+# CHECK: PASS: shtest-format :: requires-any-present.txt
# CHECK: UNSUPPORTED: shtest-format :: requires-missing.txt
# CHECK: PASS: shtest-format :: requires-present.txt
# CHECK: UNSUPPORTED: shtest-format :: unsupported_dir/some-test.txt
@@ -69,9 +70,9 @@
# CHECK: shtest-format :: external_shell/fail_with_bad_encoding.txt
# CHECK: shtest-format :: fail.txt
-# CHECK: Expected Passes : 4
+# CHECK: Expected Passes : 5
# CHECK: Expected Failures : 3
-# CHECK: Unsupported Tests : 2
+# CHECK: Unsupported Tests : 3
# CHECK: Unresolved Tests : 1
# CHECK: Unexpected Passes : 1
# CHECK: Unexpected Failures: 3
diff --git a/utils/lit/tests/shtest-output-printing.py b/utils/lit/tests/shtest-output-printing.py
new file mode 100644
index 0000000000000..24580b37f1f54
--- /dev/null
+++ b/utils/lit/tests/shtest-output-printing.py
@@ -0,0 +1,28 @@
+# Check the various features of the ShTest format.
+#
+# RUN: not %{lit} -j 1 -v %{inputs}/shtest-output-printing > %t.out
+# RUN: FileCheck --input-file %t.out %s
+#
+# END.
+
+# CHECK: -- Testing:
+
+# CHECK: FAIL: shtest-output-printing :: basic.txt
+# CHECK-NEXT: *** TEST 'shtest-output-printing :: basic.txt' FAILED ***
+# CHECK-NEXT: Script:
+# CHECK-NEXT: --
+# CHECK: --
+# CHECK-NEXT: Exit Code: 1
+#
+# CHECK: Command Output
+# CHECK-NEXT: --
+# CHECK-NEXT: $ "true"
+# CHECK-NEXT: $ "echo" "hi"
+# CHECK-NEXT: # command output:
+# CHECK-NEXT: hi
+#
+# CHECK: $ "wc" "missing-file"
+# CHECK-NEXT: # redirected output from '{{.*}}/basic.txt.tmp.out':
+# CHECK-NEXT: missing-file{{.*}} No such file or directory
+# CHECK: note: command had no output on stdout or stderr
+# CHECK-NEXT: error: command failed with exit status: 1
diff --git a/utils/lit/tests/shtest-shell.py b/utils/lit/tests/shtest-shell.py
index 32479e19a1026..18b80cd7d0877 100644
--- a/utils/lit/tests/shtest-shell.py
+++ b/utils/lit/tests/shtest-shell.py
@@ -1,7 +1,7 @@
# Check the internal shell handling component of the ShTest format.
#
# RUN: not %{lit} -j 1 -v %{inputs}/shtest-shell > %t.out
-# RUN: FileCheck < %t.out %s
+# RUN: FileCheck --input-file %t.out %s
#
# END.
@@ -9,10 +9,10 @@
# CHECK: FAIL: shtest-shell :: error-0.txt
# CHECK: *** TEST 'shtest-shell :: error-0.txt' FAILED ***
-# CHECK: Command 0: "not-a-real-command"
-# CHECK: Command 0 Result: 127
-# CHECK: Command 0 Stderr:
+# CHECK: $ "not-a-real-command"
+# CHECK: # command stderr:
# CHECK: 'not-a-real-command': command not found
+# CHECK: error: command failed with exit status: 127
# CHECK: ***
# FIXME: The output here sucks.
diff --git a/utils/llvm-build/llvmbuild/main.py b/utils/llvm-build/llvmbuild/main.py
index f2472f698a671..fccfc7e6ece32 100644
--- a/utils/llvm-build/llvmbuild/main.py
+++ b/utils/llvm-build/llvmbuild/main.py
@@ -413,7 +413,7 @@ subdirectories = %s
if library_name is None:
library_name_as_cstr = 'nullptr'
else:
- library_name_as_cstr = '"lib%s.a"' % library_name
+ library_name_as_cstr = '"%s"' % library_name
if is_installed:
is_installed_as_cstr = 'true'
else:
diff --git a/utils/llvm-lit/Makefile b/utils/llvm-lit/Makefile
deleted file mode 100644
index ce1cac9c32e90..0000000000000
--- a/utils/llvm-lit/Makefile
+++ /dev/null
@@ -1,27 +0,0 @@
-##===- utils/llvm-lit/Makefile -----------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-
-include $(LEVEL)/Makefile.common
-
-# llvm-lit needs suffix.py for multiprocess to find a main module.
-ifeq ($(HOST_OS),MingW)
- Suffix := .py
-endif
-
-all:: $(ToolDir)/llvm-lit$(Suffix)
-
-$(ToolDir)/llvm-lit$(Suffix): llvm-lit.in Makefile $(ToolDir)/.dir
- $(Echo) "Creating 'llvm-lit' script..."
- $(Verb)$(ECHOPATH) s=@LLVM_SOURCE_DIR@=$(LLVM_SRC_ROOT)=g > lit.tmp
- $(Verb)$(ECHOPATH) s=@LLVM_BINARY_DIR@=$(LLVM_OBJ_ROOT)=g >> lit.tmp
- $(Verb)sed -f lit.tmp $< > $@
- $(Verb)chmod +x $@
- $(Verb)rm -f lit.tmp
diff --git a/utils/llvm.natvis b/utils/llvm.natvis
deleted file mode 100644
index 6c410a40ecbdc..0000000000000
--- a/utils/llvm.natvis
+++ /dev/null
@@ -1,169 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Visual Studio 2012 Native Debugging Visualizers for LLVM
-
-Put this file into "%USERPROFILE%\Documents\Visual Studio 2012\Visualizers"
-or create a symbolic link so it updates automatically.
--->
-<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
-
- <Type Name="llvm::SmallVectorImpl&lt;*&gt;">
- <DisplayString Condition="(($T1*)EndX - ($T1*)BeginX) == 0">empty</DisplayString>
- <DisplayString Condition="(($T1*)EndX - ($T1*)BeginX) != 0">{{ size={($T1*)EndX - ($T1*)BeginX} }}</DisplayString>
- <Expand>
- <Item Name="[size]">($T1*)EndX - ($T1*)BeginX</Item>
- <Item Name="[capacity]">($T1*)CapacityX - ($T1*)BeginX</Item>
- <ArrayItems>
- <Size>($T1*)EndX - ($T1*)BeginX</Size>
- <ValuePointer>($T1*)BeginX</ValuePointer>
- </ArrayItems>
- </Expand>
- </Type>
-
- <Type Name="llvm::SmallString&lt;*&gt;">
- <DisplayString>{BeginX,s}</DisplayString>
- <StringView>BeginX,s</StringView>
- <Expand>
- <Item Name="[size]">(char*)EndX - (char*)BeginX</Item>
- <Item Name="[capacity]">(char*)CapacityX - (char*)BeginX</Item>
- <ArrayItems>
- <Size>(char*)EndX - (char*)BeginX</Size>
- <ValuePointer>(char*)BeginX</ValuePointer>
- </ArrayItems>
- </Expand>
- </Type>
-
- <Type Name="llvm::StringRef">
- <DisplayString>{Data,[Length]s}</DisplayString>
- <StringView>Data,[Length]s</StringView>
- <Expand>
- <Item Name="[size]">Length</Item>
- <ArrayItems>
- <Size>Length</Size>
- <ValuePointer>Data</ValuePointer>
- </ArrayItems>
- </Expand>
- </Type>
-
- <Type Name="llvm::PointerIntPair&lt;*,*,*,*&gt;">
- <DisplayString>{(void*)(Value &amp; PointerBitMask)} [{($T3)((Value &gt;&gt; IntShift) &amp; IntMask)}]</DisplayString>
- <Expand>
- <Item Name="[ptr]">($T1*)(Value &amp; PointerBitMask)</Item>
- <Item Name="[int]">($T3)((Value &gt;&gt; IntShift) &amp; IntMask)</Item>
- </Expand>
- </Type>
-
- <Type Name="llvm::PointerUnion&lt;*,*&gt;">
- <DisplayString Condition="((Val.Value &gt;&gt; Val.IntShift) &amp; Val.IntMask) == 0">{"$T1", s8b} {(void*)(Val.Value &amp; Val.PointerBitMask)}</DisplayString>
- <DisplayString Condition="((Val.Value &gt;&gt; Val.IntShift) &amp; Val.IntMask) != 0">{"$T2", s8b} {(void*)(Val.Value &amp; Val.PointerBitMask)}</DisplayString>
- <Expand>
- <ExpandedItem Condition="((Val.Value &gt;&gt; Val.IntShift) &amp; Val.IntMask) == 0">($T1)(Val.Value &amp; Val.PointerBitMask)</ExpandedItem>
- <ExpandedItem Condition="((Val.Value &gt;&gt; Val.IntShift) &amp; Val.IntMask) != 0">($T2)(Val.Value &amp; Val.PointerBitMask)</ExpandedItem>
- </Expand>
- </Type>
-
- <Type Name="llvm::PointerUnion3&lt;*,*,*&gt;">
- <DisplayString Condition="(Val.Val.Value &amp; 2) != 2 &amp;&amp; (Val.Val.Value &amp; 1) != 1">{"$T1", s8b} {(void*)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
- <DisplayString Condition="(Val.Val.Value &amp; 2) == 2">{"$T2", s8b} {(void*)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
- <DisplayString Condition="(Val.Val.Value &amp; 1) == 1">{"$T3", s8b} {(void*)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
- <Expand>
- <ExpandedItem Condition="(Val.Val.Value &amp; 2) != 2 &amp;&amp; (Val.Val.Value &amp; 1) != 1">($T1)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</ExpandedItem>
- <ExpandedItem Condition="(Val.Val.Value &amp; 2) == 2">($T2)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</ExpandedItem>
- <ExpandedItem Condition="(Val.Val.Value &amp; 1) == 1">($T3)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</ExpandedItem>
- </Expand>
- </Type>
-
- <Type Name="llvm::PointerUnion4&lt;*,*,*,*&gt;">
- <DisplayString Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 2) != 2 &amp;&amp; (Val.Val.Value &amp; 1) != 1">{"$T1", s8b} {(void*)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
- <DisplayString Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 2) == 2">{"$T2", s8b} {(void*)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
- <DisplayString Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 1) == 1">{"$T3", s8b} {(void*)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
- <DisplayString Condition="(Val.Val.Value &amp; 3) == 3">{"$T4", s8b} {(void*)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)}</DisplayString>
- <Expand>
- <ExpandedItem Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 2) != 2 &amp;&amp; (Val.Val.Value &amp; 1) != 1">($T1)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</ExpandedItem>
- <ExpandedItem Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 2) == 2">($T2)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</ExpandedItem>
- <ExpandedItem Condition="(Val.Val.Value &amp; 3) != 3 &amp;&amp; (Val.Val.Value &amp; 1) == 1">($T3)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</ExpandedItem>
- <ExpandedItem Condition="(Val.Val.Value &amp; 3) == 3">($T4)((Val.Val.Value &gt;&gt; 2) &lt;&lt; 2)</ExpandedItem>
- </Expand>
- </Type>
-
- <Type Name="llvm::iplist&lt;*,*&gt;">
- <DisplayString Condition="Head == 0">{{ empty }}</DisplayString>
- <DisplayString Condition="Head != 0">{{ head={Head} }}</DisplayString>
- <Expand>
- <LinkedListItems>
- <HeadPointer>Head</HeadPointer>
- <NextPointer>Next</NextPointer>
- <ValueNode>this</ValueNode>
- </LinkedListItems>
- </Expand>
- </Type>
-
- <Type Name="llvm::IntrusiveRefCntPtr&lt;*&gt;">
- <DisplayString Condition="Obj == 0">empty</DisplayString>
- <DisplayString Condition="(Obj != 0) &amp;&amp; (Obj-&gt;ref_cnt == 1)">RefPtr [1 ref] {*Obj}</DisplayString>
- <DisplayString Condition="(Obj != 0) &amp;&amp; (Obj-&gt;ref_cnt != 1)">RefPtr [{Obj-&gt;ref_cnt} refs] {*Obj}</DisplayString>
- <Expand>
- <Item Condition="Obj != 0" Name="[refs]">Obj-&gt;ref_cnt</Item>
- <ExpandedItem Condition="Obj != 0">Obj</ExpandedItem>
- </Expand>
- </Type>
-
- <Type Name="llvm::SmallPtrSet&lt;*,*&gt;">
- <DisplayString Condition="CurArray == SmallArray">{{ [Small Mode] size={NumElements}, capacity={CurArraySize} }}</DisplayString>
- <DisplayString Condition="CurArray != SmallArray">{{ [Big Mode] size={NumElements}, capacity={CurArraySize} }}</DisplayString>
- <Expand>
- <Item Name="[size]">NumElements</Item>
- <Item Name="[capacity]">CurArraySize</Item>
- <ArrayItems>
- <Size>CurArraySize</Size>
- <ValuePointer>($T1*)CurArray</ValuePointer>
- </ArrayItems>
- </Expand>
- </Type>
-
- <Type Name="llvm::DenseMap&lt;*,*,*&gt;">
- <DisplayString Condition="NumEntries == 0">empty</DisplayString>
- <DisplayString Condition="NumEntries != 0">{{ size={NumEntries}, buckets={NumBuckets} }}</DisplayString>
- <Expand>
- <Item Name="[size]">NumEntries</Item>
- <Item Name="[buckets]">NumBuckets</Item>
- <ArrayItems>
- <Size>NumBuckets</Size>
- <ValuePointer>Buckets</ValuePointer>
- </ArrayItems>
- </Expand>
- </Type>
-
- <Type Name="llvm::StringMap&lt;*,*&gt;">
- <DisplayString>{{ size={NumItems}, buckets={NumBuckets} }}</DisplayString>
- <Expand>
- <Item Name="[size]">NumItems</Item>
- <Item Name="[buckets]">NumBuckets</Item>
- <ArrayItems>
- <Size>NumBuckets</Size>
- <ValuePointer>(MapEntryTy**)TheTable</ValuePointer>
- </ArrayItems>
- </Expand>
- </Type>
-
- <Type Name="llvm::StringMapEntry&lt;*&gt;">
- <DisplayString Condition="StrLen == 0">empty</DisplayString>
- <DisplayString Condition="StrLen != 0">({this+1,s}, {second})</DisplayString>
- <Expand>
- <Item Name="[key]">this+1,s</Item>
- <Item Name="[value]" Condition="StrLen != 0">second</Item>
- </Expand>
- </Type>
-
- <Type Name="llvm::Triple">
- <DisplayString>{Data}</DisplayString>
- </Type>
-
- <Type Name="llvm::Optional&lt;*&gt;">
- <DisplayString Condition="!hasVal">empty</DisplayString>
- <DisplayString Condition="hasVal">{*(($T1 *)(unsigned char *)storage.buffer)}</DisplayString>
- <Expand>
- <Item Name="[underlying]" Condition="hasVal">*(($T1 *)(unsigned char *)storage.buffer)</Item>
- </Expand>
- </Type>
-</AutoVisualizer>
diff --git a/utils/not/Makefile b/utils/not/Makefile
deleted file mode 100644
index 26b7450d48b07..0000000000000
--- a/utils/not/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-##===- utils/not/Makefile ----------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-TOOLNAME = not
-USEDLIBS = LLVMSupport.a
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-# FIXME: Don't install this utility
-#NO_INSTALL = 1
-
-include $(LEVEL)/Makefile.common
-
diff --git a/utils/prepare-code-coverage-artifact.py b/utils/prepare-code-coverage-artifact.py
new file mode 100644
index 0000000000000..e233c2c6efec0
--- /dev/null
+++ b/utils/prepare-code-coverage-artifact.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+'''Prepare a code coverage artifact.
+
+- Collate raw profiles into one indexed profile.
+- Delete the raw profiles.
+- Copy the coverage mappings in the binaries directory.
+'''
+
+import argparse
+import glob
+import os
+import subprocess
+import sys
+
+def merge_raw_profiles(host_llvm_profdata, profile_data_dir):
+ print ':: Merging raw profiles...',
+ sys.stdout.flush()
+ raw_profiles = glob.glob(os.path.join(profile_data_dir, '*.profraw'))
+ manifest_path = os.path.join(profile_data_dir, 'profiles.manifest')
+ profdata_path = os.path.join(profile_data_dir, 'Coverage.profdata')
+ with open(manifest_path, 'w') as manifest:
+ manifest.write('\n'.join(raw_profiles))
+ subprocess.check_call([host_llvm_profdata, 'merge', '-sparse', '-f',
+ manifest_path, '-o', profdata_path])
+ for raw_profile in raw_profiles:
+ os.remove(raw_profile)
+ print 'Done!'
+
+def extract_covmappings(host_llvm_cov, profile_data_dir, llvm_bin_dir):
+ print ':: Extracting covmappings...',
+ sys.stdout.flush()
+ for prog in os.listdir(llvm_bin_dir):
+ if prog == 'llvm-lit':
+ continue
+ covmapping_path = os.path.join(profile_data_dir,
+ os.path.basename(prog) + '.covmapping')
+ subprocess.check_call([host_llvm_cov, 'convert-for-testing',
+ os.path.join(llvm_bin_dir, prog), '-o',
+ covmapping_path])
+ print 'Done!'
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('host_llvm_profdata', help='Path to llvm-profdata')
+ parser.add_argument('host_llvm_cov', help='Path to llvm-cov')
+ parser.add_argument('profile_data_dir',
+ help='Path to the directory containing the raw profiles')
+ parser.add_argument('llvm_bin_dir',
+ help='Path to the directory containing llvm binaries')
+ args = parser.parse_args()
+
+ merge_raw_profiles(args.host_llvm_profdata, args.profile_data_dir)
+ extract_covmappings(args.host_llvm_cov, args.profile_data_dir,
+ args.llvm_bin_dir)
diff --git a/utils/release/build_llvm_package.bat b/utils/release/build_llvm_package.bat
index 830f25e5cf389..5542ca613f310 100755
--- a/utils/release/build_llvm_package.bat
+++ b/utils/release/build_llvm_package.bat
@@ -19,8 +19,8 @@ set PATH=%PATH%;c:\gnuwin32\bin
set revision=%1
set branch=trunk
-set package_version=3.8.0-r%revision%
-set clang_format_vs_version=3.8.0.%revision%
+set package_version=3.9.0-r%revision%
+set clang_format_vs_version=3.9.0.%revision%
set build_dir=llvm_package_%revision%
echo Branch: %branch%
@@ -40,9 +40,11 @@ svn.exe export -r %revision% http://llvm.org/svn/llvm-project/cfe/%branch% llvm/
svn.exe export -r %revision% http://llvm.org/svn/llvm-project/clang-tools-extra/%branch% llvm/tools/clang/tools/extra || exit /b
svn.exe export -r %revision% http://llvm.org/svn/llvm-project/lld/%branch% llvm/tools/lld || exit /b
svn.exe export -r %revision% http://llvm.org/svn/llvm-project/compiler-rt/%branch% llvm/projects/compiler-rt || exit /b
+svn.exe export -r %revision% http://llvm.org/svn/llvm-project/openmp/%branch% llvm/projects/openmp || exit /b
-set cmake_flags=-DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_INSTALL_TOOLCHAIN_ONLY=ON -DLLVM_USE_CRT_RELEASE=MT -DCLANG_FORMAT_VS_VERSION=%clang_format_vs_version% -DPACKAGE_VERSION=%package_version%
+REM Setting CMAKE_CL_SHOWINCLUDES_PREFIX to work around PR27226.
+set cmake_flags=-DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_INSTALL_TOOLCHAIN_ONLY=ON -DLLVM_USE_CRT_RELEASE=MT -DCLANG_FORMAT_VS_VERSION=%clang_format_vs_version% -DPACKAGE_VERSION=%package_version% -DCMAKE_CL_SHOWINCLUDES_PREFIX="Note: including file: "
REM TODO: Run all tests, including lld and compiler-rt.
diff --git a/utils/release/export.sh b/utils/release/export.sh
index 2fd4206b74062..d978055f01837 100755
--- a/utils/release/export.sh
+++ b/utils/release/export.sh
@@ -20,7 +20,7 @@ base_url="https://llvm.org/svn/llvm-project"
release=""
rc=""
-function usage() {
+usage() {
echo "Export the SVN sources and build tarballs from them"
echo "usage: `basename $0`"
echo " "
@@ -29,7 +29,7 @@ function usage() {
echo " -final The final tag"
}
-function export_sources() {
+export_sources() {
release_no_dot=`echo $release | sed -e 's,\.,,g'`
tag_dir="tags/RELEASE_$release_no_dot/$rc"
diff --git a/utils/release/merge.sh b/utils/release/merge.sh
index 93e08c7ce1357..b48932248347d 100755
--- a/utils/release/merge.sh
+++ b/utils/release/merge.sh
@@ -17,12 +17,14 @@ set -e
rev=""
proj=""
revert="no"
+srcdir=""
-function usage() {
+usage() {
echo "usage: `basename $0` [OPTIONS]"
echo " -proj PROJECT The project to merge the result into"
echo " -rev NUM The revision to merge into the project"
echo " -revert Revert rather than merge the commit"
+ echo " -srcdir The root of the project checkout"
}
while [ $# -gt 0 ]; do
@@ -35,6 +37,10 @@ while [ $# -gt 0 ]; do
shift
proj=$1
;;
+ --srcdir | -srcdir | -s)
+ shift
+ srcdir=$1
+ ;;
-h | -help | --help )
usage
;;
@@ -51,6 +57,10 @@ while [ $# -gt 0 ]; do
shift
done
+if [ -z "$srcdir" ]; then
+ srcdir="$proj.src"
+fi
+
if [ "x$rev" = "x" -o "x$proj" = "x" ]; then
echo "error: need to specify project and revision"
echo
@@ -72,7 +82,7 @@ else
fi
svn log -c $rev http://llvm.org/svn/llvm-project/$proj/trunk >> $tempfile 2>&1
-cd $proj.src
+cd "$srcdir"
echo "# Updating tree"
svn up
diff --git a/utils/release/tag.sh b/utils/release/tag.sh
index caefc7f7b71bd..c3e839d932385 100755
--- a/utils/release/tag.sh
+++ b/utils/release/tag.sh
@@ -23,7 +23,7 @@ revision="HEAD"
base_url="https://llvm.org/svn/llvm-project"
-function usage() {
+usage() {
echo "usage: `basename $0` -release <num> [-rebranch] [-revision <num>] [-dry-run]"
echo "usage: `basename $0` -release <num> -rc <num> [-dry-run]"
echo " "
@@ -35,7 +35,7 @@ function usage() {
echo " -dry-run Make no changes to the repository, just print the commands"
}
-function tag_version() {
+tag_version() {
set -x
for proj in $projects; do
if svn ls $base_url/$proj/branches/release_$branch_release > /dev/null 2>&1 ; then
@@ -53,7 +53,7 @@ function tag_version() {
set +x
}
-function tag_release_candidate() {
+tag_release_candidate() {
set -x
for proj in $projects ; do
if ! svn ls $base_url/$proj/tags/RELEASE_$tag_release > /dev/null 2>&1 ; then
diff --git a/utils/release/test-release.sh b/utils/release/test-release.sh
index 69de8371d6318..37af976ec0c50 100755
--- a/utils/release/test-release.sh
+++ b/utils/release/test-release.sh
@@ -12,7 +12,8 @@
#
#===------------------------------------------------------------------------===#
-if [ `uname -s` = "FreeBSD" ]; then
+System=`uname -s`
+if [ "$System" = "FreeBSD" ]; then
MAKE=gmake
else
MAKE=make
@@ -35,6 +36,7 @@ do_libs="yes"
do_libunwind="yes"
do_test_suite="yes"
do_openmp="yes"
+do_lldb="no"
BuildDir="`pwd`"
use_autoconf="no"
ExtraConfigureFlags=""
@@ -63,6 +65,8 @@ function usage() {
echo " -no-libunwind Disable check-out & build libunwind"
echo " -no-test-suite Disable check-out & build test-suite"
echo " -no-openmp Disable check-out & build libomp"
+ echo " -lldb Enable check-out & build lldb"
+ echo " -no-lldb Disable check-out & build lldb (default)"
}
while [ $# -gt 0 ]; do
@@ -141,6 +145,12 @@ while [ $# -gt 0 ]; do
-no-openmp )
do_openmp="no"
;;
+ -lldb )
+ do_lldb="yes"
+ ;;
+ -no-lldb )
+ do_lldb="no"
+ ;;
-help | --help | -h | --h | -\? )
usage
exit 0
@@ -213,6 +223,9 @@ esac
if [ $do_openmp = "yes" ]; then
projects="$projects openmp"
fi
+if [ $do_lldb = "yes" ]; then
+ projects="$projects lldb"
+fi
# Go to the build directory (may be different from CWD)
BuildDir=$BuildDir/$RC
@@ -249,7 +262,7 @@ function check_program_exists() {
fi
}
-if [ `uname -s` != "Darwin" ]; then
+if [ "$System" != "Darwin" ]; then
check_program_exists 'chrpath'
check_program_exists 'file'
check_program_exists 'objdump'
@@ -279,6 +292,9 @@ function export_sources() {
cfe)
projsrc=llvm.src/tools/clang
;;
+ lldb)
+ projsrc=llvm.src/tools/$proj
+ ;;
clang-tools-extra)
projsrc=llvm.src/tools/clang/tools/extra
;;
@@ -359,13 +375,13 @@ function configure_llvmCore() {
echo "#" env CC="$c_compiler" CXX="$cxx_compiler" \
cmake -G "Unix Makefiles" \
-DCMAKE_BUILD_TYPE=$BuildType -DLLVM_ENABLE_ASSERTIONS=$Assertions \
- -DLLVM_ENABLE_TIMESTAMPS=OFF -DLLVM_CONFIGTIME="(timestamp not enabled)" \
+ -DLLVM_CONFIGTIME="(timestamp not enabled)" \
$ExtraConfigureFlags $BuildDir/llvm.src \
2>&1 | tee $LogDir/llvm.configure-Phase$Phase-$Flavor.log
env CC="$c_compiler" CXX="$cxx_compiler" \
cmake -G "Unix Makefiles" \
-DCMAKE_BUILD_TYPE=$BuildType -DLLVM_ENABLE_ASSERTIONS=$Assertions \
- -DLLVM_ENABLE_TIMESTAMPS=OFF -DLLVM_CONFIGTIME="(timestamp not enabled)" \
+ -DLLVM_CONFIGTIME="(timestamp not enabled)" \
$ExtraConfigureFlags $BuildDir/llvm.src \
2>&1 | tee $LogDir/llvm.configure-Phase$Phase-$Flavor.log
fi
@@ -418,7 +434,7 @@ function test_llvmCore() {
# Clean RPATH. Libtool adds the build directory to the search path, which is
# not necessary --- and even harmful --- for the binary packages we release.
function clean_RPATH() {
- if [ `uname -s` = "Darwin" ]; then
+ if [ "$System" = "Darwin" ]; then
return
fi
local InstallPath="$1"
diff --git a/utils/unittest/Makefile b/utils/unittest/Makefile
deleted file mode 100644
index 6a09341832bc3..0000000000000
--- a/utils/unittest/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-##===- utils/unittest/Makefile -----------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-PARALLEL_DIRS = googletest UnitTestMain
-
-include $(LEVEL)/Makefile.common
diff --git a/utils/unittest/UnitTestMain/Makefile b/utils/unittest/UnitTestMain/Makefile
deleted file mode 100644
index 7bcb724950492..0000000000000
--- a/utils/unittest/UnitTestMain/Makefile
+++ /dev/null
@@ -1,32 +0,0 @@
-##===- utils/unittest/UnitTestMain/Makefile ----------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../../..
-
-include $(LEVEL)/Makefile.config
-
-LIBRARYNAME = gtest_main
-BUILD_ARCHIVE = 1
-REQUIRES_RTTI = 1
-
-CPP.Flags += -I$(LLVM_SRC_ROOT)/utils/unittest/googletest/include
-CPP.Flags += $(NO_MISSING_FIELD_INITIALIZERS) $(NO_VARIADIC_MACROS)
-CPP.Flags += -DGTEST_HAS_RTTI=0
-# libstdc++'s TR1 <tuple> header depends on RTTI and uses C++'0x features not
-# supported by Clang, so force googletest to use its own tuple implementation.
-CPP.Flags += -DGTEST_USE_OWN_TR1_TUPLE
-
-# Disable pthreads if LLVM was configured without them.
-ifneq ($(HAVE_PTHREAD), 1)
- CPP.Flags += -DGTEST_HAS_PTHREAD=0
-endif
-
-NO_INSTALL = 1
-
-include $(LEVEL)/Makefile.common
diff --git a/utils/unittest/UnitTestMain/TestMain.cpp b/utils/unittest/UnitTestMain/TestMain.cpp
index fb2b0f16ee3f2..36cec2d474249 100644
--- a/utils/unittest/UnitTestMain/TestMain.cpp
+++ b/utils/unittest/UnitTestMain/TestMain.cpp
@@ -22,7 +22,8 @@
const char *TestMainArgv0;
int main(int argc, char **argv) {
- llvm::sys::PrintStackTraceOnErrorSignal(true /* Disable crash reporting */);
+ llvm::sys::PrintStackTraceOnErrorSignal(argv[0],
+ true /* Disable crash reporting */);
testing::InitGoogleTest(&argc, argv);
llvm::cl::ParseCommandLineOptions(argc, argv);
diff --git a/utils/unittest/googletest/Makefile b/utils/unittest/googletest/Makefile
deleted file mode 100644
index 3d85e7da0ba60..0000000000000
--- a/utils/unittest/googletest/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-##===- utils/unittest/googletest/Makefile ------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL := ../../..
-
-include $(LEVEL)/Makefile.config
-
-LIBRARYNAME = gtest
-BUILD_ARCHIVE = 1
-REQUIRES_RTTI = 1
-
-# Note that these flags are duplicated when building individual tests in
-# unittests/Makefile.unittest and ../UnitTestMain/Makefile; ensure that any
-# changes are made to both.
-CPP.Flags += -I$(LLVM_SRC_ROOT)/utils/unittest/googletest/include
-CPP.Flags += -I$(LLVM_SRC_ROOT)/utils/unittest/googletest
-CPP.Flags += $(NO_MISSING_FIELD_INITIALIZERS) $(NO_VARIADIC_MACROS)
-CPP.Flags += -DGTEST_HAS_RTTI=0
-# libstdc++'s TR1 <tuple> header depends on RTTI and uses C++'0x features not
-# supported by Clang, so force googletest to use its own tuple implementation.
-CPP.Flags += -DGTEST_USE_OWN_TR1_TUPLE
-
-# Disable pthreads if LLVM was configured without them.
-ifneq ($(HAVE_PTHREAD), 1)
- CPP.Flags += -DGTEST_HAS_PTHREAD=0
-endif
-
-ifeq ($(HOST_OS),MingW)
- CPP.Flags += -DGTEST_OS_WINDOWS=1
-endif
-
-NO_INSTALL = 1
-
-SOURCES = src/gtest-all.cc
-
-include $(LEVEL)/Makefile.common
diff --git a/utils/unittest/googletest/README.LLVM b/utils/unittest/googletest/README.LLVM
index 5f7fffe26a43f..afaae9963f391 100644
--- a/utils/unittest/googletest/README.LLVM
+++ b/utils/unittest/googletest/README.LLVM
@@ -17,6 +17,7 @@ $ mv COPYING LICENSE.TXT
Modified as follows:
* Added support for FreeBSD.
+* Added support for Minix (PR6797).
* To GTestStreamToHelper in include/gtest/internal/gtest-internal.h,
added the ability to stream with raw_os_ostream.
* To refresh Haiku support in include/gtest/internal/gtest-port.h,
diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-port.h b/utils/unittest/googletest/include/gtest/internal/gtest-port.h
index 6b942e9f9d9e7..cac04a7bb72be 100644
--- a/utils/unittest/googletest/include/gtest/internal/gtest-port.h
+++ b/utils/unittest/googletest/include/gtest/internal/gtest-port.h
@@ -92,6 +92,7 @@
// GTEST_OS_LINUX - Linux
// GTEST_OS_LINUX_ANDROID - Google Android
// GTEST_OS_MAC - Mac OS X
+// GTEST_OS_MINIX - Minix
// GTEST_OS_NACL - Google Native Client (NaCl)
// GTEST_OS_SOLARIS - Sun Solaris
// GTEST_OS_SYMBIAN - Symbian
@@ -248,6 +249,8 @@
# define GTEST_OS_NACL 1
#elif defined(__HAIKU__)
# define GTEST_OS_HAIKU 1
+#elif defined(_MINIX)
+# define GTEST_OS_MINIX 1
#endif // __CYGWIN__
// Brings in definitions for functions used in the testing::internal::posix
@@ -359,7 +362,7 @@
// no support for it at least as recent as Froyo (2.2).
// Minix currently doesn't support it either.
# define GTEST_HAS_STD_WSTRING \
- (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || GTEST_OS_HAIKU || defined(_MINIX)))
+ (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || GTEST_OS_HAIKU || GTEST_OS_MINIX))
#endif // GTEST_HAS_STD_WSTRING
diff --git a/utils/update_llc_test_checks.py b/utils/update_llc_test_checks.py
index cfdf830907f50..d2df5b6511e15 100755
--- a/utils/update_llc_test_checks.py
+++ b/utils/update_llc_test_checks.py
@@ -9,50 +9,132 @@ a single test function.
import argparse
import itertools
+import os # Used to advertise this file's name ("autogenerated_note").
import string
import subprocess
import sys
import tempfile
import re
-
+# Invoke the tool that is being tested.
def llc(args, cmd_args, ir):
with open(ir) as ir_file:
stdout = subprocess.check_output(args.llc_binary + ' ' + cmd_args,
shell=True, stdin=ir_file)
+ # Fix line endings to unix CR style.
+ stdout = stdout.replace('\r\n', '\n')
return stdout
-ASM_SCRUB_WHITESPACE_RE = re.compile(r'(?!^(| \w))[ \t]+', flags=re.M)
-ASM_SCRUB_TRAILING_WHITESPACE_RE = re.compile(r'[ \t]+$', flags=re.M)
-ASM_SCRUB_SHUFFLES_RE = (
+# RegEx: this is where the magic happens.
+
+SCRUB_WHITESPACE_RE = re.compile(r'(?!^(| \w))[ \t]+', flags=re.M)
+SCRUB_TRAILING_WHITESPACE_RE = re.compile(r'[ \t]+$', flags=re.M)
+SCRUB_X86_SHUFFLES_RE = (
re.compile(
- r'^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem) = .*)$',
+ r'^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem)( \{%k\d+\}( \{z\})?)? = .*)$',
flags=re.M))
-ASM_SCRUB_SP_RE = re.compile(r'\d+\(%(esp|rsp)\)')
-ASM_SCRUB_RIP_RE = re.compile(r'[.\w]+\(%rip\)')
-ASM_SCRUB_KILL_COMMENT_RE = re.compile(r'^ *#+ +kill:.*\n')
+SCRUB_X86_SP_RE = re.compile(r'\d+\(%(esp|rsp)\)')
+SCRUB_X86_RIP_RE = re.compile(r'[.\w]+\(%rip\)')
+SCRUB_X86_LCP_RE = re.compile(r'\.LCPI[0-9]+_[0-9]+')
+SCRUB_KILL_COMMENT_RE = re.compile(r'^ *#+ +kill:.*\n')
+
+RUN_LINE_RE = re.compile('^\s*;\s*RUN:\s*(.*)$')
+IR_FUNCTION_RE = re.compile('^\s*define\s+(?:internal\s+)?[^@]*@(\w+)\s*\(')
+ASM_FUNCTION_RE = re.compile(
+ r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n[^:]*?'
+ r'(?P<body>^##?[ \t]+[^:]+:.*?)\s*'
+ r'^\s*(?:[^:\n]+?:\s*\n\s*\.size|\.cfi_endproc|\.globl|\.comm|\.(?:sub)?section)',
+ flags=(re.M | re.S))
+CHECK_PREFIX_RE = re.compile('--check-prefix=(\S+)')
+CHECK_RE = re.compile(r'^\s*;\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL)?:')
def scrub_asm(asm):
# Scrub runs of whitespace out of the assembly, but leave the leading
# whitespace in place.
- asm = ASM_SCRUB_WHITESPACE_RE.sub(r' ', asm)
+ asm = SCRUB_WHITESPACE_RE.sub(r' ', asm)
# Expand the tabs used for indentation.
asm = string.expandtabs(asm, 2)
# Detect shuffle asm comments and hide the operands in favor of the comments.
- asm = ASM_SCRUB_SHUFFLES_RE.sub(r'\1 {{.*#+}} \2', asm)
+ asm = SCRUB_X86_SHUFFLES_RE.sub(r'\1 {{.*#+}} \2', asm)
# Generically match the stack offset of a memory operand.
- asm = ASM_SCRUB_SP_RE.sub(r'{{[0-9]+}}(%\1)', asm)
+ asm = SCRUB_X86_SP_RE.sub(r'{{[0-9]+}}(%\1)', asm)
# Generically match a RIP-relative memory operand.
- asm = ASM_SCRUB_RIP_RE.sub(r'{{.*}}(%rip)', asm)
+ asm = SCRUB_X86_RIP_RE.sub(r'{{.*}}(%rip)', asm)
+ # Generically match a LCP symbol.
+ asm = SCRUB_X86_LCP_RE.sub(r'{{\.LCPI.*}}', asm)
# Strip kill operands inserted into the asm.
- asm = ASM_SCRUB_KILL_COMMENT_RE.sub('', asm)
+ asm = SCRUB_KILL_COMMENT_RE.sub('', asm)
# Strip trailing whitespace.
- asm = ASM_SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
+ asm = SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm)
return asm
+# Build up a dictionary of all the function bodies.
+def build_function_body_dictionary(raw_tool_output, prefixes, func_dict, verbose):
+ for m in ASM_FUNCTION_RE.finditer(raw_tool_output):
+ if not m:
+ continue
+ func = m.group('func')
+ scrubbed_body = scrub_asm(m.group('body'))
+ if func.startswith('stress'):
+ # We only use the last line of the function body for stress tests.
+ scrubbed_body = '\n'.join(scrubbed_body.splitlines()[-1:])
+ if verbose:
+ print >>sys.stderr, 'Processing function: ' + func
+ for l in scrubbed_body.splitlines():
+ print >>sys.stderr, ' ' + l
+ for prefix in prefixes:
+ if func in func_dict[prefix] and func_dict[prefix][func] != scrubbed_body:
+ if prefix == prefixes[-1]:
+ print >>sys.stderr, ('WARNING: Found conflicting asm under the '
+ 'same prefix: %r!' % (prefix,))
+ else:
+ func_dict[prefix][func] = None
+ continue
+
+ func_dict[prefix][func] = scrubbed_body
+
+
+def add_checks(output_lines, prefix_list, func_dict, func_name):
+ printed_prefixes = []
+ for checkprefixes, _ in prefix_list:
+ for checkprefix in checkprefixes:
+ if checkprefix in printed_prefixes:
+ break
+ if not func_dict[checkprefix][func_name]:
+ continue
+ # Add some space between different check prefixes.
+ if len(printed_prefixes) != 0:
+ output_lines.append(';')
+ printed_prefixes.append(checkprefix)
+ output_lines.append('; %s-LABEL: %s:' % (checkprefix, func_name))
+ func_body = func_dict[checkprefix][func_name].splitlines()
+ output_lines.append('; %s: %s' % (checkprefix, func_body[0]))
+ for func_line in func_body[1:]:
+ output_lines.append('; %s-NEXT: %s' % (checkprefix, func_line))
+ # Add space between different check prefixes and the first line of code.
+ # output_lines.append(';')
+ break
+ return output_lines
+
+
+def should_add_line_to_output(input_line, prefix_set):
+ # Skip any blank comment lines in the IR.
+ if input_line.strip() == ';':
+ return False
+ # Skip any blank lines in the IR.
+ #if input_line.strip() == '':
+ # return False
+ # And skip any CHECK lines. We're building our own.
+ m = CHECK_RE.match(input_line)
+ if m and m.group(1) in prefix_set:
+ return False
+
+ return True
+
+
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('-v', '--verbose', action='store_true',
@@ -64,32 +146,23 @@ def main():
parser.add_argument('tests', nargs='+')
args = parser.parse_args()
- run_line_re = re.compile('^\s*;\s*RUN:\s*(.*)$')
- ir_function_re = re.compile('^\s*define\s+(?:internal\s+)?[^@]*@(\w+)\s*\(')
- asm_function_re = re.compile(
- r'^_?(?P<f>[^:]+):[ \t]*#+[ \t]*@(?P=f)\n[^:]*?'
- r'(?P<body>^##?[ \t]+[^:]+:.*?)\s*'
- r'^\s*(?:[^:\n]+?:\s*\n\s*\.size|\.cfi_endproc|\.globl|\.comm|\.(?:sub)?section)',
- flags=(re.M | re.S))
- check_prefix_re = re.compile('--check-prefix=(\S+)')
- check_re = re.compile(r'^\s*;\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL)?:')
autogenerated_note = ('; NOTE: Assertions have been autogenerated by '
- 'utils/update_llc_test_checks.py')
+ 'utils/' + os.path.basename(__file__))
for test in args.tests:
if args.verbose:
print >>sys.stderr, 'Scanning for RUN lines in test file: %s' % (test,)
with open(test) as f:
- test_lines = [l.rstrip() for l in f]
+ input_lines = [l.rstrip() for l in f]
run_lines = [m.group(1)
- for m in [run_line_re.match(l) for l in test_lines] if m]
+ for m in [RUN_LINE_RE.match(l) for l in input_lines] if m]
if args.verbose:
print >>sys.stderr, 'Found %d RUN lines:' % (len(run_lines),)
for l in run_lines:
print >>sys.stderr, ' RUN: ' + l
- checks = []
+ prefix_list = []
for l in run_lines:
(llc_cmd, filecheck_cmd) = tuple([cmd.strip() for cmd in l.split('|', 1)])
if not llc_cmd.startswith('llc '):
@@ -104,102 +177,65 @@ def main():
llc_cmd_args = llc_cmd_args.replace('< %s', '').replace('%s', '').strip()
check_prefixes = [m.group(1)
- for m in check_prefix_re.finditer(filecheck_cmd)]
+ for m in CHECK_PREFIX_RE.finditer(filecheck_cmd)]
if not check_prefixes:
check_prefixes = ['CHECK']
# FIXME: We should use multiple check prefixes to common check lines. For
# now, we just ignore all but the last.
- checks.append((check_prefixes, llc_cmd_args))
+ prefix_list.append((check_prefixes, llc_cmd_args))
- asm = {}
- for prefixes, _ in checks:
+ func_dict = {}
+ for prefixes, _ in prefix_list:
for prefix in prefixes:
- asm.update({prefix: dict()})
- for prefixes, llc_args in checks:
+ func_dict.update({prefix: dict()})
+ for prefixes, llc_args in prefix_list:
if args.verbose:
print >>sys.stderr, 'Extracted LLC cmd: llc ' + llc_args
print >>sys.stderr, 'Extracted FileCheck prefixes: ' + str(prefixes)
- raw_asm = llc(args, llc_args, test)
- # Build up a dictionary of all the function bodies.
- for m in asm_function_re.finditer(raw_asm):
- if not m:
- continue
- f = m.group('f')
- f_asm = scrub_asm(m.group('body'))
- if f.startswith('stress'):
- # We only use the last line of the asm for stress tests.
- f_asm = '\n'.join(f_asm.splitlines()[-1:])
- if args.verbose:
- print >>sys.stderr, 'Processing asm for function: ' + f
- for l in f_asm.splitlines():
- print >>sys.stderr, ' ' + l
- for prefix in prefixes:
- if f in asm[prefix] and asm[prefix][f] != f_asm:
- if prefix == prefixes[-1]:
- print >>sys.stderr, ('WARNING: Found conflicting asm under the '
- 'same prefix: %r!' % (prefix,))
- else:
- asm[prefix][f] = None
- continue
-
- asm[prefix][f] = f_asm
+
+ raw_tool_output = llc(args, llc_args, test)
+ build_function_body_dictionary(raw_tool_output, prefixes, func_dict, args.verbose)
is_in_function = False
is_in_function_start = False
- prefix_set = set([prefix for prefixes, _ in checks for prefix in prefixes])
+ prefix_set = set([prefix for prefixes, _ in prefix_list for prefix in prefixes])
if args.verbose:
print >>sys.stderr, 'Rewriting FileCheck prefixes: %s' % (prefix_set,)
- fixed_lines = []
- fixed_lines.append(autogenerated_note)
+ output_lines = []
+ output_lines.append(autogenerated_note)
- for l in test_lines:
+ for input_line in input_lines:
if is_in_function_start:
- if l.lstrip().startswith(';'):
- m = check_re.match(l)
+ if input_line == '':
+ continue
+ if input_line.lstrip().startswith(';'):
+ m = CHECK_RE.match(input_line)
if not m or m.group(1) not in prefix_set:
- fixed_lines.append(l)
+ output_lines.append(input_line)
continue
- # Print out the various check lines here
- printed_prefixes = []
- for prefixes, _ in checks:
- for prefix in prefixes:
- if prefix in printed_prefixes:
- break
- if not asm[prefix][name]:
- continue
- if len(printed_prefixes) != 0:
- fixed_lines.append(';')
- printed_prefixes.append(prefix)
- fixed_lines.append('; %s-LABEL: %s:' % (prefix, name))
- asm_lines = asm[prefix][name].splitlines()
- fixed_lines.append('; %s: %s' % (prefix, asm_lines[0]))
- for asm_line in asm_lines[1:]:
- fixed_lines.append('; %s-NEXT: %s' % (prefix, asm_line))
- break
+ # Print out the various check lines here.
+ output_lines = add_checks(output_lines, prefix_list, func_dict, name)
is_in_function_start = False
if is_in_function:
- # Skip any blank comment lines in the IR.
- if l.strip() == ';':
+ if should_add_line_to_output(input_line, prefix_set) == True:
+ # This input line of the function body will go as-is into the output.
+ output_lines.append(input_line)
+ else:
continue
- # And skip any CHECK lines. We'll build our own.
- m = check_re.match(l)
- if m and m.group(1) in prefix_set:
- continue
- # Collect the remaining lines in the function body and look for the end
- # of the function.
- fixed_lines.append(l)
- if l.strip() == '}':
+ if input_line.strip() == '}':
is_in_function = False
continue
- if l == autogenerated_note:
+ if input_line == autogenerated_note:
continue
- fixed_lines.append(l)
- m = ir_function_re.match(l)
+ # If it's outside a function, it just gets copied to the output.
+ output_lines.append(input_line)
+
+ m = IR_FUNCTION_RE.match(input_line)
if not m:
continue
name = m.group(1)
@@ -209,10 +245,10 @@ def main():
is_in_function = is_in_function_start = True
if args.verbose:
- print>>sys.stderr, 'Writing %d fixed lines to %s...' % (
- len(fixed_lines), test)
- with open(test, 'w') as f:
- f.writelines([l + '\n' for l in fixed_lines])
+ print>>sys.stderr, 'Writing %d lines to %s...' % (len(output_lines), test)
+
+ with open(test, 'wb') as f:
+ f.writelines([l + '\n' for l in output_lines])
if __name__ == '__main__':
diff --git a/utils/update_test_checks.py b/utils/update_test_checks.py
new file mode 100755
index 0000000000000..c084debbe9863
--- /dev/null
+++ b/utils/update_test_checks.py
@@ -0,0 +1,397 @@
+#!/usr/bin/env python2.7
+
+"""A script to generate FileCheck statements for regression tests.
+
+This script is a utility to update LLVM opt or llc test cases with new
+FileCheck patterns. It can either update all of the tests in the file or
+a single test function.
+
+Example usage:
+$ update_test_checks.py --tool=../bin/opt test/foo.ll
+
+Workflow:
+1. Make a compiler patch that requires updating some number of FileCheck lines
+ in regression test files.
+2. Save the patch and revert it from your local work area.
+3. Update the RUN-lines in the affected regression tests to look canonical.
+ Example: "; RUN: opt < %s -instcombine -S | FileCheck %s"
+4. Refresh the FileCheck lines for either the entire file or select functions by
+ running this script.
+5. Commit the fresh baseline of checks.
+6. Apply your patch from step 1 and rebuild your local binaries.
+7. Re-run this script on affected regression tests.
+8. Check the diffs to ensure the script has done something reasonable.
+9. Submit a patch including the regression test diffs for review.
+
+A common pattern is to have the script insert complete checking of every
+instruction. Then, edit it down to only check the relevant instructions.
+The script is designed to make adding checks to a test case fast, it is *not*
+designed to be authoratitive about what constitutes a good test!
+"""
+
+import argparse
+import itertools
+import os # Used to advertise this file's name ("autogenerated_note").
+import string
+import subprocess
+import sys
+import tempfile
+import re
+
+ADVERT = '; NOTE: Assertions have been autogenerated by '
+
+# RegEx: this is where the magic happens.
+
+SCRUB_LEADING_WHITESPACE_RE = re.compile(r'^(\s+)')
+SCRUB_WHITESPACE_RE = re.compile(r'(?!^(| \w))[ \t]+', flags=re.M)
+SCRUB_TRAILING_WHITESPACE_RE = re.compile(r'[ \t]+$', flags=re.M)
+SCRUB_X86_SHUFFLES_RE = (
+ re.compile(
+ r'^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem)( \{%k\d+\}( \{z\})?)? = .*)$',
+ flags=re.M))
+SCRUB_X86_SP_RE = re.compile(r'\d+\(%(esp|rsp)\)')
+SCRUB_X86_RIP_RE = re.compile(r'[.\w]+\(%rip\)')
+SCRUB_X86_LCP_RE = re.compile(r'\.LCPI[0-9]+_[0-9]+')
+SCRUB_KILL_COMMENT_RE = re.compile(r'^ *#+ +kill:.*\n')
+SCRUB_IR_COMMENT_RE = re.compile(r'\s*;.*')
+
+RUN_LINE_RE = re.compile('^\s*;\s*RUN:\s*(.*)$')
+IR_FUNCTION_RE = re.compile('^\s*define\s+(?:internal\s+)?[^@]*@([\w-]+)\s*\(')
+LLC_FUNCTION_RE = re.compile(
+ r'^_?(?P<func>[^:]+):[ \t]*#+[ \t]*@(?P=func)\n[^:]*?'
+ r'(?P<body>^##?[ \t]+[^:]+:.*?)\s*'
+ r'^\s*(?:[^:\n]+?:\s*\n\s*\.size|\.cfi_endproc|\.globl|\.comm|\.(?:sub)?section)',
+ flags=(re.M | re.S))
+OPT_FUNCTION_RE = re.compile(
+ r'^\s*define\s+(?:internal\s+)?[^@]*@(?P<func>[\w-]+?)\s*\('
+ r'(\s+)?[^{]*\{\n(?P<body>.*?)\}',
+ flags=(re.M | re.S))
+CHECK_PREFIX_RE = re.compile('--check-prefix=(\S+)')
+CHECK_RE = re.compile(r'^\s*;\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL)?:')
+IR_VALUE_DEF_RE = re.compile(r'\s+%(.*) =')
+
+
+# Invoke the tool that is being tested.
+def invoke_tool(args, cmd_args, ir):
+ with open(ir) as ir_file:
+ stdout = subprocess.check_output(args.tool_binary + ' ' + cmd_args,
+ shell=True, stdin=ir_file)
+ # Fix line endings to unix CR style.
+ stdout = stdout.replace('\r\n', '\n')
+ return stdout
+
+
+# FIXME: Separate the x86-specific scrubbers, so this can be used for other targets.
+def scrub_asm(asm):
+ # Detect shuffle asm comments and hide the operands in favor of the comments.
+ asm = SCRUB_X86_SHUFFLES_RE.sub(r'\1 {{.*#+}} \2', asm)
+ # Generically match the stack offset of a memory operand.
+ asm = SCRUB_X86_SP_RE.sub(r'{{[0-9]+}}(%\1)', asm)
+ # Generically match a RIP-relative memory operand.
+ asm = SCRUB_X86_RIP_RE.sub(r'{{.*}}(%rip)', asm)
+ # Generically match a LCP symbol.
+ asm = SCRUB_X86_LCP_RE.sub(r'{{\.LCPI.*}}', asm)
+ # Strip kill operands inserted into the asm.
+ asm = SCRUB_KILL_COMMENT_RE.sub('', asm)
+ return asm
+
+
+def scrub_body(body, tool_basename):
+ # Scrub runs of whitespace out of the assembly, but leave the leading
+ # whitespace in place.
+ body = SCRUB_WHITESPACE_RE.sub(r' ', body)
+ # Expand the tabs used for indentation.
+ body = string.expandtabs(body, 2)
+ # Strip trailing whitespace.
+ body = SCRUB_TRAILING_WHITESPACE_RE.sub(r'', body)
+ if tool_basename == "llc":
+ body = scrub_asm(body)
+ return body
+
+
+# Build up a dictionary of all the function bodies.
+def build_function_body_dictionary(raw_tool_output, prefixes, func_dict, verbose, tool_basename):
+ if tool_basename == "llc":
+ func_regex = LLC_FUNCTION_RE
+ else:
+ func_regex = OPT_FUNCTION_RE
+ for m in func_regex.finditer(raw_tool_output):
+ if not m:
+ continue
+ func = m.group('func')
+ scrubbed_body = scrub_body(m.group('body'), tool_basename)
+ if func.startswith('stress'):
+ # We only use the last line of the function body for stress tests.
+ scrubbed_body = '\n'.join(scrubbed_body.splitlines()[-1:])
+ if verbose:
+ print >>sys.stderr, 'Processing function: ' + func
+ for l in scrubbed_body.splitlines():
+ print >>sys.stderr, ' ' + l
+ for prefix in prefixes:
+ if func in func_dict[prefix] and func_dict[prefix][func] != scrubbed_body:
+ if prefix == prefixes[-1]:
+ print >>sys.stderr, ('WARNING: Found conflicting asm under the '
+ 'same prefix: %r!' % (prefix,))
+ else:
+ func_dict[prefix][func] = None
+ continue
+
+ func_dict[prefix][func] = scrubbed_body
+
+
+# Create a FileCheck variable name based on an IR name.
+def get_value_name(var):
+ if var.isdigit():
+ var = 'TMP' + var
+ var = var.replace('.', '_')
+ return var.upper()
+
+
+# Create a FileCheck variable from regex.
+def get_value_definition(var):
+ return '[[' + get_value_name(var) + ':%.*]]'
+
+
+# Use a FileCheck variable.
+def get_value_use(var):
+ return '[[' + get_value_name(var) + ']]'
+
+
+# Replace IR value defs and uses with FileCheck variables.
+def genericize_check_lines(lines):
+ lines_with_def = []
+ vars_seen = []
+ for line in lines:
+ # An IR variable named '%.' matches the FileCheck regex string.
+ line = line.replace('%.', '%dot')
+ m = IR_VALUE_DEF_RE.match(line)
+ if m:
+ vars_seen.append(m.group(1))
+ line = line.replace('%' + m.group(1), get_value_definition(m.group(1)))
+
+ lines_with_def.append(line)
+
+ # A single def isn't worth replacing?
+ #if len(vars_seen) < 2:
+ # return lines
+
+ output_lines = []
+ vars_seen.sort(key=len, reverse=True)
+ for line in lines_with_def:
+ for var in vars_seen:
+ line = line.replace('%' + var, get_value_use(var))
+ output_lines.append(line)
+
+ return output_lines
+
+
+def add_checks(output_lines, prefix_list, func_dict, func_name, tool_basename):
+ # Select a label format based on the whether we're checking asm or IR.
+ if tool_basename == "llc":
+ check_label_format = "; %s-LABEL: %s:"
+ else:
+ check_label_format = "; %s-LABEL: @%s("
+
+ printed_prefixes = []
+ for checkprefixes, _ in prefix_list:
+ for checkprefix in checkprefixes:
+ if checkprefix in printed_prefixes:
+ break
+ if not func_dict[checkprefix][func_name]:
+ continue
+ # Add some space between different check prefixes, but not after the last
+ # check line (before the test code).
+ #if len(printed_prefixes) != 0:
+ # output_lines.append(';')
+ printed_prefixes.append(checkprefix)
+ output_lines.append(check_label_format % (checkprefix, func_name))
+ func_body = func_dict[checkprefix][func_name].splitlines()
+
+ # For IR output, change all defs to FileCheck variables, so we're immune
+ # to variable naming fashions.
+ if tool_basename == "opt":
+ func_body = genericize_check_lines(func_body)
+
+ # This could be selectively enabled with an optional invocation argument.
+ # Disabled for now: better to check everything. Be safe rather than sorry.
+
+ # Handle the first line of the function body as a special case because
+ # it's often just noise (a useless asm comment or entry label).
+ #if func_body[0].startswith("#") or func_body[0].startswith("entry:"):
+ # is_blank_line = True
+ #else:
+ # output_lines.append('; %s: %s' % (checkprefix, func_body[0]))
+ # is_blank_line = False
+
+ # For llc tests, there may be asm directives between the label and the
+ # first checked line (most likely that first checked line is "# BB#0").
+ if tool_basename == "opt":
+ is_blank_line = False
+ else:
+ is_blank_line = True;
+
+ for func_line in func_body:
+ if func_line.strip() == '':
+ is_blank_line = True
+ continue
+ # Do not waste time checking IR comments.
+ if tool_basename == "opt":
+ func_line = SCRUB_IR_COMMENT_RE.sub(r'', func_line)
+
+ # Skip blank lines instead of checking them.
+ if is_blank_line == True:
+ output_lines.append('; %s: %s' % (checkprefix, func_line))
+ else:
+ output_lines.append('; %s-NEXT: %s' % (checkprefix, func_line))
+ is_blank_line = False
+
+ # Add space between different check prefixes and also before the first
+ # line of code in the test function.
+ output_lines.append(';')
+ break
+ return output_lines
+
+
+def should_add_line_to_output(input_line, prefix_set):
+ # Skip any blank comment lines in the IR.
+ if input_line.strip() == ';':
+ return False
+ # Skip any blank lines in the IR.
+ #if input_line.strip() == '':
+ # return False
+ # And skip any CHECK lines. We're building our own.
+ m = CHECK_RE.match(input_line)
+ if m and m.group(1) in prefix_set:
+ return False
+
+ return True
+
+
+def main():
+ from argparse import RawTextHelpFormatter
+ parser = argparse.ArgumentParser(description=__doc__, formatter_class=RawTextHelpFormatter)
+ parser.add_argument('-v', '--verbose', action='store_true',
+ help='Show verbose output')
+ parser.add_argument('--tool-binary', default='llc',
+ help='The tool used to generate the test case')
+ parser.add_argument(
+ '--function', help='The function in the test file to update')
+ parser.add_argument('tests', nargs='+')
+ args = parser.parse_args()
+
+ autogenerated_note = (ADVERT + 'utils/' + os.path.basename(__file__))
+
+ tool_basename = os.path.basename(args.tool_binary)
+ if (tool_basename != "llc" and tool_basename != "opt"):
+ print >>sys.stderr, 'ERROR: Unexpected tool name: ' + tool_basename
+ sys.exit(1)
+
+ for test in args.tests:
+ if args.verbose:
+ print >>sys.stderr, 'Scanning for RUN lines in test file: %s' % (test,)
+ with open(test) as f:
+ input_lines = [l.rstrip() for l in f]
+
+ run_lines = [m.group(1)
+ for m in [RUN_LINE_RE.match(l) for l in input_lines] if m]
+ if args.verbose:
+ print >>sys.stderr, 'Found %d RUN lines:' % (len(run_lines),)
+ for l in run_lines:
+ print >>sys.stderr, ' RUN: ' + l
+
+ prefix_list = []
+ for l in run_lines:
+ (tool_cmd, filecheck_cmd) = tuple([cmd.strip() for cmd in l.split('|', 1)])
+
+ if not tool_cmd.startswith(tool_basename + ' '):
+ print >>sys.stderr, 'WARNING: Skipping non-%s RUN line: %s' % (tool_basename, l)
+ continue
+
+ if not filecheck_cmd.startswith('FileCheck '):
+ print >>sys.stderr, 'WARNING: Skipping non-FileChecked RUN line: ' + l
+ continue
+
+ tool_cmd_args = tool_cmd[len(tool_basename):].strip()
+ tool_cmd_args = tool_cmd_args.replace('< %s', '').replace('%s', '').strip()
+
+ check_prefixes = [m.group(1)
+ for m in CHECK_PREFIX_RE.finditer(filecheck_cmd)]
+ if not check_prefixes:
+ check_prefixes = ['CHECK']
+
+ # FIXME: We should use multiple check prefixes to common check lines. For
+ # now, we just ignore all but the last.
+ prefix_list.append((check_prefixes, tool_cmd_args))
+
+ func_dict = {}
+ for prefixes, _ in prefix_list:
+ for prefix in prefixes:
+ func_dict.update({prefix: dict()})
+ for prefixes, tool_args in prefix_list:
+ if args.verbose:
+ print >>sys.stderr, 'Extracted tool cmd: ' + tool_basename + ' ' + tool_args
+ print >>sys.stderr, 'Extracted FileCheck prefixes: ' + str(prefixes)
+
+ raw_tool_output = invoke_tool(args, tool_args, test)
+ build_function_body_dictionary(raw_tool_output, prefixes, func_dict, args.verbose, tool_basename)
+
+ is_in_function = False
+ is_in_function_start = False
+ prefix_set = set([prefix for prefixes, _ in prefix_list for prefix in prefixes])
+ if args.verbose:
+ print >>sys.stderr, 'Rewriting FileCheck prefixes: %s' % (prefix_set,)
+ output_lines = []
+ output_lines.append(autogenerated_note)
+
+ for input_line in input_lines:
+ if is_in_function_start:
+ if input_line == '':
+ continue
+ if input_line.lstrip().startswith(';'):
+ m = CHECK_RE.match(input_line)
+ if not m or m.group(1) not in prefix_set:
+ output_lines.append(input_line)
+ continue
+
+ # Print out the various check lines here.
+ output_lines = add_checks(output_lines, prefix_list, func_dict, name, tool_basename)
+ is_in_function_start = False
+
+ if is_in_function:
+ if should_add_line_to_output(input_line, prefix_set) == True:
+ # This input line of the function body will go as-is into the output.
+ # Except make leading whitespace uniform: 2 spaces.
+ input_line = SCRUB_LEADING_WHITESPACE_RE.sub(r' ', input_line)
+ output_lines.append(input_line)
+ else:
+ continue
+ if input_line.strip() == '}':
+ is_in_function = False
+ continue
+
+ # Discard any previous script advertising.
+ if input_line.startswith(ADVERT):
+ continue
+
+ # If it's outside a function, it just gets copied to the output.
+ output_lines.append(input_line)
+
+ m = IR_FUNCTION_RE.match(input_line)
+ if not m:
+ continue
+ name = m.group(1)
+ if args.function is not None and name != args.function:
+ # When filtering on a specific function, skip all others.
+ continue
+ is_in_function = is_in_function_start = True
+
+ if args.verbose:
+ print>>sys.stderr, 'Writing %d lines to %s...' % (len(output_lines), test)
+
+ with open(test, 'wb') as f:
+ f.writelines([l + '\n' for l in output_lines])
+
+
+if __name__ == '__main__':
+ main()
+
diff --git a/utils/vim/syntax/llvm.vim b/utils/vim/syntax/llvm.vim
index 68a53ec2383d9..8f6829dc9e9fc 100644
--- a/utils/vim/syntax/llvm.vim
+++ b/utils/vim/syntax/llvm.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: llvm
" Maintainer: The LLVM team, http://llvm.org/
-" Version: $Revision: 256512 $
+" Version: $Revision: 275248 $
if version < 600
syntax clear
@@ -36,28 +36,122 @@ syn keyword llvmStatement umax umin une uno unreachable unwind urem va_arg
syn keyword llvmStatement xchg xor zext
" Keywords.
-syn keyword llvmKeyword acq_rel acquire sanitize_address addrspace alias align
-syn keyword llvmKeyword alignstack alwaysinline appending arm_aapcs_vfpcc
-syn keyword llvmKeyword arm_aapcscc arm_apcscc asm atomic available_externally
-syn keyword llvmKeyword blockaddress byval c catch cc ccc cleanup coldcc common
-syn keyword llvmKeyword constant datalayout declare default define deplibs
-syn keyword llvmKeyword distinct dllexport dllimport except extern_weak external
-syn keyword llvmKeyword externally_initialized fastcc filter gc global hhvmcc
-syn keyword llvmKeyword hhvm_ccc hidden initialexec inlinehint inreg
-syn keyword llvmKeyword intel_ocl_bicc inteldialect internal linkonce
-syn keyword llvmKeyword linkonce_odr localdynamic localexec minsize module
-syn keyword llvmKeyword monotonic msp430_intrcc musttail naked nest
-syn keyword llvmKeyword noalias nocapture noimplicitfloat noinline nonlazybind
-syn keyword llvmKeyword noredzone noreturn nounwind optnone optsize personality
-syn keyword llvmKeyword private protected ptx_device ptx_kernel readnone
-syn keyword llvmKeyword readonly release returns_twice sanitize_thread
-syn keyword llvmKeyword sanitize_memory section seq_cst sideeffect signext
-syn keyword llvmKeyword singlethread spir_func spir_kernel sret ssp sspreq
-syn keyword llvmKeyword sspstrong tail target thread_local to triple
-syn keyword llvmKeyword unnamed_addr unordered uwtable volatile weak weak_odr
-syn keyword llvmKeyword x86_fastcallcc x86_stdcallcc x86_thiscallcc
-syn keyword llvmKeyword x86_64_sysvcc x86_64_win64cc zeroext uselistorder
-syn keyword llvmKeyword uselistorder_bb musttail
+syn keyword llvmKeyword
+ \ acq_rel
+ \ acquire
+ \ addrspace
+ \ alias
+ \ align
+ \ alignstack
+ \ alwaysinline
+ \ appending
+ \ arm_aapcscc
+ \ arm_aapcs_vfpcc
+ \ arm_apcscc
+ \ asm
+ \ atomic
+ \ available_externally
+ \ blockaddress
+ \ byval
+ \ c
+ \ catch
+ \ cc
+ \ ccc
+ \ cleanup
+ \ coldcc
+ \ common
+ \ constant
+ \ datalayout
+ \ declare
+ \ default
+ \ define
+ \ deplibs
+ \ distinct
+ \ dllexport
+ \ dllimport
+ \ except
+ \ external
+ \ externally_initialized
+ \ extern_weak
+ \ fastcc
+ \ filter
+ \ gc
+ \ global
+ \ hhvmcc
+ \ hhvm_ccc
+ \ hidden
+ \ initialexec
+ \ inlinehint
+ \ inreg
+ \ inteldialect
+ \ intel_ocl_bicc
+ \ internal
+ \ linkonce
+ \ linkonce_odr
+ \ localdynamic
+ \ localexec
+ \ local_unnamed_addr
+ \ minsize
+ \ module
+ \ monotonic
+ \ msp430_intrcc
+ \ musttail
+ \ naked
+ \ nest
+ \ noalias
+ \ nocapture
+ \ noimplicitfloat
+ \ noinline
+ \ nonlazybind
+ \ noredzone
+ \ noreturn
+ \ nounwind
+ \ optnone
+ \ optsize
+ \ personality
+ \ private
+ \ protected
+ \ ptx_device
+ \ ptx_kernel
+ \ readnone
+ \ readonly
+ \ release
+ \ returns_twice
+ \ sanitize_address
+ \ sanitize_memory
+ \ sanitize_thread
+ \ section
+ \ seq_cst
+ \ sideeffect
+ \ signext
+ \ singlethread
+ \ source_filename
+ \ spir_func
+ \ spir_kernel
+ \ sret
+ \ ssp
+ \ sspreq
+ \ sspstrong
+ \ swiftcc
+ \ tail
+ \ target
+ \ thread_local
+ \ to
+ \ triple
+ \ unnamed_addr
+ \ unordered
+ \ uselistorder
+ \ uselistorder_bb
+ \ uwtable
+ \ volatile
+ \ weak
+ \ weak_odr
+ \ x86_64_sysvcc
+ \ x86_64_win64cc
+ \ x86_fastcallcc
+ \ x86_stdcallcc
+ \ x86_thiscallcc
+ \ zeroext
" Obsolete keywords.
syn keyword llvmError getresult begin end
diff --git a/utils/yaml-bench/Makefile b/utils/yaml-bench/Makefile
deleted file mode 100644
index 07e91226c7a99..0000000000000
--- a/utils/yaml-bench/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-##===- utils/yaml-bench/Makefile ---------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-TOOLNAME = yaml-bench
-USEDLIBS = LLVMSupport.a
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-# Don't install this utility
-NO_INSTALL = 1
-
-include $(LEVEL)/Makefile.common