diff options
Diffstat (limited to 'utils')
69 files changed, 1264 insertions, 955 deletions
diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index 59affa1ada1ba..8fe2f88a3e70e 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -73,6 +73,7 @@ namespace Check { CheckNone = 0, CheckPlain, CheckNext, + CheckSame, CheckNot, CheckDAG, CheckLabel, @@ -620,6 +621,9 @@ struct CheckString { /// CheckNext - Verify there is a single line in the given buffer. bool CheckNext(const SourceMgr &SM, StringRef Buffer) const; + /// CheckSame - Verify there is no newline in the given buffer. + bool CheckSame(const SourceMgr &SM, StringRef Buffer) const; + /// CheckNot - Verify there's no "not strings" in the given buffer. bool CheckNot(const SourceMgr &SM, StringRef Buffer, const std::vector<const Pattern *> &NotStrings, @@ -683,6 +687,9 @@ static size_t CheckTypeSize(Check::CheckType Ty) { case Check::CheckNext: return sizeof("-NEXT:") - 1; + case Check::CheckSame: + return sizeof("-SAME:") - 1; + case Check::CheckNot: return sizeof("-NOT:") - 1; @@ -713,6 +720,9 @@ static Check::CheckType FindCheckType(StringRef Buffer, StringRef Prefix) { if (Rest.startswith("NEXT:")) return Check::CheckNext; + if (Rest.startswith("SAME:")) + return Check::CheckSame; + if (Rest.startswith("NOT:")) return Check::CheckNot; @@ -919,10 +929,12 @@ static bool ReadCheckFile(SourceMgr &SM, Buffer = Buffer.substr(EOL); // Verify that CHECK-NEXT lines have at least one CHECK line before them. - if ((CheckTy == Check::CheckNext) && CheckStrings.empty()) { + if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame) && + CheckStrings.empty()) { + StringRef Type = CheckTy == Check::CheckNext ? "NEXT" : "SAME"; SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, - "found '" + UsedPrefix + "-NEXT:' without previous '" + "found '" + UsedPrefix + "-" + Type + "' without previous '" + UsedPrefix + ": line"); return true; } @@ -946,7 +958,7 @@ static bool ReadCheckFile(SourceMgr &SM, // prefix as a filler for the error message. if (!DagNotMatches.empty()) { CheckStrings.push_back(CheckString(Pattern(Check::CheckEOF), - CheckPrefixes[0], + *CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data()), Check::CheckEOF)); std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); @@ -955,12 +967,14 @@ static bool ReadCheckFile(SourceMgr &SM, if (CheckStrings.empty()) { errs() << "error: no check strings found with prefix" << (CheckPrefixes.size() > 1 ? "es " : " "); - for (size_t I = 0, N = CheckPrefixes.size(); I != N; ++I) { - StringRef Prefix(CheckPrefixes[I]); - errs() << '\'' << Prefix << ":'"; - if (I != N - 1) - errs() << ", "; + prefix_iterator I = CheckPrefixes.begin(); + prefix_iterator E = CheckPrefixes.end(); + if (I != E) { + errs() << "\'" << *I << ":'"; + ++I; } + for (; I != E; ++I) + errs() << ", \'" << *I << ":'"; errs() << '\n'; return true; @@ -1041,7 +1055,6 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer, PrintCheckFailed(SM, *this, MatchBuffer, VariableTable); return StringRef::npos; } - MatchPos += LastPos; // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT // or CHECK-NOT @@ -1053,13 +1066,18 @@ size_t CheckString::Check(const SourceMgr &SM, StringRef Buffer, if (CheckNext(SM, SkippedRegion)) return StringRef::npos; + // If this check is a "CHECK-SAME", verify that the previous match was on + // the same line (i.e. that there is no newline between them). + if (CheckSame(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; } - return MatchPos; + return LastPos + MatchPos; } bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { @@ -1101,6 +1119,34 @@ bool CheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { return false; } +bool CheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const { + if (CheckTy != Check::CheckSame) + return false; + + // Count the number of newlines between the previous match and this one. + assert(Buffer.data() != + SM.getMemoryBuffer(SM.FindBufferContainingLoc( + SMLoc::getFromPointer(Buffer.data()))) + ->getBufferStart() && + "CHECK-SAME can't be the first check in a file"); + + const char *FirstNewLine = nullptr; + unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine); + + if (NumNewLines != 0) { + SM.PrintMessage(Loc, SourceMgr::DK_Error, + Prefix + + "-SAME: is not on the same line as the previous match"); + SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note, + "'next' match was here"); + SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, + "previous match ended here"); + return true; + } + + return false; +} + bool CheckString::CheckNot(const SourceMgr &SM, StringRef Buffer, const std::vector<const Pattern *> &NotStrings, StringMap<StringRef> &VariableTable) const { diff --git a/utils/KillTheDoctor/KillTheDoctor.cpp b/utils/KillTheDoctor/KillTheDoctor.cpp index 111bad209584f..fae3b1a8b9d84 100644 --- a/utils/KillTheDoctor/KillTheDoctor.cpp +++ b/utils/KillTheDoctor/KillTheDoctor.cpp @@ -38,6 +38,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/WindowsError.h" diff --git a/utils/Makefile b/utils/Makefile index 04261923e1b5f..a59318de4834e 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -9,7 +9,7 @@ LEVEL = .. PARALLEL_DIRS := FileCheck TableGen PerfectShuffle count fpcmp llvm-lit not \ - unittest + unittest yaml-bench EXTRA_DIST := check-each-file codegen-diff countloc.sh \ DSAclean.py DSAextract.py emacs findsym.pl GenLibDeps.pl \ diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 5ee20dda02616..d8f261939540f 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -264,6 +264,11 @@ public: } /// operator< - Compare two classes. + // FIXME: This ordering seems to be broken. For example: + // u64 < i64, i64 < s8, s8 < u64, forming a cycle + // u64 is a subset of i64 + // i64 and s8 are not subsets of each other, so are ordered by name + // s8 and u64 are not subsets of each other, so are ordered by name bool operator<(const ClassInfo &RHS) const { if (this == &RHS) return false; @@ -433,12 +438,21 @@ struct MatchableInfo { /// If this instruction is deprecated in some form. bool HasDeprecation; + /// If this is an alias, this is use to determine whether or not to using + /// the conversion function defined by the instruction's AsmMatchConverter + /// or to use the function generated by the alias. + bool UseInstAsmMatchConverter; + MatchableInfo(const CodeGenInstruction &CGI) - : AsmVariantID(0), AsmString(CGI.AsmString), TheDef(CGI.TheDef), DefRec(&CGI) { + : AsmVariantID(0), AsmString(CGI.AsmString), TheDef(CGI.TheDef), DefRec(&CGI), + UseInstAsmMatchConverter(true) { } MatchableInfo(std::unique_ptr<const CodeGenInstAlias> Alias) - : AsmVariantID(0), AsmString(Alias->AsmString), TheDef(Alias->TheDef), DefRec(Alias.release()) { + : AsmVariantID(0), AsmString(Alias->AsmString), TheDef(Alias->TheDef), + DefRec(Alias.release()), + UseInstAsmMatchConverter( + TheDef->getValueAsBit("UseInstAsmMatchConverter")) { } ~MatchableInfo() { @@ -979,6 +993,7 @@ static std::string getEnumNameForToken(StringRef Str) { case '.': Res += "_DOT_"; break; case '<': Res += "_LT_"; break; case '>': Res += "_GT_"; break; + case '-': Res += "_MINUS_"; break; default: if ((*it >= 'A' && *it <= 'Z') || (*it >= 'a' && *it <= 'z') || @@ -1446,8 +1461,9 @@ void AsmMatcherInfo::buildInfo() { II->buildAliasResultOperands(); } if (!NewMatchables.empty()) - std::move(NewMatchables.begin(), NewMatchables.end(), - std::back_inserter(Matchables)); + Matchables.insert(Matchables.end(), + std::make_move_iterator(NewMatchables.begin()), + std::make_move_iterator(NewMatchables.end())); // Process token alias definitions and set up the associated superclass // information. @@ -1742,7 +1758,7 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, // Check if we have a custom match function. std::string AsmMatchConverter = II->getResultInst()->TheDef->getValueAsString("AsmMatchConverter"); - if (!AsmMatchConverter.empty()) { + if (!AsmMatchConverter.empty() && II->UseInstAsmMatchConverter) { std::string Signature = "ConvertCustom_" + AsmMatchConverter; II->ConversionFnKind = Signature; @@ -1848,6 +1864,7 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, case MatchableInfo::ResOperand::ImmOperand: { int64_t Val = OpInfo.ImmVal; std::string Ty = "imm_" + itostr(Val); + Ty = getEnumNameForToken(Ty); Signature += "__" + Ty; std::string Name = "CVT_" + Ty; @@ -1862,7 +1879,7 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, break; CvtOS << " case " << Name << ":\n" - << " Inst.addOperand(MCOperand::CreateImm(" << Val << "));\n" + << " Inst.addOperand(MCOperand::createImm(" << Val << "));\n" << " break;\n"; OpOS << " case " << Name << ":\n" @@ -1893,7 +1910,7 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, if (!IsNewConverter) break; CvtOS << " case " << Name << ":\n" - << " Inst.addOperand(MCOperand::CreateReg(" << Reg << "));\n" + << " Inst.addOperand(MCOperand::createReg(" << Reg << "));\n" << " break;\n"; OpOS << " case " << Name << ":\n" @@ -2240,7 +2257,7 @@ static void emitComputeAvailableFeatures(AsmMatcherInfo &Info, Info.AsmParser->getValueAsString("AsmParserClassName"); OS << "uint64_t " << Info.Target.getName() << ClassName << "::\n" - << "ComputeAvailableFeatures(uint64_t FB) const {\n"; + << "ComputeAvailableFeatures(const FeatureBitset& FB) const {\n"; OS << " uint64_t Features = 0;\n"; for (const auto &SF : Info.SubtargetFeatures) { const SubtargetFeatureInfo &SFI = SF.second; @@ -2262,12 +2279,10 @@ static void emitComputeAvailableFeatures(AsmMatcherInfo &Info, Cond = Cond.substr(1); } - OS << "((FB & " << Info.Target.getName() << "::" << Cond << ")"; + OS << "("; if (Neg) - OS << " == 0"; - else - OS << " != 0"; - OS << ")"; + OS << "!"; + OS << "FB[" << Info.Target.getName() << "::" << Cond << "])"; if (Comma.second.empty()) break; @@ -2637,7 +2652,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << "#undef GET_ASSEMBLER_HEADER\n"; OS << " // This should be included into the middle of the declaration of\n"; OS << " // your subclasses implementation of MCTargetAsmParser.\n"; - OS << " uint64_t ComputeAvailableFeatures(uint64_t FeatureBits) const;\n"; + OS << " uint64_t ComputeAvailableFeatures(const FeatureBitset& FB) const;\n"; OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, " << "unsigned Opcode,\n" << " const OperandVector " @@ -2651,7 +2666,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { << " bool matchingInlineAsm,\n" << " unsigned VariantID = 0);\n"; - if (Info.OperandMatchInfo.size()) { + if (!Info.OperandMatchInfo.empty()) { OS << "\n enum OperandMatchResultTy {\n"; OS << " MatchOperand_Success, // operand matched successfully\n"; OS << " MatchOperand_NoMatch, // operand did not match\n"; @@ -2879,7 +2894,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " uint64_t MissingFeatures = ~0ULL;\n"; OS << " // Set ErrorInfo to the operand that mismatches if it is\n"; OS << " // wrong for all instances of the instruction.\n"; - OS << " ErrorInfo = ~0U;\n"; + OS << " ErrorInfo = ~0ULL;\n"; // Emit code to search the table. OS << " // Find the appropriate table for this asm variant.\n"; @@ -2954,8 +2969,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " HadMatchOtherThanFeatures = true;\n"; OS << " uint64_t NewMissingFeatures = it->RequiredFeatures & " "~AvailableFeatures;\n"; - OS << " if (CountPopulation_64(NewMissingFeatures) <=\n" - " CountPopulation_64(MissingFeatures))\n"; + OS << " if (countPopulation(NewMissingFeatures) <=\n" + " countPopulation(MissingFeatures))\n"; OS << " MissingFeatures = NewMissingFeatures;\n"; OS << " continue;\n"; OS << " }\n"; @@ -3009,7 +3024,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " return Match_MissingFeature;\n"; OS << "}\n\n"; - if (Info.OperandMatchInfo.size()) + if (!Info.OperandMatchInfo.empty()) emitCustomOperandParsing(OS, Target, Info, ClassName, StringTable, MaxMnemonicIndex); diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp index 5924d5f48dc46..389889ab80f0a 100644 --- a/utils/TableGen/AsmWriterEmitter.cpp +++ b/utils/TableGen/AsmWriterEmitter.cpp @@ -278,12 +278,15 @@ static void UnescapeString(std::string &Str) { void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { Record *AsmWriter = Target.getAsmWriter(); std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); + unsigned PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget"); O << "/// printInstruction - This method is automatically generated by tablegen\n" "/// from the instruction set description.\n" "void " << Target.getName() << ClassName - << "::printInstruction(const MCInst *MI, raw_ostream &O) {\n"; + << "::printInstruction(const MCInst *MI, " + << (PassSubtarget ? "const MCSubtargetInfo &STI, " : "") + << "raw_ostream &O) {\n"; // Build an aggregate string, and build a table of offsets into it. SequenceToOffsetTable<std::string> StringTable; @@ -727,7 +730,7 @@ public: OS.flush(); // Emit the string. - O.indent(6) << "AsmString = \"" << OutString.str() << "\";\n"; + O.indent(6) << "AsmString = \"" << OutString << "\";\n"; O.indent(6) << "break;\n"; O.indent(4) << '}'; @@ -787,6 +790,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { // Emit the method that prints the alias instruction. std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); unsigned Variant = AsmWriter->getValueAsInt("Variant"); + unsigned PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget"); std::vector<Record*> AllInstAliases = Records.getAllDerivedDefinitions("InstAlias"); @@ -949,7 +953,8 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { HeaderO << "bool " << Target.getName() << ClassName << "::printAliasInstr(const MCInst" - << " *MI, raw_ostream &OS) {\n"; + << " *MI, " << (PassSubtarget ? "const MCSubtargetInfo &STI, " : "") + << "raw_ostream &OS) {\n"; std::string Cases; raw_string_ostream CasesO(Cases); @@ -998,7 +1003,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { return; } - if (MCOpPredicates.size()) + if (!MCOpPredicates.empty()) O << "static bool " << Target.getName() << ClassName << "ValidateMCOperand(\n" << " const MCOperand &MCOp, unsigned PredicateIndex);\n"; @@ -1027,9 +1032,13 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { O << " ++I;\n"; O << " int OpIdx = AsmString[I++] - 1;\n"; O << " int PrintMethodIdx = AsmString[I++] - 1;\n"; - O << " printCustomAliasOperand(MI, OpIdx, PrintMethodIdx, OS);\n"; + O << " printCustomAliasOperand(MI, OpIdx, PrintMethodIdx, "; + O << (PassSubtarget ? "STI, " : ""); + O << "OS);\n"; O << " } else\n"; - O << " printOperand(MI, unsigned(AsmString[I++]) - 1, OS);\n"; + O << " printOperand(MI, unsigned(AsmString[I++]) - 1, "; + O << (PassSubtarget ? "STI, " : ""); + O << "OS);\n"; O << " } else {\n"; O << " OS << AsmString[I++];\n"; O << " }\n"; @@ -1046,7 +1055,9 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { O << "void " << Target.getName() << ClassName << "::" << "printCustomAliasOperand(\n" << " const MCInst *MI, unsigned OpIdx,\n" - << " unsigned PrintMethodIdx, raw_ostream &OS) {\n"; + << " unsigned PrintMethodIdx,\n" + << (PassSubtarget ? " const MCSubtargetInfo &STI,\n" : "") + << " raw_ostream &OS) {\n"; if (PrintMethods.empty()) O << " llvm_unreachable(\"Unknown PrintMethod kind\");\n"; else { @@ -1057,14 +1068,15 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { for (unsigned i = 0; i < PrintMethods.size(); ++i) { O << " case " << i << ":\n" - << " " << PrintMethods[i] << "(MI, OpIdx, OS);\n" + << " " << PrintMethods[i] << "(MI, OpIdx, " + << (PassSubtarget ? "STI, " : "") << "OS);\n" << " break;\n"; } O << " }\n"; } O << "}\n\n"; - if (MCOpPredicates.size()) { + if (!MCOpPredicates.empty()) { O << "static bool " << Target.getName() << ClassName << "ValidateMCOperand(\n" << " const MCOperand &MCOp, unsigned PredicateIndex) {\n" @@ -1094,7 +1106,8 @@ AsmWriterEmitter::AsmWriterEmitter(RecordKeeper &R) : Records(R), Target(R) { for (const CodeGenInstruction *I : Target.instructions()) if (!I->AsmString.empty() && I->TheDef->getName() != "PHI") Instructions.push_back( - AsmWriterInst(*I, AsmWriter->getValueAsInt("Variant"))); + AsmWriterInst(*I, AsmWriter->getValueAsInt("Variant"), + AsmWriter->getValueAsInt("PassSubtarget"))); // Get the instruction numbering. NumberedInstructions = &Target.getInstructionsByEnumValue(); diff --git a/utils/TableGen/AsmWriterInst.cpp b/utils/TableGen/AsmWriterInst.cpp index 6ddc510473ed5..a66b1a01cae45 100644 --- a/utils/TableGen/AsmWriterInst.cpp +++ b/utils/TableGen/AsmWriterInst.cpp @@ -39,6 +39,8 @@ std::string AsmWriterOperand::getCode() const { std::string Result = Str + "(MI"; if (MIOpNo != ~0U) Result += ", " + utostr(MIOpNo); + if (PassSubtarget) + Result += ", STI"; Result += ", O"; if (!MiModifier.empty()) Result += ", \"" + MiModifier + '"'; @@ -48,7 +50,8 @@ std::string AsmWriterOperand::getCode() const { /// ParseAsmString - Parse the specified Instruction's AsmString into this /// AsmWriterInst. /// -AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) { +AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant, + unsigned PassSubtarget) { this->CGI = &CGI; // NOTE: Any extensions to this code need to be mirrored in the @@ -163,7 +166,8 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) { Operands.push_back(AsmWriterOperand("PrintSpecial", ~0U, ~0U, - Modifier)); + Modifier, + PassSubtarget)); } else { // Otherwise, normal operand. unsigned OpNo = CGI.Operands.getOperandNamed(VarName); @@ -171,7 +175,8 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) { unsigned MIOp = OpInfo.MIOperandNo; Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName, - OpNo, MIOp, Modifier)); + OpNo, MIOp, Modifier, + PassSubtarget)); } LastEmitted = VarEnd; } diff --git a/utils/TableGen/AsmWriterInst.h b/utils/TableGen/AsmWriterInst.h index 6a900b7997011..a597e6ba1a558 100644 --- a/utils/TableGen/AsmWriterInst.h +++ b/utils/TableGen/AsmWriterInst.h @@ -53,6 +53,11 @@ namespace llvm { /// an operand, specified with syntax like ${opname:modifier}. std::string MiModifier; + // PassSubtarget - Pass MCSubtargetInfo to the print method if this is + // equal to 1. + // FIXME: Remove after all ports are updated. + unsigned PassSubtarget; + // To make VS STL happy AsmWriterOperand(OpType op = isLiteralTextOperand):OperandType(op) {} @@ -64,9 +69,10 @@ namespace llvm { unsigned _CGIOpNo, unsigned _MIOpNo, const std::string &Modifier, + unsigned PassSubtarget, OpType op = isMachineInstrOperand) : OperandType(op), Str(Printer), CGIOpNo(_CGIOpNo), MIOpNo(_MIOpNo), - MiModifier(Modifier) {} + MiModifier(Modifier), PassSubtarget(PassSubtarget) {} bool operator!=(const AsmWriterOperand &Other) const { if (OperandType != Other.OperandType || Str != Other.Str) return true; @@ -88,7 +94,7 @@ namespace llvm { const CodeGenInstruction *CGI; AsmWriterInst(const CodeGenInstruction &CGI, - unsigned Variant); + unsigned Variant, unsigned PassSubtarget); /// MatchesAllButOneOp - If this instruction is exactly identical to the /// specified instruction except for one differing operand, return the diff --git a/utils/TableGen/CallingConvEmitter.cpp b/utils/TableGen/CallingConvEmitter.cpp index 6a65e5e97821b..051a7e9814140 100644 --- a/utils/TableGen/CallingConvEmitter.cpp +++ b/utils/TableGen/CallingConvEmitter.cpp @@ -124,7 +124,7 @@ void CallingConvEmitter::EmitAction(Record *Action, } O << "\n" << IndentStr << "};\n"; O << IndentStr << "if (unsigned Reg = State.AllocateReg(RegList" - << Counter << ", " << RegList->getSize() << ")) {\n"; + << Counter << ")) {\n"; } O << IndentStr << " State.addLoc(CCValAssign::getReg(ValNo, ValVT, " << "Reg, LocVT, LocInfo));\n"; @@ -166,7 +166,7 @@ void CallingConvEmitter::EmitAction(Record *Action, O << IndentStr << "if (unsigned Reg = State.AllocateReg(RegList" << RegListNumber << ", " << "RegList" << ShadowRegListNumber - << ", " << RegList->getSize() << ")) {\n"; + << ")) {\n"; } O << IndentStr << " State.addLoc(CCValAssign::getReg(ValNo, ValVT, " << "Reg, LocVT, LocInfo));\n"; @@ -182,14 +182,14 @@ void CallingConvEmitter::EmitAction(Record *Action, O << Size << ", "; else O << "\n" << IndentStr - << " State.getMachineFunction().getSubtarget().getDataLayout()" + << " State.getMachineFunction().getTarget().getDataLayout()" "->getTypeAllocSize(EVT(LocVT).getTypeForEVT(State.getContext()))," " "; if (Align) O << Align; else O << "\n" << IndentStr - << " State.getMachineFunction().getSubtarget().getDataLayout()" + << " State.getMachineFunction().getTarget().getDataLayout()" "->getABITypeAlignment(EVT(LocVT).getTypeForEVT(State.getContext()" "))"; O << ");\n" << IndentStr @@ -215,8 +215,7 @@ void CallingConvEmitter::EmitAction(Record *Action, O << IndentStr << "unsigned Offset" << ++Counter << " = State.AllocateStack(" << Size << ", " << Align << ", " - << "ShadowRegList" << ShadowRegListNumber << ", " - << ShadowRegList->getSize() << ");\n"; + << "ShadowRegList" << ShadowRegListNumber << ");\n"; O << IndentStr << "State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset" << Counter << ", LocVT, LocInfo));\n"; O << IndentStr << "return false;\n"; diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp index 11911b63b7bd5..46fcdf5e96ffd 100644 --- a/utils/TableGen/CodeEmitterGen.cpp +++ b/utils/TableGen/CodeEmitterGen.cpp @@ -96,7 +96,7 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName, /// generated emitter, skip it. while (NumberedOp < NumberOps && (CGI.Operands.isFlatOperandNotEmitted(NumberedOp) || - (NamedOpIndices.size() && NamedOpIndices.count( + (!NamedOpIndices.empty() && NamedOpIndices.count( CGI.Operands.getSubOperandNumber(NumberedOp).first)))) { ++NumberedOp; diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp index c3de37e94533d..fd02bbdc6b488 100644 --- a/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -53,7 +53,7 @@ EEVT::TypeSet::TypeSet(MVT::SimpleValueType VT, TreePattern &TP) { EnforceVector(TP); else { assert((VT < MVT::LAST_VALUETYPE || VT == MVT::iPTR || - VT == MVT::iPTRAny) && "Not a concrete type!"); + VT == MVT::iPTRAny || VT == MVT::Any) && "Not a concrete type!"); TypeVec.push_back(VT); } } @@ -389,52 +389,6 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { else if (!Other.hasScalarTypes()) MadeChange |= EnforceVector(TP); - // For vectors we need to ensure that smaller size doesn't produce larger - // vector and vice versa. - if (isConcrete() && isVector(getConcrete())) { - MVT IVT = getConcrete(); - unsigned Size = IVT.getSizeInBits(); - - // Only keep types that have at least as many bits. - TypeSet InputSet(Other); - - for (unsigned i = 0; i != Other.TypeVec.size(); ++i) { - assert(isVector(Other.TypeVec[i]) && "EnforceVector didn't work"); - if (MVT(Other.TypeVec[i]).getSizeInBits() < Size) { - Other.TypeVec.erase(Other.TypeVec.begin()+i--); - MadeChange = true; - } - } - - if (Other.TypeVec.empty()) { // FIXME: Really want an SMLoc here! - TP.error("Type inference contradiction found, forcing '" + - InputSet.getName() + "' to have at least as many bits as " + - getName() + "'"); - return false; - } - } else if (Other.isConcrete() && isVector(Other.getConcrete())) { - MVT IVT = Other.getConcrete(); - unsigned Size = IVT.getSizeInBits(); - - // Only keep types with the same or fewer total bits - TypeSet InputSet(*this); - - for (unsigned i = 0; i != TypeVec.size(); ++i) { - assert(isVector(TypeVec[i]) && "EnforceVector didn't work"); - if (MVT(TypeVec[i]).getSizeInBits() > Size) { - TypeVec.erase(TypeVec.begin()+i--); - MadeChange = true; - } - } - - if (TypeVec.empty()) { // FIXME: Really want an SMLoc here! - TP.error("Type inference contradiction found, forcing '" + - InputSet.getName() + "' to have the same or fewer bits than " + - Other.getName() + "'"); - return false; - } - } - // This code does not currently handle nodes which have multiple types, // where some types are integer, and some are fp. Assert that this is not // the case. @@ -445,12 +399,22 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { if (TP.hasError()) return false; - // Okay, find the smallest scalar type from the other set and remove - // anything the same or smaller from the current set. + // Okay, find the smallest type from current set and remove anything the + // same or smaller from the other set. We need to ensure that the scalar + // type size is smaller than the scalar size of the smallest type. For + // vectors, we also need to make sure that the total size is no larger than + // the size of the smallest type. TypeSet InputSet(Other); - MVT::SimpleValueType Smallest = TypeVec[0]; + MVT Smallest = TypeVec[0]; for (unsigned i = 0; i != Other.TypeVec.size(); ++i) { - if (Other.TypeVec[i] <= Smallest) { + MVT OtherVT = Other.TypeVec[i]; + // Don't compare vector and non-vector types. + if (OtherVT.isVector() != Smallest.isVector()) + continue; + // The getSizeInBits() check here is only needed for vectors, but is + // a subset of the scalar check for scalars so no need to qualify. + if (OtherVT.getScalarSizeInBits() <= Smallest.getScalarSizeInBits() || + OtherVT.getSizeInBits() < Smallest.getSizeInBits()) { Other.TypeVec.erase(Other.TypeVec.begin()+i--); MadeChange = true; } @@ -462,12 +426,22 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { return false; } - // Okay, find the largest scalar type from the other set and remove - // anything the same or larger from the current set. + // Okay, find the largest type from the other set and remove anything the + // same or smaller from the current set. We need to ensure that the scalar + // type size is larger than the scalar size of the largest type. For + // vectors, we also need to make sure that the total size is no smaller than + // the size of the largest type. InputSet = TypeSet(*this); - MVT::SimpleValueType Largest = Other.TypeVec[Other.TypeVec.size()-1]; + MVT Largest = Other.TypeVec[Other.TypeVec.size()-1]; for (unsigned i = 0; i != TypeVec.size(); ++i) { - if (TypeVec[i] >= Largest) { + MVT OtherVT = TypeVec[i]; + // Don't compare vector and non-vector types. + if (OtherVT.isVector() != Largest.isVector()) + continue; + // The getSizeInBits() check here is only needed for vectors, but is + // a subset of the scalar check for scalars so no need to qualify. + if (OtherVT.getScalarSizeInBits() >= Largest.getScalarSizeInBits() || + OtherVT.getSizeInBits() > Largest.getSizeInBits()) { TypeVec.erase(TypeVec.begin()+i--); MadeChange = true; } @@ -484,6 +458,34 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { /// EnforceVectorEltTypeIs - 'this' is now constrainted to be a vector type /// whose element is specified by VTOperand. +bool EEVT::TypeSet::EnforceVectorEltTypeIs(MVT::SimpleValueType VT, + TreePattern &TP) { + bool MadeChange = false; + + MadeChange |= EnforceVector(TP); + + TypeSet InputSet(*this); + + // Filter out all the types which don't have the right element type. + for (unsigned i = 0; i != TypeVec.size(); ++i) { + assert(isVector(TypeVec[i]) && "EnforceVector didn't work"); + if (MVT(TypeVec[i]).getVectorElementType().SimpleTy != VT) { + TypeVec.erase(TypeVec.begin()+i--); + MadeChange = true; + } + } + + if (TypeVec.empty()) { // FIXME: Really want an SMLoc here! + TP.error("Type inference contradiction found, forcing '" + + InputSet.getName() + "' to have a vector element"); + return false; + } + + return MadeChange; +} + +/// EnforceVectorEltTypeIs - 'this' is now constrainted to be a vector type +/// whose element is specified by VTOperand. bool EEVT::TypeSet::EnforceVectorEltTypeIs(EEVT::TypeSet &VTOperand, TreePattern &TP) { if (TP.hasError()) @@ -609,6 +611,64 @@ bool EEVT::TypeSet::EnforceVectorSubVectorTypeIs(EEVT::TypeSet &VTOperand, return MadeChange; } +/// EnforceVectorSameNumElts - 'this' is now constrainted to +/// be a vector with same num elements as VTOperand. +bool EEVT::TypeSet::EnforceVectorSameNumElts(EEVT::TypeSet &VTOperand, + TreePattern &TP) { + if (TP.hasError()) + return false; + + // "This" must be a vector and "VTOperand" must be a vector. + bool MadeChange = false; + MadeChange |= EnforceVector(TP); + MadeChange |= VTOperand.EnforceVector(TP); + + // If we know one of the vector types, it forces the other type to agree. + if (isConcrete()) { + MVT IVT = getConcrete(); + unsigned NumElems = IVT.getVectorNumElements(); + + // Only keep types that have same elements as VTOperand. + TypeSet InputSet(VTOperand); + + for (unsigned i = 0; i != VTOperand.TypeVec.size(); ++i) { + assert(isVector(VTOperand.TypeVec[i]) && "EnforceVector didn't work"); + if (MVT(VTOperand.TypeVec[i]).getVectorNumElements() != NumElems) { + VTOperand.TypeVec.erase(VTOperand.TypeVec.begin()+i--); + MadeChange = true; + } + } + if (VTOperand.TypeVec.empty()) { // FIXME: Really want an SMLoc here! + TP.error("Type inference contradiction found, forcing '" + + InputSet.getName() + "' to have same number elements as '" + + getName() + "'"); + return false; + } + } else if (VTOperand.isConcrete()) { + MVT IVT = VTOperand.getConcrete(); + unsigned NumElems = IVT.getVectorNumElements(); + + // Only keep types that have same elements as 'this'. + TypeSet InputSet(*this); + + for (unsigned i = 0; i != TypeVec.size(); ++i) { + assert(isVector(TypeVec[i]) && "EnforceVector didn't work"); + if (MVT(TypeVec[i]).getVectorNumElements() != NumElems) { + TypeVec.erase(TypeVec.begin()+i--); + MadeChange = true; + } + } + if (TypeVec.empty()) { // FIXME: Really want an SMLoc here! + TP.error("Type inference contradiction found, forcing '" + + InputSet.getName() + "' to have same number elements than '" + + VTOperand.getName() + "'"); + return false; + } + } + + return MadeChange; +} + //===----------------------------------------------------------------------===// // Helpers for working with extended types. @@ -839,9 +899,21 @@ SDTypeConstraint::SDTypeConstraint(Record *R) { ConstraintType = SDTCisSubVecOfVec; x.SDTCisSubVecOfVec_Info.OtherOperandNum = R->getValueAsInt("OtherOpNum"); + } else if (R->isSubClassOf("SDTCVecEltisVT")) { + ConstraintType = SDTCVecEltisVT; + x.SDTCVecEltisVT_Info.VT = getValueType(R->getValueAsDef("VT")); + if (MVT(x.SDTCVecEltisVT_Info.VT).isVector()) + PrintFatalError(R->getLoc(), "Cannot use vector type as SDTCVecEltisVT"); + if (!MVT(x.SDTCVecEltisVT_Info.VT).isInteger() && + !MVT(x.SDTCVecEltisVT_Info.VT).isFloatingPoint()) + PrintFatalError(R->getLoc(), "Must use integer or floating point type " + "as SDTCVecEltisVT"); + } else if (R->isSubClassOf("SDTCisSameNumEltsAs")) { + ConstraintType = SDTCisSameNumEltsAs; + x.SDTCisSameNumEltsAs_Info.OtherOperandNum = + R->getValueAsInt("OtherOperandNum"); } else { - errs() << "Unrecognized SDTypeConstraint '" << R->getName() << "'!\n"; - exit(1); + PrintFatalError("Unrecognized SDTypeConstraint '" + R->getName() + "'!\n"); } } @@ -859,11 +931,12 @@ static TreePatternNode *getOperandNum(unsigned OpNo, TreePatternNode *N, OpNo -= NumResults; if (OpNo >= N->getNumChildren()) { - errs() << "Invalid operand number in type constraint " + std::string S; + raw_string_ostream OS(S); + OS << "Invalid operand number in type constraint " << (OpNo+NumResults) << " "; - N->dump(); - errs() << '\n'; - exit(1); + N->print(OS); + PrintFatalError(OS.str()); } return N->getChild(OpNo); @@ -901,8 +974,8 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, unsigned OResNo = 0; TreePatternNode *OtherNode = getOperandNum(x.SDTCisSameAs_Info.OtherOperandNum, N, NodeInfo, OResNo); - return NodeToApply->UpdateNodeType(OResNo, OtherNode->getExtType(ResNo),TP)| - OtherNode->UpdateNodeType(ResNo,NodeToApply->getExtType(OResNo),TP); + return NodeToApply->UpdateNodeType(ResNo, OtherNode->getExtType(OResNo),TP)| + OtherNode->UpdateNodeType(OResNo,NodeToApply->getExtType(ResNo),TP); } case SDTCisVTSmallerThanOp: { // The NodeToApply must be a leaf node that is a VT. OtherOperandNum must @@ -956,6 +1029,18 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, return BigVecOperand->getExtType(VResNo). EnforceVectorSubVectorTypeIs(NodeToApply->getExtType(ResNo), TP); } + case SDTCVecEltisVT: { + return NodeToApply->getExtType(ResNo). + EnforceVectorEltTypeIs(x.SDTCVecEltisVT_Info.VT, TP); + } + case SDTCisSameNumEltsAs: { + unsigned OResNo = 0; + TreePatternNode *OtherNode = + getOperandNum(x.SDTCisSameNumEltsAs_Info.OtherOperandNum, + N, NodeInfo, OResNo); + return OtherNode->getExtType(OResNo). + EnforceVectorSameNumElts(NodeToApply->getExtType(ResNo), TP); + } } llvm_unreachable("Invalid ConstraintType!"); } @@ -1031,9 +1116,9 @@ SDNodeInfo::SDNodeInfo(Record *R) : Def(R) { } else if (PropList[i]->getName() == "SDNPVariadic") { Properties |= 1 << SDNPVariadic; } else { - errs() << "Unknown SD Node property '" << PropList[i]->getName() - << "' on node '" << R->getName() << "'!\n"; - exit(1); + PrintFatalError("Unknown SD Node property '" + + PropList[i]->getName() + "' on node '" + + R->getName() + "'!"); } } @@ -1111,8 +1196,16 @@ static unsigned GetNumNodeResults(Record *Operator, CodeGenDAGPatterns &CDP) { if (Operator->isSubClassOf("Instruction")) { CodeGenInstruction &InstInfo = CDP.getTargetInfo().getInstruction(Operator); - // FIXME: Should allow access to all the results here. - unsigned NumDefsToAdd = InstInfo.Operands.NumDefs ? 1 : 0; + unsigned NumDefsToAdd = InstInfo.Operands.NumDefs; + + // Subtract any defaulted outputs. + for (unsigned i = 0; i != InstInfo.Operands.NumDefs; ++i) { + Record *OperandNode = InstInfo.Operands[i].Rec; + + if (OperandNode->isSubClassOf("OperandWithDefaultOps") && + !CDP.getDefaultOperand(OperandNode).DefaultOps.empty()) + --NumDefsToAdd; + } // Add on one implicit def if it has a resolvable type. if (InstInfo.HasOneImplicitDefWithKnownVT(CDP.getTargetInfo()) !=MVT::Other) @@ -1130,8 +1223,7 @@ static unsigned GetNumNodeResults(Record *Operator, CodeGenDAGPatterns &CDP) { return 1; Operator->dump(); - errs() << "Unhandled node in GetNumNodeResults\n"; - exit(1); + PrintFatalError("Unhandled node in GetNumNodeResults"); } void TreePatternNode::print(raw_ostream &OS) const { @@ -1689,8 +1781,8 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { // Apply the result types to the node, these come from the things in the // (outs) list of the instruction. - // FIXME: Cap at one result so far. - unsigned NumResultsToAdd = InstInfo.Operands.NumDefs ? 1 : 0; + unsigned NumResultsToAdd = std::min(InstInfo.Operands.NumDefs, + Inst.getNumResults()); for (unsigned ResNo = 0; ResNo != NumResultsToAdd; ++ResNo) MadeChange |= UpdateNodeTypeFromInst(ResNo, Inst.getResult(ResNo), TP); @@ -1971,7 +2063,7 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ } // ?:$name or just $name. - if (TheInit == UnsetInit::get()) { + if (isa<UnsetInit>(TheInit)) { if (OpName.empty()) error("'?' argument requires a name to match with operand list"); TreePatternNode *Res = new TreePatternNode(TheInit, 1); @@ -2280,10 +2372,9 @@ CodeGenDAGPatterns::CodeGenDAGPatterns(RecordKeeper &R) : Record *CodeGenDAGPatterns::getSDNodeNamed(const std::string &Name) const { Record *N = Records.getDef(Name); - if (!N || !N->isSubClassOf("SDNode")) { - errs() << "Error getting SDNode '" << Name << "'!\n"; - exit(1); - } + if (!N || !N->isSubClassOf("SDNode")) + PrintFatalError("Error getting SDNode '" + Name + "'!"); + return N; } @@ -2811,159 +2902,161 @@ static bool checkOperandClass(CGIOperandList::OperandInfo &OI, const DAGInstruction &CodeGenDAGPatterns::parseInstructionPattern( CodeGenInstruction &CGI, ListInit *Pat, DAGInstMap &DAGInsts) { - assert(!DAGInsts.count(CGI.TheDef) && "Instruction already parsed!"); + assert(!DAGInsts.count(CGI.TheDef) && "Instruction already parsed!"); - // Parse the instruction. - TreePattern *I = new TreePattern(CGI.TheDef, Pat, true, *this); - // Inline pattern fragments into it. - I->InlinePatternFragments(); + // Parse the instruction. + TreePattern *I = new TreePattern(CGI.TheDef, Pat, true, *this); + // Inline pattern fragments into it. + I->InlinePatternFragments(); - // Infer as many types as possible. If we cannot infer all of them, we can - // never do anything with this instruction pattern: report it to the user. - if (!I->InferAllTypes()) - I->error("Could not infer all types in pattern!"); + // Infer as many types as possible. If we cannot infer all of them, we can + // never do anything with this instruction pattern: report it to the user. + if (!I->InferAllTypes()) + I->error("Could not infer all types in pattern!"); - // InstInputs - Keep track of all of the inputs of the instruction, along - // with the record they are declared as. - std::map<std::string, TreePatternNode*> InstInputs; + // InstInputs - Keep track of all of the inputs of the instruction, along + // with the record they are declared as. + std::map<std::string, TreePatternNode*> InstInputs; - // InstResults - Keep track of all the virtual registers that are 'set' - // in the instruction, including what reg class they are. - std::map<std::string, TreePatternNode*> InstResults; + // InstResults - Keep track of all the virtual registers that are 'set' + // in the instruction, including what reg class they are. + std::map<std::string, TreePatternNode*> InstResults; - std::vector<Record*> InstImpResults; + std::vector<Record*> InstImpResults; - // Verify that the top-level forms in the instruction are of void type, and - // fill in the InstResults map. - for (unsigned j = 0, e = I->getNumTrees(); j != e; ++j) { - TreePatternNode *Pat = I->getTree(j); - if (Pat->getNumTypes() != 0) - I->error("Top-level forms in instruction pattern should have" - " void types"); + // Verify that the top-level forms in the instruction are of void type, and + // fill in the InstResults map. + for (unsigned j = 0, e = I->getNumTrees(); j != e; ++j) { + TreePatternNode *Pat = I->getTree(j); + if (Pat->getNumTypes() != 0) + I->error("Top-level forms in instruction pattern should have" + " void types"); - // Find inputs and outputs, and verify the structure of the uses/defs. - FindPatternInputsAndOutputs(I, Pat, InstInputs, InstResults, - InstImpResults); - } + // Find inputs and outputs, and verify the structure of the uses/defs. + FindPatternInputsAndOutputs(I, Pat, InstInputs, InstResults, + InstImpResults); + } - // Now that we have inputs and outputs of the pattern, inspect the operands - // list for the instruction. This determines the order that operands are - // added to the machine instruction the node corresponds to. - unsigned NumResults = InstResults.size(); + // Now that we have inputs and outputs of the pattern, inspect the operands + // list for the instruction. This determines the order that operands are + // added to the machine instruction the node corresponds to. + unsigned NumResults = InstResults.size(); - // Parse the operands list from the (ops) list, validating it. - assert(I->getArgList().empty() && "Args list should still be empty here!"); + // Parse the operands list from the (ops) list, validating it. + assert(I->getArgList().empty() && "Args list should still be empty here!"); - // Check that all of the results occur first in the list. - std::vector<Record*> Results; - TreePatternNode *Res0Node = nullptr; - for (unsigned i = 0; i != NumResults; ++i) { - if (i == CGI.Operands.size()) - I->error("'" + InstResults.begin()->first + - "' set but does not appear in operand list!"); - const std::string &OpName = CGI.Operands[i].Name; + // Check that all of the results occur first in the list. + std::vector<Record*> Results; + SmallVector<TreePatternNode *, 2> ResNodes; + for (unsigned i = 0; i != NumResults; ++i) { + if (i == CGI.Operands.size()) + I->error("'" + InstResults.begin()->first + + "' set but does not appear in operand list!"); + const std::string &OpName = CGI.Operands[i].Name; - // Check that it exists in InstResults. - TreePatternNode *RNode = InstResults[OpName]; - if (!RNode) - I->error("Operand $" + OpName + " does not exist in operand list!"); + // Check that it exists in InstResults. + TreePatternNode *RNode = InstResults[OpName]; + if (!RNode) + I->error("Operand $" + OpName + " does not exist in operand list!"); - if (i == 0) - Res0Node = RNode; - Record *R = cast<DefInit>(RNode->getLeafValue())->getDef(); - if (!R) - I->error("Operand $" + OpName + " should be a set destination: all " - "outputs must occur before inputs in operand list!"); + ResNodes.push_back(RNode); - if (!checkOperandClass(CGI.Operands[i], R)) - I->error("Operand $" + OpName + " class mismatch!"); + Record *R = cast<DefInit>(RNode->getLeafValue())->getDef(); + if (!R) + I->error("Operand $" + OpName + " should be a set destination: all " + "outputs must occur before inputs in operand list!"); - // Remember the return type. - Results.push_back(CGI.Operands[i].Rec); + if (!checkOperandClass(CGI.Operands[i], R)) + I->error("Operand $" + OpName + " class mismatch!"); - // Okay, this one checks out. - InstResults.erase(OpName); - } + // Remember the return type. + Results.push_back(CGI.Operands[i].Rec); - // Loop over the inputs next. Make a copy of InstInputs so we can destroy - // the copy while we're checking the inputs. - std::map<std::string, TreePatternNode*> InstInputsCheck(InstInputs); + // Okay, this one checks out. + InstResults.erase(OpName); + } - std::vector<TreePatternNode*> ResultNodeOperands; - std::vector<Record*> Operands; - for (unsigned i = NumResults, e = CGI.Operands.size(); i != e; ++i) { - CGIOperandList::OperandInfo &Op = CGI.Operands[i]; - const std::string &OpName = Op.Name; - if (OpName.empty()) - I->error("Operand #" + utostr(i) + " in operands list has no name!"); - - if (!InstInputsCheck.count(OpName)) { - // If this is an operand with a DefaultOps set filled in, we can ignore - // this. When we codegen it, we will do so as always executed. - if (Op.Rec->isSubClassOf("OperandWithDefaultOps")) { - // Does it have a non-empty DefaultOps field? If so, ignore this - // operand. - if (!getDefaultOperand(Op.Rec).DefaultOps.empty()) - continue; - } - I->error("Operand $" + OpName + - " does not appear in the instruction pattern"); - } - TreePatternNode *InVal = InstInputsCheck[OpName]; - InstInputsCheck.erase(OpName); // It occurred, remove from map. - - if (InVal->isLeaf() && isa<DefInit>(InVal->getLeafValue())) { - Record *InRec = static_cast<DefInit*>(InVal->getLeafValue())->getDef(); - if (!checkOperandClass(Op, InRec)) - I->error("Operand $" + OpName + "'s register class disagrees" - " between the operand and pattern"); + // Loop over the inputs next. Make a copy of InstInputs so we can destroy + // the copy while we're checking the inputs. + std::map<std::string, TreePatternNode*> InstInputsCheck(InstInputs); + + std::vector<TreePatternNode*> ResultNodeOperands; + std::vector<Record*> Operands; + for (unsigned i = NumResults, e = CGI.Operands.size(); i != e; ++i) { + CGIOperandList::OperandInfo &Op = CGI.Operands[i]; + const std::string &OpName = Op.Name; + if (OpName.empty()) + I->error("Operand #" + utostr(i) + " in operands list has no name!"); + + if (!InstInputsCheck.count(OpName)) { + // If this is an operand with a DefaultOps set filled in, we can ignore + // this. When we codegen it, we will do so as always executed. + if (Op.Rec->isSubClassOf("OperandWithDefaultOps")) { + // Does it have a non-empty DefaultOps field? If so, ignore this + // operand. + if (!getDefaultOperand(Op.Rec).DefaultOps.empty()) + continue; } - Operands.push_back(Op.Rec); + I->error("Operand $" + OpName + + " does not appear in the instruction pattern"); + } + TreePatternNode *InVal = InstInputsCheck[OpName]; + InstInputsCheck.erase(OpName); // It occurred, remove from map. - // Construct the result for the dest-pattern operand list. - TreePatternNode *OpNode = InVal->clone(); + if (InVal->isLeaf() && isa<DefInit>(InVal->getLeafValue())) { + Record *InRec = static_cast<DefInit*>(InVal->getLeafValue())->getDef(); + if (!checkOperandClass(Op, InRec)) + I->error("Operand $" + OpName + "'s register class disagrees" + " between the operand and pattern"); + } + Operands.push_back(Op.Rec); - // No predicate is useful on the result. - OpNode->clearPredicateFns(); + // Construct the result for the dest-pattern operand list. + TreePatternNode *OpNode = InVal->clone(); - // Promote the xform function to be an explicit node if set. - if (Record *Xform = OpNode->getTransformFn()) { - OpNode->setTransformFn(nullptr); - std::vector<TreePatternNode*> Children; - Children.push_back(OpNode); - OpNode = new TreePatternNode(Xform, Children, OpNode->getNumTypes()); - } + // No predicate is useful on the result. + OpNode->clearPredicateFns(); - ResultNodeOperands.push_back(OpNode); + // Promote the xform function to be an explicit node if set. + if (Record *Xform = OpNode->getTransformFn()) { + OpNode->setTransformFn(nullptr); + std::vector<TreePatternNode*> Children; + Children.push_back(OpNode); + OpNode = new TreePatternNode(Xform, Children, OpNode->getNumTypes()); } - if (!InstInputsCheck.empty()) - I->error("Input operand $" + InstInputsCheck.begin()->first + - " occurs in pattern but not in operands list!"); + ResultNodeOperands.push_back(OpNode); + } - TreePatternNode *ResultPattern = - new TreePatternNode(I->getRecord(), ResultNodeOperands, - GetNumNodeResults(I->getRecord(), *this)); - // Copy fully inferred output node type to instruction result pattern. - for (unsigned i = 0; i != NumResults; ++i) - ResultPattern->setType(i, Res0Node->getExtType(i)); + if (!InstInputsCheck.empty()) + I->error("Input operand $" + InstInputsCheck.begin()->first + + " occurs in pattern but not in operands list!"); - // Create and insert the instruction. - // FIXME: InstImpResults should not be part of DAGInstruction. - DAGInstruction TheInst(I, Results, Operands, InstImpResults); - DAGInsts.insert(std::make_pair(I->getRecord(), TheInst)); + TreePatternNode *ResultPattern = + new TreePatternNode(I->getRecord(), ResultNodeOperands, + GetNumNodeResults(I->getRecord(), *this)); + // Copy fully inferred output node types to instruction result pattern. + for (unsigned i = 0; i != NumResults; ++i) { + assert(ResNodes[i]->getNumTypes() == 1 && "FIXME: Unhandled"); + ResultPattern->setType(i, ResNodes[i]->getExtType(0)); + } - // Use a temporary tree pattern to infer all types and make sure that the - // constructed result is correct. This depends on the instruction already - // being inserted into the DAGInsts map. - TreePattern Temp(I->getRecord(), ResultPattern, false, *this); - Temp.InferAllTypes(&I->getNamedNodesMap()); + // Create and insert the instruction. + // FIXME: InstImpResults should not be part of DAGInstruction. + DAGInstruction TheInst(I, Results, Operands, InstImpResults); + DAGInsts.insert(std::make_pair(I->getRecord(), TheInst)); - DAGInstruction &TheInsertedInst = DAGInsts.find(I->getRecord())->second; - TheInsertedInst.setResultPattern(Temp.getOnlyTree()); + // Use a temporary tree pattern to infer all types and make sure that the + // constructed result is correct. This depends on the instruction already + // being inserted into the DAGInsts map. + TreePattern Temp(I->getRecord(), ResultPattern, false, *this); + Temp.InferAllTypes(&I->getNamedNodesMap()); - return TheInsertedInst; - } + DAGInstruction &TheInsertedInst = DAGInsts.find(I->getRecord())->second; + TheInsertedInst.setResultPattern(Temp.getOnlyTree()); + + return TheInsertedInst; +} /// ParseInstructions - Parse all of the instructions, inlining and resolving /// any fragments involved. This populates the Instructions list with fully @@ -2983,25 +3076,20 @@ void CodeGenDAGPatterns::ParseInstructions() { // null_frag operator is as-if no pattern were specified. Normally this // is from a multiclass expansion w/ a SDPatternOperator passed in as // null_frag. - if (!LI || LI->getSize() == 0 || hasNullFragReference(LI)) { + if (!LI || LI->empty() || hasNullFragReference(LI)) { std::vector<Record*> Results; std::vector<Record*> Operands; CodeGenInstruction &InstInfo = Target.getInstruction(Instrs[i]); if (InstInfo.Operands.size() != 0) { - if (InstInfo.Operands.NumDefs == 0) { - // These produce no results - for (unsigned j = 0, e = InstInfo.Operands.size(); j < e; ++j) - Operands.push_back(InstInfo.Operands[j].Rec); - } else { - // Assume the first operand is the result. - Results.push_back(InstInfo.Operands[0].Rec); - - // The rest are inputs. - for (unsigned j = 1, e = InstInfo.Operands.size(); j < e; ++j) - Operands.push_back(InstInfo.Operands[j].Rec); - } + for (unsigned j = 0, e = InstInfo.Operands.NumDefs; j < e; ++j) + Results.push_back(InstInfo.Operands[j].Rec); + + // The rest are inputs. + for (unsigned j = InstInfo.Operands.NumDefs, + e = InstInfo.Operands.size(); j < e; ++j) + Operands.push_back(InstInfo.Operands[j].Rec); } // Create and insert the instruction. @@ -3311,7 +3399,7 @@ void CodeGenDAGPatterns::ParsePatterns() { Pattern->InlinePatternFragments(); ListInit *LI = CurPattern->getValueAsListInit("ResultInstrs"); - if (LI->getSize() == 0) continue; // no pattern. + if (LI->empty()) continue; // no pattern. // Parse the instruction. TreePattern Result(CurPattern, LI, false, *this); diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h index c0812cf055364..9ce3cdfd7bc15 100644 --- a/utils/TableGen/CodeGenDAGPatterns.h +++ b/utils/TableGen/CodeGenDAGPatterns.h @@ -136,10 +136,18 @@ namespace EEVT { /// whose element is VT. bool EnforceVectorEltTypeIs(EEVT::TypeSet &VT, TreePattern &TP); + /// EnforceVectorEltTypeIs - 'this' is now constrainted to be a vector type + /// whose element is VT. + bool EnforceVectorEltTypeIs(MVT::SimpleValueType VT, TreePattern &TP); + /// EnforceVectorSubVectorTypeIs - 'this' is now constrainted to /// be a vector type VT. bool EnforceVectorSubVectorTypeIs(EEVT::TypeSet &VT, TreePattern &TP); + /// EnforceVectorSameNumElts - 'this' is now constrainted to + /// be a vector with same num elements as VT. + bool EnforceVectorSameNumElts(EEVT::TypeSet &VT, TreePattern &TP); + bool operator!=(const TypeSet &RHS) const { return TypeVec != RHS.TypeVec; } bool operator==(const TypeSet &RHS) const { return TypeVec == RHS.TypeVec; } @@ -165,7 +173,7 @@ struct SDTypeConstraint { enum { SDTCisVT, SDTCisPtrTy, SDTCisInt, SDTCisFP, SDTCisVec, SDTCisSameAs, SDTCisVTSmallerThanOp, SDTCisOpSmallerThanOp, SDTCisEltOfVec, - SDTCisSubVecOfVec + SDTCisSubVecOfVec, SDTCVecEltisVT, SDTCisSameNumEltsAs } ConstraintType; union { // The discriminated union. @@ -187,6 +195,12 @@ struct SDTypeConstraint { struct { unsigned OtherOperandNum; } SDTCisSubVecOfVec_Info; + struct { + MVT::SimpleValueType VT; + } SDTCVecEltisVT_Info; + struct { + unsigned OtherOperandNum; + } SDTCisSameNumEltsAs_Info; } x; /// ApplyTypeConstraint - Given a node in a pattern, apply this type diff --git a/utils/TableGen/CodeGenIntrinsics.h b/utils/TableGen/CodeGenIntrinsics.h index 1f1adf11fb3b0..f4055571b1c7b 100644 --- a/utils/TableGen/CodeGenIntrinsics.h +++ b/utils/TableGen/CodeGenIntrinsics.h @@ -80,6 +80,9 @@ namespace llvm { /// isNoReturn - True if the intrinsic is no-return. bool isNoReturn; + /// isConvergent - True if the intrinsic is marked as convergent. + bool isConvergent; + enum ArgAttribute { NoCapture, ReadOnly, diff --git a/utils/TableGen/CodeGenMapTable.cpp b/utils/TableGen/CodeGenMapTable.cpp index 7e5aa9c161b48..b52a91d0177b5 100644 --- a/utils/TableGen/CodeGenMapTable.cpp +++ b/utils/TableGen/CodeGenMapTable.cpp @@ -128,7 +128,7 @@ public: ListInit *ColValList = MapRec->getValueAsListInit("ValueCols"); // Each instruction map must specify at least one column for it to be valid. - if (ColValList->getSize() == 0) + if (ColValList->empty()) PrintFatalError(MapRec->getLoc(), "InstrMapping record `" + MapRec->getName() + "' has empty " + "`ValueCols' field!"); @@ -376,7 +376,7 @@ unsigned MapTableEmitter::emitBinSearchTable(raw_ostream &OS) { std::vector<Record*> ColInstrs = MapTable[CurInstr]; std::string OutStr(""); unsigned RelExists = 0; - if (ColInstrs.size()) { + if (!ColInstrs.empty()) { for (unsigned j = 0; j < NumCol; j++) { if (ColInstrs[j] != nullptr) { RelExists = 1; @@ -567,7 +567,7 @@ void EmitMapTable(RecordKeeper &Records, raw_ostream &OS) { std::vector<Record*> InstrMapVec; InstrMapVec = Records.getAllDerivedDefinitions("InstrMapping"); - if (!InstrMapVec.size()) + if (InstrMapVec.empty()) return; OS << "#ifdef GET_INSTRMAP_INFO\n"; diff --git a/utils/TableGen/CodeGenRegisters.cpp b/utils/TableGen/CodeGenRegisters.cpp index bef8a4b8fa12a..c6940e9fe5176 100644 --- a/utils/TableGen/CodeGenRegisters.cpp +++ b/utils/TableGen/CodeGenRegisters.cpp @@ -108,7 +108,7 @@ CodeGenRegister::CodeGenRegister(Record *R, unsigned Enum) EnumValue(Enum), CostPerUse(R->getValueAsInt("CostPerUse")), CoveredBySubRegs(R->getValueAsBit("CoveredBySubRegs")), - NumNativeRegUnits(0), + HasDisjunctSubRegs(false), SubRegsComplete(false), SuperRegsComplete(false), TopoSig(~0u) @@ -153,11 +153,11 @@ const std::string &CodeGenRegister::getName() const { namespace { // Iterate over all register units in a set of registers. class RegUnitIterator { - CodeGenRegister::Set::const_iterator RegI, RegE; - CodeGenRegister::RegUnitList::const_iterator UnitI, UnitE; + CodeGenRegister::Vec::const_iterator RegI, RegE; + CodeGenRegister::RegUnitList::iterator UnitI, UnitE; public: - RegUnitIterator(const CodeGenRegister::Set &Regs): + RegUnitIterator(const CodeGenRegister::Vec &Regs): RegI(Regs.begin()), RegE(Regs.end()), UnitI(), UnitE() { if (RegI != RegE) { @@ -192,32 +192,23 @@ protected: }; } // namespace -// Merge two RegUnitLists maintaining the order and removing duplicates. -// Overwrites MergedRU in the process. -static void mergeRegUnits(CodeGenRegister::RegUnitList &MergedRU, - const CodeGenRegister::RegUnitList &RRU) { - CodeGenRegister::RegUnitList LRU = MergedRU; - MergedRU.clear(); - std::set_union(LRU.begin(), LRU.end(), RRU.begin(), RRU.end(), - std::back_inserter(MergedRU)); -} - // Return true of this unit appears in RegUnits. static bool hasRegUnit(CodeGenRegister::RegUnitList &RegUnits, unsigned Unit) { - return std::count(RegUnits.begin(), RegUnits.end(), Unit); + return RegUnits.test(Unit); } // Inherit register units from subregisters. // Return true if the RegUnits changed. bool CodeGenRegister::inheritRegUnits(CodeGenRegBank &RegBank) { - unsigned OldNumUnits = RegUnits.size(); + bool changed = false; for (SubRegMap::const_iterator I = SubRegs.begin(), E = SubRegs.end(); I != E; ++I) { CodeGenRegister *SR = I->second; // Merge the subregister's units into this register's RegUnits. - mergeRegUnits(RegUnits, SR->RegUnits); + changed |= (RegUnits |= SR->RegUnits); } - return OldNumUnits != RegUnits.size(); + + return changed; } const CodeGenRegister::SubRegMap & @@ -227,6 +218,8 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) { return SubRegs; SubRegsComplete = true; + HasDisjunctSubRegs = ExplicitSubRegs.size() > 1; + // First insert the explicit subregs and make sure they are fully indexed. for (unsigned i = 0, e = ExplicitSubRegs.size(); i != e; ++i) { CodeGenRegister *SR = ExplicitSubRegs[i]; @@ -247,6 +240,7 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) { for (unsigned i = 0, e = ExplicitSubRegs.size(); i != e; ++i) { CodeGenRegister *SR = ExplicitSubRegs[i]; const SubRegMap &Map = SR->computeSubRegs(RegBank); + HasDisjunctSubRegs |= SR->HasDisjunctSubRegs; for (SubRegMap::const_iterator SI = Map.begin(), SE = Map.end(); SI != SE; ++SI) { @@ -363,14 +357,8 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) { // sub-registers, the other registers won't contribute any more units. for (unsigned i = 0, e = ExplicitSubRegs.size(); i != e; ++i) { CodeGenRegister *SR = ExplicitSubRegs[i]; - // Explicit sub-registers are usually disjoint, so this is a good way of - // computing the union. We may pick up a few duplicates that will be - // eliminated below. - unsigned N = RegUnits.size(); - RegUnits.append(SR->RegUnits.begin(), SR->RegUnits.end()); - std::inplace_merge(RegUnits.begin(), RegUnits.begin() + N, RegUnits.end()); + RegUnits |= SR->RegUnits; } - RegUnits.erase(std::unique(RegUnits.begin(), RegUnits.end()), RegUnits.end()); // Absent any ad hoc aliasing, we create one register unit per leaf register. // These units correspond to the maximal cliques in the register overlap @@ -389,19 +377,19 @@ CodeGenRegister::computeSubRegs(CodeGenRegBank &RegBank) { // Create a RegUnit representing this alias edge, and add it to both // registers. unsigned Unit = RegBank.newRegUnit(this, AR); - RegUnits.push_back(Unit); - AR->RegUnits.push_back(Unit); + RegUnits.set(Unit); + AR->RegUnits.set(Unit); } // Finally, create units for leaf registers without ad hoc aliases. Note that // a leaf register with ad hoc aliases doesn't get its own unit - it isn't // necessary. This means the aliasing leaf registers can share a single unit. if (RegUnits.empty()) - RegUnits.push_back(RegBank.newRegUnit(this)); + RegUnits.set(RegBank.newRegUnit(this)); // We have now computed the native register units. More may be adopted later // for balancing purposes. - NumNativeRegUnits = RegUnits.size(); + NativeRegUnits = RegUnits; return SubRegs; } @@ -535,7 +523,7 @@ CodeGenRegister::addSubRegsPreOrder(SetVector<const CodeGenRegister*> &OSet, // Get the sum of this register's unit weights. unsigned CodeGenRegister::getWeight(const CodeGenRegBank &RegBank) const { unsigned Weight = 0; - for (RegUnitList::const_iterator I = RegUnits.begin(), E = RegUnits.end(); + for (RegUnitList::iterator I = RegUnits.begin(), E = RegUnits.end(); I != E; ++I) { Weight += RegBank.getRegUnit(*I).Weight; } @@ -658,6 +646,11 @@ struct TupleExpander : SetTheory::Expander { // CodeGenRegisterClass //===----------------------------------------------------------------------===// +static void sortAndUniqueRegisters(CodeGenRegister::Vec &M) { + std::sort(M.begin(), M.end(), deref<llvm::less>()); + M.erase(std::unique(M.begin(), M.end(), deref<llvm::equal>()), M.end()); +} + CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R) : TheDef(R), Name(R->getName()), @@ -667,9 +660,7 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R) // Rename anonymous register classes. if (R->getName().size() > 9 && R->getName()[9] == '.') { static unsigned AnonCounter = 0; - R->setName("AnonRegClass_" + utostr(AnonCounter)); - // MSVC2012 ICEs if AnonCounter++ is directly passed to utostr. - ++AnonCounter; + R->setName("AnonRegClass_" + utostr(AnonCounter++)); } std::vector<Record*> TypeList = R->getValueAsListOfDefs("RegTypes"); @@ -685,19 +676,20 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R) // Allocation order 0 is the full set. AltOrders provides others. const SetTheory::RecVec *Elements = RegBank.getSets().expand(R); ListInit *AltOrders = R->getValueAsListInit("AltOrders"); - Orders.resize(1 + AltOrders->size()); + Orders.resize(1 + AltOrders->getSize()); // Default allocation order always contains all registers. for (unsigned i = 0, e = Elements->size(); i != e; ++i) { Orders[0].push_back((*Elements)[i]); const CodeGenRegister *Reg = RegBank.getReg((*Elements)[i]); - Members.insert(Reg); + Members.push_back(Reg); TopoSigs.set(Reg->getTopoSig()); } + sortAndUniqueRegisters(Members); // Alternative allocation orders may be subsets. SetTheory::RecSet Order; - for (unsigned i = 0, e = AltOrders->size(); i != e; ++i) { + for (unsigned i = 0, e = AltOrders->getSize(); i != e; ++i) { RegBank.getSets().evaluate(AltOrders->getElement(i), Order, R->getLoc()); Orders[1 + i].append(Order.begin(), Order.end()); // Verify that all altorder members are regclass members. @@ -719,6 +711,10 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, Record *R) CopyCost = R->getValueAsInt("CopyCost"); Allocatable = R->getValueAsBit("isAllocatable"); AltOrderSelect = R->getValueAsString("AltOrderSelect"); + int AllocationPriority = R->getValueAsInt("AllocationPriority"); + if (AllocationPriority < 0 || AllocationPriority > 63) + PrintFatalError(R->getLoc(), "AllocationPriority out of range [0,63]"); + this->AllocationPriority = AllocationPriority; } // Create an inferred register class that was missing from the .td files. @@ -734,10 +730,10 @@ CodeGenRegisterClass::CodeGenRegisterClass(CodeGenRegBank &RegBank, SpillSize(Props.SpillSize), SpillAlignment(Props.SpillAlignment), CopyCost(0), - Allocatable(true) { - for (CodeGenRegister::Set::iterator I = Members.begin(), E = Members.end(); - I != E; ++I) - TopoSigs.set((*I)->getTopoSig()); + Allocatable(true), + AllocationPriority(0) { + for (const auto R : Members) + TopoSigs.set(R->getTopoSig()); } // Compute inherited propertied for a synthesized register class. @@ -755,6 +751,7 @@ void CodeGenRegisterClass::inheritProperties(CodeGenRegBank &RegBank) { CopyCost = Super.CopyCost; Allocatable = Super.Allocatable; AltOrderSelect = Super.AltOrderSelect; + AllocationPriority = Super.AllocationPriority; // Copy all allocation orders, filter out foreign registers from the larger // super-class. @@ -766,15 +763,15 @@ void CodeGenRegisterClass::inheritProperties(CodeGenRegBank &RegBank) { } bool CodeGenRegisterClass::contains(const CodeGenRegister *Reg) const { - return Members.count(Reg); + return std::binary_search(Members.begin(), Members.end(), Reg, + deref<llvm::less>()); } namespace llvm { raw_ostream &operator<<(raw_ostream &OS, const CodeGenRegisterClass::Key &K) { OS << "{ S=" << K.SpillSize << ", A=" << K.SpillAlignment; - for (CodeGenRegister::Set::const_iterator I = K.Members->begin(), - E = K.Members->end(); I != E; ++I) - OS << ", " << (*I)->getName(); + for (const auto R : *K.Members) + OS << ", " << R->getName(); return OS << " }"; } } @@ -800,10 +797,10 @@ operator<(const CodeGenRegisterClass::Key &B) const { static bool testSubClass(const CodeGenRegisterClass *A, const CodeGenRegisterClass *B) { return A->SpillAlignment && B->SpillAlignment % A->SpillAlignment == 0 && - A->SpillSize <= B->SpillSize && - std::includes(A->getMembers().begin(), A->getMembers().end(), - B->getMembers().begin(), B->getMembers().end(), - CodeGenRegister::Less()); + A->SpillSize <= B->SpillSize && + std::includes(A->getMembers().begin(), A->getMembers().end(), + B->getMembers().begin(), B->getMembers().end(), + deref<llvm::less>()); } /// Sorting predicate for register classes. This provides a topological @@ -927,7 +924,7 @@ CodeGenRegBank::CodeGenRegBank(RecordKeeper &Records) { // Configure register Sets to understand register classes and tuples. Sets.addFieldExpander("RegisterClass", "MemberList"); Sets.addFieldExpander("CalleeSavedRegs", "SaveList"); - Sets.addExpander("RegisterTuples", new TupleExpander()); + Sets.addExpander("RegisterTuples", llvm::make_unique<TupleExpander>()); // Read in the user-defined (named) sub-register indices. // More indices will be synthesized later. @@ -1050,7 +1047,7 @@ void CodeGenRegBank::addToMaps(CodeGenRegisterClass *RC) { // Create a synthetic sub-class if it is missing. CodeGenRegisterClass* CodeGenRegBank::getOrCreateSubClass(const CodeGenRegisterClass *RC, - const CodeGenRegister::Set *Members, + const CodeGenRegister::Vec *Members, StringRef Name) { // Synthetic sub-class has the same size and alignment as RC. CodeGenRegisterClass::Key K(Members, RC->SpillSize, RC->SpillAlignment); @@ -1273,7 +1270,7 @@ void CodeGenRegBank::computeSubRegLaneMasks() { for (auto &RegClass : RegClasses) { unsigned LaneMask = 0; for (const auto &SubRegIndex : SubRegIndices) { - if (RegClass.getSubClassWithSubReg(&SubRegIndex) != &RegClass) + if (RegClass.getSubClassWithSubReg(&SubRegIndex) == nullptr) continue; LaneMask |= SubRegIndex.LaneMask; } @@ -1299,7 +1296,7 @@ namespace { // for which the unit weight equals the set weight. These units should not have // their weight increased. struct UberRegSet { - CodeGenRegister::Set Regs; + CodeGenRegister::Vec Regs; unsigned Weight; CodeGenRegister::RegUnitList SingularDeterminants; @@ -1328,7 +1325,7 @@ static void computeUberSets(std::vector<UberRegSet> &UberSets, if (!RegClass.Allocatable) continue; - const CodeGenRegister::Set &Regs = RegClass.getMembers(); + const CodeGenRegister::Vec &Regs = RegClass.getMembers(); if (Regs.empty()) continue; @@ -1336,8 +1333,7 @@ static void computeUberSets(std::vector<UberRegSet> &UberSets, assert(USetID && "register number 0 is invalid"); AllocatableRegs.insert((*Regs.begin())->EnumValue); - for (CodeGenRegister::Set::const_iterator I = std::next(Regs.begin()), - E = Regs.end(); I != E; ++I) { + for (auto I = std::next(Regs.begin()), E = Regs.end(); I != E; ++I) { AllocatableRegs.insert((*I)->EnumValue); UberSetIDs.join(USetID, (*I)->EnumValue); } @@ -1367,7 +1363,8 @@ static void computeUberSets(std::vector<UberRegSet> &UberSets, USetID = 0; UberRegSet *USet = &UberSets[USetID]; - USet->Regs.insert(&Reg); + USet->Regs.push_back(&Reg); + sortAndUniqueRegisters(USet->Regs); RegSets[i++] = USet; } } @@ -1409,11 +1406,10 @@ static void computeUberWeights(std::vector<UberRegSet> &UberSets, } // Find singular determinants. - for (CodeGenRegister::Set::iterator RegI = I->Regs.begin(), - RegE = I->Regs.end(); RegI != RegE; ++RegI) { - if ((*RegI)->getRegUnits().size() == 1 - && (*RegI)->getWeight(RegBank) == I->Weight) - mergeRegUnits(I->SingularDeterminants, (*RegI)->getRegUnits()); + for (const auto R : I->Regs) { + if (R->getRegUnits().count() == 1 && R->getWeight(RegBank) == I->Weight) { + I->SingularDeterminants |= R->getRegUnits(); + } } } } @@ -1431,13 +1427,14 @@ static void computeUberWeights(std::vector<UberRegSet> &UberSets, static bool normalizeWeight(CodeGenRegister *Reg, std::vector<UberRegSet> &UberSets, std::vector<UberRegSet*> &RegSets, - std::set<unsigned> &NormalRegs, + SparseBitVector<> &NormalRegs, CodeGenRegister::RegUnitList &NormalUnits, CodeGenRegBank &RegBank) { - bool Changed = false; - if (!NormalRegs.insert(Reg->EnumValue).second) - return Changed; + if (NormalRegs.test(Reg->EnumValue)) + return false; + NormalRegs.set(Reg->EnumValue); + bool Changed = false; const CodeGenRegister::SubRegMap &SRM = Reg->getSubRegs(); for (CodeGenRegister::SubRegMap::const_iterator SRI = SRM.begin(), SRE = SRM.end(); SRI != SRE; ++SRI) { @@ -1461,8 +1458,8 @@ static bool normalizeWeight(CodeGenRegister *Reg, // A register unit's weight can be adjusted only if it is the singular unit // for this register, has not been used to normalize a subregister's set, // and has not already been used to singularly determine this UberRegSet. - unsigned AdjustUnit = Reg->getRegUnits().front(); - if (Reg->getRegUnits().size() != 1 + unsigned AdjustUnit = *Reg->getRegUnits().begin(); + if (Reg->getRegUnits().count() != 1 || hasRegUnit(NormalUnits, AdjustUnit) || hasRegUnit(UberSet->SingularDeterminants, AdjustUnit)) { // We don't have an adjustable unit, so adopt a new one. @@ -1480,7 +1477,7 @@ static bool normalizeWeight(CodeGenRegister *Reg, } // Mark these units normalized so superregisters can't change their weights. - mergeRegUnits(NormalUnits, Reg->getRegUnits()); + NormalUnits |= Reg->getRegUnits(); return Changed; } @@ -1505,7 +1502,7 @@ void CodeGenRegBank::computeRegUnitWeights() { Changed = false; for (auto &Reg : Registers) { CodeGenRegister::RegUnitList NormalUnits; - std::set<unsigned> NormalRegs; + SparseBitVector<> NormalRegs; Changed |= normalizeWeight(&Reg, UberSets, RegSets, NormalRegs, NormalUnits, *this); } @@ -1768,7 +1765,7 @@ void CodeGenRegBank::computeRegUnitLaneMasks() { for (auto &Register : Registers) { // Create an initial lane mask for all register units. const auto &RegUnits = Register.getRegUnits(); - CodeGenRegister::RegUnitLaneMaskList RegUnitLaneMasks(RegUnits.size(), 0); + CodeGenRegister::RegUnitLaneMaskList RegUnitLaneMasks(RegUnits.count(), 0); // Iterate through SubRegisters. typedef CodeGenRegister::SubRegMap SubRegMap; const SubRegMap &SubRegs = Register.getSubRegs(); @@ -1783,15 +1780,18 @@ void CodeGenRegBank::computeRegUnitLaneMasks() { const CodeGenRegister *SubRegister = S->second; unsigned LaneMask = SubRegIndex->LaneMask; // Distribute LaneMask to Register Units touched. - for (const auto &SUI : SubRegister->getRegUnits()) { + for (unsigned SUI : SubRegister->getRegUnits()) { bool Found = false; - for (size_t u = 0, ue = RegUnits.size(); u < ue; ++u) { - if (SUI == RegUnits[u]) { + unsigned u = 0; + for (unsigned RU : RegUnits) { + if (SUI == RU) { RegUnitLaneMasks[u] |= LaneMask; assert(!Found); Found = true; } + ++u; } + (void)Found; assert(Found); } } @@ -1813,6 +1813,13 @@ void CodeGenRegBank::computeDerivedInfo() { computeRegUnitLaneMasks(); + // Compute register class HasDisjunctSubRegs flag. + for (CodeGenRegisterClass &RC : RegClasses) { + RC.HasDisjunctSubRegs = false; + for (const CodeGenRegister *Reg : RC.getMembers()) + RC.HasDisjunctSubRegs |= Reg->HasDisjunctSubRegs; + } + // Get the weight of each set. for (unsigned Idx = 0, EndIdx = RegUnitSets.size(); Idx != EndIdx; ++Idx) RegUnitSets[Idx].Weight = getRegUnitSetWeight(RegUnitSets[Idx].Units); @@ -1850,13 +1857,12 @@ void CodeGenRegBank::inferCommonSubClass(CodeGenRegisterClass *RC) { continue; // Compute the set intersection of RC1 and RC2. - const CodeGenRegister::Set &Memb1 = RC1->getMembers(); - const CodeGenRegister::Set &Memb2 = RC2->getMembers(); - CodeGenRegister::Set Intersection; - std::set_intersection(Memb1.begin(), Memb1.end(), - Memb2.begin(), Memb2.end(), - std::inserter(Intersection, Intersection.begin()), - CodeGenRegister::Less()); + const CodeGenRegister::Vec &Memb1 = RC1->getMembers(); + const CodeGenRegister::Vec &Memb2 = RC2->getMembers(); + CodeGenRegister::Vec Intersection; + std::set_intersection( + Memb1.begin(), Memb1.end(), Memb2.begin(), Memb2.end(), + std::inserter(Intersection, Intersection.begin()), deref<llvm::less>()); // Skip disjoint class pairs. if (Intersection.empty()) @@ -1882,19 +1888,21 @@ void CodeGenRegBank::inferCommonSubClass(CodeGenRegisterClass *RC) { // void CodeGenRegBank::inferSubClassWithSubReg(CodeGenRegisterClass *RC) { // Map SubRegIndex to set of registers in RC supporting that SubRegIndex. - typedef std::map<const CodeGenSubRegIndex *, CodeGenRegister::Set, - CodeGenSubRegIndex::Less> SubReg2SetMap; + typedef std::map<const CodeGenSubRegIndex *, CodeGenRegister::Vec, + deref<llvm::less>> SubReg2SetMap; // Compute the set of registers supporting each SubRegIndex. SubReg2SetMap SRSets; - for (CodeGenRegister::Set::const_iterator RI = RC->getMembers().begin(), - RE = RC->getMembers().end(); RI != RE; ++RI) { - const CodeGenRegister::SubRegMap &SRM = (*RI)->getSubRegs(); + for (const auto R : RC->getMembers()) { + const CodeGenRegister::SubRegMap &SRM = R->getSubRegs(); for (CodeGenRegister::SubRegMap::const_iterator I = SRM.begin(), E = SRM.end(); I != E; ++I) - SRSets[I->first].insert(*RI); + SRSets[I->first].push_back(R); } + for (auto I : SRSets) + sortAndUniqueRegisters(I.second); + // Find matching classes for all SRSets entries. Iterate in SubRegIndex // numerical order to visit synthetic indices last. for (const auto &SubIdx : SubRegIndices) { @@ -1939,9 +1947,7 @@ void CodeGenRegBank::inferMatchingSuperRegClass(CodeGenRegisterClass *RC, // Build list of (Super, Sub) pairs for this SubIdx. SSPairs.clear(); TopoSigs.reset(); - for (CodeGenRegister::Set::const_iterator RI = RC->getMembers().begin(), - RE = RC->getMembers().end(); RI != RE; ++RI) { - const CodeGenRegister *Super = *RI; + for (const auto Super : RC->getMembers()) { const CodeGenRegister *Sub = Super->getSubRegs().find(&SubIdx)->second; assert(Sub && "Missing sub-register"); SSPairs.push_back(std::make_pair(Super, Sub)); @@ -1960,22 +1966,26 @@ void CodeGenRegBank::inferMatchingSuperRegClass(CodeGenRegisterClass *RC, if (!TopoSigs.anyCommon(SubRC.getTopoSigs())) continue; // Compute the subset of RC that maps into SubRC. - CodeGenRegister::Set SubSet; + CodeGenRegister::Vec SubSetVec; for (unsigned i = 0, e = SSPairs.size(); i != e; ++i) if (SubRC.contains(SSPairs[i].second)) - SubSet.insert(SSPairs[i].first); - if (SubSet.empty()) + SubSetVec.push_back(SSPairs[i].first); + + if (SubSetVec.empty()) continue; + // RC injects completely into SubRC. - if (SubSet.size() == SSPairs.size()) { + sortAndUniqueRegisters(SubSetVec); + if (SubSetVec.size() == SSPairs.size()) { SubRC.addSuperRegClass(&SubIdx, RC); continue; } + // Only a subset of RC maps into SubRC. Make sure it is represented by a // class. - getOrCreateSubClass(RC, &SubSet, RC->getName() + "_with_" + - SubIdx.getName() + "_in_" + - SubRC.getName()); + getOrCreateSubClass(RC, &SubSetVec, RC->getName() + "_with_" + + SubIdx.getName() + "_in_" + + SubRC.getName()); } } } diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h index 87a0dcf7af3d8..dc441436537db 100644 --- a/utils/TableGen/CodeGenRegisters.h +++ b/utils/TableGen/CodeGenRegisters.h @@ -18,7 +18,9 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SparseBitVector.h" #include "llvm/CodeGen/MachineValueType.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/TableGen/Record.h" @@ -40,10 +42,10 @@ namespace llvm { struct MaskRolPair { unsigned Mask; uint8_t RotateLeft; - bool operator==(const MaskRolPair Other) { + bool operator==(const MaskRolPair Other) const { return Mask == Other.Mask && RotateLeft == Other.RotateLeft; } - bool operator!=(const MaskRolPair Other) { + bool operator!=(const MaskRolPair Other) const { return Mask != Other.Mask || RotateLeft != Other.RotateLeft; } }; @@ -72,17 +74,9 @@ namespace llvm { const std::string &getNamespace() const { return Namespace; } std::string getQualifiedName() const; - // Order CodeGenSubRegIndex pointers by EnumValue. - struct Less { - bool operator()(const CodeGenSubRegIndex *A, - const CodeGenSubRegIndex *B) const { - assert(A && B); - return A->EnumValue < B->EnumValue; - } - }; - // Map of composite subreg indices. - typedef std::map<CodeGenSubRegIndex*, CodeGenSubRegIndex*, Less> CompMap; + typedef std::map<CodeGenSubRegIndex *, CodeGenSubRegIndex *, + deref<llvm::less>> CompMap; // Returns the subreg index that results from composing this with Idx. // Returns NULL if this and Idx don't compose. @@ -124,16 +118,22 @@ namespace llvm { CompMap Composed; }; + inline bool operator<(const CodeGenSubRegIndex &A, + const CodeGenSubRegIndex &B) { + return A.EnumValue < B.EnumValue; + } + /// CodeGenRegister - Represents a register definition. struct CodeGenRegister { Record *TheDef; unsigned EnumValue; unsigned CostPerUse; bool CoveredBySubRegs; + bool HasDisjunctSubRegs; // Map SubRegIndex -> Register. - typedef std::map<CodeGenSubRegIndex*, CodeGenRegister*, - CodeGenSubRegIndex::Less> SubRegMap; + typedef std::map<CodeGenSubRegIndex *, CodeGenRegister *, deref<llvm::less>> + SubRegMap; CodeGenRegister(Record *R, unsigned Enum); @@ -197,23 +197,23 @@ namespace llvm { } // List of register units in ascending order. - typedef SmallVector<unsigned, 16> RegUnitList; + typedef SparseBitVector<> RegUnitList; typedef SmallVector<unsigned, 16> RegUnitLaneMaskList; // How many entries in RegUnitList are native? - unsigned NumNativeRegUnits; + RegUnitList NativeRegUnits; // Get the list of register units. // This is only valid after computeSubRegs() completes. const RegUnitList &getRegUnits() const { return RegUnits; } ArrayRef<unsigned> getRegUnitLaneMasks() const { - return makeArrayRef(RegUnitLaneMasks).slice(0, NumNativeRegUnits); + return makeArrayRef(RegUnitLaneMasks).slice(0, NativeRegUnits.count()); } // Get the native register units. This is a prefix of getRegUnits(). - ArrayRef<unsigned> getNativeRegUnits() const { - return makeArrayRef(RegUnits).slice(0, NumNativeRegUnits); + RegUnitList getNativeRegUnits() const { + return NativeRegUnits; } void setRegUnitLaneMasks(const RegUnitLaneMaskList &LaneMasks) { @@ -225,23 +225,14 @@ namespace llvm { bool inheritRegUnits(CodeGenRegBank &RegBank); // Adopt a register unit for pressure tracking. - // A unit is adopted iff its unit number is >= NumNativeRegUnits. - void adoptRegUnit(unsigned RUID) { RegUnits.push_back(RUID); } + // A unit is adopted iff its unit number is >= NativeRegUnits.count(). + void adoptRegUnit(unsigned RUID) { RegUnits.set(RUID); } // Get the sum of this register's register unit weights. unsigned getWeight(const CodeGenRegBank &RegBank) const; - // Order CodeGenRegister pointers by EnumValue. - struct Less { - bool operator()(const CodeGenRegister *A, - const CodeGenRegister *B) const { - assert(A && B); - return A->EnumValue < B->EnumValue; - } - }; - // Canonically ordered set. - typedef std::set<const CodeGenRegister*, Less> Set; + typedef std::vector<const CodeGenRegister*> Vec; private: bool SubRegsComplete; @@ -265,9 +256,16 @@ namespace llvm { RegUnitLaneMaskList RegUnitLaneMasks; }; + inline bool operator<(const CodeGenRegister &A, const CodeGenRegister &B) { + return A.EnumValue < B.EnumValue; + } + + inline bool operator==(const CodeGenRegister &A, const CodeGenRegister &B) { + return A.EnumValue == B.EnumValue; + } class CodeGenRegisterClass { - CodeGenRegister::Set Members; + CodeGenRegister::Vec Members; // Allocation orders. Order[0] always contains all registers in Members. std::vector<SmallVector<Record*, 16> > Orders; // Bit mask of sub-classes including this, indexed by their EnumValue. @@ -308,8 +306,11 @@ namespace llvm { int CopyCost; bool Allocatable; std::string AltOrderSelect; + uint8_t AllocationPriority; /// Contains the combination of the lane masks of all subregisters. unsigned LaneMask; + /// True if there are at least 2 subregisters which do not interfere. + bool HasDisjunctSubRegs; // Return the Record that defined this class, or NULL if the class was // created by TableGen. @@ -388,7 +389,7 @@ namespace llvm { // Get the set of registers. This set contains the same registers as // getOrder(0). - const CodeGenRegister::Set &getMembers() const { return Members; } + const CodeGenRegister::Vec &getMembers() const { return Members; } // Get a bit vector of TopoSigs present in this register class. const BitVector &getTopoSigs() const { return TopoSigs; } @@ -402,11 +403,11 @@ namespace llvm { // sub-classes. Note the ordering provided by this key is not the same as // the topological order used for the EnumValues. struct Key { - const CodeGenRegister::Set *Members; + const CodeGenRegister::Vec *Members; unsigned SpillSize; unsigned SpillAlignment; - Key(const CodeGenRegister::Set *M, unsigned S = 0, unsigned A = 0) + Key(const CodeGenRegister::Vec *M, unsigned S = 0, unsigned A = 0) : Members(M), SpillSize(S), SpillAlignment(A) {} Key(const CodeGenRegisterClass &RC) @@ -524,7 +525,7 @@ namespace llvm { // Create a synthetic sub-class if it is missing. CodeGenRegisterClass *getOrCreateSubClass(const CodeGenRegisterClass *RC, - const CodeGenRegister::Set *Membs, + const CodeGenRegister::Vec *Membs, StringRef Name); // Infer missing register classes. diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp index bfdf8dcc89e09..58363e85c5449 100644 --- a/utils/TableGen/CodeGenSchedule.cpp +++ b/utils/TableGen/CodeGenSchedule.cpp @@ -93,8 +93,8 @@ CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, // Allow Set evaluation to recognize the dags used in InstRW records: // (instrs Op1, Op1...) - Sets.addOperator("instrs", new InstrsOp); - Sets.addOperator("instregex", new InstRegexOp(Target)); + Sets.addOperator("instrs", llvm::make_unique<InstrsOp>()); + Sets.addOperator("instregex", llvm::make_unique<InstRegexOp>(Target)); // Instantiate a CodeGenProcModel for each SchedMachineModel with the values // that are explicitly referenced in tablegen records. Resources associated diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index e727a0e3f7ac5..076537002a6f0 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -57,6 +57,7 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) { case MVT::i32: return "MVT::i32"; case MVT::i64: return "MVT::i64"; case MVT::i128: return "MVT::i128"; + case MVT::Any: return "MVT::Any"; case MVT::iAny: return "MVT::iAny"; case MVT::fAny: return "MVT::fAny"; case MVT::vAny: return "MVT::vAny"; @@ -98,6 +99,7 @@ std::string llvm::getEnumName(MVT::SimpleValueType T) { case MVT::v4i64: return "MVT::v4i64"; case MVT::v8i64: return "MVT::v8i64"; case MVT::v16i64: return "MVT::v16i64"; + case MVT::v1i128: return "MVT::v1i128"; case MVT::v2f16: return "MVT::v2f16"; case MVT::v4f16: return "MVT::v4f16"; case MVT::v8f16: return "MVT::v8f16"; @@ -409,9 +411,9 @@ ComplexPattern::ComplexPattern(Record *R) { } else if (PropList[i]->getName() == "SDNPWantParent") { Properties |= 1 << SDNPWantParent; } else { - errs() << "Unsupported SD Node property '" << PropList[i]->getName() - << "' on ComplexPattern '" << R->getName() << "'!\n"; - exit(1); + PrintFatalError("Unsupported SD Node property '" + + PropList[i]->getName() + "' on ComplexPattern '" + + R->getName() + "'!"); } } @@ -442,6 +444,7 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { canThrow = false; isNoReturn = false; isNoDuplicate = false; + isConvergent = false; if (DefName.size() <= 4 || std::string(DefName.begin(), DefName.begin() + 4) != "int_") @@ -572,6 +575,8 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { canThrow = true; else if (Property->getName() == "IntrNoDuplicate") isNoDuplicate = true; + else if (Property->getName() == "IntrConvergent") + isConvergent = true; else if (Property->getName() == "IntrNoReturn") isNoReturn = true; else if (Property->isSubClassOf("NoCapture")) { diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h index 9df3b410ff268..a8a6ba5c32e15 100644 --- a/utils/TableGen/DAGISelMatcher.h +++ b/utils/TableGen/DAGISelMatcher.h @@ -194,7 +194,7 @@ public: ScopeMatcher(ArrayRef<Matcher *> children) : Matcher(Scope), Children(children.begin(), children.end()) { } - virtual ~ScopeMatcher(); + ~ScopeMatcher() override; unsigned getNumChildren() const { return Children.size(); } @@ -507,7 +507,7 @@ class SwitchOpcodeMatcher : public Matcher { public: SwitchOpcodeMatcher(ArrayRef<std::pair<const SDNodeInfo*, Matcher*> > cases) : Matcher(SwitchOpcode), Cases(cases.begin(), cases.end()) {} - virtual ~SwitchOpcodeMatcher(); + ~SwitchOpcodeMatcher() override; static inline bool classof(const Matcher *N) { return N->getKind() == SwitchOpcode; @@ -561,7 +561,7 @@ class SwitchTypeMatcher : public Matcher { public: SwitchTypeMatcher(ArrayRef<std::pair<MVT::SimpleValueType, Matcher*> > cases) : Matcher(SwitchType), Cases(cases.begin(), cases.end()) {} - virtual ~SwitchTypeMatcher(); + ~SwitchTypeMatcher() override; static inline bool classof(const Matcher *N) { return N->getKind() == SwitchType; diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp index 302f27bd0ecb4..4659dc157338b 100644 --- a/utils/TableGen/DAGISelMatcherEmitter.cpp +++ b/utils/TableGen/DAGISelMatcherEmitter.cpp @@ -188,7 +188,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, << " children in Scope"; } - OS << '\n' << TmpBuf.str(); + OS << '\n' << TmpBuf; CurrentIdx += ChildSize; } @@ -342,7 +342,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, if (!OmitComments) OS << "// ->" << CurrentIdx+ChildSize; OS << '\n'; - OS << TmpBuf.str(); + OS << TmpBuf; CurrentIdx += ChildSize; } diff --git a/utils/TableGen/DAGISelMatcherGen.cpp b/utils/TableGen/DAGISelMatcherGen.cpp index eb806192bdc39..9663b71d6620d 100644 --- a/utils/TableGen/DAGISelMatcherGen.cpp +++ b/utils/TableGen/DAGISelMatcherGen.cpp @@ -220,7 +220,7 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) { } // An UnsetInit represents a named node without any constraints. - if (N->getLeafValue() == UnsetInit::get()) { + if (isa<UnsetInit>(N->getLeafValue())) { assert(N->hasName() && "Unnamed ? leaf"); return; } @@ -268,8 +268,10 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) { // We can't model ComplexPattern uses that don't have their name taken yet. // The OPC_CheckComplexPattern operation implicitly records the results. if (N->getName().empty()) { - errs() << "We expect complex pattern uses to have names: " << *N << "\n"; - exit(1); + std::string S; + raw_string_ostream OS(S); + OS << "We expect complex pattern uses to have names: " << *N; + PrintFatalError(OS.str()); } // Remember this ComplexPattern so that we can emit it after all the other diff --git a/utils/TableGen/DFAPacketizerEmitter.cpp b/utils/TableGen/DFAPacketizerEmitter.cpp index ea14cb973ebcd..5060b6e9ce7c0 100644 --- a/utils/TableGen/DFAPacketizerEmitter.cpp +++ b/utils/TableGen/DFAPacketizerEmitter.cpp @@ -472,7 +472,7 @@ void DFAPacketizerEmitter::run(raw_ostream &OS) { current->canAddInsnClass(InsnClass)) { const State *NewState; current->AddInsnClass(InsnClass, NewStateResources); - assert(NewStateResources.size() && "New states must be generated"); + assert(!NewStateResources.empty() && "New states must be generated"); // // If we have seen this state before, then do not create a new state. diff --git a/utils/TableGen/FixedLenDecoderEmitter.cpp b/utils/TableGen/FixedLenDecoderEmitter.cpp index 7c29422ec1b90..7905b1a6268e2 100644 --- a/utils/TableGen/FixedLenDecoderEmitter.cpp +++ b/utils/TableGen/FixedLenDecoderEmitter.cpp @@ -333,8 +333,8 @@ protected: // Parent emitter const FixedLenDecoderEmitter *Emitter; - FilterChooser(const FilterChooser &) LLVM_DELETED_FUNCTION; - void operator=(const FilterChooser &) LLVM_DELETED_FUNCTION; + FilterChooser(const FilterChooser &) = delete; + void operator=(const FilterChooser &) = delete; public: FilterChooser(const std::vector<const CodeGenInstruction*> &Insts, @@ -540,7 +540,7 @@ void Filter::recurse() { // Starts by inheriting our parent filter chooser's filter bit values. std::vector<bit_value_t> BitValueArray(Owner->FilterBitValues); - if (VariableInstructions.size()) { + if (!VariableInstructions.empty()) { // Conservatively marks each segment position as BIT_UNSET. for (unsigned bitIndex = 0; bitIndex < NumBits; ++bitIndex) BitValueArray[StartBit + bitIndex] = BIT_UNSET; @@ -676,7 +676,7 @@ void Filter::emitTableEntry(DecoderTableInfo &TableInfo) const { // Returns the number of fanout produced by the filter. More fanout implies // the filter distinguishes more categories of instructions. unsigned Filter::usefulness() const { - if (VariableInstructions.size()) + if (!VariableInstructions.empty()) return FilteredInstructions.size(); else return FilteredInstructions.size() + 1; @@ -848,7 +848,7 @@ emitPredicateFunction(formatted_raw_ostream &OS, PredicateSet &Predicates, // The predicate function is just a big switch statement based on the // input predicate index. OS.indent(Indentation) << "static bool checkDecoderPredicate(unsigned Idx, " - << "uint64_t Bits) {\n"; + << "const FeatureBitset& Bits) {\n"; Indentation += 2; if (!Predicates.empty()) { OS.indent(Indentation) << "switch (Idx) {\n"; @@ -1054,7 +1054,7 @@ void FilterChooser::emitBinaryParser(raw_ostream &o, unsigned &Indentation, << "(MI, tmp, Address, Decoder)" << Emitter->GuardPostfix << "\n"; else - o.indent(Indentation) << "MI.addOperand(MCOperand::CreateImm(tmp));\n"; + o.indent(Indentation) << "MI.addOperand(MCOperand::createImm(tmp));\n"; } @@ -1091,7 +1091,7 @@ unsigned FilterChooser::getDecoderIndex(DecoderSet &Decoders, // overkill for now, though. // Make sure the predicate is in the table. - Decoders.insert(Decoder.str()); + Decoders.insert(StringRef(Decoder)); // Now figure out the index for when we write out the table. DecoderSet::const_iterator P = std::find(Decoders.begin(), Decoders.end(), @@ -1102,16 +1102,17 @@ unsigned FilterChooser::getDecoderIndex(DecoderSet &Decoders, static void emitSinglePredicateMatch(raw_ostream &o, StringRef str, const std::string &PredicateNamespace) { if (str[0] == '!') - o << "!(Bits & " << PredicateNamespace << "::" - << str.slice(1,str.size()) << ")"; + o << "!Bits[" << PredicateNamespace << "::" + << str.slice(1,str.size()) << "]"; else - o << "(Bits & " << PredicateNamespace << "::" << str << ")"; + o << "Bits[" << PredicateNamespace << "::" << str << "]"; } bool FilterChooser::emitPredicateMatch(raw_ostream &o, unsigned &Indentation, unsigned Opc) const { ListInit *Predicates = AllInstructions[Opc]->TheDef->getValueAsListInit("Predicates"); + bool IsFirstEmission = true; for (unsigned i = 0; i < Predicates->getSize(); ++i) { Record *Pred = Predicates->getElementAsRecord(i); if (!Pred->getValue("AssemblerMatcherPredicate")) @@ -1122,7 +1123,7 @@ bool FilterChooser::emitPredicateMatch(raw_ostream &o, unsigned &Indentation, if (!P.length()) continue; - if (i != 0) + if (!IsFirstEmission) o << " && "; StringRef SR(P); @@ -1133,6 +1134,7 @@ bool FilterChooser::emitPredicateMatch(raw_ostream &o, unsigned &Indentation, pairs = pairs.second.split(','); } emitSinglePredicateMatch(o, pairs.first, Emitter->PredicateNamespace); + IsFirstEmission = false; } return Predicates->getSize() > 0; } @@ -1780,7 +1782,7 @@ static bool populateInstruction(CodeGenTarget &Target, unsigned NumberOps = CGI.Operands.size(); while (NumberedOp < NumberOps && (CGI.Operands.isFlatOperandNotEmitted(NumberedOp) || - (NamedOpIndices.size() && NamedOpIndices.count( + (!NamedOpIndices.empty() && NamedOpIndices.count( CGI.Operands.getSubOperandNumber(NumberedOp).first)))) ++NumberedOp; @@ -2010,7 +2012,7 @@ static void emitDecodeInstruction(formatted_raw_ostream &OS) { << " InsnType insn, uint64_t Address,\n" << " const void *DisAsm,\n" << " const MCSubtargetInfo &STI) {\n" - << " uint64_t Bits = STI.getFeatureBits();\n" + << " const FeatureBitset& Bits = STI.getFeatureBits();\n" << "\n" << " const uint8_t *Ptr = DecodeTable;\n" << " uint32_t CurFieldValue = 0;\n" diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index fe30d60fd4ce7..7b69de56f9f74 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -248,7 +248,7 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS, OS << "#ifdef GET_INSTRINFO_OPERAND_ENUM\n"; OS << "#undef GET_INSTRINFO_OPERAND_ENUM\n"; - OS << "namespace llvm {"; + OS << "namespace llvm {\n"; OS << "namespace " << Namespace << " {\n"; OS << "namespace " << OpNameNS << " { \n"; OS << "enum {\n"; @@ -264,7 +264,7 @@ void InstrInfoEmitter::emitOperandNameMappings(raw_ostream &OS, OS << "#ifdef GET_INSTRINFO_NAMED_OPS\n"; OS << "#undef GET_INSTRINFO_NAMED_OPS\n"; - OS << "namespace llvm {"; + OS << "namespace llvm {\n"; OS << "namespace " << Namespace << " {\n"; OS << "LLVM_READONLY\n"; OS << "int16_t getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIdx) {\n"; @@ -315,7 +315,7 @@ void InstrInfoEmitter::emitOperandTypesEnum(raw_ostream &OS, OS << "\n#ifdef GET_INSTRINFO_OPERAND_TYPES_ENUM\n"; OS << "#undef GET_INSTRINFO_OPERAND_TYPES_ENUM\n"; - OS << "namespace llvm {"; + OS << "namespace llvm {\n"; OS << "namespace " << Namespace << " {\n"; OS << "namespace OpTypes { \n"; OS << "enum OperandType {\n"; @@ -430,7 +430,8 @@ void InstrInfoEmitter::run(raw_ostream &OS) { std::string ClassName = TargetName + "GenInstrInfo"; OS << "namespace llvm {\n"; OS << "struct " << ClassName << " : public TargetInstrInfo {\n" - << " explicit " << ClassName << "(int SO = -1, int DO = -1);\n" + << " explicit " << ClassName + << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1);\n" << " virtual ~" << ClassName << "();\n" << "};\n"; OS << "} // End llvm namespace \n"; @@ -444,10 +445,11 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << "extern const MCInstrDesc " << TargetName << "Insts[];\n"; OS << "extern const unsigned " << TargetName << "InstrNameIndices[];\n"; OS << "extern const char " << TargetName << "InstrNameData[];\n"; - OS << ClassName << "::" << ClassName << "(int SO, int DO)\n" - << " : TargetInstrInfo(SO, DO) {\n" - << " InitMCInstrInfo(" << TargetName << "Insts, " - << TargetName << "InstrNameIndices, " << TargetName << "InstrNameData, " + OS << ClassName << "::" << ClassName + << "(int CFSetupOpcode, int CFDestroyOpcode)\n" + << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode) {\n" + << " InitMCInstrInfo(" << TargetName << "Insts, " << TargetName + << "InstrNameIndices, " << TargetName << "InstrNameData, " << NumberedInstructions.size() << ");\n}\n" << ClassName << "::~" << ClassName << "() {}\n"; OS << "} // End llvm namespace \n"; @@ -476,7 +478,7 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, << SchedModels.getSchedClassIdx(Inst) << ",\t" << Inst.TheDef->getValueAsInt("Size") << ",\t0"; - // Emit all of the target indepedent flags... + // Emit all of the target independent flags... if (Inst.isPseudo) OS << "|(1<<MCID::Pseudo)"; if (Inst.isReturn) OS << "|(1<<MCID::Return)"; if (Inst.isBranch) OS << "|(1<<MCID::Branch)"; @@ -547,15 +549,15 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, CodeGenTarget &Target = CDP.getTargetInfo(); if (Inst.HasComplexDeprecationPredicate) // Emit a function pointer to the complex predicate method. - OS << ",0" + OS << ", -1 " << ",&get" << Inst.DeprecatedReason << "DeprecationInfo"; else if (!Inst.DeprecatedReason.empty()) // Emit the Subtarget feature. - OS << "," << Target.getInstNamespace() << "::" << Inst.DeprecatedReason - << ",nullptr"; + OS << ", " << Target.getInstNamespace() << "::" << Inst.DeprecatedReason + << " ,nullptr"; else // Instruction isn't deprecated. - OS << ",0,nullptr"; + OS << ", -1 ,nullptr"; OS << " }, // Inst #" << Num << " = " << Inst.TheDef->getName() << "\n"; } @@ -573,10 +575,8 @@ void InstrInfoEmitter::emitEnums(raw_ostream &OS) { // We must emit the PHI opcode first... std::string Namespace = Target.getInstNamespace(); - if (Namespace.empty()) { - fprintf(stderr, "No instructions defined!\n"); - exit(1); - } + if (Namespace.empty()) + PrintFatalError("No instructions defined!"); const std::vector<const CodeGenInstruction*> &NumberedInstructions = Target.getInstructionsByEnumValue(); diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp index c0cf92d761873..3f62f205fe557 100644 --- a/utils/TableGen/IntrinsicEmitter.cpp +++ b/utils/TableGen/IntrinsicEmitter.cpp @@ -259,7 +259,9 @@ enum IIT_Info { IIT_VARARG = 28, IIT_HALF_VEC_ARG = 29, IIT_SAME_VEC_WIDTH_ARG = 30, - IIT_PTR_TO_ARG = 31 + IIT_PTR_TO_ARG = 31, + IIT_VEC_OF_PTRS_TO_ELT = 32, + IIT_I128 = 33 }; @@ -274,6 +276,7 @@ static void EncodeFixedValueType(MVT::SimpleValueType VT, case 16: return Sig.push_back(IIT_I16); case 32: return Sig.push_back(IIT_I32); case 64: return Sig.push_back(IIT_I64); + case 128: return Sig.push_back(IIT_I128); } } @@ -291,7 +294,7 @@ static void EncodeFixedValueType(MVT::SimpleValueType VT, } } -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) #pragma optimize("",off) // MSVC 2010 optimizer can't deal with this function. #endif @@ -309,17 +312,18 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes, Sig.push_back(IIT_HALF_VEC_ARG); else if (R->isSubClassOf("LLVMVectorSameWidth")) { Sig.push_back(IIT_SAME_VEC_WIDTH_ARG); - Sig.push_back((Number << 2) | ArgCodes[Number]); + Sig.push_back((Number << 3) | ArgCodes[Number]); MVT::SimpleValueType VT = getValueType(R->getValueAsDef("ElTy")); EncodeFixedValueType(VT, Sig); return; } - else if (R->isSubClassOf("LLVMPointerTo")) { + else if (R->isSubClassOf("LLVMPointerTo")) Sig.push_back(IIT_PTR_TO_ARG); - } + else if (R->isSubClassOf("LLVMVectorOfPointersToElt")) + Sig.push_back(IIT_VEC_OF_PTRS_TO_ELT); else Sig.push_back(IIT_ARG); - return Sig.push_back((Number << 2) | ArgCodes[Number]); + return Sig.push_back((Number << 3) | ArgCodes[Number]); } MVT::SimpleValueType VT = getValueType(R->getValueAsDef("VT")); @@ -330,7 +334,8 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes, case MVT::iPTRAny: ++Tmp; // FALL THROUGH. case MVT::vAny: ++Tmp; // FALL THROUGH. case MVT::fAny: ++Tmp; // FALL THROUGH. - case MVT::iAny: { + case MVT::iAny: ++Tmp; // FALL THROUGH. + case MVT::Any: { // If this is an "any" valuetype, then the type is the type of the next // type in the list specified to getIntrinsic(). Sig.push_back(IIT_ARG); @@ -339,8 +344,8 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes, unsigned ArgNo = ArgCodes.size(); ArgCodes.push_back(Tmp); - // Encode what sort of argument it must be in the low 2 bits of the ArgNo. - return Sig.push_back((ArgNo << 2) | Tmp); + // Encode what sort of argument it must be in the low 3 bits of the ArgNo. + return Sig.push_back((ArgNo << 3) | Tmp); } case MVT::iPTR: { @@ -378,7 +383,7 @@ static void EncodeFixedType(Record *R, std::vector<unsigned char> &ArgCodes, EncodeFixedValueType(VT, Sig); } -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) #pragma optimize("",on) #endif @@ -532,6 +537,9 @@ struct AttributeComparator { if (L->isNoReturn != R->isNoReturn) return R->isNoReturn; + if (L->isConvergent != R->isConvergent) + return R->isConvergent; + // Try to order by readonly/readnone attribute. ModRefKind LK = getModRefKind(*L); ModRefKind RK = getModRefKind(*R); @@ -644,7 +652,7 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) { ModRefKind modRef = getModRefKind(intrinsic); if (!intrinsic.canThrow || modRef || intrinsic.isNoReturn || - intrinsic.isNoDuplicate) { + intrinsic.isNoDuplicate || intrinsic.isConvergent) { OS << " const Attribute::AttrKind Atts[] = {"; bool addComma = false; if (!intrinsic.canThrow) { @@ -663,6 +671,12 @@ EmitAttributes(const std::vector<CodeGenIntrinsic> &Ints, raw_ostream &OS) { OS << "Attribute::NoDuplicate"; addComma = true; } + if (intrinsic.isConvergent) { + if (addComma) + OS << ","; + OS << "Attribute::Convergent"; + addComma = true; + } switch (modRef) { case MRK_none: break; diff --git a/utils/TableGen/PseudoLoweringEmitter.cpp b/utils/TableGen/PseudoLoweringEmitter.cpp index ebb43f0652620..01e41d1060e0d 100644 --- a/utils/TableGen/PseudoLoweringEmitter.cpp +++ b/utils/TableGen/PseudoLoweringEmitter.cpp @@ -232,12 +232,12 @@ void PseudoLoweringEmitter::emitLoweringEmitter(raw_ostream &o) { << " TmpInst.addOperand(MCOp);\n"; break; case OpData::Imm: - o << " TmpInst.addOperand(MCOperand::CreateImm(" + o << " TmpInst.addOperand(MCOperand::createImm(" << Expansion.OperandMap[MIOpNo + i].Data.Imm << "));\n"; break; case OpData::Reg: { Record *Reg = Expansion.OperandMap[MIOpNo + i].Data.Reg; - o << " TmpInst.addOperand(MCOperand::CreateReg("; + o << " TmpInst.addOperand(MCOperand::createReg("; // "zero_reg" is special. if (Reg->getName() == "zero_reg") o << "0"; diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp index 1c3de4a2c2b85..a8423a98ae855 100644 --- a/utils/TableGen/RegisterInfoEmitter.cpp +++ b/utils/TableGen/RegisterInfoEmitter.cpp @@ -180,7 +180,7 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank, << "getRegClassWeight(const TargetRegisterClass *RC) const {\n" << " static const RegClassWeight RCWeightTable[] = {\n"; for (const auto &RC : RegBank.getRegClasses()) { - const CodeGenRegister::Set &Regs = RC.getMembers(); + const CodeGenRegister::Vec &Regs = RC.getMembers(); if (Regs.empty()) OS << " {0, 0"; else { @@ -233,7 +233,7 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank, OS << "// Get the name of this register unit pressure set.\n" << "const char *" << ClassName << "::\n" << "getRegPressureSetName(unsigned Idx) const {\n" - << " static const char *PressureNameTable[] = {\n"; + << " static const char *const PressureNameTable[] = {\n"; unsigned MaxRegUnitWeight = 0; for (unsigned i = 0; i < NumSets; ++i ) { const RegUnitSet &RegUnits = RegBank.getRegSetAt(i); @@ -247,7 +247,7 @@ EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank, OS << "// Get the register unit pressure limit for this dimension.\n" << "// This limit must be adjusted dynamically for reserved registers.\n" << "unsigned " << ClassName << "::\n" - << "getRegPressureSetLimit(unsigned Idx) const {\n" + << "getRegPressureSetLimit(const MachineFunction &MF, unsigned Idx) const {\n" << " static const " << getMinimalTypeForRange(MaxRegUnitWeight) << " PressureLimitTable[] = {\n"; for (unsigned i = 0; i < NumSets; ++i ) { @@ -573,11 +573,11 @@ typedef SmallVector<unsigned, 4> MaskVec; // Differentially encode a sequence of numbers into V. The starting value and // terminating 0 are not added to V, so it will have the same size as List. static -DiffVec &diffEncode(DiffVec &V, unsigned InitVal, ArrayRef<unsigned> List) { +DiffVec &diffEncode(DiffVec &V, unsigned InitVal, SparseBitVector<> List) { assert(V.empty() && "Clear DiffVec before diffEncode."); uint16_t Val = uint16_t(InitVal); - for (unsigned i = 0; i != List.size(); ++i) { - uint16_t Cur = List[i]; + + for (uint16_t Cur : List) { V.push_back(Cur - Val); Val = Cur; } @@ -610,17 +610,19 @@ static void printMask(raw_ostream &OS, unsigned Val) { static bool combine(const CodeGenSubRegIndex *Idx, SmallVectorImpl<CodeGenSubRegIndex*> &Vec) { const CodeGenSubRegIndex::CompMap &Map = Idx->getComposites(); - for (CodeGenSubRegIndex::CompMap::const_iterator - I = Map.begin(), E = Map.end(); I != E; ++I) { - CodeGenSubRegIndex *&Entry = Vec[I->first->EnumValue - 1]; - if (Entry && Entry != I->second) + for (const auto &I : Map) { + CodeGenSubRegIndex *&Entry = Vec[I.first->EnumValue - 1]; + if (Entry && Entry != I.second) return false; } // All entries are compatible. Make it so. - for (CodeGenSubRegIndex::CompMap::const_iterator - I = Map.begin(), E = Map.end(); I != E; ++I) - Vec[I->first->EnumValue - 1] = I->second; + for (const auto &I : Map) { + auto *&Entry = Vec[I.first->EnumValue - 1]; + assert((!Entry || Entry == I.second) && + "Expected EnumValue to be unique"); + Entry = I.second; + } return true; } @@ -714,16 +716,7 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS, for (size_t s = 0, se = Sequences.size(); s != se; ++s, SIdx = NextSIdx) { SmallVectorImpl<MaskRolPair> &Sequence = Sequences[s]; NextSIdx = SIdx + Sequence.size() + 1; - if (Sequence.size() != IdxSequence.size()) - continue; - bool Identical = true; - for (size_t o = 0, oe = Sequence.size(); o != oe; ++o) { - if (Sequence[o] != IdxSequence[o]) { - Identical = false; - break; - } - } - if (Identical) { + if (Sequence == IdxSequence) { Found = SIdx; break; } @@ -759,7 +752,7 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS, Idx += Sequence.size() + 1; } OS << " };\n" - " static const MaskRolOp *CompositeSequences[] = {\n"; + " static const MaskRolOp *const CompositeSequences[] = {\n"; for (size_t i = 0, e = SubRegIndices.size(); i != e; ++i) { OS << " "; unsigned Idx = SubReg2SequenceIndexMap[i]; @@ -815,7 +808,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, // Keep track of sub-register names as well. These are not differentially // encoded. typedef SmallVector<const CodeGenSubRegIndex*, 4> SubRegIdxVec; - SequenceToOffsetTable<SubRegIdxVec, CodeGenSubRegIndex::Less> SubRegIdxSeqs; + SequenceToOffsetTable<SubRegIdxVec, deref<llvm::less>> SubRegIdxSeqs; SmallVector<SubRegIdxVec, 4> SubRegIdxLists(Regs.size()); SequenceToOffsetTable<std::string> RegStrings; @@ -856,13 +849,13 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, // // Check the neighboring registers for arithmetic progressions. unsigned ScaleA = ~0u, ScaleB = ~0u; - ArrayRef<unsigned> RUs = Reg.getNativeRegUnits(); + SparseBitVector<> RUs = Reg.getNativeRegUnits(); if (I != Regs.begin() && - std::prev(I)->getNativeRegUnits().size() == RUs.size()) - ScaleB = RUs.front() - std::prev(I)->getNativeRegUnits().front(); + std::prev(I)->getNativeRegUnits().count() == RUs.count()) + ScaleB = *RUs.begin() - *std::prev(I)->getNativeRegUnits().begin(); if (std::next(I) != Regs.end() && - std::next(I)->getNativeRegUnits().size() == RUs.size()) - ScaleA = std::next(I)->getNativeRegUnits().front() - RUs.front(); + std::next(I)->getNativeRegUnits().count() == RUs.count()) + ScaleA = *std::next(I)->getNativeRegUnits().begin() - *RUs.begin(); unsigned Scale = std::min(ScaleB, ScaleA); // Default the scale to 0 if it can't be encoded in 4 bits. if (Scale >= 16) @@ -1095,7 +1088,8 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target, << " unsigned getRegUnitWeight(unsigned RegUnit) const override;\n" << " unsigned getNumRegPressureSets() const override;\n" << " const char *getRegPressureSetName(unsigned Idx) const override;\n" - << " unsigned getRegPressureSetLimit(unsigned Idx) const override;\n" + << " unsigned getRegPressureSetLimit(const MachineFunction &MF, unsigned " + "Idx) const override;\n" << " const int *getRegClassPressureSets(" << "const TargetRegisterClass *RC) const override;\n" << " const int *getRegUnitPressureSets(" @@ -1205,7 +1199,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, // Compress the sub-reg index lists. typedef std::vector<const CodeGenSubRegIndex*> IdxList; SmallVector<IdxList, 8> SuperRegIdxLists(RegisterClasses.size()); - SequenceToOffsetTable<IdxList, CodeGenSubRegIndex::Less> SuperRegIdxSeqs; + SequenceToOffsetTable<IdxList, deref<llvm::less>> SuperRegIdxSeqs; BitVector MaskBV(RegisterClasses.size()); for (const auto &RC : RegisterClasses) { @@ -1292,7 +1286,10 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, << "VTLists + " << VTSeqs.get(RC.VTs) << ",\n " << RC.getName() << "SubClassMask,\n SuperRegIdxSeqs + " << SuperRegIdxSeqs.get(SuperRegIdxLists[RC.EnumValue]) << ",\n " - << format("0x%08x,\n ", RC.LaneMask); + << format("0x%08x,\n ", RC.LaneMask) + << (unsigned)RC.AllocationPriority << ",\n " + << (RC.HasDisjunctSubRegs?"true":"false") + << ", /* HasDisjunctSubRegs */\n "; if (RC.getSuperClasses().empty()) OS << "NullRegClasses,\n "; else diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index 9f2fc929d96a0..de9c7a656a0d4 100644 --- a/utils/TableGen/SubtargetEmitter.cpp +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -16,6 +16,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/MC/MCInstrItineraries.h" +#include "llvm/MC/SubtargetFeature.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" #include "llvm/TableGen/Error.h" @@ -62,7 +63,7 @@ class SubtargetEmitter { CodeGenSchedModels &SchedModels; std::string Target; - void Enumeration(raw_ostream &OS, const char *ClassName, bool isBits); + void Enumeration(raw_ostream &OS, const char *ClassName); unsigned FeatureKeyValues(raw_ostream &OS); unsigned CPUKeyValues(raw_ostream &OS); void FormItineraryStageString(const std::string &Names, @@ -112,8 +113,7 @@ public: // Enumeration - Emit the specified class as an enumeration. // void SubtargetEmitter::Enumeration(raw_ostream &OS, - const char *ClassName, - bool isBits) { + const char *ClassName) { // Get all records of class and sort std::vector<Record*> DefList = Records.getAllDerivedDefinitions(ClassName); std::sort(DefList.begin(), DefList.end(), LessRecord()); @@ -121,50 +121,28 @@ void SubtargetEmitter::Enumeration(raw_ostream &OS, unsigned N = DefList.size(); if (N == 0) return; - if (N > 64) { - errs() << "Too many (> 64) subtarget features!\n"; - exit(1); - } + if (N > MAX_SUBTARGET_FEATURES) + PrintFatalError("Too many subtarget features! Bump MAX_SUBTARGET_FEATURES."); OS << "namespace " << Target << " {\n"; - // For bit flag enumerations with more than 32 items, emit constants. - // Emit an enum for everything else. - if (isBits && N > 32) { - // For each record - for (unsigned i = 0; i < N; i++) { - // Next record - Record *Def = DefList[i]; - - // Get and emit name and expression (1 << i) - OS << " const uint64_t " << Def->getName() << " = 1ULL << " << i << ";\n"; - } - } else { - // Open enumeration - OS << "enum {\n"; - - // For each record - for (unsigned i = 0; i < N;) { - // Next record - Record *Def = DefList[i]; + // Open enumeration. Use a 64-bit underlying type. + OS << "enum : uint64_t {\n"; - // Get and emit name - OS << " " << Def->getName(); - - // If bit flags then emit expression (1 << i) - if (isBits) OS << " = " << " 1ULL << " << i; - - // Depending on 'if more in the list' emit comma - if (++i < N) OS << ","; + // For each record + for (unsigned i = 0; i < N;) { + // Next record + Record *Def = DefList[i]; - OS << "\n"; - } + // Get and emit name + OS << " " << Def->getName() << " = " << i; + if (++i < N) OS << ","; - // Close enumeration - OS << "};\n"; + OS << "\n"; } - OS << "}\n"; + // Close enumeration and namespace + OS << "};\n}\n"; } // @@ -198,22 +176,24 @@ unsigned SubtargetEmitter::FeatureKeyValues(raw_ostream &OS) { if (CommandLineName.empty()) continue; - // Emit as { "feature", "description", featureEnum, i1 | i2 | ... | in } + // Emit as { "feature", "description", { featureEnum }, { i1 , i2 , ... , in } } OS << " { " << "\"" << CommandLineName << "\", " << "\"" << Desc << "\", " - << Target << "::" << Name << ", "; + << "{ " << Target << "::" << Name << " }, "; const std::vector<Record*> &ImpliesList = Feature->getValueAsListOfDefs("Implies"); if (ImpliesList.empty()) { - OS << "0ULL"; + OS << "{ }"; } else { + OS << "{ "; for (unsigned j = 0, M = ImpliesList.size(); j < M;) { OS << Target << "::" << ImpliesList[j]->getName(); - if (++j < M) OS << " | "; + if (++j < M) OS << ", "; } + OS << " }"; } OS << " }"; @@ -255,22 +235,24 @@ unsigned SubtargetEmitter::CPUKeyValues(raw_ostream &OS) { const std::vector<Record*> &FeatureList = Processor->getValueAsListOfDefs("Features"); - // Emit as { "cpu", "description", f1 | f2 | ... fn }, + // Emit as { "cpu", "description", { f1 , f2 , ... fn } }, OS << " { " << "\"" << Name << "\", " << "\"Select the " << Name << " processor\", "; if (FeatureList.empty()) { - OS << "0ULL"; + OS << "{ }"; } else { + OS << "{ "; for (unsigned j = 0, M = FeatureList.size(); j < M;) { OS << Target << "::" << FeatureList[j]->getName(); - if (++j < M) OS << " | "; + if (++j < M) OS << ", "; } + OS << " }"; } - // The "0" is for the "implies" section of this data structure. - OS << ", 0ULL }"; + // The { } is for the "implies" section of this data structure. + OS << ", { } }"; // Depending on 'if more in the list' emit comma if (++i < N) OS << ","; @@ -404,7 +386,7 @@ EmitStageAndOperandCycleData(raw_ostream &OS, OS << "}\n"; std::vector<Record*> BPs = PI->ItinsDef->getValueAsListOfDefs("BP"); - if (BPs.size()) { + if (!BPs.empty()) { OS << "\n// Pipeline forwarding pathes for itineraries \"" << Name << "\"\n" << "namespace " << Name << "Bypass {\n"; @@ -1398,7 +1380,7 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS, } OS << " InitMCProcessorInfo(CPU, FS);\n" - << " uint64_t Bits = getFeatureBits();\n"; + << " const FeatureBitset& Bits = getFeatureBits();\n"; for (unsigned i = 0; i < Features.size(); i++) { // Next record @@ -1408,12 +1390,12 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS, const std::string &Attribute = R->getValueAsString("Attribute"); if (Value=="true" || Value=="false") - OS << " if ((Bits & " << Target << "::" - << Instance << ") != 0) " + OS << " if (Bits[" << Target << "::" + << Instance << "]) " << Attribute << " = " << Value << ";\n"; else - OS << " if ((Bits & " << Target << "::" - << Instance << ") != 0 && " + OS << " if (Bits[" << Target << "::" + << Instance << "] && " << Attribute << " < " << Value << ") " << Attribute << " = " << Value << ";\n"; } @@ -1431,7 +1413,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << "#undef GET_SUBTARGETINFO_ENUM\n"; OS << "namespace llvm {\n"; - Enumeration(OS, "SubtargetFeature", true); + Enumeration(OS, "SubtargetFeature"); OS << "} // End llvm namespace \n"; OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n"; @@ -1487,6 +1469,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n"; OS << "#include \"llvm/Support/Debug.h\"\n"; + OS << "#include \"llvm/Support/raw_ostream.h\"\n"; ParseFeaturesFunction(OS, NumFeatures, NumProcs); OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n"; diff --git a/utils/TableGen/X86DisassemblerShared.h b/utils/TableGen/X86DisassemblerShared.h index 58952776b7568..e5889e92415df 100644 --- a/utils/TableGen/X86DisassemblerShared.h +++ b/utils/TableGen/X86DisassemblerShared.h @@ -10,7 +10,7 @@ #ifndef LLVM_UTILS_TABLEGEN_X86DISASSEMBLERSHARED_H #define LLVM_UTILS_TABLEGEN_X86DISASSEMBLERSHARED_H -#include <string.h> +#include <cstring> #include <string> #include "../../lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h" diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp index fbe5502bc90e8..f59652c79e748 100644 --- a/utils/TableGen/X86DisassemblerTables.cpp +++ b/utils/TableGen/X86DisassemblerTables.cpp @@ -215,11 +215,17 @@ static inline bool inheritsFrom(InstructionContext child, return inheritsFrom(child, IC_EVEX_W_K) || inheritsFrom(child, IC_EVEX_L_W_K); case IC_EVEX_XS_K: + case IC_EVEX_XS_K_B: + case IC_EVEX_XS_KZ_B: return inheritsFrom(child, IC_EVEX_W_XS_K) || inheritsFrom(child, IC_EVEX_L_W_XS_K); case IC_EVEX_XD_K: + case IC_EVEX_XD_K_B: + case IC_EVEX_XD_KZ_B: return inheritsFrom(child, IC_EVEX_W_XD_K) || inheritsFrom(child, IC_EVEX_L_W_XD_K); + case IC_EVEX_XS_B: + case IC_EVEX_XD_B: case IC_EVEX_K_B: case IC_EVEX_KZ: return false; @@ -253,17 +259,27 @@ static inline bool inheritsFrom(InstructionContext child, case IC_EVEX_W_KZ: case IC_EVEX_W_XS_KZ: case IC_EVEX_W_XD_KZ: + case IC_EVEX_W_XS_B: + case IC_EVEX_W_XD_B: + case IC_EVEX_W_XS_K_B: + case IC_EVEX_W_XD_K_B: + case IC_EVEX_W_XS_KZ_B: + case IC_EVEX_W_XD_KZ_B: case IC_EVEX_W_OPSIZE_KZ: case IC_EVEX_W_OPSIZE_KZ_B: return false; case IC_EVEX_L_KZ: case IC_EVEX_L_XS_KZ: + case IC_EVEX_L_XS_B: + case IC_EVEX_L_XS_K_B: case IC_EVEX_L_XD_KZ: case IC_EVEX_L_OPSIZE_KZ: case IC_EVEX_L_OPSIZE_KZ_B: return false; case IC_EVEX_L_W_K: case IC_EVEX_L_W_XS_K: + case IC_EVEX_L_W_XS_B: + case IC_EVEX_L_W_XS_K_B: case IC_EVEX_L_W_XD_K: case IC_EVEX_L_W_OPSIZE_K: case IC_EVEX_L_W_OPSIZE_B: @@ -279,6 +295,7 @@ static inline bool inheritsFrom(InstructionContext child, case IC_EVEX_L2_K_B: case IC_EVEX_L2_KZ_B: case IC_EVEX_L2_XS_K: + case IC_EVEX_L2_XS_K_B: case IC_EVEX_L2_XS_B: case IC_EVEX_L2_XD_B: case IC_EVEX_L2_XD_K: @@ -294,6 +311,8 @@ static inline bool inheritsFrom(InstructionContext child, case IC_EVEX_L2_W_K: case IC_EVEX_L2_W_B: case IC_EVEX_L2_W_XS_K: + case IC_EVEX_L2_W_XS_B: + case IC_EVEX_L2_W_XS_K_B: case IC_EVEX_L2_W_XD_K: case IC_EVEX_L2_W_XD_B: case IC_EVEX_L2_W_OPSIZE_K: @@ -585,7 +604,8 @@ void DisassemblerTables::emitInstructionInfo(raw_ostream &o, o << "static const struct OperandSpecifier x86OperandSets[][" << X86_MAX_OPERANDS << "] = {\n"; - typedef std::vector<std::pair<const char *, const char *> > OperandListTy; + typedef SmallVector<std::pair<OperandEncoding, OperandType>, + X86_MAX_OPERANDS> OperandListTy; std::map<OperandListTy, unsigned> OperandSets; unsigned OperandSetNum = 0; @@ -594,12 +614,10 @@ void DisassemblerTables::emitInstructionInfo(raw_ostream &o, for (unsigned OperandIndex = 0; OperandIndex < X86_MAX_OPERANDS; ++OperandIndex) { - const char *Encoding = - stringForOperandEncoding((OperandEncoding)InstructionSpecifiers[Index] - .operands[OperandIndex].encoding); - const char *Type = - stringForOperandType((OperandType)InstructionSpecifiers[Index] - .operands[OperandIndex].type); + OperandEncoding Encoding = (OperandEncoding)InstructionSpecifiers[Index] + .operands[OperandIndex].encoding; + OperandType Type = (OperandType)InstructionSpecifiers[Index] + .operands[OperandIndex].type; OperandList.push_back(std::make_pair(Encoding, Type)); } unsigned &N = OperandSets[OperandList]; @@ -609,8 +627,9 @@ void DisassemblerTables::emitInstructionInfo(raw_ostream &o, o << " { /* " << (OperandSetNum - 1) << " */\n"; for (unsigned i = 0, e = OperandList.size(); i != e; ++i) { - o << " { " << OperandList[i].first << ", " - << OperandList[i].second << " },\n"; + const char *Encoding = stringForOperandEncoding(OperandList[i].first); + const char *Type = stringForOperandType(OperandList[i].second); + o << " { " << Encoding << ", " << Type << " },\n"; } o << " },\n"; } @@ -622,32 +641,24 @@ void DisassemblerTables::emitInstructionInfo(raw_ostream &o, i++; for (unsigned index = 0; index < NumInstructions; ++index) { - o.indent(i * 2) << "{ /* " << index << " */" << "\n"; + o.indent(i * 2) << "{ /* " << index << " */\n"; i++; OperandListTy OperandList; for (unsigned OperandIndex = 0; OperandIndex < X86_MAX_OPERANDS; ++OperandIndex) { - const char *Encoding = - stringForOperandEncoding((OperandEncoding)InstructionSpecifiers[index] - .operands[OperandIndex].encoding); - const char *Type = - stringForOperandType((OperandType)InstructionSpecifiers[index] - .operands[OperandIndex].type); + OperandEncoding Encoding = (OperandEncoding)InstructionSpecifiers[index] + .operands[OperandIndex].encoding; + OperandType Type = (OperandType)InstructionSpecifiers[index] + .operands[OperandIndex].type; OperandList.push_back(std::make_pair(Encoding, Type)); } o.indent(i * 2) << (OperandSets[OperandList] - 1) << ",\n"; - o.indent(i * 2) << "/* " << InstructionSpecifiers[index].name << " */"; - o << "\n"; + o.indent(i * 2) << "/* " << InstructionSpecifiers[index].name << " */\n"; i--; - o.indent(i * 2) << "}"; - - if (index + 1 < NumInstructions) - o << ","; - - o << "\n"; + o.indent(i * 2) << "},\n"; } i--; diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index 198ad1090493b..ae461bcfbc880 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -28,54 +28,65 @@ using namespace llvm; MAP(C2, 34) \ MAP(C3, 35) \ MAP(C4, 36) \ - MAP(C8, 37) \ - MAP(C9, 38) \ - MAP(CA, 39) \ - MAP(CB, 40) \ - MAP(CF, 41) \ - MAP(D0, 42) \ - MAP(D1, 43) \ - MAP(D4, 44) \ - MAP(D5, 45) \ - MAP(D6, 46) \ - MAP(D7, 47) \ - MAP(D8, 48) \ - MAP(D9, 49) \ - MAP(DA, 50) \ - MAP(DB, 51) \ - MAP(DC, 52) \ - MAP(DD, 53) \ - MAP(DE, 54) \ - MAP(DF, 55) \ - MAP(E0, 56) \ - MAP(E1, 57) \ - MAP(E2, 58) \ - MAP(E3, 59) \ - MAP(E4, 60) \ - MAP(E5, 61) \ - MAP(E8, 62) \ - MAP(E9, 63) \ - MAP(EA, 64) \ - MAP(EB, 65) \ - MAP(EC, 66) \ - MAP(ED, 67) \ - MAP(EE, 68) \ - MAP(F0, 69) \ - MAP(F1, 70) \ - MAP(F2, 71) \ - MAP(F3, 72) \ - MAP(F4, 73) \ - MAP(F5, 74) \ - MAP(F6, 75) \ - MAP(F7, 76) \ - MAP(F8, 77) \ - MAP(F9, 78) \ - MAP(FA, 79) \ - MAP(FB, 80) \ - MAP(FC, 81) \ - MAP(FD, 82) \ - MAP(FE, 83) \ - MAP(FF, 84) + MAP(C5, 37) \ + MAP(C6, 38) \ + MAP(C7, 39) \ + MAP(C8, 40) \ + MAP(C9, 41) \ + MAP(CA, 42) \ + MAP(CB, 43) \ + MAP(CC, 44) \ + MAP(CD, 45) \ + MAP(CE, 46) \ + MAP(CF, 47) \ + MAP(D0, 48) \ + MAP(D1, 49) \ + MAP(D2, 50) \ + MAP(D3, 51) \ + MAP(D4, 52) \ + MAP(D5, 53) \ + MAP(D6, 54) \ + MAP(D7, 55) \ + MAP(D8, 56) \ + MAP(D9, 57) \ + MAP(DA, 58) \ + MAP(DB, 59) \ + MAP(DC, 60) \ + MAP(DD, 61) \ + MAP(DE, 62) \ + MAP(DF, 63) \ + MAP(E0, 64) \ + MAP(E1, 65) \ + MAP(E2, 66) \ + MAP(E3, 67) \ + MAP(E4, 68) \ + MAP(E5, 69) \ + MAP(E6, 70) \ + MAP(E7, 71) \ + MAP(E8, 72) \ + MAP(E9, 73) \ + MAP(EA, 74) \ + MAP(EB, 75) \ + MAP(EC, 76) \ + MAP(ED, 77) \ + MAP(EE, 78) \ + MAP(EF, 79) \ + MAP(F0, 80) \ + MAP(F1, 81) \ + MAP(F2, 82) \ + MAP(F3, 83) \ + MAP(F4, 84) \ + MAP(F5, 85) \ + MAP(F6, 86) \ + MAP(F7, 87) \ + MAP(F8, 88) \ + MAP(F9, 89) \ + MAP(FA, 90) \ + MAP(FB, 91) \ + MAP(FC, 92) \ + MAP(FD, 93) \ + MAP(FE, 94) \ + MAP(FF, 95) // A clone of X86 since we can't depend on something that is generated. namespace X86Local { @@ -514,7 +525,7 @@ void RecognizableInstr::emitInstructionSpecifier() { assert(numOperands <= X86_MAX_OPERANDS && "X86_MAX_OPERANDS is not large enough"); for (unsigned operandIndex = 0; operandIndex < numOperands; ++operandIndex) { - if (OperandList[operandIndex].Constraints.size()) { + if (!OperandList[operandIndex].Constraints.empty()) { const CGIOperandList::ConstraintInfo &Constraint = OperandList[operandIndex].Constraints[0]; if (Constraint.isTied()) { @@ -803,9 +814,7 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { // Special cases where the LLVM tables are not complete #define MAP(from, to) \ - case X86Local::MRM_##from: \ - filter = new ExactFilter(0x##from); \ - break; + case X86Local::MRM_##from: OpcodeType opcodeType = (OpcodeType)-1; @@ -854,6 +863,8 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { filter = new ExtendedFilter(false, Form - X86Local::MRM0m); break; MRM_MAPPING + filter = new ExactFilter(0xC0 + Form - X86Local::MRM_C0); \ + break; } // switch (Form) opcodeToSet = Opcode; @@ -932,6 +943,8 @@ OperandType RecognizableInstr::typeFromString(const std::string &s, TYPE("GR64", TYPE_R64) TYPE("i8mem", TYPE_M8) TYPE("i8imm", TYPE_IMM8) + TYPE("u8imm", TYPE_UIMM8) + TYPE("i32u8imm", TYPE_UIMM8) TYPE("GR8", TYPE_R8) TYPE("VR128", TYPE_XMM128) TYPE("VR128X", TYPE_XMM128) @@ -954,7 +967,9 @@ OperandType RecognizableInstr::typeFromString(const std::string &s, TYPE("i16imm_pcrel", TYPE_REL16) TYPE("i32imm_pcrel", TYPE_REL32) TYPE("SSECC", TYPE_IMM3) + TYPE("XOPCC", TYPE_IMM3) TYPE("AVXCC", TYPE_IMM5) + TYPE("AVX512ICC", TYPE_AVX512ICC) TYPE("AVX512RC", TYPE_IMM32) TYPE("brtarget32", TYPE_RELv) TYPE("brtarget16", TYPE_RELv) @@ -1034,7 +1049,9 @@ RecognizableInstr::immediateEncodingFromString(const std::string &s, } ENCODING("i32i8imm", ENCODING_IB) ENCODING("SSECC", ENCODING_IB) + ENCODING("XOPCC", ENCODING_IB) ENCODING("AVXCC", ENCODING_IB) + ENCODING("AVX512ICC", ENCODING_IB) ENCODING("AVX512RC", ENCODING_IB) ENCODING("i16imm", ENCODING_Iv) ENCODING("i16i8imm", ENCODING_IB) @@ -1042,6 +1059,8 @@ RecognizableInstr::immediateEncodingFromString(const std::string &s, ENCODING("i64i32imm", ENCODING_ID) ENCODING("i64i8imm", ENCODING_IB) ENCODING("i8imm", ENCODING_IB) + ENCODING("u8imm", ENCODING_IB) + ENCODING("i32u8imm", ENCODING_IB) // This is not a typo. Instructions like BLENDVPD put // register IDs in 8-bit immediates nowadays. ENCODING("FR32", ENCODING_IB) @@ -1077,6 +1096,8 @@ RecognizableInstr::rmRegisterEncodingFromString(const std::string &s, ENCODING("VR256X", ENCODING_RM) ENCODING("VR512", ENCODING_RM) ENCODING("VK1", ENCODING_RM) + ENCODING("VK2", ENCODING_RM) + ENCODING("VK4", ENCODING_RM) ENCODING("VK8", ENCODING_RM) ENCODING("VK16", ENCODING_RM) ENCODING("VK32", ENCODING_RM) @@ -1114,8 +1135,12 @@ RecognizableInstr::roRegisterEncodingFromString(const std::string &s, ENCODING("VK32", ENCODING_REG) ENCODING("VK64", ENCODING_REG) ENCODING("VK1WM", ENCODING_REG) + ENCODING("VK2WM", ENCODING_REG) + ENCODING("VK4WM", ENCODING_REG) ENCODING("VK8WM", ENCODING_REG) ENCODING("VK16WM", ENCODING_REG) + ENCODING("VK32WM", ENCODING_REG) + ENCODING("VK64WM", ENCODING_REG) errs() << "Unhandled reg/opcode register encoding " << s << "\n"; llvm_unreachable("Unhandled reg/opcode register encoding"); } @@ -1210,6 +1235,8 @@ RecognizableInstr::relocationEncodingFromString(const std::string &s, ENCODING("i64i32imm", ENCODING_ID) ENCODING("i64i8imm", ENCODING_IB) ENCODING("i8imm", ENCODING_IB) + ENCODING("u8imm", ENCODING_IB) + ENCODING("i32u8imm", ENCODING_IB) ENCODING("i64i32imm_pcrel", ENCODING_ID) ENCODING("i16imm_pcrel", ENCODING_IW) ENCODING("i32imm_pcrel", ENCODING_ID) diff --git a/utils/create_ladder_graph.py b/utils/create_ladder_graph.py new file mode 100644 index 0000000000000..d29e3ad3a10d1 --- /dev/null +++ b/utils/create_ladder_graph.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python +"""A ladder graph creation program. + +This is a python program that creates c source code that will generate +CFGs that are ladder graphs. Ladder graphs are generally the worst case +for a lot of dominance related algorithms (Dominance frontiers, etc), +and often generate N^2 or worse behavior. + +One good use of this program is to test whether your linear time algorithm is +really behaving linearly. +""" + +import argparse +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('rungs', type=int, + help="Number of ladder rungs. Must be a multiple of 2") + args = parser.parse_args() + if (args.rungs % 2) != 0: + print "Rungs must be a multiple of 2" + return + print "int ladder(int *foo, int *bar, int x) {" + rung1 = xrange(0, args.rungs, 2) + rung2 = xrange(1, args.rungs, 2) + for i in rung1: + print "rung1%d:" % i + print "*foo = x++;" + if i != rung1[-1]: + print "if (*bar) goto rung1%d;" % (i+2) + print "else goto rung2%d;" % (i+1) + else: + print "goto rung2%d;" % (i+1) + for i in rung2: + print "rung2%d:" % i + print "*foo = x++;" + if i != rung2[-1]: + print "goto rung2%d;" % (i+2) + else: + print "return *foo;" + print "}" + +if __name__ == '__main__': + main() diff --git a/utils/emacs/emacs.el b/utils/emacs/emacs.el index 2ebc3c677cef7..4a3a5031026a1 100644 --- a/utils/emacs/emacs.el +++ b/utils/emacs/emacs.el @@ -1,34 +1,22 @@ ;; LLVM coding style guidelines in emacs ;; Maintainer: LLVM Team, http://llvm.org/ -;; Add a cc-mode style for editing LLVM C++ code +;; Add a cc-mode style for editing LLVM C and C++ code (c-add-style "llvm.org" - '((fill-column . 80) + '("gnu" + (fill-column . 80) (c++-indent-level . 2) (c-basic-offset . 2) (indent-tabs-mode . nil) (c-offsets-alist . ((arglist-intro . ++) (innamespace . 0) - (member-init-intro . ++) - )) - )) + (member-init-intro . ++))))) ;; Files with "llvm" in their names will automatically be set to the ;; llvm.org coding style. -(add-hook 'c-mode-hook +(add-hook 'c-mode-common-hook (function (lambda nil (if (string-match "llvm" buffer-file-name) (progn - (c-set-style "llvm.org") - ) - )))) - -(add-hook 'c++-mode-hook - (function - (lambda nil - (if (string-match "llvm" buffer-file-name) - (progn - (c-set-style "llvm.org") - ) - )))) + (c-set-style "llvm.org")))))) diff --git a/utils/emacs/llvm-mode.el b/utils/emacs/llvm-mode.el index 6d8395cc111b8..5fb1eb38cc62d 100644 --- a/utils/emacs/llvm-mode.el +++ b/utils/emacs/llvm-mode.el @@ -23,7 +23,7 @@ ;; Unnamed variable slots '("%[-]?[0-9]+" . font-lock-variable-name-face) ;; Types - `(,(regexp-opt '("void" "i[0-9]+" "float" "double" "type" "label" "opaque") 'words) . font-lock-type-face) + `(,(regexp-opt '("void" "i1" "i8" "i16" "i32" "i64" "i128" "float" "double" "type" "label" "opaque") 'symbol) . font-lock-type-face) ;; Integer literals '("\\b[-]?[0-9]+\\b" . font-lock-preprocessor-face) ;; Floating point constants @@ -35,28 +35,28 @@ "define" "global" "constant" "const" "internal" "linkonce" "linkonce_odr" "weak" "weak_odr" "appending" "uninitialized" "implementation" "..." "null" "undef" "to" "except" "not" "target" "endian" "little" "big" - "pointersize" "volatile" "fastcc" "coldcc" "cc") 'words) . font-lock-keyword-face) + "pointersize" "volatile" "fastcc" "coldcc" "cc" "personality") 'symbols) . font-lock-keyword-face) ;; Arithmetic and Logical Operators `(,(regexp-opt '("add" "sub" "mul" "sdiv" "udiv" "urem" "srem" "and" "or" "xor" - "setne" "seteq" "setlt" "setgt" "setle" "setge") 'words) . font-lock-keyword-face) + "setne" "seteq" "setlt" "setgt" "setle" "setge") 'symbols) . font-lock-keyword-face) ;; Floating-point operators - `(,(regexp-opt '("fadd" "fsub" "fmul" "fdiv" "frem") 'words) . font-lock-keyword-face) + `(,(regexp-opt '("fadd" "fsub" "fmul" "fdiv" "frem") 'symbols) . font-lock-keyword-face) ;; Special instructions - `(,(regexp-opt '("phi" "tail" "call" "select" "to" "shl" "lshr" "ashr" "fcmp" "icmp" "va_arg" "landingpad") 'words) . font-lock-keyword-face) + `(,(regexp-opt '("phi" "tail" "call" "select" "to" "shl" "lshr" "ashr" "fcmp" "icmp" "va_arg" "landingpad") 'symbols) . font-lock-keyword-face) ;; Control instructions - `(,(regexp-opt '("ret" "br" "switch" "invoke" "resume" "unwind" "unreachable" "indirectbr") 'words) . font-lock-keyword-face) + `(,(regexp-opt '("ret" "br" "switch" "invoke" "resume" "unwind" "unreachable" "indirectbr") 'symbols) . font-lock-keyword-face) ;; Memory operators - `(,(regexp-opt '("malloc" "alloca" "free" "load" "store" "getelementptr" "fence" "cmpxchg" "atomicrmw") 'words) . font-lock-keyword-face) + `(,(regexp-opt '("malloc" "alloca" "free" "load" "store" "getelementptr" "fence" "cmpxchg" "atomicrmw") 'symbols) . font-lock-keyword-face) ;; Casts - `(,(regexp-opt '("bitcast" "inttoptr" "ptrtoint" "trunc" "zext" "sext" "fptrunc" "fpext" "fptoui" "fptosi" "uitofp" "sitofp" "addrspacecast") 'words) . font-lock-keyword-face) + `(,(regexp-opt '("bitcast" "inttoptr" "ptrtoint" "trunc" "zext" "sext" "fptrunc" "fpext" "fptoui" "fptosi" "uitofp" "sitofp" "addrspacecast") 'symbols) . font-lock-keyword-face) ;; Vector ops - `(,(regexp-opt '("extractelement" "insertelement" "shufflevector") 'words) . font-lock-keyword-face) + `(,(regexp-opt '("extractelement" "insertelement" "shufflevector") 'symbols) . font-lock-keyword-face) ;; Aggregate ops - `(,(regexp-opt '("extractvalue" "insertvalue") 'words) . font-lock-keyword-face) + `(,(regexp-opt '("extractvalue" "insertvalue") 'symbols) . font-lock-keyword-face) ;; Metadata types - `(,(regexp-opt '("distinct") 'words) . font-lock-keyword-face) + `(,(regexp-opt '("distinct") 'symbols) . font-lock-keyword-face) ;; Use-list order directives - `(,(regexp-opt '("uselistorder" "uselistorder_bb") 'words) . font-lock-keyword-face) + `(,(regexp-opt '("uselistorder" "uselistorder_bb") 'symbols) . font-lock-keyword-face) ) "Syntax highlighting for LLVM." @@ -83,7 +83,7 @@ ;; word constituents (`w') ;;[?< "w"] ;;[?> "w"] - [?\% "w"] + [?% "w"] ;;[?_ "w "] ;; comments [?\; "< "] @@ -93,16 +93,9 @@ ;; symbol constituents (`_') ;; punctuation (`.') ;; open paren (`(') - [?\( "("] - [?\[ "("] - [?\{ "("] ;; close paren (`)') - [?\) ")"] - [?\] ")"] - [?\} ")"] ;; string quote ('"') - [?\" "\""] - )))) + [?\" "\""])))) ;; --------------------- Abbrev table ----------------------------- diff --git a/utils/git-svn/git-svnrevert b/utils/git-svn/git-svnrevert index f15e7abfb3f10..4185ee7ae87af 100755 --- a/utils/git-svn/git-svnrevert +++ b/utils/git-svn/git-svnrevert @@ -14,8 +14,13 @@ fi COMMIT=$1 OTHER=$(git svn find-rev "$COMMIT") -if [ $? -ne 0 ]; then +if [ $? -ne 0 ] || [ "$OTHER" = "" ]; then echo "Error! Could not find an svn/git revision for commit $COMMIT!" + echo + echo "Possible problems are:" + echo " * Your revision number ($COMMIT) is wrong" + echo " * This tree is not up to date (before that commit)" + echo " * This commit in in another three (llvm, clang, compiler-rt, etc)" exit 1 fi diff --git a/utils/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py index b0dde5db86868..b8183801bfca7 100644 --- a/utils/lit/lit/LitConfig.py +++ b/utils/lit/lit/LitConfig.py @@ -76,7 +76,6 @@ class LitConfig: self.bashPath = lit.util.which('bash') if self.bashPath is None: - self.warning("Unable to find 'bash'.") self.bashPath = '' return self.bashPath @@ -91,7 +90,6 @@ class LitConfig: # bash self.bashPath = lit.util.which('bash', dir) if self.bashPath is None: - self.note("Unable to find 'bash.exe'.") self.bashPath = '' return dir diff --git a/utils/lit/lit/Test.py b/utils/lit/lit/Test.py index b81023010d70a..38bb41b0252d5 100644 --- a/utils/lit/lit/Test.py +++ b/utils/lit/lit/Test.py @@ -91,7 +91,8 @@ class JSONMetricValue(MetricValue): self.value = value def format(self): - return str(self.value) + e = JSONEncoder(indent=2, sort_keys=True) + return e.encode(self.value) def todata(self): return self.value diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index 268e46c38f744..f1734eca37263 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -22,33 +22,56 @@ kUseCloseFDs = not kIsWindows # Use temporary files to replace /dev/null on Windows. kAvoidDevNull = kIsWindows -def executeShCmd(cmd, cfg, cwd, results): +class ShellEnvironment(object): + + """Mutable shell environment containing things like CWD and env vars. + + Environment variables are not implemented, but cwd tracking is. + """ + + def __init__(self, cwd, env): + self.cwd = cwd + self.env = env + +def executeShCmd(cmd, shenv, results): if isinstance(cmd, ShUtil.Seq): if cmd.op == ';': - res = executeShCmd(cmd.lhs, cfg, cwd, results) - return executeShCmd(cmd.rhs, cfg, cwd, results) + res = executeShCmd(cmd.lhs, shenv, results) + return executeShCmd(cmd.rhs, shenv, results) if cmd.op == '&': raise InternalShellError(cmd,"unsupported shell operator: '&'") if cmd.op == '||': - res = executeShCmd(cmd.lhs, cfg, cwd, results) + res = executeShCmd(cmd.lhs, shenv, results) if res != 0: - res = executeShCmd(cmd.rhs, cfg, cwd, results) + res = executeShCmd(cmd.rhs, shenv, results) return res if cmd.op == '&&': - res = executeShCmd(cmd.lhs, cfg, cwd, results) + res = executeShCmd(cmd.lhs, shenv, results) if res is None: return res if res == 0: - res = executeShCmd(cmd.rhs, cfg, cwd, results) + res = executeShCmd(cmd.rhs, shenv, results) return res raise ValueError('Unknown shell command: %r' % cmd.op) - assert isinstance(cmd, ShUtil.Pipeline) + + # Handle shell builtins first. + if cmd.commands[0].args[0] == 'cd': + # Update the cwd in the environment. + if len(cmd.commands[0].args) != 2: + raise ValueError('cd supports only one argument') + newdir = cmd.commands[0].args[1] + if os.path.isabs(newdir): + shenv.cwd = newdir + else: + shenv.cwd = os.path.join(shenv.cwd, newdir) + return 0 + procs = [] input = subprocess.PIPE stderrTempFiles = [] @@ -102,7 +125,9 @@ def executeShCmd(cmd, cfg, cwd, results): if kAvoidDevNull and r[0] == '/dev/null': r[2] = tempfile.TemporaryFile(mode=r[1]) else: - r[2] = open(r[0], r[1]) + # Make sure relative paths are relative to the cwd. + redir_filename = os.path.join(shenv.cwd, r[0]) + r[2] = open(redir_filename, r[1]) # Workaround a Win32 and/or subprocess bug when appending. # # FIXME: Actually, this is probably an instance of PR6753. @@ -132,7 +157,7 @@ def executeShCmd(cmd, cfg, cwd, results): # Resolve the executable path ourselves. args = list(j.args) - executable = lit.util.which(args[0], cfg.environment['PATH']) + executable = lit.util.which(args[0], shenv.env['PATH']) if not executable: raise InternalShellError(j, '%r: command not found' % j.args[0]) @@ -146,12 +171,12 @@ def executeShCmd(cmd, cfg, cwd, results): args[i] = f.name try: - procs.append(subprocess.Popen(args, cwd=cwd, + procs.append(subprocess.Popen(args, cwd=shenv.cwd, executable = executable, stdin = stdin, stdout = stdout, stderr = stderr, - env = cfg.environment, + env = shenv.env, close_fds = kUseCloseFDs)) except OSError as e: raise InternalShellError(j, 'Could not create process due to {}'.format(e)) @@ -257,7 +282,8 @@ def executeScriptInternal(test, litConfig, tmpBase, commands, cwd): results = [] try: - exitCode = executeShCmd(cmd, test.config, cwd, results) + shenv = ShellEnvironment(cwd, test.config.environment) + exitCode = executeShCmd(cmd, shenv, results) except InternalShellError: e = sys.exc_info()[1] exitCode = 127 diff --git a/utils/lit/lit/formats/googletest.py b/utils/lit/lit/formats/googletest.py index 59ac3c5cb3700..3ce57917113aa 100644 --- a/utils/lit/lit/formats/googletest.py +++ b/utils/lit/lit/formats/googletest.py @@ -53,6 +53,11 @@ class GoogleTest(TestFormat): ln = ln[index*2:] if ln.endswith('.'): nested_tests.append(ln) + elif any([name.startswith('DISABLED_') + for name in nested_tests + [ln]]): + # Gtest will internally skip these tests. No need to launch a + # child process for it. + continue else: yield ''.join(nested_tests) + ln @@ -95,7 +100,7 @@ class GoogleTest(TestFormat): # Handle GTest parametrized and typed tests, whose name includes # some '/'s. testPath, namePrefix = os.path.split(testPath) - testName = os.path.join(namePrefix, testName) + testName = namePrefix + '/' + testName cmd = [testPath, '--gtest_filter=' + testName] if litConfig.useValgrind: @@ -107,7 +112,14 @@ class GoogleTest(TestFormat): out, err, exitCode = lit.util.executeCommand( cmd, env=test.config.environment) - if not exitCode: - return lit.Test.PASS,'' + if exitCode: + return lit.Test.FAIL, out + err + + passing_test_line = '[ PASSED ] 1 test.' + if passing_test_line not in out: + msg = ('Unable to find %r in gtest output:\n\n%s%s' % + (passing_test_line, out, err)) + return lit.Test.UNRESOLVED, msg + + return lit.Test.PASS,'' - return lit.Test.FAIL, out + err diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index f2aedc906bb15..e3722674f63f2 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -146,7 +146,7 @@ def main(builtinParameters = {}): parser.add_option("", "--config-prefix", dest="configPrefix", metavar="NAME", help="Prefix for 'lit' config files", action="store", default=None) - parser.add_option("", "--param", dest="userParameters", + parser.add_option("-D", "--param", dest="userParameters", metavar="NAME=VAL", help="Add 'NAME' = 'VAL' to the user defined parameters", type=str, action="append", default=[]) diff --git a/utils/lit/utils/check-coverage b/utils/lit/utils/check-coverage index 128e827f22dcb..cded7a2921c55 100755 --- a/utils/lit/utils/check-coverage +++ b/utils/lit/utils/check-coverage @@ -23,7 +23,7 @@ fi # sitecustomize. if ! python -c \ 'import sitecustomize, sys; sys.exit("coverage" not in dir(sitecustomize))' \ - &> /dev/null; then + >/dev/null 2>&1; then printf 1>&2 "error: active python does not appear to enable coverage in its 'sitecustomize.py'\n" exit 1 fi diff --git a/utils/lldbDataFormatters.py b/utils/lldbDataFormatters.py index f570fb49f3473..687729f61eddd 100644 --- a/utils/lldbDataFormatters.py +++ b/utils/lldbDataFormatters.py @@ -15,6 +15,9 @@ def __lldb_init_module(debugger, internal_dict): debugger.HandleCommand('type synthetic add -w llvm ' '-l lldbDataFormatters.ArrayRefSynthProvider ' '-x "^llvm::ArrayRef<.+>$"') + debugger.HandleCommand('type summary add -w llvm ' + '-F lldbDataFormatters.OptionalSummaryProvider ' + '-x "^llvm::Optional<.+>$"') # Pretty printer for llvm::SmallVector/llvm::SmallVectorImpl class SmallVectorSynthProvider: @@ -86,3 +89,10 @@ class ArrayRefSynthProvider: self.data_type = self.data.GetType().GetPointeeType() self.type_size = self.data_type.GetByteSize() assert self.type_size != 0 + +def OptionalSummaryProvider(valobj, internal_dict): + if not valobj.GetChildMemberWithName('hasVal').GetValueAsUnsigned(0): + return 'None' + underlying_type = valobj.GetType().GetTemplateArgumentType(0) + storage = valobj.GetChildMemberWithName('storage') + return str(storage.Cast(underlying_type)) diff --git a/utils/release/export.sh b/utils/release/export.sh index 38e5a819c01d0..9aee306f96645 100755 --- a/utils/release/export.sh +++ b/utils/release/export.sh @@ -14,7 +14,7 @@ set -e -projects="llvm cfe dragonegg test-suite compiler-rt libcxx libcxxabi clang-tools-extra polly lldb lld openmp" +projects="llvm cfe test-suite compiler-rt libcxx libcxxabi clang-tools-extra polly lldb lld openmp" base_url="https://llvm.org/svn/llvm-project" release="" @@ -79,5 +79,8 @@ if [ "x$release" = "x" ]; then exit 1 fi +# Make sure umask is not overly restrictive. +umask 0022 + export_sources exit 0 diff --git a/utils/release/test-release.sh b/utils/release/test-release.sh index 20f8d97ebc0d7..89519c47e35b6 100755 --- a/utils/release/test-release.sh +++ b/utils/release/test-release.sh @@ -18,7 +18,7 @@ else MAKE=make fi -projects="llvm cfe dragonegg compiler-rt libcxx libcxxabi test-suite clang-tools-extra" +projects="llvm cfe compiler-rt libcxx libcxxabi test-suite clang-tools-extra" # Base SVN URL for the sources. Base_url="http://llvm.org/svn/llvm-project" @@ -29,11 +29,7 @@ RC="" Triple="" use_gzip="no" do_checkout="yes" -do_ada="no" do_clang="yes" -do_dragonegg="no" -do_fortran="no" -do_objc="yes" do_64bit="yes" do_debug="no" do_asserts="no" @@ -54,7 +50,6 @@ function usage() { echo " -no-64bit Don't test the 64-bit version. [default: yes]" echo " -enable-ada Build Ada. [default: disable]" echo " -disable-clang Do not test clang. [default: enable]" - echo " -enable-dragonegg Test dragonegg. [default: disable]" echo " -enable-fortran Enable Fortran build. [default: disable]" echo " -disable-objc Disable ObjC build. [default: enable]" echo " -test-debug Test the debug build. [default: no]" @@ -104,21 +99,9 @@ while [ $# -gt 0 ]; do -no-64bit | --no-64bit ) do_64bit="no" ;; - -enable-ada | --enable-ada ) - do_ada="yes" - ;; -disable-clang | --disable-clang ) do_clang="no" ;; - -enable-dragonegg | --enable-dragonegg ) - do_dragonegg="yes" - ;; - -enable-fortran | --enable-fortran ) - do_fortran="yes" - ;; - -disable-objc | --disable-objc ) - do_objc="no" - ;; -test-debug | --test-debug ) do_debug="yes" ;; @@ -188,27 +171,6 @@ if [ $RC != "final" ]; then fi Package=$Package-$Triple -# Find compilers. -if [ "$do_dragonegg" = "yes" ]; then - gcc_compiler="$GCC" - if [ -z "$gcc_compiler" ]; then - gcc_compiler="`which gcc`" - if [ -z "$gcc_compiler" ]; then - echo "error: cannot find gcc to use with dragonegg" - exit 1 - fi - fi - - gxx_compiler="$GXX" - if [ -z "$gxx_compiler" ]; then - gxx_compiler="`which g++`" - if [ -z "$gxx_compiler" ]; then - echo "error: cannot find g++ to use with dragonegg" - exit 1 - fi - fi -fi - # Make sure that a required program is available function check_program_exists() { local program="$1" @@ -344,28 +306,6 @@ function build_llvmCore() { cd $BuildDir } -function build_dragonegg() { - Phase="$1" - Flavor="$2" - LLVMInstallDir="$3" - DragonEggObjDir="$4" - LLVM_CONFIG=$LLVMInstallDir/bin/llvm-config - TOP_DIR=$BuildDir/dragonegg.src - - echo "# Targeted compiler: $gcc_compiler" - - cd $DragonEggObjDir - echo "# Compiling phase $Phase dragonegg $Release-$RC $Flavor" - echo -n "# CXX=$cxx_compiler TOP_DIR=$TOP_DIR GCC=$gcc_compiler " - echo -n "LLVM_CONFIG=$LLVM_CONFIG ${MAKE} -f $TOP_DIR/Makefile " - echo "-j $NumJobs VERBOSE=1" - CXX="$cxx_compiler" TOP_DIR="$TOP_DIR" GCC="$gcc_compiler" \ - LLVM_CONFIG="$LLVM_CONFIG" ${MAKE} -f $TOP_DIR/Makefile \ - -j $NumJobs VERBOSE=1 \ - 2>&1 | tee $LogDir/dragonegg-Phase$Phase-$Flavor.log - cd $BuildDir -} - function test_llvmCore() { Phase="$1" Flavor="$2" @@ -445,51 +385,42 @@ for Flavor in $Flavors ; do llvmCore_phase1_objdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-$RC.obj llvmCore_phase1_installdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-$RC.install - dragonegg_phase1_objdir=$BuildDir/Phase1/$Flavor/DragonEgg-$Release-$RC.obj llvmCore_phase2_objdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-$RC.obj llvmCore_phase2_installdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-$RC.install llvmCore_de_phase2_objdir=$BuildDir/Phase2/$Flavor/llvmCore-DragonEgg-$Release-$RC.obj llvmCore_de_phase2_installdir=$BuildDir/Phase2/$Flavor/llvmCore-DragonEgg-$Release-$RC.install - dragonegg_phase2_objdir=$BuildDir/Phase2/$Flavor/DragonEgg-$Release-$RC.obj llvmCore_phase3_objdir=$BuildDir/Phase3/$Flavor/llvmCore-$Release-$RC.obj llvmCore_phase3_installdir=$BuildDir/Phase3/$Flavor/llvmCore-$Release-$RC.install llvmCore_de_phase3_objdir=$BuildDir/Phase3/$Flavor/llvmCore-DragonEgg-$Release-$RC.obj llvmCore_de_phase3_installdir=$BuildDir/Phase3/$Flavor/llvmCore-DragonEgg-$Release-$RC.install - dragonegg_phase3_objdir=$BuildDir/Phase3/$Flavor/DragonEgg-$Release-$RC.obj rm -rf $llvmCore_phase1_objdir rm -rf $llvmCore_phase1_installdir - rm -rf $dragonegg_phase1_objdir rm -rf $llvmCore_phase2_objdir rm -rf $llvmCore_phase2_installdir rm -rf $llvmCore_de_phase2_objdir rm -rf $llvmCore_de_phase2_installdir - rm -rf $dragonegg_phase2_objdir rm -rf $llvmCore_phase3_objdir rm -rf $llvmCore_phase3_installdir rm -rf $llvmCore_de_phase3_objdir rm -rf $llvmCore_de_phase3_installdir - rm -rf $dragonegg_phase3_objdir mkdir -p $llvmCore_phase1_objdir mkdir -p $llvmCore_phase1_installdir - mkdir -p $dragonegg_phase1_objdir mkdir -p $llvmCore_phase2_objdir mkdir -p $llvmCore_phase2_installdir mkdir -p $llvmCore_de_phase2_objdir mkdir -p $llvmCore_de_phase2_installdir - mkdir -p $dragonegg_phase2_objdir mkdir -p $llvmCore_phase3_objdir mkdir -p $llvmCore_phase3_installdir mkdir -p $llvmCore_de_phase3_objdir mkdir -p $llvmCore_de_phase3_installdir - mkdir -p $dragonegg_phase3_objdir ############################################################################ # Phase 1: Build llvmCore and clang @@ -544,62 +475,8 @@ for Flavor in $Flavors ; do fi fi - # Test dragonegg - if [ "$do_dragonegg" = "yes" ]; then - # Build dragonegg using the targeted gcc. This isn't necessary, but - # helps avoid using broken versions of gcc (which are legion), tests - # that the targeted gcc is basically sane and is consistent with the - # later phases in which the targeted gcc + dragonegg are used. - c_compiler="$gcc_compiler" - cxx_compiler="$gxx_compiler" - build_dragonegg 1 $Flavor $llvmCore_phase1_installdir $dragonegg_phase1_objdir - - ######################################################################## - # Phase 2: Build llvmCore with newly built dragonegg from phase 1. - c_compiler="$gcc_compiler -fplugin=$dragonegg_phase1_objdir/dragonegg.so" - cxx_compiler="$gxx_compiler -fplugin=$dragonegg_phase1_objdir/dragonegg.so" - echo "# Phase 2: Building llvmCore with dragonegg" - configure_llvmCore 2 $Flavor \ - $llvmCore_de_phase2_objdir $llvmCore_de_phase2_installdir - build_llvmCore 2 $Flavor \ - $llvmCore_de_phase2_objdir - build_dragonegg 2 $Flavor $llvmCore_de_phase2_installdir $dragonegg_phase2_objdir - clean_RPATH $llvmCore_de_phase2_installdir - - ######################################################################## - # 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" - configure_llvmCore 3 $Flavor \ - $llvmCore_de_phase3_objdir $llvmCore_de_phase3_installdir - build_llvmCore 3 $Flavor \ - $llvmCore_de_phase3_objdir - build_dragonegg 3 $Flavor $llvmCore_de_phase3_installdir $dragonegg_phase3_objdir - clean_RPATH $llvmCore_de_phase3_installdir - - ######################################################################## - # Testing: Test phase 3 - c_compiler="$gcc_compiler -fplugin=$dragonegg_phase3_objdir/dragonegg.so" - cxx_compiler="$gxx_compiler -fplugin=$dragonegg_phase3_objdir/dragonegg.so" - echo "# Testing - built with dragonegg" - test_llvmCore 3 $Flavor $llvmCore_de_phase3_objdir - - ######################################################################## - # Compare .o files between Phase2 and Phase3 and report which ones differ. - echo - echo "# Comparing Phase 2 and Phase 3 files" - for o in `find $llvmCore_de_phase2_objdir -name '*.o'` \ - `find $dragonegg_phase2_objdir -name '*.o'` ; do - p3=`echo $o | sed -e 's,Phase2,Phase3,'` - if ! cmp --ignore-initial=16 $o $p3 > /dev/null 2>&1 ; then - echo "file `basename $o` differs between dragonegg phase 2 and phase 3" - fi - done - fi - # Otherwise just test the core. - if [ "$do_clang" != "yes" -a "$do_dragonegg" != "yes" ]; then + if [ "$do_clang" != "yes" ]; then echo "# Testing - built with system compiler" test_llvmCore 1 $Flavor $llvmCore_phase1_objdir fi diff --git a/utils/shuffle_fuzz.py b/utils/shuffle_fuzz.py index 384a93aa98848..985d1dab9e23e 100755 --- a/utils/shuffle_fuzz.py +++ b/utils/shuffle_fuzz.py @@ -173,7 +173,7 @@ entry:""" % dict(subst, # Generate some string constants that we can use to report errors. for i, r in enumerate(result): if r != -1: - s = ('FAIL(%(seed)s): lane %(lane)d, expected %(result)d, found %%d\\0A' % + s = ('FAIL(%(seed)s): lane %(lane)d, expected %(result)d, found %%d\n\\0A' % {'seed': args.seed, 'lane': i, 'result': r}) s += ''.join(['\\00' for _ in itertools.repeat(None, 128 - len(s) + 2)]) print """ @@ -235,8 +235,7 @@ die.%(i)d: %%bad.%(i)d = trunc i2048 %%tmp.%(i)d to i32 call i32 (i8*, i8*, ...)* @sprintf(i8* %%str.ptr, i8* getelementptr inbounds ([128 x i8]* @error.%(i)d, i32 0, i32 0), i32 %%bad.%(i)d) %%length.%(i)d = call i32 @strlen(i8* %%str.ptr) - %%size.%(i)d = add i32 %%length.%(i)d, 1 - call i32 @write(i32 2, i8* %%str.ptr, i32 %%size.%(i)d) + call i32 @write(i32 2, i8* %%str.ptr, i32 %%length.%(i)d) call void @llvm.trap() unreachable """ % dict(subst, i=i, next_i=i + 1, r=r) diff --git a/utils/sort_includes.py b/utils/sort_includes.py index fef97550db8d8..70bfdedfc6d32 100755 --- a/utils/sort_includes.py +++ b/utils/sort_includes.py @@ -29,7 +29,8 @@ def sort_includes(f): headers_end = 0 api_headers = [] local_headers = [] - project_headers = [] + subproject_headers = [] + llvm_headers = [] system_headers = [] for (i, l) in enumerate(lines): if l.strip() == '': @@ -44,12 +45,16 @@ def sort_includes(f): api_headers.append(header) look_for_api_header = False continue - if header.startswith('<') or header.startswith('"gtest/'): + if (header.startswith('<') or header.startswith('"gtest/') or + header.startswith('"isl/') or header.startswith('"json/')): system_headers.append(header) continue - if (header.startswith('"llvm/') or header.startswith('"llvm-c/') or - header.startswith('"clang/') or header.startswith('"clang-c/')): - project_headers.append(header) + if (header.startswith('"clang/') or header.startswith('"clang-c/') or + header.startswith('"polly/')): + subproject_headers.append(header) + continue + if (header.startswith('"llvm/') or header.startswith('"llvm-c/')): + llvm_headers.append(header) continue local_headers.append(header) continue @@ -65,9 +70,10 @@ def sort_includes(f): return local_headers = sorted(set(local_headers)) - project_headers = sorted(set(project_headers)) + subproject_headers = sorted(set(subproject_headers)) + llvm_headers = sorted(set(llvm_headers)) system_headers = sorted(set(system_headers)) - headers = api_headers + local_headers + project_headers + system_headers + headers = api_headers + local_headers + subproject_headers + llvm_headers + system_headers header_lines = ['#include ' + h for h in headers] lines = lines[:headers_begin] + header_lines + lines[headers_end + 1:] diff --git a/utils/unittest/CMakeLists.txt b/utils/unittest/CMakeLists.txt index b6d2d6d9e0e99..b34e22ae0cb42 100644 --- a/utils/unittest/CMakeLists.txt +++ b/utils/unittest/CMakeLists.txt @@ -32,17 +32,20 @@ if (NOT LLVM_ENABLE_THREADS) add_definitions( -DGTEST_HAS_PTHREAD=0 ) endif() -# Visual Studio 2012 only supports up to 8 template parameters in -# std::tr1::tuple by default, but gtest requires 10 -if(MSVC AND MSVC_VERSION EQUAL 1700) - add_definitions(-D_VARIADIC_MAX=10) -endif () +set(LIBS + LLVMSupport # Depends on llvm::raw_ostream +) + +find_library(PTHREAD_LIBRARY_PATH pthread) +if (PTHREAD_LIBRARY_PATH) + list(APPEND LIBS pthread) +endif() add_llvm_library(gtest googletest/src/gtest-all.cc LINK_LIBS - LLVMSupport # Depends on llvm::raw_ostream - ) + ${LIBS} +) add_subdirectory(UnitTestMain) diff --git a/utils/unittest/UnitTestMain/TestMain.cpp b/utils/unittest/UnitTestMain/TestMain.cpp index 5387512e6fb54..f5b09a5cf6735 100644 --- a/utils/unittest/UnitTestMain/TestMain.cpp +++ b/utils/unittest/UnitTestMain/TestMain.cpp @@ -23,7 +23,7 @@ const char *TestMainArgv0; int main(int argc, char **argv) { - llvm::sys::PrintStackTraceOnErrorSignal(); + llvm::sys::PrintStackTraceOnErrorSignal(true /* Disable crash reporting */); testing::InitGoogleTest(&argc, argv); llvm::cl::ParseCommandLineOptions(argc, argv); diff --git a/utils/unittest/googletest/include/gtest/gtest-spi.h b/utils/unittest/googletest/include/gtest/gtest-spi.h index b226e55048959..736f692e48f75 100644 --- a/utils/unittest/googletest/include/gtest/gtest-spi.h +++ b/utils/unittest/googletest/include/gtest/gtest-spi.h @@ -68,14 +68,15 @@ class GTEST_API_ ScopedFakeTestPartResultReporter TestPartResultArray* result); // The d'tor restores the previous test part result reporter. - virtual ~ScopedFakeTestPartResultReporter(); + ~ScopedFakeTestPartResultReporter() override; // Appends the TestPartResult object to the TestPartResultArray // received in the constructor. // // This method is from the TestPartResultReporterInterface // interface. - virtual void ReportTestPartResult(const TestPartResult& result); + void ReportTestPartResult(const TestPartResult &result) override; + private: void Init(); diff --git a/utils/unittest/googletest/include/gtest/gtest-test-part.h b/utils/unittest/googletest/include/gtest/gtest-test-part.h index 98e8b844915d1..d2410c00a3ffb 100644 --- a/utils/unittest/googletest/include/gtest/gtest-test-part.h +++ b/utils/unittest/googletest/include/gtest/gtest-test-part.h @@ -159,8 +159,8 @@ class GTEST_API_ HasNewFatalFailureHelper : public TestPartResultReporterInterface { public: HasNewFatalFailureHelper(); - virtual ~HasNewFatalFailureHelper(); - virtual void ReportTestPartResult(const TestPartResult& result); + ~HasNewFatalFailureHelper() override; + void ReportTestPartResult(const TestPartResult &result) override; bool has_new_fatal_failure() const { return has_new_fatal_failure_; } private: bool has_new_fatal_failure_; diff --git a/utils/unittest/googletest/include/gtest/gtest.h b/utils/unittest/googletest/include/gtest/gtest.h index 07ed92b57c0dc..92ca5cc91c82b 100644 --- a/utils/unittest/googletest/include/gtest/gtest.h +++ b/utils/unittest/googletest/include/gtest/gtest.h @@ -74,7 +74,7 @@ // define it to 0 to indicate otherwise. // // If the user's ::std::string and ::string are the same class due to -// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. +// aliasing, they should define GTEST_HAS_GLOBAL_STRING to 0. // // If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined // heuristically. @@ -982,21 +982,22 @@ class TestEventListener { class EmptyTestEventListener : public TestEventListener { virtual void anchor(); public: - virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, - int /*iteration*/) {} - virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} - virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} - virtual void OnTestStart(const TestInfo& /*test_info*/) {} - virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} - virtual void OnTestEnd(const TestInfo& /*test_info*/) {} - virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} - virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} - virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, - int /*iteration*/) {} - virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + void OnTestProgramStart(const UnitTest & /*unit_test*/) override {} + void OnTestIterationStart(const UnitTest & /*unit_test*/, + int /*iteration*/) override {} + void OnEnvironmentsSetUpStart(const UnitTest & /*unit_test*/) override {} + void OnEnvironmentsSetUpEnd(const UnitTest & /*unit_test*/) override {} + void OnTestCaseStart(const TestCase & /*test_case*/) override {} + void OnTestStart(const TestInfo & /*test_info*/) override {} + void OnTestPartResult(const TestPartResult & /*test_part_result*/) override { + } + void OnTestEnd(const TestInfo & /*test_info*/) override {} + void OnTestCaseEnd(const TestCase & /*test_case*/) override {} + void OnEnvironmentsTearDownStart(const UnitTest & /*unit_test*/) override {} + void OnEnvironmentsTearDownEnd(const UnitTest & /*unit_test*/) override {} + void OnTestIterationEnd(const UnitTest & /*unit_test*/, + int /*iteration*/) override {} + void OnTestProgramEnd(const UnitTest & /*unit_test*/) override {} }; // TestEventListeners lets users add listeners to track events in Google Test. diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h b/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h index 8d53c4528078b..04c676ce5ff7b 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-death-test-internal.h @@ -147,8 +147,8 @@ class DeathTestFactory { // A concrete DeathTestFactory implementation for normal use. class DefaultDeathTestFactory : public DeathTestFactory { public: - virtual bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test); + bool Create(const char *statement, const RE *regex, const char *file, + int line, DeathTest **test) override; }; // Returns true if exit_status describes a process that was terminated diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-internal.h b/utils/unittest/googletest/include/gtest/internal/gtest-internal.h index 63f72acdfb572..3c7eee81b1d91 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-internal.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-internal.h @@ -555,7 +555,7 @@ class TestFactoryBase { template <class TestClass> class TestFactoryImpl : public TestFactoryBase { public: - virtual Test* CreateTest() { return new TestClass; } + Test *CreateTest() override { return new TestClass; } }; #if GTEST_OS_WINDOWS diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-param-util-generated.h b/utils/unittest/googletest/include/gtest/internal/gtest-param-util-generated.h index 258267500ec18..e32c762f75ada 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-param-util-generated.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-param-util-generated.h @@ -100,9 +100,6 @@ class ValueArray2 { } private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray2& other); - const T1 v1_; const T2 v2_; }; diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h b/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h index 3bb2ffb355666..dea4d5cc6bcb1 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-param-util.h @@ -270,12 +270,12 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> { template <typename ForwardIterator> ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) : container_(begin, end) {} - virtual ~ValuesInIteratorRangeGenerator() {} + ~ValuesInIteratorRangeGenerator() override {} - virtual ParamIteratorInterface<T>* Begin() const { + ParamIteratorInterface<T> *Begin() const override { return new Iterator(this, container_.begin()); } - virtual ParamIteratorInterface<T>* End() const { + ParamIteratorInterface<T> *End() const override { return new Iterator(this, container_.end()); } @@ -287,16 +287,16 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> { Iterator(const ParamGeneratorInterface<T>* base, typename ContainerType::const_iterator iterator) : base_(base), iterator_(iterator) {} - virtual ~Iterator() {} + ~Iterator() override {} - virtual const ParamGeneratorInterface<T>* BaseGenerator() const { + const ParamGeneratorInterface<T> *BaseGenerator() const override { return base_; } - virtual void Advance() { + void Advance() override { ++iterator_; value_.reset(); } - virtual ParamIteratorInterface<T>* Clone() const { + ParamIteratorInterface<T> *Clone() const override { return new Iterator(*this); } // We need to use cached value referenced by iterator_ because *iterator_ @@ -306,12 +306,12 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> { // can advance iterator_ beyond the end of the range, and we cannot // detect that fact. The client code, on the other hand, is // responsible for not calling Current() on an out-of-range iterator. - virtual const T* Current() const { + const T *Current() const override { if (value_.get() == NULL) value_.reset(new T(*iterator_)); return value_.get(); } - virtual bool Equals(const ParamIteratorInterface<T>& other) const { + bool Equals(const ParamIteratorInterface<T> &other) const override { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) @@ -355,7 +355,7 @@ class ParameterizedTestFactory : public TestFactoryBase { typedef typename TestClass::ParamType ParamType; explicit ParameterizedTestFactory(ParamType parameter) : parameter_(parameter) {} - virtual Test* CreateTest() { + Test *CreateTest() override { TestClass::SetParam(¶meter_); return new TestClass(); } @@ -394,7 +394,7 @@ class TestMetaFactory TestMetaFactory() {} - virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { + TestFactoryBase *CreateTestFactory(ParamType parameter) override { return new ParameterizedTestFactory<TestCase>(parameter); } @@ -454,9 +454,9 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { : test_case_name_(name) {} // Test case base name for display purposes. - virtual const string& GetTestCaseName() const { return test_case_name_; } + const string &GetTestCaseName() const override { return test_case_name_; } // Test case id to verify identity. - virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); } + TypeId GetTestCaseTypeId() const override { return GetTypeId<TestCase>(); } // TEST_P macro uses AddTestPattern() to record information // about a single test in a LocalTestInfo structure. // test_case_name is the base name of the test case (without invocation @@ -484,7 +484,7 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { // This method should not be called more then once on any single // instance of a ParameterizedTestCaseInfoBase derived class. // UnitTest has a guard to prevent from calling this method more then once. - virtual void RegisterTests() { + void RegisterTests() override { for (typename TestInfoContainer::iterator test_it = tests_.begin(); test_it != tests_.end(); ++test_it) { linked_ptr<TestInfo> test_info = *test_it; diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-port.h b/utils/unittest/googletest/include/gtest/internal/gtest-port.h index f5bfd4e1d2eec..6b942e9f9d9e7 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-port.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-port.h @@ -503,7 +503,7 @@ # define _TR1_FUNCTIONAL 1 # include <tr1/tuple> # undef _TR1_FUNCTIONAL // Allows the user to #include - // <tr1/functional> if he chooses to. + // <tr1/functional> if they choose to. # else # include <tr1/tuple> // NOLINT # endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 @@ -1165,7 +1165,7 @@ class ThreadWithParam : public ThreadWithParamBase { GTEST_CHECK_POSIX_SUCCESS_( pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); } - ~ThreadWithParam() { Join(); } + ~ThreadWithParam() override { Join(); } void Join() { if (!finished_) { @@ -1174,7 +1174,7 @@ class ThreadWithParam : public ThreadWithParamBase { } } - virtual void Run() { + void Run() override { if (thread_can_start_ != NULL) thread_can_start_->WaitForNotification(); func_(param_); diff --git a/utils/unittest/googletest/src/gtest-death-test.cc b/utils/unittest/googletest/src/gtest-death-test.cc index 314dba2116e97..47c1a15b820cd 100644 --- a/utils/unittest/googletest/src/gtest-death-test.cc +++ b/utils/unittest/googletest/src/gtest-death-test.cc @@ -334,10 +334,10 @@ class DeathTestImpl : public DeathTest { write_fd_(-1) {} // read_fd_ is expected to be closed and cleared by a derived class. - ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } + ~DeathTestImpl() override { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } - void Abort(AbortReason reason); - virtual bool Passed(bool status_ok); + void Abort(AbortReason reason) override; + bool Passed(bool status_ok) override; const char* statement() const { return statement_; } const RE* regex() const { return regex_; } @@ -744,7 +744,7 @@ class ForkingDeathTest : public DeathTestImpl { ForkingDeathTest(const char* statement, const RE* regex); // All of these virtual functions are inherited from DeathTest. - virtual int Wait(); + int Wait() override; protected: void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } @@ -780,7 +780,7 @@ class NoExecDeathTest : public ForkingDeathTest { public: NoExecDeathTest(const char* a_statement, const RE* a_regex) : ForkingDeathTest(a_statement, a_regex) { } - virtual TestRole AssumeRole(); + TestRole AssumeRole() override; }; // The AssumeRole process for a fork-and-run death test. It implements a @@ -835,7 +835,8 @@ class ExecDeathTest : public ForkingDeathTest { ExecDeathTest(const char* a_statement, const RE* a_regex, const char* file, int line) : ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } - virtual TestRole AssumeRole(); + TestRole AssumeRole() override; + private: // The name of the file in which the death test is located. const char* const file_; diff --git a/utils/unittest/googletest/src/gtest-internal-inl.h b/utils/unittest/googletest/src/gtest-internal-inl.h index 1bae630127b52..35e865ff07fe9 100644 --- a/utils/unittest/googletest/src/gtest-internal-inl.h +++ b/utils/unittest/googletest/src/gtest-internal-inl.h @@ -431,8 +431,8 @@ class OsStackTraceGetterInterface { class OsStackTraceGetter : public OsStackTraceGetterInterface { public: OsStackTraceGetter() : caller_frame_(NULL) {} - virtual String CurrentStackTrace(int max_depth, int skip_count); - virtual void UponLeavingGTest(); + String CurrentStackTrace(int max_depth, int skip_count) override; + void UponLeavingGTest() override; // This string is inserted in place of stack frames that are part of // Google Test's implementation. @@ -465,7 +465,7 @@ class DefaultGlobalTestPartResultReporter explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. Reports the test part // result in the current test. - virtual void ReportTestPartResult(const TestPartResult& result); + void ReportTestPartResult(const TestPartResult &result) override; private: UnitTestImpl* const unit_test_; @@ -481,7 +481,7 @@ class DefaultPerThreadTestPartResultReporter explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. The implementation just // delegates to the current global test part result reporter of *unit_test_. - virtual void ReportTestPartResult(const TestPartResult& result); + void ReportTestPartResult(const TestPartResult &result) override; private: UnitTestImpl* const unit_test_; diff --git a/utils/unittest/googletest/src/gtest.cc b/utils/unittest/googletest/src/gtest.cc index bf850c6cd9774..57807646ea173 100644 --- a/utils/unittest/googletest/src/gtest.cc +++ b/utils/unittest/googletest/src/gtest.cc @@ -2663,19 +2663,19 @@ class PrettyUnitTestResultPrinter : public TestEventListener { } // The following methods override what's in the TestEventListener class. - virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + void OnTestProgramStart(const UnitTest & /*unit_test*/) override {} + void OnTestIterationStart(const UnitTest &unit_test, int iteration) override; + void OnEnvironmentsSetUpStart(const UnitTest &unit_test) override; + void OnEnvironmentsSetUpEnd(const UnitTest & /*unit_test*/) override {} + void OnTestCaseStart(const TestCase &test_case) override; + void OnTestStart(const TestInfo &test_info) override; + void OnTestPartResult(const TestPartResult &result) override; + void OnTestEnd(const TestInfo &test_info) override; + void OnTestCaseEnd(const TestCase &test_case) override; + void OnEnvironmentsTearDownStart(const UnitTest &unit_test) override; + void OnEnvironmentsTearDownEnd(const UnitTest & /*unit_test*/) override {} + void OnTestIterationEnd(const UnitTest &unit_test, int iteration) override; + void OnTestProgramEnd(const UnitTest & /*unit_test*/) override {} private: static void PrintFailedTests(const UnitTest& unit_test); @@ -2869,7 +2869,7 @@ void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, class TestEventRepeater : public TestEventListener { public: TestEventRepeater() : forwarding_enabled_(true) {} - virtual ~TestEventRepeater(); + ~TestEventRepeater() override; void Append(TestEventListener *listener); TestEventListener* Release(TestEventListener* listener); @@ -2878,19 +2878,19 @@ class TestEventRepeater : public TestEventListener { bool forwarding_enabled() const { return forwarding_enabled_; } void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } - virtual void OnTestProgramStart(const UnitTest& unit_test); - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& unit_test); + void OnTestProgramStart(const UnitTest &unit_test) override; + void OnTestIterationStart(const UnitTest &unit_test, int iteration) override; + void OnEnvironmentsSetUpStart(const UnitTest &unit_test) override; + void OnEnvironmentsSetUpEnd(const UnitTest &unit_test) override; + void OnTestCaseStart(const TestCase &test_case) override; + void OnTestStart(const TestInfo &test_info) override; + void OnTestPartResult(const TestPartResult &result) override; + void OnTestEnd(const TestInfo &test_info) override; + void OnTestCaseEnd(const TestCase &test_case) override; + void OnEnvironmentsTearDownStart(const UnitTest &unit_test) override; + void OnEnvironmentsTearDownEnd(const UnitTest &unit_test) override; + void OnTestIterationEnd(const UnitTest &unit_test, int iteration) override; + void OnTestProgramEnd(const UnitTest &unit_test) override; private: // Controls whether events will be forwarded to listeners_. Set to false @@ -2983,7 +2983,7 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { public: explicit XmlUnitTestResultPrinter(const char* output_file); - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + void OnTestIterationEnd(const UnitTest &unit_test, int iteration) override; private: // Is c a whitespace character that is normalized to a space character @@ -3310,16 +3310,16 @@ class StreamingListener : public EmptyTestEventListener { Send("gtest_streaming_protocol_version=1.0\n"); } - virtual ~StreamingListener() { + ~StreamingListener() override { if (sockfd_ != -1) CloseConnection(); } - void OnTestProgramStart(const UnitTest& /* unit_test */) { + void OnTestProgramStart(const UnitTest & /* unit_test */) override { Send("event=TestProgramStart\n"); } - void OnTestProgramEnd(const UnitTest& unit_test) { + void OnTestProgramEnd(const UnitTest &unit_test) override { // Note that Google Test current only report elapsed time for each // test iteration, not for the entire test program. Send(String::Format("event=TestProgramEnd&passed=%d\n", @@ -3329,39 +3329,41 @@ class StreamingListener : public EmptyTestEventListener { CloseConnection(); } - void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { + void OnTestIterationStart(const UnitTest & /* unit_test */, + int iteration) override { Send(String::Format("event=TestIterationStart&iteration=%d\n", iteration)); } - void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { + void OnTestIterationEnd(const UnitTest &unit_test, + int /* iteration */) override { Send(String::Format("event=TestIterationEnd&passed=%d&elapsed_time=%sms\n", unit_test.Passed(), StreamableToString(unit_test.elapsed_time()).c_str())); } - void OnTestCaseStart(const TestCase& test_case) { + void OnTestCaseStart(const TestCase &test_case) override { Send(String::Format("event=TestCaseStart&name=%s\n", test_case.name())); } - void OnTestCaseEnd(const TestCase& test_case) { + void OnTestCaseEnd(const TestCase &test_case) override { Send(String::Format("event=TestCaseEnd&passed=%d&elapsed_time=%sms\n", test_case.Passed(), StreamableToString(test_case.elapsed_time()).c_str())); } - void OnTestStart(const TestInfo& test_info) { + void OnTestStart(const TestInfo &test_info) override { Send(String::Format("event=TestStart&name=%s\n", test_info.name())); } - void OnTestEnd(const TestInfo& test_info) { + void OnTestEnd(const TestInfo &test_info) override { Send(String::Format( "event=TestEnd&passed=%d&elapsed_time=%sms\n", (test_info.result())->Passed(), StreamableToString((test_info.result())->elapsed_time()).c_str())); } - void OnTestPartResult(const TestPartResult& test_part_result) { + void OnTestPartResult(const TestPartResult &test_part_result) override { const char* file_name = test_part_result.file_name(); if (file_name == NULL) file_name = ""; diff --git a/utils/update_llc_test_checks.py b/utils/update_llc_test_checks.py index 4125ea981ec15..df01d8973c464 100755 --- a/utils/update_llc_test_checks.py +++ b/utils/update_llc_test_checks.py @@ -24,6 +24,7 @@ def llc(args, cmd_args, ir): ASM_SCRUB_WHITESPACE_RE = re.compile(r'(?!^(| \w))[ \t]+', flags=re.M) +ASM_SCRUB_TRAILING_WHITESPACE_RE = re.compile(r'[ \t]+$', flags=re.M) ASM_SCRUB_SHUFFLES_RE = ( re.compile( r'^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem) = .*)$', @@ -47,6 +48,8 @@ def scrub_asm(asm): asm = ASM_SCRUB_RIP_RE.sub(r'{{.*}}(%rip)', asm) # Strip kill operands inserted into the asm. asm = ASM_SCRUB_KILL_COMMENT_RE.sub('', asm) + # Strip trailing whitespace. + asm = ASM_SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) return asm @@ -66,7 +69,7 @@ def main(): asm_function_re = re.compile( r'^_?(?P<f>[^:]+):[ \t]*#+[ \t]*@(?P=f)\n[^:]*?' r'(?P<body>^##?[ \t]+[^:]+:.*?)\s*' - r'^\s*(?:[^:\n]+?:\s*\n\s*\.size|\.cfi_endproc|\.globl|\.(?:sub)?section)', + r'^\s*(?:[^:\n]+?:\s*\n\s*\.size|\.cfi_endproc|\.globl|\.comm|\.(?:sub)?section)', flags=(re.M | re.S)) check_prefix_re = re.compile('--check-prefix=(\S+)') check_re = re.compile(r'^\s*;\s*([^:]+?)(?:-NEXT|-NOT|-DAG|-LABEL)?:') @@ -122,6 +125,9 @@ def main(): continue f = m.group('f') f_asm = scrub_asm(m.group('body')) + if f.startswith('stress'): + # We only use the last line of the asm for stress tests. + f_asm = '\n'.join(f_asm.splitlines()[-1:]) if args.verbose: print >>sys.stderr, 'Processing asm for function: ' + f for l in f_asm.splitlines(): diff --git a/utils/vim/README b/utils/vim/README index bca25bfe61272..1fe00992b0ab1 100644 --- a/utils/vim/README +++ b/utils/vim/README @@ -1,33 +1,12 @@ -*- llvm/utils/vim/README -*- -These are syntax highlighting files for the VIM editor. Included are: +This directory contains settings for the vim editor to work on llvm *.ll and +tablegen *.td files. It comes with filetype detection rules in the (ftdetect), +syntax highlighting (syntax), some minimal sensible default settings (ftplugin) +and indentation plugins (indent). -* llvm.vim - - Syntax highlighting mode for LLVM assembly files. To use, copy `llvm.vim' to - ~/.vim/syntax and add this code to your ~/.vimrc : - - augroup filetype - au! BufRead,BufNewFile *.ll set filetype=llvm - augroup END - -* tablegen.vim - - Syntax highlighting mode for TableGen description files. To use, copy - `tablegen.vim' to ~/.vim/syntax and add this code to your ~/.vimrc : - - augroup filetype - au! BufRead,BufNewFile *.td set filetype=tablegen - augroup END - - -If you prefer, instead of making copies you can make symlinks from -~/.vim/syntax/... to the syntax files in your LLVM source tree. Apparently -this did not work with older versions of vim however, so if this doesn't -work you may need to make actual copies of the files. - -Another option, if you do not already have a ~/.vim/syntax directory, is -to symlink ~/.vim/syntax itself to llvm/utils/vim . +To install copy all subdirectories to your $HOME/.vim or if you prefer create +symlinks to the files here. Do not copy the vimrc file here it is only meant as an inspiration and starting point for those working on llvm c++ code. Note: If you notice missing or incorrect syntax highlighting, please contact <llvmbugs [at] cs.uiuc.edu>; if you wish to provide a patch to improve the diff --git a/utils/vim/ftdetect/llvm-lit.vim b/utils/vim/ftdetect/llvm-lit.vim new file mode 100644 index 0000000000000..fa651e1268cb5 --- /dev/null +++ b/utils/vim/ftdetect/llvm-lit.vim @@ -0,0 +1 @@ +au BufRead,BufNewFile lit.*cfg set filetype=python diff --git a/utils/vim/ftdetect/llvm.vim b/utils/vim/ftdetect/llvm.vim new file mode 100644 index 0000000000000..161ceb2bd5595 --- /dev/null +++ b/utils/vim/ftdetect/llvm.vim @@ -0,0 +1 @@ +au BufRead,BufNewFile *.ll set filetype=llvm diff --git a/utils/vim/ftdetect/tablegen.vim b/utils/vim/ftdetect/tablegen.vim new file mode 100644 index 0000000000000..95efa6efdd0aa --- /dev/null +++ b/utils/vim/ftdetect/tablegen.vim @@ -0,0 +1 @@ +au BufRead,BufNewFile *.td set filetype=tablegen diff --git a/utils/vim/ftplugin/llvm.vim b/utils/vim/ftplugin/llvm.vim new file mode 100644 index 0000000000000..04bb9e0016966 --- /dev/null +++ b/utils/vim/ftplugin/llvm.vim @@ -0,0 +1,11 @@ +" Vim filetype plugin file +" Language: LLVM Assembly +" Maintainer: The LLVM team, http://llvm.org/ + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +setlocal softtabstop=2 shiftwidth=2 +setlocal expandtab diff --git a/utils/vim/ftplugin/tablegen.vim b/utils/vim/ftplugin/tablegen.vim new file mode 100644 index 0000000000000..cfae846c818b8 --- /dev/null +++ b/utils/vim/ftplugin/tablegen.vim @@ -0,0 +1,12 @@ +" Vim filetype plugin file +" Language: LLVM TableGen +" Maintainer: The LLVM team, http://llvm.org/ + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +setlocal matchpairs+=<:> +setlocal softtabstop=2 shiftwidth=2 +setlocal expandtab diff --git a/utils/vim/indent/llvm.vim b/utils/vim/indent/llvm.vim new file mode 100644 index 0000000000000..d1d8c83d11861 --- /dev/null +++ b/utils/vim/indent/llvm.vim @@ -0,0 +1,72 @@ +" Vim indent file +" Language: llvm +" Maintainer: The LLVM team, http://llvm.org/ +" What this indent plugin currently does: +" - If no other rule matches copy indent from previous non-empty, +" non-commented line +" - On '}' align the same as the line containing the matching '{' +" - If previous line ends with ':' increase indentation +" - If the current line ends with ':' indent at the same level as the +" enclosing '{'/'}' block +" Stuff that would be nice to add: +" - Continue comments on next line +" - If there is an opening+unclosed parenthesis on previous line indent to that +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal shiftwidth=2 expandtab + +setlocal indentkeys=0{,0},<:>,!^F,o,O,e +setlocal indentexpr=GetLLVMIndent() + +if exists("*GetLLVMIndent") + finish +endif + +function! FindOpenBrace(lnum) + call cursor(a:lnum, 1) + return searchpair('{', '', '}', 'bW') +endfun + +function! GetLLVMIndent() + " On '}' align the same as the line containing the matching '{' + let thisline = getline(v:lnum) + if thisline =~ '^\s*}' + call cursor(v:lnum, 1) + silent normal % + let opening_lnum = line('.') + if opening_lnum != v:lnum + return indent(opening_lnum) + endif + endif + + " Indent labels the same as the current opening block + if thisline =~ ':\s*$' + let blockbegin = FindOpenBrace(v:lnum) + if blockbegin > 0 + return indent(blockbegin) + endif + endif + + " Find a non-blank not-completely commented line above the current line. + let prev_lnum = prevnonblank(v:lnum - 1) + while prev_lnum > 0 && synIDattr(synID(prev_lnum, indent(prev_lnum)+1, 0), "name") =? "string\|comment" + let prev_lnum = prevnonblank(prev_lnum-1) + endwhile + " Hit the start of the file, use zero indent. + if prev_lnum == 0 + return 0 + endif + + let ind = indent(prev_lnum) + let prevline = getline(prev_lnum) + + " Add a 'shiftwidth' after lines that start a block or labels + if prevline =~ '{\s*$' || prevline =~ ':\s*$' + let ind = ind + &shiftwidth + endif + + return ind +endfunction diff --git a/utils/vim/llvm.vim b/utils/vim/syntax/llvm.vim index f767fda16f873..c8e73cd94a57d 100644 --- a/utils/vim/llvm.vim +++ b/utils/vim/syntax/llvm.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: llvm " Maintainer: The LLVM team, http://llvm.org/ -" Version: $Revision: 225830 $ +" Version: $Revision: 235369 $ if version < 600 syntax clear @@ -77,6 +77,12 @@ syn match llvmIdentifier /[%@][-a-zA-Z$._][-a-zA-Z$._0-9]*/ syn match llvmIdentifier /![-a-zA-Z$._][-a-zA-Z$._0-9]*\ze\s*$/ syn match llvmIdentifier /![-a-zA-Z$._][-a-zA-Z$._0-9]*\ze\s*[=!]/ syn match llvmType /!\zs\a\+\ze\s*(/ +syn match llvmConstant /\<DW_TAG_[a-z_]\+\>/ +syn match llvmConstant /\<DW_ATE_[a-zA-Z_]\+\>/ +syn match llvmConstant /\<DW_OP_[a-zA-Z0-9_]\+\>/ +syn match llvmConstant /\<DW_LANG_[a-zA-Z0-9_]\+\>/ +syn match llvmConstant /\<DW_VIRTUALITY_[a-z_]\+\>/ +syn match llvmConstant /\<DIFlag[A-Za-z]\+\>/ " Syntax-highlight dejagnu test commands. syn match llvmSpecialComment /;\s*RUN:.*$/ diff --git a/utils/vim/tablegen.vim b/utils/vim/syntax/tablegen.vim index 40d8d78bba128..21f4848933537 100644 --- a/utils/vim/tablegen.vim +++ b/utils/vim/syntax/tablegen.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: TableGen " Maintainer: The LLVM team, http://llvm.org/ -" Version: $Revision: 151164 $ +" Version: $Revision: 235369 $ if version < 600 syntax clear diff --git a/utils/yaml-bench/YAMLBench.cpp b/utils/yaml-bench/YAMLBench.cpp index 8bd1ea17ea8e2..634622a710c80 100644 --- a/utils/yaml-bench/YAMLBench.cpp +++ b/utils/yaml-bench/YAMLBench.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/Timer.h" +#include "llvm/Support/Process.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/raw_ostream.h" #include <system_error> @@ -52,6 +53,10 @@ static cl::opt<unsigned> "Do not use more megabytes of memory"), cl::init(1000)); +cl::opt<cl::boolOrDefault> + UseColor("use-color", cl::desc("Emit colored output (default=autodetect)"), + cl::init(cl::BOU_UNSET)); + struct indent { unsigned distance; indent(unsigned d) : distance(d) {} @@ -69,7 +74,7 @@ static std::string prettyTag(yaml::Node *N) { if (StringRef(Tag).startswith("tag:yaml.org,2002:")) { std::string Ret = "!!"; Ret += StringRef(Tag).substr(18); - return std::move(Ret); + return Ret; } std::string Ret = "!<"; Ret += Tag; @@ -91,6 +96,8 @@ static void dumpNode( yaml::Node *n SmallString<32> Storage; StringRef Val = sn->getValue(Storage); outs() << prettyTag(n) << " \"" << yaml::escape(Val) << "\""; + } else if (yaml::BlockScalarNode *BN = dyn_cast<yaml::BlockScalarNode>(n)) { + outs() << prettyTag(n) << " \"" << yaml::escape(BN->getValue()) << "\""; } else if (yaml::SequenceNode *sn = dyn_cast<yaml::SequenceNode>(n)) { outs() << prettyTag(n) << " [\n"; ++Indent; @@ -117,7 +124,7 @@ static void dumpNode( yaml::Node *n outs() << indent(Indent) << "}"; } else if (yaml::AliasNode *an = dyn_cast<yaml::AliasNode>(n)){ outs() << "*" << an->getName(); - } else if (dyn_cast<yaml::NullNode>(n)) { + } else if (isa<yaml::NullNode>(n)) { outs() << prettyTag(n) << " null"; } } @@ -187,6 +194,9 @@ static std::string createJSONText(size_t MemoryMB, unsigned ValueSize) { int main(int argc, char **argv) { llvm::cl::ParseCommandLineOptions(argc, argv); + bool ShowColors = UseColor == cl::BOU_UNSET + ? sys::Process::StandardOutHasColors() + : UseColor == cl::BOU_TRUE; if (Input.getNumOccurrences()) { ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = MemoryBuffer::getFileOrSTDIN(Input); @@ -200,8 +210,10 @@ int main(int argc, char **argv) { } if (DumpCanonical) { - yaml::Stream stream(Buf.getBuffer(), sm); + yaml::Stream stream(Buf.getBuffer(), sm, ShowColors); dumpStream(stream); + if (stream.failed()) + return 1; } } |