aboutsummaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/FileCheck/FileCheck.cpp130
-rw-r--r--utils/FileUpdate/FileUpdate.cpp4
-rw-r--r--utils/TableGen/AsmMatcherEmitter.cpp187
-rw-r--r--utils/TableGen/AsmWriterInst.cpp55
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.cpp4
-rw-r--r--utils/TableGen/CodeGenIntrinsics.h4
-rw-r--r--utils/TableGen/CodeGenRegisters.cpp141
-rw-r--r--utils/TableGen/CodeGenRegisters.h20
-rw-r--r--utils/TableGen/CodeGenSchedule.cpp15
-rw-r--r--utils/TableGen/CodeGenSchedule.h5
-rw-r--r--utils/TableGen/CodeGenTarget.cpp8
-rw-r--r--utils/TableGen/FixedLenDecoderEmitter.cpp21
-rw-r--r--utils/TableGen/InstrInfoEmitter.cpp137
-rw-r--r--utils/TableGen/IntrinsicEmitter.cpp24
-rw-r--r--utils/TableGen/OptParserEmitter.cpp17
-rw-r--r--utils/TableGen/RegisterInfoEmitter.cpp20
-rw-r--r--utils/TableGen/SubtargetEmitter.cpp13
-rw-r--r--utils/TableGen/X86DisassemblerTables.cpp101
-rw-r--r--utils/TableGen/X86RecognizableInstr.cpp165
-rw-r--r--utils/TableGen/X86RecognizableInstr.h10
-rwxr-xr-xutils/buildit/build_llvm3
-rw-r--r--utils/fpcmp/fpcmp.cpp5
-rw-r--r--utils/lit/lit/LitConfig.py38
-rw-r--r--utils/lit/lit/ProgressBar.py6
-rw-r--r--utils/lit/lit/ShCommands.py42
-rw-r--r--utils/lit/lit/ShUtil.py50
-rw-r--r--utils/lit/lit/TestFormats.py43
-rw-r--r--utils/lit/lit/TestRunner.py55
-rw-r--r--utils/lit/lit/TestingConfig.py22
-rw-r--r--utils/lit/lit/Util.py29
-rw-r--r--utils/lit/lit/__init__.py3
-rw-r--r--utils/lit/lit/discovery.py4
-rwxr-xr-xutils/lit/lit/main.py161
-rw-r--r--utils/lit/tests/discovery.py56
-rw-r--r--utils/not/not.cpp24
-rwxr-xr-xutils/release/test-release.sh2
-rw-r--r--utils/vim/llvm.vim13
37 files changed, 1214 insertions, 423 deletions
diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp
index 07294a3..8d5af58 100644
--- a/utils/FileCheck/FileCheck.cpp
+++ b/utils/FileCheck/FileCheck.cpp
@@ -115,6 +115,9 @@ public:
void PrintFailureInfo(const SourceMgr &SM, StringRef Buffer,
const StringMap<StringRef> &VariableTable) const;
+ bool hasVariable() const { return !(VariableUses.empty() &&
+ VariableDefs.empty()); }
+
void setMatchNot(bool Not) { MatchNot = Not; }
bool getMatchNot() const { return MatchNot; }
@@ -594,17 +597,21 @@ struct CheckString {
/// to a CHECK: directive.
bool IsCheckNext;
+ /// IsCheckLabel - This is true if this is a CHECK-LABEL: directive (as
+ /// opposed to a CHECK: directive.
+ bool IsCheckLabel;
+
/// 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, SMLoc L, bool isCheckNext)
- : Pat(P), Loc(L), IsCheckNext(isCheckNext) {}
+ CheckString(const Pattern &P, SMLoc L, bool isCheckNext, bool isCheckLabel)
+ : Pat(P), Loc(L), IsCheckNext(isCheckNext), IsCheckLabel(isCheckLabel) {}
/// Check - Match check string and its "not strings" and/or "dag strings".
- size_t Check(const SourceMgr &SM, StringRef Buffer, size_t &MatchLen,
- StringMap<StringRef> &VariableTable) const;
+ size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabel,
+ size_t &MatchLen, StringMap<StringRef> &VariableTable) const;
/// CheckNext - Verify there is a single line in the given buffer.
bool CheckNext(const SourceMgr &SM, StringRef Buffer) const;
@@ -667,7 +674,7 @@ static bool ReadCheckFile(SourceMgr &SM,
std::vector<CheckString> &CheckStrings) {
OwningPtr<MemoryBuffer> File;
if (error_code ec =
- MemoryBuffer::getFileOrSTDIN(CheckFilename.c_str(), File)) {
+ MemoryBuffer::getFileOrSTDIN(CheckFilename, File)) {
errs() << "Could not open check file '" << CheckFilename << "': "
<< ec.message() << '\n';
return true;
@@ -703,7 +710,8 @@ static bool ReadCheckFile(SourceMgr &SM,
// When we find a check prefix, keep track of whether we find CHECK: or
// CHECK-NEXT:
- bool IsCheckNext = false, IsCheckNot = false, IsCheckDag = false;
+ bool IsCheckNext = false, IsCheckNot = false, IsCheckDag = false,
+ IsCheckLabel = false;
// Verify that the : is present after the prefix.
if (Buffer[CheckPrefix.size()] == ':') {
@@ -720,6 +728,10 @@ static bool ReadCheckFile(SourceMgr &SM,
memcmp(Buffer.data()+CheckPrefix.size(), "-DAG:", 5) == 0) {
Buffer = Buffer.substr(CheckPrefix.size()+5);
IsCheckDag = true;
+ } else if (Buffer.size() > CheckPrefix.size()+7 &&
+ memcmp(Buffer.data()+CheckPrefix.size(), "-LABEL:", 7) == 0) {
+ Buffer = Buffer.substr(CheckPrefix.size()+7);
+ IsCheckLabel = true;
} else {
Buffer = Buffer.substr(1);
continue;
@@ -740,6 +752,15 @@ static bool ReadCheckFile(SourceMgr &SM,
if (P.ParsePattern(Buffer.substr(0, EOL), SM, LineNumber))
return true;
+ // Verify that CHECK-LABEL lines do not define or use variables
+ if (IsCheckLabel && P.hasVariable()) {
+ SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart),
+ SourceMgr::DK_Error,
+ "found '"+CheckPrefix+"-LABEL:' with variable definition"
+ " or use'");
+ return true;
+ }
+
P.setMatchNot(IsCheckNot);
P.setMatchDag(IsCheckDag);
@@ -763,7 +784,8 @@ static bool ReadCheckFile(SourceMgr &SM,
// Okay, add the string we captured to the output vector and move on.
CheckStrings.push_back(CheckString(P,
PatternLoc,
- IsCheckNext));
+ IsCheckNext,
+ IsCheckLabel));
std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
}
@@ -771,6 +793,7 @@ static bool ReadCheckFile(SourceMgr &SM,
if (!DagNotMatches.empty()) {
CheckStrings.push_back(CheckString(Pattern(true),
SMLoc::getFromPointer(Buffer.data()),
+ false,
false));
std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
}
@@ -829,15 +852,17 @@ static unsigned CountNumNewlinesBetween(StringRef Range) {
}
size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer,
- size_t &MatchLen,
+ bool IsLabel, size_t &MatchLen,
StringMap<StringRef> &VariableTable) const {
size_t LastPos = 0;
std::vector<const Pattern *> NotStrings;
- // Match "dag strings" (with mixed "not strings" if any).
- LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable);
- if (LastPos == StringRef::npos)
- return StringRef::npos;
+ if (!IsLabel) {
+ // Match "dag strings" (with mixed "not strings" if any).
+ LastPos = CheckDag(SM, Buffer, NotStrings, VariableTable);
+ if (LastPos == StringRef::npos)
+ return StringRef::npos;
+ }
// Match itself from the last position after matching CHECK-DAG.
StringRef MatchBuffer = Buffer.substr(LastPos);
@@ -848,17 +873,19 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer,
}
MatchPos += LastPos;
- StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);
+ if (!IsLabel) {
+ StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);
- // If this check is a "CHECK-NEXT", verify that the previous match was on
- // the previous line (i.e. that there is one newline between them).
- if (CheckNext(SM, SkippedRegion))
- return StringRef::npos;
+ // If this check is a "CHECK-NEXT", verify that the previous match was on
+ // the previous line (i.e. that there is one newline between them).
+ if (CheckNext(SM, SkippedRegion))
+ return StringRef::npos;
- // If this match had "not strings", verify that they don't exist in the
- // skipped region.
- if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable))
- return StringRef::npos;
+ // If this match had "not strings", verify that they don't exist in the
+ // skipped region.
+ if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable))
+ return StringRef::npos;
+ }
return MatchPos;
}
@@ -986,8 +1013,7 @@ size_t CheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
// CHECK-DAG, verify that there's no 'not' strings occurred in that
// region.
StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);
- size_t Pos = CheckNot(SM, SkippedRegion, NotStrings, VariableTable);
- if (Pos != StringRef::npos)
+ if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable))
return StringRef::npos;
// Clear "not strings".
NotStrings.clear();
@@ -1015,7 +1041,7 @@ int main(int argc, char **argv) {
// Open the file to check and add it to SourceMgr.
OwningPtr<MemoryBuffer> File;
if (error_code ec =
- MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), File)) {
+ MemoryBuffer::getFileOrSTDIN(InputFilename, File)) {
errs() << "Could not open input file '" << InputFilename << "': "
<< ec.message() << '\n';
return 2;
@@ -1040,18 +1066,56 @@ int main(int argc, char **argv) {
// file.
StringRef Buffer = F->getBuffer();
- for (unsigned StrNo = 0, e = CheckStrings.size(); StrNo != e; ++StrNo) {
- const CheckString &CheckStr = CheckStrings[StrNo];
+ bool hasError = false;
- // Find StrNo in the file.
- size_t MatchLen = 0;
- size_t MatchPos = CheckStr.Check(SM, Buffer, MatchLen, VariableTable);
+ unsigned i = 0, j = 0, e = CheckStrings.size();
+
+ while (true) {
+ StringRef CheckRegion;
+ if (j == e) {
+ CheckRegion = Buffer;
+ } else {
+ const CheckString &CheckLabelStr = CheckStrings[j];
+ if (!CheckLabelStr.IsCheckLabel) {
+ ++j;
+ continue;
+ }
+
+ // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG
+ size_t MatchLabelLen = 0;
+ size_t MatchLabelPos = CheckLabelStr.Check(SM, Buffer, true,
+ MatchLabelLen, VariableTable);
+ if (MatchLabelPos == StringRef::npos) {
+ hasError = true;
+ break;
+ }
- if (MatchPos == StringRef::npos)
- return 1;
+ CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen);
+ Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen);
+ ++j;
+ }
- Buffer = Buffer.substr(MatchPos + MatchLen);
+ for ( ; i != j; ++i) {
+ const CheckString &CheckStr = CheckStrings[i];
+
+ // Check each string within the scanned region, including a second check
+ // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG)
+ size_t MatchLen = 0;
+ size_t MatchPos = CheckStr.Check(SM, CheckRegion, false, MatchLen,
+ VariableTable);
+
+ if (MatchPos == StringRef::npos) {
+ hasError = true;
+ i = j;
+ break;
+ }
+
+ CheckRegion = CheckRegion.substr(MatchPos + MatchLen);
+ }
+
+ if (j == e)
+ break;
}
- return 0;
+ return hasError ? 1 : 0;
}
diff --git a/utils/FileUpdate/FileUpdate.cpp b/utils/FileUpdate/FileUpdate.cpp
index 9b48f94..fbcd927 100644
--- a/utils/FileUpdate/FileUpdate.cpp
+++ b/utils/FileUpdate/FileUpdate.cpp
@@ -45,7 +45,7 @@ int main(int argc, char **argv) {
// Get the input data.
OwningPtr<MemoryBuffer> In;
- if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), In)) {
+ if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, In)) {
errs() << argv[0] << ": error: Unable to get input '"
<< InputFilename << "': " << ec.message() << '\n';
return 1;
@@ -71,7 +71,7 @@ int main(int argc, char **argv) {
<< "', contents changed.\n";
std::string ErrorStr;
tool_output_file OutStream(OutputFilename.c_str(), ErrorStr,
- raw_fd_ostream::F_Binary);
+ sys::fs::F_Binary);
if (!ErrorStr.empty()) {
errs() << argv[0] << ": Unable to write output '"
<< OutputFilename << "': " << ErrorStr << '\n';
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp
index 218af21..468ce1c 100644
--- a/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/utils/TableGen/AsmMatcherEmitter.cpp
@@ -114,6 +114,7 @@
#include <cassert>
#include <map>
#include <set>
+#include <sstream>
using namespace llvm;
static cl::opt<std::string>
@@ -836,9 +837,11 @@ void MatchableInfo::tokenizeAsmString(const AsmMatcherInfo &Info) {
}
case '.':
- if (InTok)
- AsmOperands.push_back(AsmOperand(String.slice(Prev, i)));
- Prev = i;
+ if (!Info.AsmParser->getValueAsBit("MnemonicContainsDot")) {
+ if (InTok)
+ AsmOperands.push_back(AsmOperand(String.slice(Prev, i)));
+ Prev = i;
+ }
InTok = true;
break;
@@ -2066,9 +2069,12 @@ static void emitIsSubclass(CodeGenTarget &Target,
OS << " if (A == B)\n";
OS << " return true;\n\n";
- OS << " switch (A) {\n";
- OS << " default:\n";
- OS << " return false;\n";
+ std::string OStr;
+ raw_string_ostream SS(OStr);
+ unsigned Count = 0;
+ SS << " switch (A) {\n";
+ SS << " default:\n";
+ SS << " return false;\n";
for (std::vector<ClassInfo*>::iterator it = Infos.begin(),
ie = Infos.end(); it != ie; ++it) {
ClassInfo &A = **it;
@@ -2084,21 +2090,35 @@ static void emitIsSubclass(CodeGenTarget &Target,
if (SuperClasses.empty())
continue;
+ ++Count;
- OS << "\n case " << A.Name << ":\n";
+ SS << "\n case " << A.Name << ":\n";
if (SuperClasses.size() == 1) {
- OS << " return B == " << SuperClasses.back() << ";\n";
+ SS << " return B == " << SuperClasses.back().str() << ";\n";
continue;
}
- OS << " switch (B) {\n";
- OS << " default: return false;\n";
- for (unsigned i = 0, e = SuperClasses.size(); i != e; ++i)
- OS << " case " << SuperClasses[i] << ": return true;\n";
- OS << " }\n";
+ if (!SuperClasses.empty()) {
+ SS << " switch (B) {\n";
+ SS << " default: return false;\n";
+ for (unsigned i = 0, e = SuperClasses.size(); i != e; ++i)
+ SS << " case " << SuperClasses[i].str() << ": return true;\n";
+ SS << " }\n";
+ } else {
+ // No case statement to emit
+ SS << " return false;\n";
+ }
}
- OS << " }\n";
+ SS << " }\n";
+
+ // If there were case statements emitted into the string stream, write them
+ // to the output stream, otherwise write the default.
+ if (Count)
+ OS << SS.str();
+ else
+ OS << " return false;\n";
+
OS << "}\n\n";
}
@@ -2194,18 +2214,24 @@ static void emitOperandDiagnosticTypes(AsmMatcherInfo &Info, raw_ostream &OS) {
static void emitGetSubtargetFeatureName(AsmMatcherInfo &Info, raw_ostream &OS) {
OS << "// User-level names for subtarget features that participate in\n"
<< "// instruction matching.\n"
- << "static const char *getSubtargetFeatureName(unsigned Val) {\n"
- << " switch(Val) {\n";
- for (std::map<Record*, SubtargetFeatureInfo*>::const_iterator
- it = Info.SubtargetFeatures.begin(),
- ie = Info.SubtargetFeatures.end(); it != ie; ++it) {
- SubtargetFeatureInfo &SFI = *it->second;
- // FIXME: Totally just a placeholder name to get the algorithm working.
- OS << " case " << SFI.getEnumName() << ": return \""
- << SFI.TheDef->getValueAsString("PredicateName") << "\";\n";
+ << "static const char *getSubtargetFeatureName(unsigned Val) {\n";
+ if (!Info.SubtargetFeatures.empty()) {
+ OS << " switch(Val) {\n";
+ for (std::map<Record*, SubtargetFeatureInfo*>::const_iterator
+ it = Info.SubtargetFeatures.begin(),
+ ie = Info.SubtargetFeatures.end(); it != ie; ++it) {
+ SubtargetFeatureInfo &SFI = *it->second;
+ // FIXME: Totally just a placeholder name to get the algorithm working.
+ OS << " case " << SFI.getEnumName() << ": return \""
+ << SFI.TheDef->getValueAsString("PredicateName") << "\";\n";
+ }
+ OS << " default: return \"(unknown)\";\n";
+ OS << " }\n";
+ } else {
+ // Nothing to emit, so skip the switch
+ OS << " return \"(unknown)\";\n";
}
- OS << " default: return \"(unknown)\";\n";
- OS << " }\n}\n\n";
+ OS << "}\n\n";
}
/// emitComputeAvailableFeatures - Emit the function to compute the list of
@@ -2303,7 +2329,7 @@ static void emitMnemonicAliasVariant(raw_ostream &OS,const AsmMatcherInfo &Info,
}
if (AliasesFromMnemonic.empty())
return;
-
+
// Process each alias a "from" mnemonic at a time, building the code executed
// by the string remapper.
std::vector<StringMatcher::StringPair> Cases;
@@ -2632,7 +2658,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
<< "&Operands);\n";
OS << " void convertToMapAndConstraints(unsigned Kind,\n ";
OS << " const SmallVectorImpl<MCParsedAsmOperand*> &Operands);\n";
- OS << " bool mnemonicIsValid(StringRef Mnemonic);\n";
+ OS << " bool mnemonicIsValid(StringRef Mnemonic, unsigned VariantID);\n";
OS << " unsigned MatchInstructionImpl(\n";
OS.indent(27);
OS << "const SmallVectorImpl<MCParsedAsmOperand*> &Operands,\n"
@@ -2754,7 +2780,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
<< " RequiredFeatures;\n";
OS << " " << getMinimalTypeForRange(Info.Classes.size())
<< " Classes[" << MaxNumOperands << "];\n";
- OS << " uint8_t AsmVariantID;\n\n";
OS << " StringRef getMnemonic() const {\n";
OS << " return StringRef(MnemonicTable + Mnemonic + 1,\n";
OS << " MnemonicTable[Mnemonic]);\n";
@@ -2776,51 +2801,73 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << "} // end anonymous namespace.\n\n";
- OS << "static const MatchEntry MatchTable["
- << Info.Matchables.size() << "] = {\n";
+ unsigned VariantCount = Target.getAsmParserVariantCount();
+ for (unsigned VC = 0; VC != VariantCount; ++VC) {
+ Record *AsmVariant = Target.getAsmParserVariant(VC);
+ std::string CommentDelimiter =
+ AsmVariant->getValueAsString("CommentDelimiter");
+ std::string RegisterPrefix = AsmVariant->getValueAsString("RegisterPrefix");
+ int AsmVariantNo = AsmVariant->getValueAsInt("Variant");
- for (std::vector<MatchableInfo*>::const_iterator it =
- Info.Matchables.begin(), ie = Info.Matchables.end();
- it != ie; ++it) {
- MatchableInfo &II = **it;
+ OS << "static const MatchEntry MatchTable" << VC << "[] = {\n";
- // Store a pascal-style length byte in the mnemonic.
- std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.str();
- OS << " { " << StringTable.GetOrAddStringOffset(LenMnemonic, false)
- << " /* " << II.Mnemonic << " */, "
- << Target.getName() << "::"
- << II.getResultInst()->TheDef->getName() << ", "
- << II.ConversionFnKind << ", ";
+ for (std::vector<MatchableInfo*>::const_iterator it =
+ Info.Matchables.begin(), ie = Info.Matchables.end();
+ it != ie; ++it) {
+ MatchableInfo &II = **it;
+ if (II.AsmVariantID != AsmVariantNo)
+ continue;
- // Write the required features mask.
- if (!II.RequiredFeatures.empty()) {
- for (unsigned i = 0, e = II.RequiredFeatures.size(); i != e; ++i) {
- if (i) OS << "|";
- OS << II.RequiredFeatures[i]->getEnumName();
- }
- } else
- OS << "0";
+ // Store a pascal-style length byte in the mnemonic.
+ std::string LenMnemonic = char(II.Mnemonic.size()) + II.Mnemonic.str();
+ OS << " { " << StringTable.GetOrAddStringOffset(LenMnemonic, false)
+ << " /* " << II.Mnemonic << " */, "
+ << Target.getName() << "::"
+ << II.getResultInst()->TheDef->getName() << ", "
+ << II.ConversionFnKind << ", ";
+
+ // Write the required features mask.
+ if (!II.RequiredFeatures.empty()) {
+ for (unsigned i = 0, e = II.RequiredFeatures.size(); i != e; ++i) {
+ if (i) OS << "|";
+ OS << II.RequiredFeatures[i]->getEnumName();
+ }
+ } else
+ OS << "0";
- OS << ", { ";
- for (unsigned i = 0, e = II.AsmOperands.size(); i != e; ++i) {
- MatchableInfo::AsmOperand &Op = II.AsmOperands[i];
+ OS << ", { ";
+ for (unsigned i = 0, e = II.AsmOperands.size(); i != e; ++i) {
+ MatchableInfo::AsmOperand &Op = II.AsmOperands[i];
- if (i) OS << ", ";
- OS << Op.Class->Name;
+ if (i) OS << ", ";
+ OS << Op.Class->Name;
+ }
+ OS << " }, },\n";
}
- OS << " }, " << II.AsmVariantID;
- OS << "},\n";
- }
- OS << "};\n\n";
+ OS << "};\n\n";
+ }
// A method to determine if a mnemonic is in the list.
OS << "bool " << Target.getName() << ClassName << "::\n"
- << "mnemonicIsValid(StringRef Mnemonic) {\n";
+ << "mnemonicIsValid(StringRef Mnemonic, unsigned VariantID) {\n";
+ OS << " // Find the appropriate table for this asm variant.\n";
+ OS << " const MatchEntry *Start, *End;\n";
+ OS << " switch (VariantID) {\n";
+ OS << " default: // unreachable\n";
+ for (unsigned VC = 0; VC != VariantCount; ++VC) {
+ Record *AsmVariant = Target.getAsmParserVariant(VC);
+ std::string CommentDelimiter =
+ AsmVariant->getValueAsString("CommentDelimiter");
+ std::string RegisterPrefix = AsmVariant->getValueAsString("RegisterPrefix");
+ int AsmVariantNo = AsmVariant->getValueAsInt("Variant");
+ OS << " case " << AsmVariantNo << ": Start = MatchTable" << VC
+ << "; End = array_endof(MatchTable" << VC << "); break;\n";
+ }
+ OS << " }\n";
OS << " // Search the table.\n";
OS << " std::pair<const MatchEntry*, const MatchEntry*> MnemonicRange =\n";
- OS << " std::equal_range(MatchTable, MatchTable+"
- << Info.Matchables.size() << ", Mnemonic, LessOpcode());\n";
+ OS << " std::equal_range(Start, End, Mnemonic, LessOpcode());\n";
OS << " return MnemonicRange.first != MnemonicRange.second;\n";
OS << "}\n\n";
@@ -2862,10 +2909,23 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " ErrorInfo = ~0U;\n";
// Emit code to search the table.
+ OS << " // Find the appropriate table for this asm variant.\n";
+ OS << " const MatchEntry *Start, *End;\n";
+ OS << " switch (VariantID) {\n";
+ OS << " default: // unreachable\n";
+ for (unsigned VC = 0; VC != VariantCount; ++VC) {
+ Record *AsmVariant = Target.getAsmParserVariant(VC);
+ std::string CommentDelimiter =
+ AsmVariant->getValueAsString("CommentDelimiter");
+ std::string RegisterPrefix = AsmVariant->getValueAsString("RegisterPrefix");
+ int AsmVariantNo = AsmVariant->getValueAsInt("Variant");
+ OS << " case " << AsmVariantNo << ": Start = MatchTable" << VC
+ << "; End = array_endof(MatchTable" << VC << "); break;\n";
+ }
+ OS << " }\n";
OS << " // Search the table.\n";
OS << " std::pair<const MatchEntry*, const MatchEntry*> MnemonicRange =\n";
- OS << " std::equal_range(MatchTable, MatchTable+"
- << Info.Matchables.size() << ", Mnemonic, LessOpcode());\n\n";
+ OS << " std::equal_range(Start, End, Mnemonic, LessOpcode());\n\n";
OS << " // Return a more specific error code if no mnemonics match.\n";
OS << " if (MnemonicRange.first == MnemonicRange.second)\n";
@@ -2879,7 +2939,6 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " assert(Mnemonic == it->getMnemonic());\n";
// Emit check that the subclasses match.
- OS << " if (VariantID != it->AsmVariantID) continue;\n";
OS << " bool OperandsValid = true;\n";
OS << " for (unsigned i = 0; i != " << MaxNumOperands << "; ++i) {\n";
OS << " if (i + 1 >= Operands.size()) {\n";
diff --git a/utils/TableGen/AsmWriterInst.cpp b/utils/TableGen/AsmWriterInst.cpp
index fe1f756..1c2004f 100644
--- a/utils/TableGen/AsmWriterInst.cpp
+++ b/utils/TableGen/AsmWriterInst.cpp
@@ -32,10 +32,10 @@ std::string AsmWriterOperand::getCode() const {
return "O << '" + Str + "'; ";
return "O << \"" + Str + "\"; ";
}
-
+
if (OperandType == isLiteralStatementOperand)
return Str;
-
+
std::string Result = Str + "(MI";
if (MIOpNo != ~0U)
Result += ", " + utostr(MIOpNo);
@@ -53,12 +53,12 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI,
int FirstOperandColumn,
int OperandSpacing) {
this->CGI = &CGI;
-
+
// This is the number of tabs we've seen if we're doing columnar layout.
unsigned CurColumn = 0;
-
-
- // NOTE: Any extensions to this code need to be mirrored in the
+
+
+ // NOTE: Any extensions to this code need to be mirrored in the
// AsmPrinter::printInlineAsm code that executes as compile time (assuming
// that inline asm strings should also get the new feature)!
std::string AsmString = CGI.FlattenAsmStringVariants(CGI.AsmString, Variant);
@@ -67,7 +67,7 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI,
std::string::size_type DollarPos =
AsmString.find_first_of("$\\", LastEmitted);
if (DollarPos == std::string::npos) DollarPos = AsmString.size();
-
+
// Emit a constant string fragment.
if (DollarPos != LastEmitted) {
for (; LastEmitted != DollarPos; ++LastEmitted)
@@ -82,7 +82,7 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI,
AddLiteralString("\\t");
} else {
// We recognize a tab as an operand delimeter.
- unsigned DestColumn = FirstOperandColumn +
+ unsigned DestColumn = FirstOperandColumn +
CurColumn++ * OperandSpacing;
Operands.push_back(
AsmWriterOperand(
@@ -112,15 +112,15 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI,
AddLiteralString("\\t");
break;
}
-
+
// We recognize a tab as an operand delimeter.
- unsigned DestColumn = FirstOperandColumn +
+ unsigned DestColumn = FirstOperandColumn +
CurColumn++ * OperandSpacing;
Operands.push_back(
AsmWriterOperand("O.PadToColumn(" + utostr(DestColumn) + ");\n",
AsmWriterOperand::isLiteralStatementOperand));
break;
- } else if (std::string("${|}\\").find(AsmString[DollarPos+1])
+ } else if (std::string("${|}\\").find(AsmString[DollarPos+1])
!= std::string::npos) {
AddLiteralString(std::string(1, AsmString[DollarPos+1]));
} else {
@@ -137,7 +137,7 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI,
} else {
// Get the name of the variable.
std::string::size_type VarEnd = DollarPos+1;
-
+
// handle ${foo}bar as $foo by detecting whether the character following
// the dollar sign is a curly brace. If so, advance VarEnd and DollarPos
// so the variable name does not contain the leading curly brace.
@@ -147,17 +147,17 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI,
++DollarPos;
++VarEnd;
}
-
+
while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd]))
++VarEnd;
std::string VarName(AsmString.begin()+DollarPos+1,
AsmString.begin()+VarEnd);
-
+
// Modifier - Support ${foo:modifier} syntax, where "modifier" is passed
// into printOperand. Also support ${:feature}, which is passed into
// PrintSpecial.
std::string Modifier;
-
+
// In order to avoid starting the next string at the terminating curly
// brace, advance the end position past it if we found an opening curly
// brace.
@@ -165,14 +165,14 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI,
if (VarEnd >= AsmString.size())
PrintFatalError("Reached end of string before terminating curly brace in '"
+ CGI.TheDef->getName() + "'");
-
+
// Look for a modifier string.
if (AsmString[VarEnd] == ':') {
++VarEnd;
if (VarEnd >= AsmString.size())
PrintFatalError("Reached end of string before terminating curly brace in '"
+ CGI.TheDef->getName() + "'");
-
+
unsigned ModifierStart = VarEnd;
while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd]))
++VarEnd;
@@ -181,7 +181,7 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI,
if (Modifier.empty())
PrintFatalError("Bad operand modifier name in '"+ CGI.TheDef->getName() + "'");
}
-
+
if (AsmString[VarEnd] != '}')
PrintFatalError("Variable name beginning with '{' did not end with '}' in '"
+ CGI.TheDef->getName() + "'");
@@ -190,26 +190,26 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI,
if (VarName.empty() && Modifier.empty())
PrintFatalError("Stray '$' in '" + CGI.TheDef->getName() +
"' asm string, maybe you want $$?");
-
+
if (VarName.empty()) {
// Just a modifier, pass this into PrintSpecial.
- Operands.push_back(AsmWriterOperand("PrintSpecial",
- ~0U,
- ~0U,
+ Operands.push_back(AsmWriterOperand("PrintSpecial",
+ ~0U,
+ ~0U,
Modifier));
} else {
// Otherwise, normal operand.
unsigned OpNo = CGI.Operands.getOperandNamed(VarName);
CGIOperandList::OperandInfo OpInfo = CGI.Operands[OpNo];
-
+
unsigned MIOp = OpInfo.MIOperandNo;
- Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName,
+ Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName,
OpNo, MIOp, Modifier));
}
LastEmitted = VarEnd;
}
}
-
+
Operands.push_back(AsmWriterOperand("return;",
AsmWriterOperand::isLiteralStatementOperand));
}
@@ -220,14 +220,13 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI,
/// if the instructions are identical return ~0.
unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst &Other)const{
if (Operands.size() != Other.Operands.size()) return ~1;
-
+
unsigned MismatchOperand = ~0U;
for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
if (Operands[i] != Other.Operands[i]) {
if (MismatchOperand != ~0U) // Already have one mismatch?
return ~1U;
- else
- MismatchOperand = i;
+ MismatchOperand = i;
}
}
return MismatchOperand;
diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp
index 8e5bb77..ee025a0 100644
--- a/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -438,7 +438,7 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) {
int OtherIntSize = 0;
int OtherFPSize = 0;
- for (SmallVector<MVT::SimpleValueType, 2>::iterator TVI =
+ for (SmallVectorImpl<MVT::SimpleValueType>::iterator TVI =
Other.TypeVec.begin();
TVI != Other.TypeVec.end();
/* NULL */) {
@@ -496,7 +496,7 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) {
int IntSize = 0;
int FPSize = 0;
- for (SmallVector<MVT::SimpleValueType, 2>::iterator TVI =
+ for (SmallVectorImpl<MVT::SimpleValueType>::iterator TVI =
TypeVec.begin();
TVI != TypeVec.end();
/* NULL */) {
diff --git a/utils/TableGen/CodeGenIntrinsics.h b/utils/TableGen/CodeGenIntrinsics.h
index f0570f9..ababfa4 100644
--- a/utils/TableGen/CodeGenIntrinsics.h
+++ b/utils/TableGen/CodeGenIntrinsics.h
@@ -77,7 +77,9 @@ namespace llvm {
bool isNoReturn;
enum ArgAttribute {
- NoCapture
+ NoCapture,
+ ReadOnly,
+ ReadNone
};
std::vector<std::pair<unsigned, ArgAttribute> > ArgumentAttributes;
diff --git a/utils/TableGen/CodeGenRegisters.cpp b/utils/TableGen/CodeGenRegisters.cpp
index daa7eab..43de2be 100644
--- a/utils/TableGen/CodeGenRegisters.cpp
+++ b/utils/TableGen/CodeGenRegisters.cpp
@@ -12,6 +12,8 @@
//
//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "regalloc-emitter"
+
#include "CodeGenRegisters.h"
#include "CodeGenTarget.h"
#include "llvm/ADT/IntEqClasses.h"
@@ -19,6 +21,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Debug.h"
#include "llvm/TableGen/Error.h"
using namespace llvm;
@@ -938,7 +941,7 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records) {
// Read in the register definitions.
std::vector<Record*> Regs = Records.getAllDerivedDefinitions("Register");
- std::sort(Regs.begin(), Regs.end(), LessRecord());
+ std::sort(Regs.begin(), Regs.end(), LessRecordRegister());
Registers.reserve(Regs.size());
// Assign the enumeration values.
for (unsigned i = 0, e = Regs.size(); i != e; ++i)
@@ -947,10 +950,16 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records) {
// Expand tuples and number the new registers.
std::vector<Record*> Tups =
Records.getAllDerivedDefinitions("RegisterTuples");
+
+ std::vector<Record*> TupRegsCopy;
for (unsigned i = 0, e = Tups.size(); i != e; ++i) {
const std::vector<Record*> *TupRegs = Sets.expand(Tups[i]);
- for (unsigned j = 0, je = TupRegs->size(); j != je; ++j)
- getReg((*TupRegs)[j]);
+ TupRegsCopy.reserve(TupRegs->size());
+ TupRegsCopy.assign(TupRegs->begin(), TupRegs->end());
+ std::sort(TupRegsCopy.begin(), TupRegsCopy.end(), LessRecordRegister());
+ for (unsigned j = 0, je = TupRegsCopy.size(); j != je; ++j)
+ getReg((TupRegsCopy)[j]);
+ TupRegsCopy.clear();
}
// Now all the registers are known. Build the object graph of explicit
@@ -1082,7 +1091,7 @@ CodeGenRegBank::getCompositeSubRegIndex(CodeGenSubRegIndex *A,
}
CodeGenSubRegIndex *CodeGenRegBank::
-getConcatSubRegIndex(const SmallVector<CodeGenSubRegIndex*, 8> &Parts) {
+getConcatSubRegIndex(const SmallVector<CodeGenSubRegIndex *, 8> &Parts) {
assert(Parts.size() > 1 && "Need two parts to concatenate");
// Look for an existing entry.
@@ -1323,9 +1332,18 @@ static void computeUberWeights(std::vector<UberRegSet> &UberSets,
}
if (Weight > MaxWeight)
MaxWeight = Weight;
-
- // Update the set weight.
- I->Weight = MaxWeight;
+ if (I->Weight != MaxWeight) {
+ DEBUG(
+ dbgs() << "UberSet " << I - UberSets.begin() << " Weight " << MaxWeight;
+ for (CodeGenRegister::Set::iterator
+ UnitI = I->Regs.begin(), UnitE = I->Regs.end();
+ UnitI != UnitE; ++UnitI) {
+ dbgs() << " " << (*UnitI)->getName();
+ }
+ dbgs() << "\n");
+ // Update the set weight.
+ I->Weight = MaxWeight;
+ }
// Find singular determinants.
for (CodeGenRegister::Set::iterator RegI = I->Regs.begin(),
@@ -1452,7 +1470,23 @@ static bool isRegUnitSubSet(const std::vector<unsigned> &RUSubSet,
RUSubSet.begin(), RUSubSet.end());
}
-// Iteratively prune unit sets.
+/// Iteratively prune unit sets. Prune subsets that are close to the superset,
+/// but with one or two registers removed. We occasionally have registers like
+/// APSR and PC thrown in with the general registers. We also see many
+/// special-purpose register subsets, such as tail-call and Thumb
+/// encodings. Generating all possible overlapping sets is combinatorial and
+/// overkill for modeling pressure. Ideally we could fix this statically in
+/// tablegen by (1) having the target define register classes that only include
+/// the allocatable registers and marking other classes as non-allocatable and
+/// (2) having a way to mark special purpose classes as "don't-care" classes for
+/// the purpose of pressure. However, we make an attempt to handle targets that
+/// are not nicely defined by merging nearly identical register unit sets
+/// statically. This generates smaller tables. Then, dynamically, we adjust the
+/// set limit by filtering the reserved registers.
+///
+/// Merge sets only if the units have the same weight. For example, on ARM,
+/// Q-tuples with ssub index 0 include all S regs but also include D16+. We
+/// should not expand the S set to include D regs.
void CodeGenRegBank::pruneUnitSets() {
assert(RegClassUnitSets.empty() && "this invalidates RegClassUnitSets");
@@ -1466,9 +1500,14 @@ void CodeGenRegBank::pruneUnitSets() {
if (SuperIdx == SubIdx)
continue;
+ unsigned UnitWeight = RegUnits[SubSet.Units[0]].Weight;
const RegUnitSet &SuperSet = RegUnitSets[SuperIdx];
if (isRegUnitSubSet(SubSet.Units, SuperSet.Units)
- && (SubSet.Units.size() + 3 > SuperSet.Units.size())) {
+ && (SubSet.Units.size() + 3 > SuperSet.Units.size())
+ && UnitWeight == RegUnits[SuperSet.Units[0]].Weight
+ && UnitWeight == RegUnits[SuperSet.Units.back()].Weight) {
+ DEBUG(dbgs() << "UnitSet " << SubIdx << " subsumed by " << SuperIdx
+ << "\n");
break;
}
}
@@ -1493,6 +1532,7 @@ void CodeGenRegBank::pruneUnitSets() {
// RegisterInfoEmitter will map each RegClass to its RegUnitClass and any
// RegUnitSet that is a superset of that RegUnitClass.
void CodeGenRegBank::computeRegUnitSets() {
+ assert(RegUnitSets.empty() && "dirty RegUnitSets");
// Compute a unique RegUnitSet for each RegClass.
const ArrayRef<CodeGenRegisterClass*> &RegClasses = getRegClasses();
@@ -1515,9 +1555,32 @@ void CodeGenRegBank::computeRegUnitSets() {
RegUnitSets.pop_back();
}
+ DEBUG(dbgs() << "\nBefore pruning:\n";
+ for (unsigned USIdx = 0, USEnd = RegUnitSets.size();
+ USIdx < USEnd; ++USIdx) {
+ dbgs() << "UnitSet " << USIdx << " " << RegUnitSets[USIdx].Name
+ << ":";
+ ArrayRef<unsigned> Units = RegUnitSets[USIdx].Units;
+ for (unsigned i = 0, e = Units.size(); i < e; ++i)
+ dbgs() << " " << RegUnits[Units[i]].Roots[0]->getName();
+ dbgs() << "\n";
+ });
+
// Iteratively prune unit sets.
pruneUnitSets();
+ DEBUG(dbgs() << "\nBefore union:\n";
+ for (unsigned USIdx = 0, USEnd = RegUnitSets.size();
+ USIdx < USEnd; ++USIdx) {
+ dbgs() << "UnitSet " << USIdx << " " << RegUnitSets[USIdx].Name
+ << ":";
+ ArrayRef<unsigned> Units = RegUnitSets[USIdx].Units;
+ for (unsigned i = 0, e = Units.size(); i < e; ++i)
+ dbgs() << " " << RegUnits[Units[i]].Roots[0]->getName();
+ dbgs() << "\n";
+ }
+ dbgs() << "\nUnion sets:\n");
+
// Iterate over all unit sets, including new ones added by this loop.
unsigned NumRegUnitSubSets = RegUnitSets.size();
for (unsigned Idx = 0, EndIdx = RegUnitSets.size(); Idx != EndIdx; ++Idx) {
@@ -1555,12 +1618,31 @@ void CodeGenRegBank::computeRegUnitSets() {
findRegUnitSet(RegUnitSets, RegUnitSets.back());
if (SetI != llvm::prior(RegUnitSets.end()))
RegUnitSets.pop_back();
+ else {
+ DEBUG(dbgs() << "UnitSet " << RegUnitSets.size()-1
+ << " " << RegUnitSets.back().Name << ":";
+ ArrayRef<unsigned> Units = RegUnitSets.back().Units;
+ for (unsigned i = 0, e = Units.size(); i < e; ++i)
+ dbgs() << " " << RegUnits[Units[i]].Roots[0]->getName();
+ dbgs() << "\n";);
+ }
}
}
// Iteratively prune unit sets after inferring supersets.
pruneUnitSets();
+ DEBUG(dbgs() << "\n";
+ for (unsigned USIdx = 0, USEnd = RegUnitSets.size();
+ USIdx < USEnd; ++USIdx) {
+ dbgs() << "UnitSet " << USIdx << " " << RegUnitSets[USIdx].Name
+ << ":";
+ ArrayRef<unsigned> Units = RegUnitSets[USIdx].Units;
+ for (unsigned i = 0, e = Units.size(); i < e; ++i)
+ dbgs() << " " << RegUnits[Units[i]].Roots[0]->getName();
+ dbgs() << "\n";
+ });
+
// For each register class, list the UnitSets that are supersets.
RegClassUnitSets.resize(NumRegClasses);
for (unsigned RCIdx = 0, RCEnd = NumRegClasses; RCIdx != RCEnd; ++RCIdx) {
@@ -1568,19 +1650,27 @@ void CodeGenRegBank::computeRegUnitSets() {
continue;
// Recompute the sorted list of units in this class.
- std::vector<unsigned> RegUnits;
- RegClasses[RCIdx]->buildRegUnitSet(RegUnits);
+ std::vector<unsigned> RCRegUnits;
+ RegClasses[RCIdx]->buildRegUnitSet(RCRegUnits);
// Don't increase pressure for unallocatable regclasses.
- if (RegUnits.empty())
+ if (RCRegUnits.empty())
continue;
+ DEBUG(dbgs() << "RC " << RegClasses[RCIdx]->getName() << " Units: \n";
+ for (unsigned i = 0, e = RCRegUnits.size(); i < e; ++i)
+ dbgs() << RegUnits[RCRegUnits[i]].getRoots()[0]->getName() << " ";
+ dbgs() << "\n UnitSetIDs:");
+
// Find all supersets.
for (unsigned USIdx = 0, USEnd = RegUnitSets.size();
USIdx != USEnd; ++USIdx) {
- if (isRegUnitSubSet(RegUnits, RegUnitSets[USIdx].Units))
+ if (isRegUnitSubSet(RCRegUnits, RegUnitSets[USIdx].Units)) {
+ DEBUG(dbgs() << " " << USIdx);
RegClassUnitSets[RCIdx].push_back(USIdx);
+ }
}
+ DEBUG(dbgs() << "\n");
assert(!RegClassUnitSets[RCIdx].empty() && "missing unit set for regclass");
}
@@ -1614,6 +1704,16 @@ void CodeGenRegBank::computeRegUnitSets() {
}
}
+struct LessUnits {
+ const CodeGenRegBank &RegBank;
+ LessUnits(const CodeGenRegBank &RB): RegBank(RB) {}
+
+ bool operator()(unsigned ID1, unsigned ID2) {
+ return RegBank.getRegPressureSet(ID1).Units.size()
+ < RegBank.getRegPressureSet(ID2).Units.size();
+ }
+};
+
void CodeGenRegBank::computeDerivedInfo() {
computeComposites();
computeSubRegIndexLaneMasks();
@@ -1625,6 +1725,21 @@ void CodeGenRegBank::computeDerivedInfo() {
// Compute a unique set of RegUnitSets. One for each RegClass and inferred
// supersets for the union of overlapping sets.
computeRegUnitSets();
+
+ // Get the weight of each set.
+ for (unsigned Idx = 0, EndIdx = RegUnitSets.size(); Idx != EndIdx; ++Idx)
+ RegUnitSets[Idx].Weight = getRegUnitSetWeight(RegUnitSets[Idx].Units);
+
+ // Find the order of each set.
+ RegUnitSetOrder.reserve(RegUnitSets.size());
+ for (unsigned Idx = 0, EndIdx = RegUnitSets.size(); Idx != EndIdx; ++Idx)
+ RegUnitSetOrder.push_back(Idx);
+
+ std::stable_sort(RegUnitSetOrder.begin(), RegUnitSetOrder.end(),
+ LessUnits(*this));
+ for (unsigned Idx = 0, EndIdx = RegUnitSets.size(); Idx != EndIdx; ++Idx) {
+ RegUnitSets[RegUnitSetOrder[Idx]].Order = Idx;
+ }
}
//
diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h
index f9edc65..37f75b4 100644
--- a/utils/TableGen/CodeGenRegisters.h
+++ b/utils/TableGen/CodeGenRegisters.h
@@ -433,6 +433,10 @@ namespace llvm {
std::string Name;
std::vector<unsigned> Units;
+ unsigned Weight; // Cache the sum of all unit weights.
+ unsigned Order; // Cache the sort key.
+
+ RegUnitSet() : Weight(0), Order(0) {}
};
// Base vector for identifying TopoSigs. The contents uniquely identify a
@@ -484,6 +488,9 @@ namespace llvm {
// already exist for a register class, we create a new entry in this vector.
std::vector<std::vector<unsigned> > RegClassUnitSets;
+ // Give each register unit set an order based on sorting criteria.
+ std::vector<unsigned> RegUnitSetOrder;
+
// Add RC to *2RC maps.
void addToMaps(CodeGenRegisterClass*);
@@ -534,10 +541,10 @@ namespace llvm {
// Find or create a sub-register index representing the concatenation of
// non-overlapping sibling indices.
CodeGenSubRegIndex *
- getConcatSubRegIndex(const SmallVector<CodeGenSubRegIndex*, 8>&);
+ getConcatSubRegIndex(const SmallVector<CodeGenSubRegIndex *, 8>&);
void
- addConcatSubRegIndex(const SmallVector<CodeGenSubRegIndex*, 8> &Parts,
+ addConcatSubRegIndex(const SmallVector<CodeGenSubRegIndex *, 8> &Parts,
CodeGenSubRegIndex *Idx) {
ConcatIdx.insert(std::make_pair(Parts, Idx));
}
@@ -622,6 +629,13 @@ namespace llvm {
return Weight;
}
+ unsigned getRegSetIDAt(unsigned Order) const {
+ return RegUnitSetOrder[Order];
+ }
+ const RegUnitSet &getRegSetAt(unsigned Order) const {
+ return RegUnitSets[RegUnitSetOrder[Order]];
+ }
+
// Increase a RegUnitWeight.
void increaseRegUnitWeight(unsigned RUID, unsigned Inc) {
getRegUnit(RUID).Weight += Inc;
@@ -631,7 +645,7 @@ namespace llvm {
unsigned getNumRegPressureSets() const { return RegUnitSets.size(); }
// Get a set of register unit IDs for a given dimension of pressure.
- RegUnitSet getRegPressureSet(unsigned Idx) const {
+ const RegUnitSet &getRegPressureSet(unsigned Idx) const {
return RegUnitSets[Idx];
}
diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp
index 8015e34..001e97d 100644
--- a/utils/TableGen/CodeGenSchedule.cpp
+++ b/utils/TableGen/CodeGenSchedule.cpp
@@ -1102,7 +1102,7 @@ void PredTransitions::getIntersectingVariants(
TransVariant &Variant = Variants[VIdx];
// Don't expand variants if the processor models don't intersect.
// A zero processor index means any processor.
- SmallVector<unsigned, 4> &ProcIndices = TransVec[TransIdx].ProcIndices;
+ SmallVectorImpl<unsigned> &ProcIndices = TransVec[TransIdx].ProcIndices;
if (ProcIndices[0] && Variants[VIdx].ProcIdx) {
unsigned Cnt = std::count(ProcIndices.begin(), ProcIndices.end(),
Variant.ProcIdx);
@@ -1476,6 +1476,19 @@ void CodeGenSchedModels::collectProcResources() {
Record *ModelDef = (*RAI)->getValueAsDef("SchedModel");
addReadAdvance(*RAI, getProcModel(ModelDef).Index);
}
+ // Add ProcResGroups that are defined within this processor model, which may
+ // not be directly referenced but may directly specify a buffer size.
+ RecVec ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup");
+ for (RecIter RI = ProcResGroups.begin(), RE = ProcResGroups.end();
+ RI != RE; ++RI) {
+ if (!(*RI)->getValueInit("SchedModel")->isComplete())
+ continue;
+ CodeGenProcModel &PM = getProcModel((*RI)->getValueAsDef("SchedModel"));
+ RecIter I = std::find(PM.ProcResourceDefs.begin(),
+ PM.ProcResourceDefs.end(), *RI);
+ if (I == PM.ProcResourceDefs.end())
+ PM.ProcResourceDefs.push_back(*RI);
+ }
// Finalize each ProcModel by sorting the record arrays.
for (unsigned PIdx = 0, PEnd = ProcModels.size(); PIdx != PEnd; ++PIdx) {
CodeGenProcModel &PM = ProcModels[PIdx];
diff --git a/utils/TableGen/CodeGenSchedule.h b/utils/TableGen/CodeGenSchedule.h
index 2e0a149..fa964cf 100644
--- a/utils/TableGen/CodeGenSchedule.h
+++ b/utils/TableGen/CodeGenSchedule.h
@@ -266,11 +266,14 @@ public:
return ProcModels[I->second];
}
- const CodeGenProcModel &getProcModel(Record *ModelDef) const {
+ CodeGenProcModel &getProcModel(Record *ModelDef) {
ProcModelMapTy::const_iterator I = ProcModelMap.find(ModelDef);
assert(I != ProcModelMap.end() && "missing machine model");
return ProcModels[I->second];
}
+ const CodeGenProcModel &getProcModel(Record *ModelDef) const {
+ return const_cast<CodeGenSchedModels*>(this)->getProcModel(ModelDef);
+ }
// Iterate over the unique processor models.
typedef std::vector<CodeGenProcModel>::const_iterator ProcIter;
diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp
index 8b292b9..b2c883d 100644
--- a/utils/TableGen/CodeGenTarget.cpp
+++ b/utils/TableGen/CodeGenTarget.cpp
@@ -298,7 +298,7 @@ struct SortInstByName {
/// target, ordered by their enum value.
void CodeGenTarget::ComputeInstrsByEnum() const {
// The ordering here must match the ordering in TargetOpcodes.h.
- const char *const FixedInstrs[] = {
+ static const char *const FixedInstrs[] = {
"PHI",
"INLINEASM",
"PROLOG_LABEL",
@@ -552,6 +552,12 @@ 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("ReadOnly")) {
+ unsigned ArgNo = Property->getValueAsInt("ArgNo");
+ ArgumentAttributes.push_back(std::make_pair(ArgNo, ReadOnly));
+ } else if (Property->isSubClassOf("ReadNone")) {
+ unsigned ArgNo = Property->getValueAsInt("ArgNo");
+ ArgumentAttributes.push_back(std::make_pair(ArgNo, ReadNone));
} else
llvm_unreachable("Unknown property!");
}
diff --git a/utils/TableGen/FixedLenDecoderEmitter.cpp b/utils/TableGen/FixedLenDecoderEmitter.cpp
index 0c3017f..6e45240 100644
--- a/utils/TableGen/FixedLenDecoderEmitter.cpp
+++ b/utils/TableGen/FixedLenDecoderEmitter.cpp
@@ -879,15 +879,20 @@ emitPredicateFunction(formatted_raw_ostream &OS, PredicateSet &Predicates,
OS.indent(Indentation) << "static bool checkDecoderPredicate(unsigned Idx, "
<< "uint64_t Bits) {\n";
Indentation += 2;
- OS.indent(Indentation) << "switch (Idx) {\n";
- OS.indent(Indentation) << "default: llvm_unreachable(\"Invalid index!\");\n";
- unsigned Index = 0;
- for (PredicateSet::const_iterator I = Predicates.begin(), E = Predicates.end();
- I != E; ++I, ++Index) {
- OS.indent(Indentation) << "case " << Index << ":\n";
- OS.indent(Indentation+2) << "return (" << *I << ");\n";
+ if (!Predicates.empty()) {
+ OS.indent(Indentation) << "switch (Idx) {\n";
+ OS.indent(Indentation) << "default: llvm_unreachable(\"Invalid index!\");\n";
+ unsigned Index = 0;
+ for (PredicateSet::const_iterator I = Predicates.begin(), E = Predicates.end();
+ I != E; ++I, ++Index) {
+ OS.indent(Indentation) << "case " << Index << ":\n";
+ OS.indent(Indentation+2) << "return (" << *I << ");\n";
+ }
+ OS.indent(Indentation) << "}\n";
+ } else {
+ // No case statement to emit
+ OS.indent(Indentation) << "llvm_unreachable(\"Invalid index!\");\n";
}
- OS.indent(Indentation) << "}\n";
Indentation -= 2;
OS.indent(Indentation) << "}\n\n";
}
diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp
index d6020a8..c8304de 100644
--- a/utils/TableGen/InstrInfoEmitter.cpp
+++ b/utils/TableGen/InstrInfoEmitter.cpp
@@ -45,11 +45,25 @@ private:
void emitEnums(raw_ostream &OS);
typedef std::map<std::vector<std::string>, unsigned> OperandInfoMapTy;
+
+ /// The keys of this map are maps which have OpName enum values as their keys
+ /// and instruction operand indices as their values. The values of this map
+ /// are lists of instruction names.
+ typedef std::map<std::map<unsigned, unsigned>,
+ std::vector<std::string> > OpNameMapTy;
+ typedef std::map<std::string, unsigned>::iterator StrUintMapIter;
void emitRecord(const CodeGenInstruction &Inst, unsigned Num,
Record *InstrInfo,
std::map<std::vector<Record*>, unsigned> &EL,
const OperandInfoMapTy &OpInfo,
raw_ostream &OS);
+ void initOperandMapData(
+ const std::vector<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);
// Operand information.
void EmitOperandInfo(raw_ostream &OS, OperandInfoMapTy &OperandInfoIDs);
@@ -176,6 +190,127 @@ void InstrInfoEmitter::EmitOperandInfo(raw_ostream &OS,
}
}
+
+/// Initialize data structures for generating operand name mappings.
+///
+/// \param Operands [out] A map used to generate the OpName enum with operand
+/// names as its keys and operand enum values as its values.
+/// \param OperandMap [out] A map for representing the operand name mappings for
+/// 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,
+ const std::string &Namespace,
+ std::map<std::string, unsigned> &Operands,
+ OpNameMapTy &OperandMap) {
+
+ unsigned NumOperands = 0;
+ for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
+ const CodeGenInstruction *Inst = NumberedInstructions[i];
+ if (!Inst->TheDef->getValueAsBit("UseNamedOperandTable")) {
+ continue;
+ }
+ std::map<unsigned, unsigned> OpList;
+ for (unsigned j = 0, je = Inst->Operands.size(); j != je; ++j) {
+ const CGIOperandList::OperandInfo &Info = Inst->Operands[j];
+ StrUintMapIter I = Operands.find(Info.Name);
+
+ if (I == Operands.end()) {
+ I = Operands.insert(Operands.begin(),
+ std::pair<std::string, unsigned>(Info.Name, NumOperands++));
+ }
+ OpList[I->second] = Info.MIOperandNo;
+ }
+ OperandMap[OpList].push_back(Namespace + "::" + Inst->TheDef->getName());
+ }
+}
+
+/// Generate a table and function for looking up the indices of operands by
+/// name.
+///
+/// This code generates:
+/// - An enum in the llvm::TargetNamespace::OpName namespace, with one entry
+/// for each operand name.
+/// - A 2-dimensional table called OperandMap for mapping OpName enum values to
+/// operand indices.
+/// - A function called getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIdx)
+/// for looking up the operand index for an instruction, given a value from
+/// OpName enum
+void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS,
+ const CodeGenTarget &Target,
+ const std::vector<const CodeGenInstruction*> &NumberedInstructions) {
+
+ const std::string &Namespace = Target.getInstNamespace();
+ std::string OpNameNS = "OpName";
+ // Map of operand names to their enumeration value. This will be used to
+ // generate the OpName enum.
+ std::map<std::string, unsigned> Operands;
+ OpNameMapTy OperandMap;
+
+ initOperandMapData(NumberedInstructions, Namespace, Operands, OperandMap);
+
+ OS << "#ifdef GET_INSTRINFO_OPERAND_ENUM\n";
+ OS << "#undef GET_INSTRINFO_OPERAND_ENUM\n";
+ OS << "namespace llvm {";
+ OS << "namespace " << Namespace << " {\n";
+ OS << "namespace " << OpNameNS << " { \n";
+ OS << "enum {\n";
+ for (StrUintMapIter i = Operands.begin(), e = Operands.end(); i != e; ++i)
+ OS << " " << i->first << " = " << i->second << ",\n";
+
+ OS << "OPERAND_LAST";
+ OS << "\n};\n";
+ OS << "} // End namespace OpName\n";
+ OS << "} // End namespace " << Namespace << "\n";
+ OS << "} // End namespace llvm\n";
+ OS << "#endif //GET_INSTRINFO_OPERAND_ENUM\n";
+
+ OS << "#ifdef GET_INSTRINFO_NAMED_OPS\n";
+ OS << "#undef GET_INSTRINFO_NAMED_OPS\n";
+ OS << "namespace llvm {";
+ OS << "namespace " << Namespace << " {\n";
+ OS << "int16_t getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIdx) {\n";
+ if (!Operands.empty()) {
+ OS << " static const int16_t OperandMap [][" << Operands.size()
+ << "] = {\n";
+ for (OpNameMapTy::iterator i = OperandMap.begin(), e = OperandMap.end();
+ i != e; ++i) {
+ const std::map<unsigned, unsigned> &OpList = i->first;
+ OS << "{";
+
+ // Emit a row of the OperandMap table
+ for (unsigned ii = 0, ie = Operands.size(); ii != ie; ++ii)
+ OS << (OpList.count(ii) == 0 ? -1 : (int)OpList.find(ii)->second)
+ << ", ";
+
+ OS << "},\n";
+ }
+ OS << "};\n";
+
+ OS << " switch(Opcode) {\n";
+ unsigned TableIndex = 0;
+ for (OpNameMapTy::iterator i = OperandMap.begin(), e = OperandMap.end();
+ i != e; ++i) {
+ std::vector<std::string> &OpcodeList = i->second;
+
+ for (unsigned ii = 0, ie = OpcodeList.size(); ii != ie; ++ii)
+ OS << " case " << OpcodeList[ii] << ":\n";
+
+ OS << " return OperandMap[" << TableIndex++ << "][NamedIdx];\n";
+ }
+ OS << " default: return -1;\n";
+ OS << " }\n";
+ } else {
+ // There are no operands, so no need to emit anything
+ OS << " return -1;\n";
+ }
+ OS << "}\n";
+ OS << "} // End namespace " << Namespace << "\n";
+ OS << "} // End namespace llvm\n";
+ OS << "#endif //GET_INSTRINFO_NAMED_OPS\n";
+
+}
+
//===----------------------------------------------------------------------===//
// Main Output.
//===----------------------------------------------------------------------===//
@@ -293,6 +428,8 @@ void InstrInfoEmitter::run(raw_ostream &OS) {
OS << "} // End llvm namespace \n";
OS << "#endif // GET_INSTRINFO_CTOR\n\n";
+
+ emitOperandNameMappings(OS, Target, NumberedInstructions);
}
void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num,
diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp
index df4d847..c508795 100644
--- a/utils/TableGen/IntrinsicEmitter.cpp
+++ b/utils/TableGen/IntrinsicEmitter.cpp
@@ -131,6 +131,20 @@ void IntrinsicEmitter::EmitEnumInfo(const std::vector<CodeGenIntrinsic> &Ints,
OS << "#endif\n\n";
}
+struct IntrinsicNameSorter {
+ IntrinsicNameSorter(const std::vector<CodeGenIntrinsic> &I)
+ : Ints(I) {}
+
+ // Sort in reverse order of intrinsic name so "abc.def" appears after
+ // "abd.def.ghi" in the overridden name matcher
+ bool operator()(unsigned i, unsigned j) {
+ return Ints[i].Name > Ints[j].Name;
+ }
+
+private:
+ const std::vector<CodeGenIntrinsic> &Ints;
+};
+
void IntrinsicEmitter::
EmitFnNameRecognizer(const std::vector<CodeGenIntrinsic> &Ints,
raw_ostream &OS) {
@@ -144,12 +158,16 @@ EmitFnNameRecognizer(const std::vector<CodeGenIntrinsic> &Ints,
OS << " StringRef NameR(Name+6, Len-6); // Skip over 'llvm.'\n";
OS << " switch (Name[5]) { // Dispatch on first letter.\n";
OS << " default: break;\n";
+ IntrinsicNameSorter Sorter(Ints);
// 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 intrinsics in reverse order of their names
+ std::sort(IntList.begin(), IntList.end(), Sorter);
+
// Emit all the overloaded intrinsics first, build a table of the
// non-overloaded ones.
std::vector<StringMatcher::StringPair> MatchTable;
@@ -579,6 +597,12 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) {
case CodeGenIntrinsic::NoCapture:
OS << " AttrVec.push_back(Attribute::NoCapture);\n";
break;
+ case CodeGenIntrinsic::ReadOnly:
+ OS << " AttrVec.push_back(Attribute::ReadOnly);\n";
+ break;
+ case CodeGenIntrinsic::ReadNone:
+ OS << " AttrVec.push_back(Attribute::ReadNone);\n";
+ break;
}
++ai;
diff --git a/utils/TableGen/OptParserEmitter.cpp b/utils/TableGen/OptParserEmitter.cpp
index 0c1f623..86328bf 100644
--- a/utils/TableGen/OptParserEmitter.cpp
+++ b/utils/TableGen/OptParserEmitter.cpp
@@ -178,7 +178,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
OS << "INVALID";
// The other option arguments (unused for groups).
- OS << ", INVALID, 0, 0";
+ OS << ", INVALID, 0, 0, 0";
// The option help text.
if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
@@ -228,6 +228,21 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
else
OS << "INVALID";
+ // The option alias arguments (if any).
+ // Emitted as a \0 separated list in a string, e.g. ["foo", "bar"]
+ // would become "foo\0bar\0". Note that the compiler adds an implicit
+ // terminating \0 at the end.
+ OS << ", ";
+ std::vector<std::string> AliasArgs = R.getValueAsListOfStrings("AliasArgs");
+ if (AliasArgs.size() == 0) {
+ OS << "0";
+ } else {
+ OS << "\"";
+ for (size_t i = 0, e = AliasArgs.size(); i != e; ++i)
+ OS << AliasArgs[i] << "\\0";
+ OS << "\"";
+ }
+
// The option flags.
const ListInit *LI = R.getValueAsListInit("Flags");
if (LI->empty()) {
diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp
index 2a337f0..731dccf 100644
--- a/utils/TableGen/RegisterInfoEmitter.cpp
+++ b/utils/TableGen/RegisterInfoEmitter.cpp
@@ -223,7 +223,7 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
<< "getRegPressureSetName(unsigned Idx) const {\n"
<< " static const char *PressureNameTable[] = {\n";
for (unsigned i = 0; i < NumSets; ++i ) {
- OS << " \"" << RegBank.getRegPressureSet(i).Name << "\",\n";
+ OS << " \"" << RegBank.getRegSetAt(i).Name << "\",\n";
}
OS << " 0 };\n"
<< " return PressureNameTable[Idx];\n"
@@ -235,9 +235,9 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
<< "getRegPressureSetLimit(unsigned Idx) const {\n"
<< " static const unsigned PressureLimitTable[] = {\n";
for (unsigned i = 0; i < NumSets; ++i ) {
- const RegUnitSet &RegUnits = RegBank.getRegPressureSet(i);
- OS << " " << RegBank.getRegUnitSetWeight(RegUnits.Units)
- << ", \t// " << i << ": " << RegUnits.Name << "\n";
+ const RegUnitSet &RegUnits = RegBank.getRegSetAt(i);
+ OS << " " << RegUnits.Weight << ", \t// " << i << ": "
+ << RegUnits.Name << "\n";
}
OS << " 0 };\n"
<< " return PressureLimitTable[Idx];\n"
@@ -252,9 +252,15 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
for (unsigned i = 0, StartIdx = 0, e = NumRCUnitSets; i != e; ++i) {
RCSetStarts[i] = StartIdx;
ArrayRef<unsigned> PSetIDs = RegBank.getRCPressureSetIDs(i);
+ std::vector<unsigned> PSets;
+ PSets.reserve(PSetIDs.size());
for (ArrayRef<unsigned>::iterator PSetI = PSetIDs.begin(),
PSetE = PSetIDs.end(); PSetI != PSetE; ++PSetI) {
- OS << *PSetI << ", ";
+ PSets.push_back(RegBank.getRegPressureSet(*PSetI).Order);
+ }
+ std::sort(PSets.begin(), PSets.end());
+ for (unsigned j = 0, e = PSets.size(); j < e; ++j) {
+ OS << PSets[j] << ", ";
++StartIdx;
}
OS << "-1, \t// #" << RCSetStarts[i] << " ";
@@ -264,7 +270,7 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,
OS << "inferred";
for (ArrayRef<unsigned>::iterator PSetI = PSetIDs.begin(),
PSetE = PSetIDs.end(); PSetI != PSetE; ++PSetI) {
- OS << "~" << RegBank.getRegPressureSet(*PSetI).Name;
+ OS << "~" << RegBank.getRegSetAt(*PSetI).Name;
}
}
OS << "\n ";
@@ -309,7 +315,7 @@ RegisterInfoEmitter::EmitRegMappingTables(raw_ostream &OS,
const std::vector<CodeGenRegister*> &Regs,
bool isCtor) {
// Collect all information about dwarf register numbers
- typedef std::map<Record*, std::vector<int64_t>, LessRecord> DwarfRegNumsMapTy;
+ typedef std::map<Record*, std::vector<int64_t>, LessRecordRegister> DwarfRegNumsMapTy;
DwarfRegNumsMapTy DwarfRegNums;
// First, just pull all provided information to the map
diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp
index 993eead..81bb6f8 100644
--- a/utils/TableGen/SubtargetEmitter.cpp
+++ b/utils/TableGen/SubtargetEmitter.cpp
@@ -634,16 +634,11 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel,
Record *SuperDef = 0;
unsigned SuperIdx = 0;
unsigned NumUnits = 0;
- bool IsBuffered = true;
+ 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) {
- if (!NumUnits)
- IsBuffered = (*RUI)->getValueAsBit("Buffered");
- else if(IsBuffered != (*RUI)->getValueAsBit("Buffered"))
- PrintFatalError(PRDef->getLoc(),
- "Mixing buffered and unbuffered resources.");
NumUnits += (*RUI)->getValueAsInt("NumUnits");
}
}
@@ -655,7 +650,6 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel,
SuperIdx = ProcModel.getProcResourceIdx(SuperDef);
}
NumUnits = PRDef->getValueAsInt("NumUnits");
- IsBuffered = PRDef->getValueAsBit("Buffered");
}
// Emit the ProcResourceDesc
if (i+1 == e)
@@ -664,7 +658,7 @@ void SubtargetEmitter::EmitProcessorResources(const CodeGenProcModel &ProcModel,
if (PRDef->getName().size() < 15)
OS.indent(15 - PRDef->getName().size());
OS << NumUnits << ", " << SuperIdx << ", "
- << IsBuffered << "}" << Sep << " // #" << i+1;
+ << BufferSize << "}" << Sep << " // #" << i+1;
if (SuperDef)
OS << ", Super=" << SuperDef->getName();
OS << "\n";
@@ -1200,10 +1194,9 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
OS << "\n";
OS << "static const llvm::MCSchedModel " << PI->ModelName << "(\n";
EmitProcessorProp(OS, PI->ModelDef, "IssueWidth", ',');
- EmitProcessorProp(OS, PI->ModelDef, "MinLatency", ',');
+ EmitProcessorProp(OS, PI->ModelDef, "MicroOpBufferSize", ',');
EmitProcessorProp(OS, PI->ModelDef, "LoadLatency", ',');
EmitProcessorProp(OS, PI->ModelDef, "HighLatency", ',');
- EmitProcessorProp(OS, PI->ModelDef, "ILPWindow", ',');
EmitProcessorProp(OS, PI->ModelDef, "MispredictPenalty", ',');
OS << " " << PI->Index << ", // Processor ID\n";
if (PI->hasInstrSchedModel())
diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp
index 40a0c1b..0838ac4 100644
--- a/utils/TableGen/X86DisassemblerTables.cpp
+++ b/utils/TableGen/X86DisassemblerTables.cpp
@@ -81,16 +81,20 @@ static inline bool inheritsFrom(InstructionContext child,
case IC_64BIT_REXW_OPSIZE:
return false;
case IC_VEX:
- return inheritsFrom(child, IC_VEX_W) ||
+ return inheritsFrom(child, IC_VEX_L_W) ||
+ inheritsFrom(child, IC_VEX_W) ||
(VEX_LIG && inheritsFrom(child, IC_VEX_L));
case IC_VEX_XS:
- return inheritsFrom(child, IC_VEX_W_XS) ||
+ return inheritsFrom(child, IC_VEX_L_W_XS) ||
+ inheritsFrom(child, IC_VEX_W_XS) ||
(VEX_LIG && inheritsFrom(child, IC_VEX_L_XS));
case IC_VEX_XD:
- return inheritsFrom(child, IC_VEX_W_XD) ||
+ return inheritsFrom(child, IC_VEX_L_W_XD) ||
+ inheritsFrom(child, IC_VEX_W_XD) ||
(VEX_LIG && inheritsFrom(child, IC_VEX_L_XD));
case IC_VEX_OPSIZE:
- return inheritsFrom(child, IC_VEX_W_OPSIZE) ||
+ return inheritsFrom(child, IC_VEX_L_W_OPSIZE) ||
+ inheritsFrom(child, IC_VEX_W_OPSIZE) ||
(VEX_LIG && inheritsFrom(child, IC_VEX_L_OPSIZE));
case IC_VEX_W:
case IC_VEX_W_XS:
@@ -100,11 +104,90 @@ static inline bool inheritsFrom(InstructionContext child,
case IC_VEX_L:
case IC_VEX_L_XS:
case IC_VEX_L_XD:
- return false;
case IC_VEX_L_OPSIZE:
- return inheritsFrom(child, IC_VEX_L_W_OPSIZE);
+ return false;
+ case IC_VEX_L_W:
+ case IC_VEX_L_W_XS:
+ case IC_VEX_L_W_XD:
case IC_VEX_L_W_OPSIZE:
return false;
+ case IC_EVEX:
+ return inheritsFrom(child, IC_EVEX_W) ||
+ inheritsFrom(child, IC_EVEX_L_W);
+ case IC_EVEX_XS:
+ return inheritsFrom(child, IC_EVEX_W_XS) ||
+ inheritsFrom(child, IC_EVEX_L_W_XS);
+ case IC_EVEX_XD:
+ return inheritsFrom(child, IC_EVEX_W_XD) ||
+ inheritsFrom(child, IC_EVEX_L_W_XD);
+ case IC_EVEX_OPSIZE:
+ return inheritsFrom(child, IC_EVEX_W_OPSIZE) ||
+ inheritsFrom(child, IC_EVEX_W_OPSIZE);
+ case IC_EVEX_W:
+ case IC_EVEX_W_XS:
+ case IC_EVEX_W_XD:
+ case IC_EVEX_W_OPSIZE:
+ return false;
+ case IC_EVEX_L:
+ case IC_EVEX_L_XS:
+ case IC_EVEX_L_XD:
+ case IC_EVEX_L_OPSIZE:
+ return false;
+ case IC_EVEX_L_W:
+ case IC_EVEX_L_W_XS:
+ case IC_EVEX_L_W_XD:
+ case IC_EVEX_L_W_OPSIZE:
+ return false;
+ case IC_EVEX_L2:
+ case IC_EVEX_L2_XS:
+ case IC_EVEX_L2_XD:
+ case IC_EVEX_L2_OPSIZE:
+ return false;
+ case IC_EVEX_L2_W:
+ case IC_EVEX_L2_W_XS:
+ case IC_EVEX_L2_W_XD:
+ case IC_EVEX_L2_W_OPSIZE:
+ return false;
+ case IC_EVEX_K:
+ return inheritsFrom(child, IC_EVEX_W_K) ||
+ inheritsFrom(child, IC_EVEX_L_W_K);
+ case IC_EVEX_XS_K:
+ return inheritsFrom(child, IC_EVEX_W_XS_K) ||
+ inheritsFrom(child, IC_EVEX_L_W_XS_K);
+ case IC_EVEX_XD_K:
+ return inheritsFrom(child, IC_EVEX_W_XD_K) ||
+ inheritsFrom(child, IC_EVEX_L_W_XD_K);
+ case IC_EVEX_OPSIZE_K:
+ return inheritsFrom(child, IC_EVEX_W_OPSIZE_K) ||
+ inheritsFrom(child, IC_EVEX_W_OPSIZE_K);
+ case IC_EVEX_W_K:
+ case IC_EVEX_W_XS_K:
+ case IC_EVEX_W_XD_K:
+ case IC_EVEX_W_OPSIZE_K:
+ return false;
+ case IC_EVEX_L_K:
+ case IC_EVEX_L_XS_K:
+ case IC_EVEX_L_XD_K:
+ case IC_EVEX_L_OPSIZE_K:
+ return false;
+ case IC_EVEX_L_W_K:
+ case IC_EVEX_L_W_XS_K:
+ case IC_EVEX_L_W_XD_K:
+ case IC_EVEX_L_W_OPSIZE_K:
+ return false;
+ case IC_EVEX_L2_K:
+ case IC_EVEX_L2_B:
+ case IC_EVEX_L2_XS_K:
+ case IC_EVEX_L2_XD_K:
+ case IC_EVEX_L2_OPSIZE_K:
+ case IC_EVEX_L2_OPSIZE_B:
+ return false;
+ case IC_EVEX_L2_W_K:
+ case IC_EVEX_L2_W_XS_K:
+ case IC_EVEX_L2_W_XD_K:
+ case IC_EVEX_L2_W_OPSIZE_K:
+ case IC_EVEX_L2_W_OPSIZE_B:
+ return false;
default:
llvm_unreachable("Unknown instruction class");
}
@@ -123,10 +206,13 @@ static inline bool outranks(InstructionContext upper,
assert(lower < IC_max);
#define ENUM_ENTRY(n, r, d) r,
+#define ENUM_ENTRY_K_B(n, r, d) ENUM_ENTRY(n, r, d) \
+ ENUM_ENTRY(n##_K_B, r, d) ENUM_ENTRY(n##_K, r, d) ENUM_ENTRY(n##_B, r, d)
static int ranks[IC_max] = {
INSTRUCTION_CONTEXTS
};
#undef ENUM_ENTRY
+#undef ENUM_ENTRY_K_B
return (ranks[upper] > ranks[lower]);
}
@@ -142,8 +228,11 @@ static inline const char* stringForContext(InstructionContext insnContext) {
default:
llvm_unreachable("Unhandled instruction class");
#define ENUM_ENTRY(n, r, d) case n: return #n; break;
+#define ENUM_ENTRY_K_B(n, r, d) ENUM_ENTRY(n, r, d) ENUM_ENTRY(n##_K_B, r, d)\
+ ENUM_ENTRY(n##_K, r, d) ENUM_ENTRY(n##_B, r, d)
INSTRUCTION_CONTEXTS
#undef ENUM_ENTRY
+#undef ENUM_ENTRY_K_B
}
}
diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp
index 46f2052..7962f9b 100644
--- a/utils/TableGen/X86RecognizableInstr.cpp
+++ b/utils/TableGen/X86RecognizableInstr.cpp
@@ -236,6 +236,10 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables,
HasVEX_WPrefix = Rec->getValueAsBit("hasVEX_WPrefix");
HasMemOp4Prefix = Rec->getValueAsBit("hasMemOp4Prefix");
IgnoresVEX_L = Rec->getValueAsBit("ignoresVEX_L");
+ HasEVEXPrefix = Rec->getValueAsBit("hasEVEXPrefix");
+ HasEVEX_L2Prefix = Rec->getValueAsBit("hasEVEX_L2");
+ HasEVEX_K = Rec->getValueAsBit("hasEVEX_K");
+ HasEVEX_B = Rec->getValueAsBit("hasEVEX_B");
HasLockPrefix = Rec->getValueAsBit("hasLockPrefix");
IsCodeGenOnly = Rec->getValueAsBit("isCodeGenOnly");
@@ -295,15 +299,97 @@ void RecognizableInstr::processInstr(DisassemblerTables &tables,
recogInstr.emitDecodePath(tables);
}
+#define EVEX_KB(n) (HasEVEX_K && HasEVEX_B? n##_K_B : \
+ (HasEVEX_K? n##_K : (HasEVEX_B ? n##_B : n)))
+
InstructionContext RecognizableInstr::insnContext() const {
InstructionContext insnContext;
- if (HasVEX_4VPrefix || HasVEX_4VOp3Prefix|| HasVEXPrefix) {
+ if (HasEVEXPrefix) {
+ if (HasVEX_LPrefix && HasEVEX_L2Prefix) {
+ errs() << "Don't support VEX.L if EVEX_L2 is enabled: " << Name << "\n";
+ llvm_unreachable("Don't support VEX.L if EVEX_L2 is enabled");
+ }
+ // VEX_L & VEX_W
+ if (HasVEX_LPrefix && HasVEX_WPrefix) {
+ if (HasOpSizePrefix)
+ insnContext = EVEX_KB(IC_EVEX_L_W_OPSIZE);
+ else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
+ insnContext = EVEX_KB(IC_EVEX_L_W_XS);
+ else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
+ Prefix == X86Local::TAXD)
+ insnContext = EVEX_KB(IC_EVEX_L_W_XD);
+ else
+ insnContext = EVEX_KB(IC_EVEX_L_W);
+ } else if (HasVEX_LPrefix) {
+ // VEX_L
+ if (HasOpSizePrefix)
+ insnContext = EVEX_KB(IC_EVEX_L_OPSIZE);
+ else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
+ insnContext = EVEX_KB(IC_EVEX_L_XS);
+ else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
+ Prefix == X86Local::TAXD)
+ insnContext = EVEX_KB(IC_EVEX_L_XD);
+ else
+ insnContext = EVEX_KB(IC_EVEX_L);
+ }
+ else if (HasEVEX_L2Prefix && HasVEX_WPrefix) {
+ // EVEX_L2 & VEX_W
+ if (HasOpSizePrefix)
+ insnContext = EVEX_KB(IC_EVEX_L2_W_OPSIZE);
+ else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
+ insnContext = EVEX_KB(IC_EVEX_L2_W_XS);
+ else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
+ Prefix == X86Local::TAXD)
+ insnContext = EVEX_KB(IC_EVEX_L2_W_XD);
+ else
+ insnContext = EVEX_KB(IC_EVEX_L2_W);
+ } else if (HasEVEX_L2Prefix) {
+ // EVEX_L2
+ if (HasOpSizePrefix)
+ insnContext = EVEX_KB(IC_EVEX_L2_OPSIZE);
+ else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
+ Prefix == X86Local::TAXD)
+ insnContext = EVEX_KB(IC_EVEX_L2_XD);
+ else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
+ insnContext = EVEX_KB(IC_EVEX_L2_XS);
+ else
+ insnContext = EVEX_KB(IC_EVEX_L2);
+ }
+ else if (HasVEX_WPrefix) {
+ // VEX_W
+ if (HasOpSizePrefix)
+ insnContext = EVEX_KB(IC_EVEX_W_OPSIZE);
+ else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
+ insnContext = EVEX_KB(IC_EVEX_W_XS);
+ else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
+ Prefix == X86Local::TAXD)
+ insnContext = EVEX_KB(IC_EVEX_W_XD);
+ else
+ insnContext = EVEX_KB(IC_EVEX_W);
+ }
+ // No L, no W
+ else if (HasOpSizePrefix)
+ insnContext = EVEX_KB(IC_EVEX_OPSIZE);
+ else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
+ Prefix == X86Local::TAXD)
+ insnContext = EVEX_KB(IC_EVEX_XD);
+ else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
+ insnContext = EVEX_KB(IC_EVEX_XS);
+ else
+ insnContext = EVEX_KB(IC_EVEX);
+ /// eof EVEX
+ } else if (HasVEX_4VPrefix || HasVEX_4VOp3Prefix|| HasVEXPrefix) {
if (HasVEX_LPrefix && HasVEX_WPrefix) {
if (HasOpSizePrefix)
insnContext = IC_VEX_L_W_OPSIZE;
+ else if (Prefix == X86Local::XS || Prefix == X86Local::T8XS)
+ insnContext = IC_VEX_L_W_XS;
+ else if (Prefix == X86Local::XD || Prefix == X86Local::T8XD ||
+ Prefix == X86Local::TAXD)
+ insnContext = IC_VEX_L_W_XD;
else
- llvm_unreachable("Don't support VEX.L and VEX.W together");
+ insnContext = IC_VEX_L_W;
} else if (HasOpSizePrefix && HasVEX_LPrefix)
insnContext = IC_VEX_L_OPSIZE;
else if (HasOpSizePrefix && HasVEX_WPrefix)
@@ -461,6 +547,12 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const {
Name == "VMOVQs64rr")
return FILTER_WEAK;
+ // XACQUIRE and XRELEASE reuse REPNE and REP respectively.
+ // For now, just prefer the REP versions.
+ if (Name == "XACQUIRE_PREFIX" ||
+ Name == "XRELEASE_PREFIX")
+ return FILTER_WEAK;
+
if (HasFROperands && Name.find("MOV") != Name.npos &&
((Name.find("2") != Name.npos && Name.find("32") == Name.npos) ||
(Name.find("to") != Name.npos)))
@@ -635,6 +727,9 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
"Unexpected number of operands for MRMDestMemFrm");
HANDLE_OPERAND(memory)
+ if (HasEVEX_K)
+ HANDLE_OPERAND(writemaskRegister)
+
if (HasVEX_4VPrefix)
// FIXME: In AVX, the register below becomes the one encoded
// in ModRMVEX and the one above the one in the VEX.VVVV field
@@ -659,6 +754,9 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
HANDLE_OPERAND(roRegister)
+ if (HasEVEX_K)
+ HANDLE_OPERAND(writemaskRegister)
+
if (HasVEX_4VPrefix)
// FIXME: In AVX, the register below becomes the one encoded
// in ModRMVEX and the one above the one in the VEX.VVVV field
@@ -692,6 +790,9 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
HANDLE_OPERAND(roRegister)
+ if (HasEVEX_K)
+ HANDLE_OPERAND(writemaskRegister)
+
if (HasVEX_4VPrefix)
// FIXME: In AVX, the register below becomes the one encoded
// in ModRMVEX and the one above the one in the VEX.VVVV field
@@ -1073,17 +1174,22 @@ OperandType RecognizableInstr::typeFromString(const std::string &s,
TYPE("i8imm", TYPE_IMM8)
TYPE("GR8", TYPE_R8)
TYPE("VR128", TYPE_XMM128)
+ TYPE("VR128X", TYPE_XMM128)
TYPE("f128mem", TYPE_M128)
TYPE("f256mem", TYPE_M256)
+ TYPE("f512mem", TYPE_M512)
TYPE("FR64", TYPE_XMM64)
+ TYPE("FR64X", TYPE_XMM64)
TYPE("f64mem", TYPE_M64FP)
TYPE("sdmem", TYPE_M64FP)
TYPE("FR32", TYPE_XMM32)
+ TYPE("FR32X", TYPE_XMM32)
TYPE("f32mem", TYPE_M32FP)
TYPE("ssmem", TYPE_M32FP)
TYPE("RST", TYPE_ST)
TYPE("i128mem", TYPE_M128)
TYPE("i256mem", TYPE_M256)
+ TYPE("i512mem", TYPE_M512)
TYPE("i64i32imm_pcrel", TYPE_REL64)
TYPE("i16imm_pcrel", TYPE_REL16)
TYPE("i32imm_pcrel", TYPE_REL32)
@@ -1110,13 +1216,22 @@ OperandType RecognizableInstr::typeFromString(const std::string &s,
TYPE("offset32", TYPE_MOFFS32)
TYPE("offset64", TYPE_MOFFS64)
TYPE("VR256", TYPE_XMM256)
+ TYPE("VR256X", TYPE_XMM256)
+ TYPE("VR512", TYPE_XMM512)
+ TYPE("VK8", TYPE_VK8)
+ TYPE("VK8WM", TYPE_VK8)
+ TYPE("VK16", TYPE_VK16)
+ TYPE("VK16WM", TYPE_VK16)
TYPE("GR16_NOAX", TYPE_Rv)
TYPE("GR32_NOAX", TYPE_Rv)
TYPE("GR64_NOAX", TYPE_R64)
TYPE("vx32mem", TYPE_M32)
TYPE("vy32mem", TYPE_M32)
+ TYPE("vz32mem", TYPE_M32)
TYPE("vx64mem", TYPE_M64)
TYPE("vy64mem", TYPE_M64)
+ TYPE("vy64xmem", TYPE_M64)
+ TYPE("vz64mem", TYPE_M64)
errs() << "Unhandled type string " << s << "\n";
llvm_unreachable("Unhandled type string");
}
@@ -1143,10 +1258,15 @@ OperandEncoding RecognizableInstr::immediateEncodingFromString
ENCODING("i8imm", ENCODING_IB)
// This is not a typo. Instructions like BLENDVPD put
// register IDs in 8-bit immediates nowadays.
- ENCODING("VR256", ENCODING_IB)
- ENCODING("VR128", ENCODING_IB)
ENCODING("FR32", ENCODING_IB)
ENCODING("FR64", ENCODING_IB)
+ ENCODING("VR128", ENCODING_IB)
+ ENCODING("VR256", ENCODING_IB)
+ ENCODING("FR32X", ENCODING_IB)
+ ENCODING("FR64X", ENCODING_IB)
+ ENCODING("VR128X", ENCODING_IB)
+ ENCODING("VR256X", ENCODING_IB)
+ ENCODING("VR512", ENCODING_IB)
errs() << "Unhandled immediate encoding " << s << "\n";
llvm_unreachable("Unhandled immediate encoding");
}
@@ -1159,10 +1279,17 @@ OperandEncoding RecognizableInstr::rmRegisterEncodingFromString
ENCODING("GR64", ENCODING_RM)
ENCODING("GR8", ENCODING_RM)
ENCODING("VR128", ENCODING_RM)
+ ENCODING("VR128X", ENCODING_RM)
ENCODING("FR64", ENCODING_RM)
ENCODING("FR32", ENCODING_RM)
+ ENCODING("FR64X", ENCODING_RM)
+ ENCODING("FR32X", ENCODING_RM)
ENCODING("VR64", ENCODING_RM)
ENCODING("VR256", ENCODING_RM)
+ ENCODING("VR256X", ENCODING_RM)
+ ENCODING("VR512", ENCODING_RM)
+ ENCODING("VK8", ENCODING_RM)
+ ENCODING("VK16", ENCODING_RM)
errs() << "Unhandled R/M register encoding " << s << "\n";
llvm_unreachable("Unhandled R/M register encoding");
}
@@ -1182,6 +1309,15 @@ OperandEncoding RecognizableInstr::roRegisterEncodingFromString
ENCODING("DEBUG_REG", ENCODING_REG)
ENCODING("CONTROL_REG", ENCODING_REG)
ENCODING("VR256", ENCODING_REG)
+ ENCODING("VR256X", ENCODING_REG)
+ ENCODING("VR128X", ENCODING_REG)
+ ENCODING("FR64X", ENCODING_REG)
+ ENCODING("FR32X", ENCODING_REG)
+ ENCODING("VR512", ENCODING_REG)
+ ENCODING("VK8", ENCODING_REG)
+ ENCODING("VK16", ENCODING_REG)
+ ENCODING("VK8WM", ENCODING_REG)
+ ENCODING("VK16WM", ENCODING_REG)
errs() << "Unhandled reg/opcode register encoding " << s << "\n";
llvm_unreachable("Unhandled reg/opcode register encoding");
}
@@ -1195,10 +1331,26 @@ OperandEncoding RecognizableInstr::vvvvRegisterEncodingFromString
ENCODING("FR64", ENCODING_VVVV)
ENCODING("VR128", ENCODING_VVVV)
ENCODING("VR256", ENCODING_VVVV)
+ ENCODING("FR32X", ENCODING_VVVV)
+ ENCODING("FR64X", ENCODING_VVVV)
+ ENCODING("VR128X", ENCODING_VVVV)
+ ENCODING("VR256X", ENCODING_VVVV)
+ ENCODING("VR512", ENCODING_VVVV)
+ ENCODING("VK8", ENCODING_VVVV)
+ ENCODING("VK16", ENCODING_VVVV)
errs() << "Unhandled VEX.vvvv register encoding " << s << "\n";
llvm_unreachable("Unhandled VEX.vvvv register encoding");
}
+OperandEncoding RecognizableInstr::writemaskRegisterEncodingFromString
+ (const std::string &s,
+ bool hasOpSizePrefix) {
+ ENCODING("VK8WM", ENCODING_WRITEMASK)
+ ENCODING("VK16WM", ENCODING_WRITEMASK)
+ errs() << "Unhandled mask register encoding " << s << "\n";
+ llvm_unreachable("Unhandled mask register encoding");
+}
+
OperandEncoding RecognizableInstr::memoryEncodingFromString
(const std::string &s,
bool hasOpSizePrefix) {
@@ -1210,10 +1362,12 @@ OperandEncoding RecognizableInstr::memoryEncodingFromString
ENCODING("sdmem", ENCODING_RM)
ENCODING("f128mem", ENCODING_RM)
ENCODING("f256mem", ENCODING_RM)
+ ENCODING("f512mem", ENCODING_RM)
ENCODING("f64mem", ENCODING_RM)
ENCODING("f32mem", ENCODING_RM)
ENCODING("i128mem", ENCODING_RM)
ENCODING("i256mem", ENCODING_RM)
+ ENCODING("i512mem", ENCODING_RM)
ENCODING("f80mem", ENCODING_RM)
ENCODING("lea32mem", ENCODING_RM)
ENCODING("lea64_32mem", ENCODING_RM)
@@ -1224,8 +1378,11 @@ OperandEncoding RecognizableInstr::memoryEncodingFromString
ENCODING("opaque512mem", ENCODING_RM)
ENCODING("vx32mem", ENCODING_RM)
ENCODING("vy32mem", ENCODING_RM)
+ ENCODING("vz32mem", ENCODING_RM)
ENCODING("vx64mem", ENCODING_RM)
ENCODING("vy64mem", ENCODING_RM)
+ ENCODING("vy64xmem", ENCODING_RM)
+ ENCODING("vz64mem", ENCODING_RM)
errs() << "Unhandled memory encoding " << s << "\n";
llvm_unreachable("Unhandled memory encoding");
}
diff --git a/utils/TableGen/X86RecognizableInstr.h b/utils/TableGen/X86RecognizableInstr.h
index 9ec36a3..7e1d362 100644
--- a/utils/TableGen/X86RecognizableInstr.h
+++ b/utils/TableGen/X86RecognizableInstr.h
@@ -66,6 +66,14 @@ private:
bool HasMemOp4Prefix;
/// The ignoreVEX_L field from the record
bool IgnoresVEX_L;
+ /// The hasEVEXPrefix field from the record
+ bool HasEVEXPrefix;
+ /// The hasEVEX_L2Prefix field from the record
+ bool HasEVEX_L2Prefix;
+ /// The hasEVEX_K field from the record
+ bool HasEVEX_K;
+ /// The hasEVEX_B field from the record
+ bool HasEVEX_B;
/// The hasLockPrefix field from the record
bool HasLockPrefix;
/// The isCodeGenOnly filed from the record
@@ -176,6 +184,8 @@ private:
bool hasOpSizePrefix);
static OperandEncoding vvvvRegisterEncodingFromString(const std::string &s,
bool HasOpSizePrefix);
+ static OperandEncoding writemaskRegisterEncodingFromString(const std::string &s,
+ bool HasOpSizePrefix);
/// handleOperand - Converts a single operand from the LLVM table format to
/// the emitted table format, handling any duplicate operands it encounters
diff --git a/utils/buildit/build_llvm b/utils/buildit/build_llvm
index c056b97..4ed25f2 100755
--- a/utils/buildit/build_llvm
+++ b/utils/buildit/build_llvm
@@ -103,7 +103,8 @@ COMMON_CONFIGURE_OPTS="\
--prefix=$DEST_DIR$DEST_ROOT \
--enable-assertions=$LLVM_ASSERTIONS \
--enable-optimized=$LLVM_OPTIMIZED \
- --disable-bindings"
+ --disable-bindings \
+ --disable-zlib"
COMMON_MAKEFLAGS="\
UNIVERSAL=1 \
diff --git a/utils/fpcmp/fpcmp.cpp b/utils/fpcmp/fpcmp.cpp
index 5f6b5e8..bbe7276 100644
--- a/utils/fpcmp/fpcmp.cpp
+++ b/utils/fpcmp/fpcmp.cpp
@@ -33,9 +33,8 @@ int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv);
std::string ErrorMsg;
- int DF = DiffFilesWithTolerance(sys::PathWithStatus(File1),
- sys::PathWithStatus(File2),
- AbsTolerance, RelTolerance, &ErrorMsg);
+ int DF = DiffFilesWithTolerance(File1, File2, AbsTolerance, RelTolerance,
+ &ErrorMsg);
if (!ErrorMsg.empty())
errs() << argv[0] << ": " << ErrorMsg << "\n";
return DF;
diff --git a/utils/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py
index 9bcf20b..bd7a603 100644
--- a/utils/lit/lit/LitConfig.py
+++ b/utils/lit/lit/LitConfig.py
@@ -1,3 +1,11 @@
+from __future__ import absolute_import
+import os
+
+import lit.Test
+import lit.TestFormats
+import lit.TestingConfig
+import lit.Util
+
class LitConfig:
"""LitConfig - Configuration data for a 'lit' test runner instance, shared
across all tests.
@@ -9,17 +17,17 @@ class LitConfig:
"""
# Provide access to Test module.
- import Test
+ Test = lit.Test
# Provide access to built-in formats.
- import TestFormats as formats
+ formats = lit.TestFormats
# Provide access to built-in utility functions.
- import Util as util
+ util = lit.Util
def __init__(self, progname, path, quiet,
useValgrind, valgrindLeakCheck, valgrindArgs,
- noExecute, ignoreStdErr, debug, isWindows,
+ noExecute, debug, isWindows,
params, config_prefix = None):
# The name of the test runner.
self.progname = progname
@@ -30,7 +38,6 @@ class LitConfig:
self.valgrindLeakCheck = bool(valgrindLeakCheck)
self.valgrindUserArgs = list(valgrindArgs)
self.noExecute = noExecute
- self.ignoreStdErr = ignoreStdErr
self.debug = debug
self.isWindows = bool(isWindows)
self.params = dict(params)
@@ -61,21 +68,19 @@ class LitConfig:
def load_config(self, config, path):
"""load_config(config, path) - Load a config object from an alternate
path."""
- from TestingConfig import TestingConfig
if self.debug:
self.note('load_config from %r' % path)
- return TestingConfig.frompath(path, config.parent, self,
- mustExist = True,
- config = config)
+ return lit.TestingConfig.TestingConfig.frompath(
+ path, config.parent, self, mustExist = True, config = config)
def getBashPath(self):
"""getBashPath - Get the path to 'bash'"""
- import os, Util
+ import os
if self.bashPath is not None:
return self.bashPath
- self.bashPath = Util.which('bash', os.pathsep.join(self.path))
+ self.bashPath = lit.Util.which('bash', os.pathsep.join(self.path))
if self.bashPath is None:
# Check some known paths.
for path in ('/bin/bash', '/usr/bin/bash', '/usr/local/bin/bash'):
@@ -90,15 +95,14 @@ class LitConfig:
return self.bashPath
def getToolsPath(self, dir, paths, tools):
- import os, Util
if dir is not None and os.path.isabs(dir) and os.path.isdir(dir):
- if not Util.checkToolsPath(dir, tools):
+ if not lit.Util.checkToolsPath(dir, tools):
return None
else:
- dir = Util.whichTools(tools, paths)
+ dir = lit.Util.whichTools(tools, paths)
# bash
- self.bashPath = Util.which('bash', dir)
+ self.bashPath = lit.Util.which('bash', dir)
if self.bashPath is None:
self.note("Unable to find 'bash.exe'.")
self.bashPath = ''
@@ -115,8 +119,8 @@ class LitConfig:
file,line,_,_,_ = inspect.getframeinfo(f)
location = '%s:%d' % (os.path.basename(file), line)
- print >>sys.stderr, '%s: %s: %s: %s' % (self.progname, location,
- kind, message)
+ sys.stderr.write('%s: %s: %s: %s\n' % (self.progname, location,
+ kind, message))
def note(self, message):
self._write_message('note', message)
diff --git a/utils/lit/lit/ProgressBar.py b/utils/lit/lit/ProgressBar.py
index 5c85a17..0454ba2 100644
--- a/utils/lit/lit/ProgressBar.py
+++ b/utils/lit/lit/ProgressBar.py
@@ -16,13 +16,13 @@ class TerminalController:
output to the terminal:
>>> term = TerminalController()
- >>> print 'This is '+term.GREEN+'green'+term.NORMAL
+ >>> print('This is '+term.GREEN+'green'+term.NORMAL)
Alternatively, the `render()` method can used, which replaces
'${action}' with the string required to perform 'action':
>>> term = TerminalController()
- >>> print term.render('This is ${GREEN}green${NORMAL}')
+ >>> print(term.render('This is ${GREEN}green${NORMAL}'))
If the terminal doesn't support a given action, then the value of
the corresponding instance variable will be set to ''. As a
@@ -34,7 +34,7 @@ class TerminalController:
>>> term = TerminalController()
>>> if term.CLEAR_SCREEN:
- ... print 'This terminal supports clearning the screen.'
+ ... print('This terminal supports clearning the screen.')
Finally, if the width and height of the terminal are known, then
they will be stored in the `COLS` and `LINES` attributes.
diff --git a/utils/lit/lit/ShCommands.py b/utils/lit/lit/ShCommands.py
index 4550437..9ca9e8c 100644
--- a/utils/lit/lit/ShCommands.py
+++ b/utils/lit/lit/ShCommands.py
@@ -6,12 +6,12 @@ class Command:
def __repr__(self):
return 'Command(%r, %r)' % (self.args, self.redirects)
- def __cmp__(self, other):
+ def __eq__(self, other):
if not isinstance(other, Command):
- return -1
+ return False
- return cmp((self.args, self.redirects),
- (other.args, other.redirects))
+ return ((self.args, self.redirects) ==
+ (other.args, other.redirects))
def toShell(self, file):
for arg in self.args:
@@ -20,20 +20,20 @@ class Command:
elif '"' not in arg and '$' not in arg:
quoted = '"%s"' % arg
else:
- raise NotImplementedError,'Unable to quote %r' % arg
- print >>file, quoted,
+ raise NotImplementedError('Unable to quote %r' % arg)
+ file.write(quoted)
# For debugging / validation.
import ShUtil
dequoted = list(ShUtil.ShLexer(quoted).lex())
if dequoted != [arg]:
- raise NotImplementedError,'Unable to quote %r' % arg
+ raise NotImplementedError('Unable to quote %r' % arg)
for r in self.redirects:
if len(r[0]) == 1:
- print >>file, "%s '%s'" % (r[0][0], r[1]),
+ file.write("%s '%s'" % (r[0][0], r[1]))
else:
- print >>file, "%s%s '%s'" % (r[0][1], r[0][0], r[1]),
+ file.write("%s%s '%s'" % (r[0][1], r[0][0], r[1]))
class Pipeline:
def __init__(self, commands, negate=False, pipe_err=False):
@@ -45,22 +45,22 @@ class Pipeline:
return 'Pipeline(%r, %r, %r)' % (self.commands, self.negate,
self.pipe_err)
- def __cmp__(self, other):
+ def __eq__(self, other):
if not isinstance(other, Pipeline):
- return -1
+ return False
- return cmp((self.commands, self.negate, self.pipe_err),
- (other.commands, other.negate, self.pipe_err))
+ return ((self.commands, self.negate, self.pipe_err) ==
+ (other.commands, other.negate, self.pipe_err))
def toShell(self, file, pipefail=False):
if pipefail != self.pipe_err:
- raise ValueError,'Inconsistent "pipefail" attribute!'
+ raise ValueError('Inconsistent "pipefail" attribute!')
if self.negate:
- print >>file, '!',
+ file.write('! ')
for cmd in self.commands:
cmd.toShell(file)
if cmd is not self.commands[-1]:
- print >>file, '|\n ',
+ file.write('|\n ')
class Seq:
def __init__(self, lhs, op, rhs):
@@ -72,14 +72,14 @@ class Seq:
def __repr__(self):
return 'Seq(%r, %r, %r)' % (self.lhs, self.op, self.rhs)
- def __cmp__(self, other):
+ def __eq__(self, other):
if not isinstance(other, Seq):
- return -1
+ return False
- return cmp((self.lhs, self.op, self.rhs),
- (other.lhs, other.op, other.rhs))
+ return ((self.lhs, self.op, self.rhs) ==
+ (other.lhs, other.op, other.rhs))
def toShell(self, file, pipefail=False):
self.lhs.toShell(file, pipefail)
- print >>file, ' %s\n' % self.op
+ file.write(' %s\n' % self.op)
self.rhs.toShell(file, pipefail)
diff --git a/utils/lit/lit/ShUtil.py b/utils/lit/lit/ShUtil.py
index 50f7910..fb0689b 100644
--- a/utils/lit/lit/ShUtil.py
+++ b/utils/lit/lit/ShUtil.py
@@ -1,7 +1,8 @@
+from __future__ import absolute_import
import itertools
-import Util
-from ShCommands import Command, Pipeline, Seq
+import lit.Util
+from lit.ShCommands import Command, Pipeline, Seq
class ShLexer:
def __init__(self, data, win32Escapes = False):
@@ -74,8 +75,8 @@ class ShLexer:
# Outside of a string, '\\' escapes everything.
self.eat()
if self.pos == self.end:
- Util.warning("escape at end of quoted argument in: %r" %
- self.data)
+ lit.Util.warning(
+ "escape at end of quoted argument in: %r" % self.data)
return str
str += self.eat()
else:
@@ -92,8 +93,8 @@ class ShLexer:
# Inside a '"' quoted string, '\\' only escapes the quote
# character and backslash, otherwise it is preserved.
if self.pos == self.end:
- Util.warning("escape at end of quoted argument in: %r" %
- self.data)
+ lit.Util.warning(
+ "escape at end of quoted argument in: %r" % self.data)
return str
c = self.eat()
if c == '"': #
@@ -104,7 +105,7 @@ class ShLexer:
str += '\\' + c
else:
str += c
- Util.warning("missing quote character in %r" % self.data)
+ lit.Util.warning("missing quote character in %r" % self.data)
return str
def lex_arg_checked(self, c):
@@ -116,9 +117,11 @@ class ShLexer:
reference = self.lex_arg_slow(c)
if res is not None:
if res != reference:
- raise ValueError,"Fast path failure: %r != %r" % (res, reference)
+ raise ValueError("Fast path failure: %r != %r" % (
+ res, reference))
if self.pos != end:
- raise ValueError,"Fast path failure: %r != %r" % (self.pos, end)
+ raise ValueError("Fast path failure: %r != %r" % (
+ self.pos, end))
return reference
def lex_arg(self, c):
@@ -166,28 +169,28 @@ class ShLexer:
###
class ShParser:
- def __init__(self, data, win32Escapes = False):
+ def __init__(self, data, win32Escapes = False, pipefail = False):
self.data = data
+ self.pipefail = pipefail
self.tokens = ShLexer(data, win32Escapes = win32Escapes).lex()
def lex(self):
- try:
- return self.tokens.next()
- except StopIteration:
- return None
+ for item in self.tokens:
+ return item
+ return None
def look(self):
- next = self.lex()
- if next is not None:
- self.tokens = itertools.chain([next], self.tokens)
- return next
+ token = self.lex()
+ if token is not None:
+ self.tokens = itertools.chain([token], self.tokens)
+ return token
def parse_command(self):
tok = self.lex()
if not tok:
- raise ValueError,"empty command!"
+ raise ValueError("empty command!")
if isinstance(tok, tuple):
- raise ValueError,"syntax error near unexpected token %r" % tok[0]
+ raise ValueError("syntax error near unexpected token %r" % tok[0])
args = [tok]
redirects = []
@@ -212,7 +215,7 @@ class ShParser:
op = self.lex()
arg = self.lex()
if not arg:
- raise ValueError,"syntax error near token %r" % op[0]
+ raise ValueError("syntax error near token %r" % op[0])
redirects.append((op, arg))
return Command(args, redirects)
@@ -224,7 +227,7 @@ class ShParser:
while self.look() == ('|',):
self.lex()
commands.append(self.parse_command())
- return Pipeline(commands, negate)
+ return Pipeline(commands, negate, self.pipefail)
def parse(self):
lhs = self.parse_pipeline()
@@ -234,7 +237,8 @@ class ShParser:
assert isinstance(operator, tuple) and len(operator) == 1
if not self.look():
- raise ValueError, "missing argument to operator %r" % operator[0]
+ raise ValueError(
+ "missing argument to operator %r" % operator[0])
# FIXME: Operator precedence!!
lhs = Seq(lhs, operator[0], self.parse_pipeline())
diff --git a/utils/lit/lit/TestFormats.py b/utils/lit/lit/TestFormats.py
index 27085b9..9e0c7a0 100644
--- a/utils/lit/lit/TestFormats.py
+++ b/utils/lit/lit/TestFormats.py
@@ -1,9 +1,10 @@
+from __future__ import absolute_import
import os
import sys
-import Test
-import TestRunner
-import Util
+import lit.Test
+import lit.TestRunner
+import lit.Util
kIsWindows = sys.platform in ['win32', 'cygwin']
@@ -27,8 +28,8 @@ class GoogleTest(object):
localConfig: TestingConfig instance"""
try:
- lines = Util.capture([path, '--gtest_list_tests'],
- env=localConfig.environment)
+ lines = lit.Util.capture([path, '--gtest_list_tests'],
+ env=localConfig.environment)
if kIsWindows:
lines = lines.replace('\r', '')
lines = lines.split('\n')
@@ -63,7 +64,7 @@ class GoogleTest(object):
# Discover the tests in this executable.
for testname in self.getGTestTests(execpath, litConfig, localConfig):
testPath = path_in_suite + (basename, testname)
- yield Test.Test(testSuite, testPath, localConfig)
+ yield lit.Test.Test(testSuite, testPath, localConfig)
def getTestsInDirectory(self, testSuite, path_in_suite,
litConfig, localConfig):
@@ -100,15 +101,15 @@ class GoogleTest(object):
cmd = litConfig.valgrindArgs + cmd
if litConfig.noExecute:
- return Test.PASS, ''
+ return lit.Test.PASS, ''
- out, err, exitCode = TestRunner.executeCommand(
+ out, err, exitCode = lit.TestRunner.executeCommand(
cmd, env=test.config.environment)
if not exitCode:
- return Test.PASS,''
+ return lit.Test.PASS,''
- return Test.FAIL, out + err
+ return lit.Test.FAIL, out + err
###
@@ -126,16 +127,16 @@ class FileBasedTest(object):
if not os.path.isdir(filepath):
base,ext = os.path.splitext(filename)
if ext in localConfig.suffixes:
- yield Test.Test(testSuite, path_in_suite + (filename,),
- localConfig)
+ yield lit.Test.Test(testSuite, path_in_suite + (filename,),
+ localConfig)
class ShTest(FileBasedTest):
def __init__(self, execute_external = False):
self.execute_external = execute_external
def execute(self, test, litConfig):
- return TestRunner.executeShTest(test, litConfig,
- self.execute_external)
+ return lit.TestRunner.executeShTest(test, litConfig,
+ self.execute_external)
###
@@ -183,9 +184,9 @@ class OneCommandPerFileTest:
suffix = path[len(dir):]
if suffix.startswith(os.sep):
suffix = suffix[1:]
- test = Test.Test(testSuite,
- path_in_suite + tuple(suffix.split(os.sep)),
- localConfig)
+ test = lit.Test.Test(
+ testSuite, path_in_suite + tuple(suffix.split(os.sep)),
+ localConfig)
# FIXME: Hack?
test.source_path = path
yield test
@@ -195,7 +196,7 @@ class OneCommandPerFileTest:
def execute(self, test, litConfig):
if test.config.unsupported:
- return (Test.UNSUPPORTED, 'Test is unsupported')
+ return (lit.Test.UNSUPPORTED, 'Test is unsupported')
cmd = list(self.command)
@@ -211,11 +212,11 @@ class OneCommandPerFileTest:
else:
cmd.append(test.getSourcePath())
- out, err, exitCode = TestRunner.executeCommand(cmd)
+ out, err, exitCode = lit.TestRunner.executeCommand(cmd)
diags = out + err
if not exitCode and not diags.strip():
- return Test.PASS,''
+ return lit.Test.PASS,''
# Try to include some useful information.
report = """Command: %s\n""" % ' '.join(["'%s'" % a
@@ -225,4 +226,4 @@ class OneCommandPerFileTest:
report += "--\n%s--\n""" % open(tmp.name).read()
report += """Output:\n--\n%s--""" % diags
- return Test.FAIL, report
+ return lit.Test.FAIL, report
diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py
index 8417699..989a992 100644
--- a/utils/lit/lit/TestRunner.py
+++ b/utils/lit/lit/TestRunner.py
@@ -1,14 +1,16 @@
+from __future__ import absolute_import
import os, signal, subprocess, sys
-import StringIO
-
-import ShUtil
-import Test
-import Util
-
+import re
import platform
import tempfile
+try:
+ from io import StringIO
+except ImportError:
+ from StringIO import StringIO
-import re
+import lit.ShUtil as ShUtil
+import lit.Test as Test
+import lit.Util as Util
class InternalShellError(Exception):
def __init__(self, command, message):
@@ -66,7 +68,7 @@ def executeShCmd(cmd, cfg, cwd, results):
res = executeShCmd(cmd.rhs, cfg, cwd, results)
return res
- raise ValueError,'Unknown shell command: %r' % cmd.op
+ raise ValueError('Unknown shell command: %r' % cmd.op)
assert isinstance(cmd, ShUtil.Pipeline)
procs = []
@@ -245,7 +247,8 @@ def executeScriptInternal(test, litConfig, tmpBase, commands, cwd):
cmds = []
for ln in commands:
try:
- cmds.append(ShUtil.ShParser(ln, litConfig.isWindows).parse())
+ cmds.append(ShUtil.ShParser(ln, litConfig.isWindows,
+ test.config.pipefail).parse())
except:
return (Test.FAIL, "shell parser error on: %r" % ln)
@@ -256,7 +259,8 @@ def executeScriptInternal(test, litConfig, tmpBase, commands, cwd):
results = []
try:
exitCode = executeShCmd(cmd, test.config, cwd, results)
- except InternalShellError,e:
+ except InternalShellError:
+ e = sys.exc_info()[1]
exitCode = 127
results.append((e.command, '', e.message, exitCode))
@@ -284,6 +288,8 @@ def executeScript(test, litConfig, tmpBase, commands, cwd):
if isWin32CMDEXE:
f.write('\nif %ERRORLEVEL% NEQ 0 EXIT\n'.join(commands))
else:
+ if test.config.pipefail:
+ f.write('set -o pipefail;')
f.write('{ ' + '; } &&\n{ '.join(commands) + '; }')
f.write('\n')
f.close()
@@ -432,23 +438,22 @@ def parseIntegratedTestScript(test, normalize_slashes=False,
return script,isXFail,tmpBase,execdir
def formatTestOutput(status, out, err, exitCode, script):
- output = StringIO.StringIO()
- print >>output, "Script:"
- print >>output, "--"
- print >>output, '\n'.join(script)
- print >>output, "--"
- print >>output, "Exit Code: %r" % exitCode,
- print >>output
+ output = StringIO()
+ output.write(u"Script:\n")
+ output.write(u"--\n")
+ output.write(u'\n'.join(script))
+ output.write(u"\n--\n")
+ output.write(u"Exit Code: %r\n\n" % exitCode)
if out:
- print >>output, "Command Output (stdout):"
- print >>output, "--"
- output.write(out)
- print >>output, "--"
+ output.write(u"Command Output (stdout):\n")
+ output.write(u"--\n")
+ output.write(unicode(out))
+ output.write(u"--\n")
if err:
- print >>output, "Command Output (stderr):"
- print >>output, "--"
- output.write(err)
- print >>output, "--"
+ output.write(u"Command Output (stderr):\n")
+ output.write(u"--\n")
+ output.write(unicode(err))
+ output.write(u"--\n")
return (status, output.getvalue())
def executeShTest(test, litConfig, useExternalSh,
diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py
index a1f79a3..f4ff89f 100644
--- a/utils/lit/lit/TestingConfig.py
+++ b/utils/lit/lit/TestingConfig.py
@@ -1,6 +1,8 @@
import os
import sys
+PY2 = sys.version_info[0] < 3
+
class TestingConfig:
""""
TestingConfig - Information on the tests inside a suite.
@@ -47,7 +49,8 @@ class TestingConfig:
test_exec_root = None,
test_source_root = None,
excludes = [],
- available_features = available_features)
+ available_features = available_features,
+ pipefail = True)
if os.path.exists(path):
# FIXME: Improve detection and error reporting of errors in the
@@ -58,13 +61,18 @@ class TestingConfig:
cfg_globals['lit'] = litConfig
cfg_globals['__file__'] = path
try:
- exec f in cfg_globals
+ data = f.read()
+ if PY2:
+ exec("exec data in cfg_globals")
+ else:
+ exec(data, cfg_globals)
if litConfig.debug:
litConfig.note('... loaded config %r' % path)
- except SystemExit,status:
+ except SystemExit:
+ e = sys.exc_info()[1]
# We allow normal system exit inside a config file to just
# return control without error.
- if status.args:
+ if e.args:
raise
f.close()
else:
@@ -79,7 +87,7 @@ class TestingConfig:
def __init__(self, parent, name, suffixes, test_format,
environment, substitutions, unsupported, on_clone,
test_exec_root, test_source_root, excludes,
- available_features):
+ available_features, pipefail):
self.parent = parent
self.name = str(name)
self.suffixes = set(suffixes)
@@ -92,6 +100,7 @@ class TestingConfig:
self.test_source_root = test_source_root
self.excludes = set(excludes)
self.available_features = set(available_features)
+ self.pipefail = pipefail
def clone(self, path):
# FIXME: Chain implementations?
@@ -101,7 +110,8 @@ class TestingConfig:
self.environment, self.substitutions,
self.unsupported, self.on_clone,
self.test_exec_root, self.test_source_root,
- self.excludes, self.available_features)
+ self.excludes, self.available_features,
+ self.pipefail)
if cfg.on_clone:
cfg.on_clone(self, cfg, path)
return cfg
diff --git a/utils/lit/lit/Util.py b/utils/lit/lit/Util.py
index f294809..6f09eed 100644
--- a/utils/lit/lit/Util.py
+++ b/utils/lit/lit/Util.py
@@ -34,7 +34,8 @@ def mkdir_p(path):
try:
os.mkdir(path)
- except OSError,e:
+ except OSError:
+ e = sys.exc_info()[1]
# Ignore EEXIST, which may occur during a race condition.
if e.errno != errno.EEXIST:
raise
@@ -94,7 +95,7 @@ def whichTools(tools, paths):
def printHistogram(items, title = 'Items'):
import itertools, math
- items.sort(key = lambda (_,v): v)
+ items.sort(key = lambda item: item[1])
maxValue = max([v for _,v in items])
@@ -115,27 +116,25 @@ def printHistogram(items, title = 'Items'):
barW = 40
hr = '-' * (barW + 34)
- print '\nSlowest %s:' % title
- print hr
+ print('\nSlowest %s:' % title)
+ print(hr)
for name,value in items[-20:]:
- print '%.2fs: %s' % (value, name)
- print '\n%s Times:' % title
- print hr
+ print('%.2fs: %s' % (value, name))
+ print('\n%s Times:' % title)
+ print(hr)
pDigits = int(math.ceil(math.log(maxValue, 10)))
pfDigits = max(0, 3-pDigits)
if pfDigits:
pDigits += pfDigits + 1
cDigits = int(math.ceil(math.log(len(items), 10)))
- print "[%s] :: [%s] :: [%s]" % ('Range'.center((pDigits+1)*2 + 3),
+ print("[%s] :: [%s] :: [%s]" % ('Range'.center((pDigits+1)*2 + 3),
'Percentage'.center(barW),
- 'Count'.center(cDigits*2 + 1))
- print hr
+ 'Count'.center(cDigits*2 + 1)))
+ print(hr)
for i,row in enumerate(histo):
pct = float(len(row)) / len(items)
w = int(barW * pct)
- print "[%*.*fs,%*.*fs)" % (pDigits, pfDigits, i*barH,
- pDigits, pfDigits, (i+1)*barH),
- print ":: [%s%s] :: [%*d/%*d]" % ('*'*w, ' '*(barW-w),
- cDigits, len(row),
- cDigits, len(items))
+ print("[%*.*fs,%*.*fs) :: [%s%s] :: [%*d/%*d]" % (
+ pDigits, pfDigits, i*barH, pDigits, pfDigits, (i+1)*barH,
+ '*'*w, ' '*(barW-w), cDigits, len(row), cDigits, len(items)))
diff --git a/utils/lit/lit/__init__.py b/utils/lit/lit/__init__.py
index 3e61bbd..b9f573d 100644
--- a/utils/lit/lit/__init__.py
+++ b/utils/lit/lit/__init__.py
@@ -1,6 +1,7 @@
"""'lit' Testing Tool"""
-from main import main
+from __future__ import absolute_import
+from .main import main
__author__ = 'Daniel Dunbar'
__email__ = 'daniel@zuster.org'
diff --git a/utils/lit/lit/discovery.py b/utils/lit/lit/discovery.py
index 64a9510..f76bd22 100644
--- a/utils/lit/lit/discovery.py
+++ b/utils/lit/lit/discovery.py
@@ -215,7 +215,7 @@ def find_tests_for_inputs(lit_config, inputs):
# If there were any errors during test discovery, exit now.
if lit_config.numErrors:
- print >>sys.stderr, '%d errors, exiting.' % lit_config.numErrors
+ sys.stderr.write('%d errors, exiting.\n' % lit_config.numErrors)
sys.exit(2)
return tests
@@ -233,7 +233,6 @@ def load_test_suite(inputs):
valgrindLeakCheck = False,
valgrindArgs = [],
noExecute = False,
- ignoreStdErr = False,
debug = False,
isWindows = (platform.system()=='Windows'),
params = {})
@@ -242,4 +241,3 @@ def load_test_suite(inputs):
# Return a unittest test suite which just runs the tests in order.
return unittest.TestSuite([LitTestCase(test, litConfig) for test in tests])
-
diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py
index de97a8e..acf6101 100755
--- a/utils/lit/lit/main.py
+++ b/utils/lit/lit/main.py
@@ -6,14 +6,13 @@ lit - LLVM Integrated Tester.
See lit.pod for more information.
"""
+from __future__ import absolute_import
import math, os, platform, random, re, sys, time, threading, traceback
-import ProgressBar
-import TestRunner
-import Util
-
-import LitConfig
-import Test
+import lit.ProgressBar
+import lit.LitConfig
+import lit.Test
+import lit.Util
import lit.discovery
@@ -59,14 +58,14 @@ class TestingProgressDisplay:
if self.progressBar:
self.progressBar.clear()
- print '%s: %s (%d of %d)' % (test.result.name, test.getFullName(),
- self.completed, self.numTests)
+ print('%s: %s (%d of %d)' % (test.result.name, test.getFullName(),
+ self.completed, self.numTests))
if test.result.isFailure and self.opts.showOutput:
- print "%s TEST '%s' FAILED %s" % ('*'*20, test.getFullName(),
- '*'*20)
- print test.output
- print "*" * 20
+ print("%s TEST '%s' FAILED %s" % ('*'*20, test.getFullName(),
+ '*'*20))
+ print(test.output)
+ print("*" * 20)
sys.stdout.flush()
@@ -76,6 +75,12 @@ class TestProvider:
self.iter = iter(tests)
self.lock = threading.Lock()
self.startTime = time.time()
+ self.canceled = False
+
+ def cancel(self):
+ self.lock.acquire()
+ self.canceled = True
+ self.lock.release()
def get(self):
# Check if we have run out of time.
@@ -85,9 +90,12 @@ class TestProvider:
# Otherwise take the next test.
self.lock.acquire()
- try:
- item = self.iter.next()
- except StopIteration:
+ if self.canceled:
+ self.lock.release()
+ return None
+ for item in self.iter:
+ break
+ else:
item = None
self.lock.release()
return item
@@ -115,12 +123,12 @@ class Tester(threading.Thread):
except KeyboardInterrupt:
# This is a sad hack. Unfortunately subprocess goes
# bonkers with ctrl-c and we start forking merrily.
- print '\nCtrl-C detected, goodbye.'
+ print('\nCtrl-C detected, goodbye.')
os.kill(0,9)
except:
if self.litConfig.debug:
raise
- result = Test.UNRESOLVED
+ result = lit.Test.UNRESOLVED
output = 'Exception during script execution:\n'
output += traceback.format_exc()
output += '\n'
@@ -232,6 +240,9 @@ def main(builtinParameters = {}):
group.add_option("", "--show-suites", dest="showSuites",
help="Show discovered test suites",
action="store_true", default=False)
+ group.add_option("", "--show-tests", dest="showTests",
+ help="Show all discovered tests",
+ action="store_true", default=False)
group.add_option("", "--repeat", dest="repeatTests", metavar="N",
help="Repeat tests N times (for timing)",
action="store", default=None, type=int)
@@ -248,7 +259,7 @@ def main(builtinParameters = {}):
# I haven't seen this bug occur with 2.5.2 and later, so only enable multiple
# threads by default there.
if sys.hexversion >= 0x2050200:
- opts.numThreads = Util.detectCPUs()
+ opts.numThreads = lit.Util.detectCPUs()
else:
opts.numThreads = 1
@@ -264,36 +275,47 @@ def main(builtinParameters = {}):
userParams[name] = val
# Create the global config object.
- litConfig = LitConfig.LitConfig(progname = os.path.basename(sys.argv[0]),
- path = opts.path,
- quiet = opts.quiet,
- useValgrind = opts.useValgrind,
- valgrindLeakCheck = opts.valgrindLeakCheck,
- valgrindArgs = opts.valgrindArgs,
- noExecute = opts.noExecute,
- ignoreStdErr = False,
- debug = opts.debug,
- isWindows = (platform.system()=='Windows'),
- params = userParams,
- config_prefix = opts.configPrefix)
+ litConfig = lit.LitConfig.LitConfig(
+ progname = os.path.basename(sys.argv[0]),
+ path = opts.path,
+ quiet = opts.quiet,
+ useValgrind = opts.useValgrind,
+ valgrindLeakCheck = opts.valgrindLeakCheck,
+ valgrindArgs = opts.valgrindArgs,
+ noExecute = opts.noExecute,
+ debug = opts.debug,
+ isWindows = (platform.system()=='Windows'),
+ params = userParams,
+ config_prefix = opts.configPrefix)
tests = lit.discovery.find_tests_for_inputs(litConfig, inputs)
- if opts.showSuites:
+ if opts.showSuites or opts.showTests:
+ # Aggregate the tests by suite.
suitesAndTests = {}
for t in tests:
if t.suite not in suitesAndTests:
suitesAndTests[t.suite] = []
suitesAndTests[t.suite].append(t)
-
- print '-- Test Suites --'
suitesAndTests = suitesAndTests.items()
- suitesAndTests.sort(key = lambda (ts,_): ts.name)
- for ts,ts_tests in suitesAndTests:
- print ' %s - %d tests' %(ts.name, len(ts_tests))
- print ' Source Root: %s' % ts.source_root
- print ' Exec Root : %s' % ts.exec_root
-
+ suitesAndTests.sort(key = lambda item: item[0].name)
+
+ # Show the suites, if requested.
+ if opts.showSuites:
+ print('-- Test Suites --')
+ for ts,ts_tests in suitesAndTests:
+ print(' %s - %d tests' %(ts.name, len(ts_tests)))
+ print(' Source Root: %s' % ts.source_root)
+ print(' Exec Root : %s' % ts.exec_root)
+
+ # Show the tests, if requested.
+ if opts.showTests:
+ print('-- Available Tests --')
+ for ts,ts_tests in suitesAndTests:
+ ts_tests.sort(key = lambda test: test.path_in_suite)
+ for test in ts_tests:
+ print(' %s' % (test.getFullName(),))
+
# Select and order the tests.
numTotalTests = len(tests)
@@ -335,27 +357,38 @@ def main(builtinParameters = {}):
if not opts.quiet:
if opts.succinct and opts.useProgressBar:
try:
- tc = ProgressBar.TerminalController()
- progressBar = ProgressBar.ProgressBar(tc, header)
+ tc = lit.ProgressBar.TerminalController()
+ progressBar = lit.ProgressBar.ProgressBar(tc, header)
except ValueError:
- print header
- progressBar = ProgressBar.SimpleProgressBar('Testing: ')
+ print(header)
+ progressBar = lit.ProgressBar.SimpleProgressBar('Testing: ')
else:
- print header
+ print(header)
startTime = time.time()
display = TestingProgressDisplay(opts, len(tests), progressBar)
provider = TestProvider(tests, opts.maxTime)
+
+ try:
+ import win32api
+ except ImportError:
+ pass
+ else:
+ def console_ctrl_handler(type):
+ provider.cancel()
+ return True
+ win32api.SetConsoleCtrlHandler(console_ctrl_handler, True)
+
runTests(opts.numThreads, litConfig, provider, display)
display.finish()
if not opts.quiet:
- print 'Testing Time: %.2fs'%(time.time() - startTime)
+ print('Testing Time: %.2fs'%(time.time() - startTime))
# Update results for any tests which weren't run.
for t in tests:
if t.result is None:
- t.setResult(Test.UNRESOLVED, '', 0.0)
+ t.setResult(lit.Test.UNRESOLVED, '', 0.0)
# List test results organized by kind.
hasFailures = False
@@ -368,16 +401,16 @@ def main(builtinParameters = {}):
hasFailures = True
# FIXME: Show unresolved and (optionally) unsupported tests.
- for title,code in (('Unexpected Passing Tests', Test.XPASS),
- ('Failing Tests', Test.FAIL)):
+ for title,code in (('Unexpected Passing Tests', lit.Test.XPASS),
+ ('Failing Tests', lit.Test.FAIL)):
elts = byCode.get(code)
if not elts:
continue
- print '*'*20
- print '%s (%d):' % (title, len(elts))
+ print('*'*20)
+ print('%s (%d):' % (title, len(elts)))
for t in elts:
- print ' %s' % t.getFullName()
- print
+ print(' %s' % t.getFullName())
+ sys.stdout.write('\n')
if opts.timeTests:
# Collate, in case we repeated tests.
@@ -387,30 +420,30 @@ def main(builtinParameters = {}):
times[key] = times.get(key, 0.) + t.elapsed
byTime = list(times.items())
- byTime.sort(key = lambda (name,elapsed): elapsed)
+ byTime.sort(key = lambda item: item[1])
if byTime:
- Util.printHistogram(byTime, title='Tests')
-
- for name,code in (('Expected Passes ', Test.PASS),
- ('Expected Failures ', Test.XFAIL),
- ('Unsupported Tests ', Test.UNSUPPORTED),
- ('Unresolved Tests ', Test.UNRESOLVED),
- ('Unexpected Passes ', Test.XPASS),
- ('Unexpected Failures', Test.FAIL),):
+ lit.Util.printHistogram(byTime, title='Tests')
+
+ for name,code in (('Expected Passes ', lit.Test.PASS),
+ ('Expected Failures ', lit.Test.XFAIL),
+ ('Unsupported Tests ', lit.Test.UNSUPPORTED),
+ ('Unresolved Tests ', lit.Test.UNRESOLVED),
+ ('Unexpected Passes ', lit.Test.XPASS),
+ ('Unexpected Failures', lit.Test.FAIL),):
if opts.quiet and not code.isFailure:
continue
N = len(byCode.get(code,[]))
if N:
- print ' %s: %d' % (name,N)
+ print(' %s: %d' % (name,N))
# If we encountered any additional errors, exit abnormally.
if litConfig.numErrors:
- print >>sys.stderr, '\n%d error(s), exiting.' % litConfig.numErrors
+ sys.stderr.write('\n%d error(s), exiting.\n' % litConfig.numErrors)
sys.exit(2)
# Warn about warnings.
if litConfig.numWarnings:
- print >>sys.stderr, '\n%d warning(s) in tests.' % litConfig.numWarnings
+ sys.stderr.write('\n%d warning(s) in tests.\n' % litConfig.numWarnings)
if hasFailures:
sys.exit(1)
diff --git a/utils/lit/tests/discovery.py b/utils/lit/tests/discovery.py
index 56d9dd0..be98c4b 100644
--- a/utils/lit/tests/discovery.py
+++ b/utils/lit/tests/discovery.py
@@ -1,7 +1,8 @@
# Check the basic discovery process, including a sub-suite.
#
# RUN: %{lit} %{inputs}/discovery \
-# RUN: -j 1 --debug --no-execute --show-suites -v > %t.out 2> %t.err
+# RUN: -j 1 --debug --show-tests --show-suites --max-tests 0 \
+# RUN: -v > %t.out 2> %t.err
# RUN: FileCheck --check-prefix=CHECK-BASIC-OUT < %t.out %s
# RUN: FileCheck --check-prefix=CHECK-BASIC-ERR < %t.err %s
#
@@ -17,12 +18,13 @@
# CHECK-BASIC-OUT: Source Root: {{.*/discovery$}}
# CHECK-BASIC-OUT: Exec Root : {{.*/discovery$}}
#
-# CHECK-BASIC-OUT: -- Testing: 5 tests, 1 threads --
-# CHECK-BASIC-OUT: PASS: sub-suite :: test-one
-# CHECK-BASIC-OUT: PASS: sub-suite :: test-two
-# CHECK-BASIC-OUT: PASS: top-level-suite :: subdir/test-three
-# CHECK-BASIC-OUT: PASS: top-level-suite :: test-one
-# CHECK-BASIC-OUT: PASS: top-level-suite :: test-two
+# CHECK-BASIC-OUT: -- Available Tests --
+# CHECK-BASIC-OUT: sub-suite :: test-one
+# CHECK-BASIC-OUT: sub-suite :: test-two
+# CHECK-BASIC-OUT: top-level-suite :: subdir/test-three
+# CHECK-BASIC-OUT: top-level-suite :: test-one
+# CHECK-BASIC-OUT: top-level-suite :: test-two
+# CHECK-BASIC-OUT: -- Testing: 0
# Check discovery when exact test names are given.
@@ -30,18 +32,20 @@
# RUN: %{lit} \
# RUN: %{inputs}/discovery/subdir/test-three.py \
# RUN: %{inputs}/discovery/subsuite/test-one.txt \
-# RUN: -j 1 --no-execute --show-suites -v > %t.out
+# RUN: -j 1 --show-tests --show-suites --max-tests 0 -v > %t.out
# RUN: FileCheck --check-prefix=CHECK-EXACT-TEST < %t.out %s
#
-# CHECK-EXACT-TEST: -- Testing: 2 tests, 1 threads --
-# CHECK-EXACT-TEST: PASS: sub-suite :: test-one
-# CHECK-EXACT-TEST: PASS: top-level-suite :: subdir/test-three
+# CHECK-EXACT-TEST: -- Available Tests --
+# CHECK-EXACT-TEST: sub-suite :: test-one
+# CHECK-EXACT-TEST: top-level-suite :: subdir/test-three
+# CHECK-EXACT-TEST: -- Testing: 0
# Check discovery when using an exec path.
#
# RUN: %{lit} %{inputs}/exec-discovery \
-# RUN: -j 1 --debug --no-execute --show-suites -v > %t.out 2> %t.err
+# RUN: -j 1 --debug --show-tests --show-suites --max-tests 0 \
+# RUN: -v > %t.out 2> %t.err
# RUN: FileCheck --check-prefix=CHECK-ASEXEC-OUT < %t.out %s
# RUN: FileCheck --check-prefix=CHECK-ASEXEC-ERR < %t.err %s
#
@@ -60,13 +64,13 @@
# CHECK-ASEXEC-OUT: Source Root: {{.*/discovery$}}
# CHECK-ASEXEC-OUT: Exec Root : {{.*/exec-discovery$}}
#
-# CHECK-ASEXEC-OUT: -- Testing: 5 tests, 1 threads --
-# CHECK-ASEXEC-OUT: PASS: sub-suite :: test-one
-# CHECK-ASEXEC-OUT: PASS: sub-suite :: test-two
-# CHECK-ASEXEC-OUT: PASS: top-level-suite :: subdir/test-three
-# CHECK-ASEXEC-OUT: PASS: top-level-suite :: test-one
-# CHECK-ASEXEC-OUT: PASS: top-level-suite :: test-two
-
+# CHECK-ASEXEC-OUT: -- Available Tests --
+# CHECK-ASEXEC-OUT: sub-suite :: test-one
+# CHECK-ASEXEC-OUT: sub-suite :: test-two
+# CHECK-ASEXEC-OUT: top-level-suite :: subdir/test-three
+# CHECK-ASEXEC-OUT: top-level-suite :: test-one
+# CHECK-ASEXEC-OUT: top-level-suite :: test-two
+# CHECK-ASEXEC-OUT: -- Testing: 0
# Check discovery when exact test names are given.
#
@@ -74,11 +78,12 @@
#
# RUN: %{lit} \
# RUN: %{inputs}/exec-discovery/subdir/test-three.py \
-# RUN: -j 1 --no-execute --show-suites -v > %t.out
+# RUN: -j 1 --show-tests --show-suites --max-tests 0 -v > %t.out
# RUN: FileCheck --check-prefix=CHECK-ASEXEC-EXACT-TEST < %t.out %s
#
-# CHECK-ASEXEC-EXACT-TEST: -- Testing: 1 tests, 1 threads --
-# CHECK-ASEXEC-EXACT-TEST: PASS: top-level-suite :: subdir/test-three
+# CHECK-ASEXEC-EXACT-TEST: -- Available Tests --
+# CHECK-ASEXEC-EXACT-TEST: top-level-suite :: subdir/test-three
+# CHECK-ASEXEC-EXACT-TEST: -- Testing: 0
# Check that we don't recurse infinitely when loading an site specific test
@@ -86,11 +91,12 @@
#
# RUN: %{lit} \
# RUN: %{inputs}/exec-discovery-in-tree/obj/ \
-# RUN: -j 1 --no-execute --show-suites -v > %t.out
+# RUN: -j 1 --show-tests --show-suites --max-tests 0 -v > %t.out
# RUN: FileCheck --check-prefix=CHECK-ASEXEC-INTREE < %t.out %s
#
# CHECK-ASEXEC-INTREE: exec-discovery-in-tree-suite - 1 tests
# CHECK-ASEXEC-INTREE-NEXT: Source Root: {{.*/exec-discovery-in-tree$}}
# CHECK-ASEXEC-INTREE-NEXT: Exec Root : {{.*/exec-discovery-in-tree/obj$}}
-# CHECK-ASEXEC-INTREE-NEXT: -- Testing: 1 tests, 1 threads --
-# CHECK-ASEXEC-INTREE-NEXT: PASS: exec-discovery-in-tree-suite :: test-one
+# CHECK-ASEXEC-INTREE-NEXT: -- Available Tests --
+# CHECK-ASEXEC-INTREE-NEXT: exec-discovery-in-tree-suite :: test-one
+# CHECK-ASEXEC-INTREE: -- Testing: 0
diff --git a/utils/not/not.cpp b/utils/not/not.cpp
index 9a924b5..ebd1618 100644
--- a/utils/not/not.cpp
+++ b/utils/not/not.cpp
@@ -13,15 +13,33 @@
using namespace llvm;
int main(int argc, const char **argv) {
- sys::Path Program = sys::Program::FindProgramByName(argv[1]);
+ bool ExpectCrash = false;
+
+ ++argv;
+ --argc;
+
+ if (argc > 0 && StringRef(argv[0]) == "--crash") {
+ ++argv;
+ --argc;
+ ExpectCrash = true;
+ }
+
+ if (argc == 0)
+ return 1;
+
+ std::string Program = sys::FindProgramByName(argv[0]);
std::string ErrMsg;
- int Result = sys::Program::ExecuteAndWait(Program, argv + 1, 0, 0, 0, 0,
- &ErrMsg);
+ int Result = sys::ExecuteAndWait(Program, argv, 0, 0, 0, 0, &ErrMsg);
if (Result < 0) {
errs() << "Error: " << ErrMsg << "\n";
+ if (ExpectCrash)
+ return 0;
return 1;
}
+ if (ExpectCrash)
+ return 1;
+
return Result == 0;
}
diff --git a/utils/release/test-release.sh b/utils/release/test-release.sh
index 104945b..6c17b46 100755
--- a/utils/release/test-release.sh
+++ b/utils/release/test-release.sh
@@ -480,7 +480,7 @@ for Flavor in $Flavors ; do
build_dragonegg 2 $Flavor $llvmCore_de_phase2_installdir $dragonegg_phase2_objdir
########################################################################
- # Phase 3: Build llvmCore with newly built clang from phase 2.
+ # Phase 3: Build llvmCore with newly built dragonegg from phase 2.
c_compiler="$gcc_compiler -fplugin=$dragonegg_phase2_objdir/dragonegg.so"
cxx_compiler="$gxx_compiler -fplugin=$dragonegg_phase2_objdir/dragonegg.so"
echo "# Phase 3: Building llvmCore with dragonegg"
diff --git a/utils/vim/llvm.vim b/utils/vim/llvm.vim
index 830476f..6c87cff 100644
--- a/utils/vim/llvm.vim
+++ b/utils/vim/llvm.vim
@@ -50,12 +50,13 @@ syn keyword llvmKeyword msp430_intrcc naked nest noalias nocapture
syn keyword llvmKeyword noimplicitfloat noinline nonlazybind noredzone noreturn
syn keyword llvmKeyword nounwind optsize personality private protected
syn keyword llvmKeyword ptx_device ptx_kernel readnone readonly release
-syn keyword llvmKeyword returns_twice 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 zeroext
-syn keyword llvmKeyword sanitize_thread sanitize_memory
+syn keyword llvmKeyword returns_twice sanitize_thread sanitize_memory
+syn keyword llvmKeyword section seq_cst sideeffect signext singlethread
+syn keyword llvmKeyword spir_func spir_kernel sret ssp sspreq sspstrong
+syn keyword llvmKeyword tail target thread_local to triple unnamed_addr
+syn keyword llvmKeyword unordered uwtable volatile weak weak_odr
+syn keyword llvmKeyword x86_fastcallcc x86_stdcallcc x86_thiscallcc x86_64_sysvcc
+syn keyword llvmKeyword x86_64_win64cc zeroext
" Obsolete keywords.
syn keyword llvmError getresult begin end