From 12f3ca4cdb95b193af905a00e722a4dcb40b3de3 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Wed, 26 Apr 2017 19:45:00 +0000 Subject: Vendor import of llvm trunk r301441: https://llvm.org/svn/llvm-project/llvm/trunk@301441 --- utils/TableGen/AsmMatcherEmitter.cpp | 2 +- utils/TableGen/CodeEmitterGen.cpp | 2 +- utils/TableGen/GlobalISelEmitter.cpp | 251 +++++++++++++++----------------- utils/TableGen/SubtargetFeatureInfo.cpp | 32 ++++ utils/TableGen/SubtargetFeatureInfo.h | 40 +++++ utils/TableGen/Types.cpp | 1 + utils/git-svn/git-llvm | 69 ++++++++- 7 files changed, 256 insertions(+), 141 deletions(-) (limited to 'utils') diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 3947d0220ed5..a5c2ea6c7aca 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -2861,7 +2861,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { emitValidateOperandClass(Info, OS); // Emit the available features compute function. - SubtargetFeatureInfo::emitComputeAvailableFeatures( + SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures( Info.Target.getName(), ClassName, "ComputeAvailableFeatures", Info.SubtargetFeatures, OS); diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp index f34c0ded0a35..565235d82143 100644 --- a/utils/TableGen/CodeEmitterGen.cpp +++ b/utils/TableGen/CodeEmitterGen.cpp @@ -336,7 +336,7 @@ void CodeEmitterGen::run(raw_ostream &o) { o << "#endif // NDEBUG\n"; // Emit the available features compute function. - SubtargetFeatureInfo::emitComputeAvailableFeatures( + SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures( Target.getName(), "MCCodeEmitter", "computeAvailableFeatures", SubtargetFeatures, o); diff --git a/utils/TableGen/GlobalISelEmitter.cpp b/utils/TableGen/GlobalISelEmitter.cpp index 7acc65e349ea..dcf10ab511da 100644 --- a/utils/TableGen/GlobalISelEmitter.cpp +++ b/utils/TableGen/GlobalISelEmitter.cpp @@ -31,6 +31,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenDAGPatterns.h" +#include "SubtargetFeatureInfo.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" @@ -79,7 +80,7 @@ public: return; } if (Ty.isVector()) { - OS << "LLT::vector(" << Ty.getNumElements() << ", " << Ty.getSizeInBits() + OS << "LLT::vector(" << Ty.getNumElements() << ", " << Ty.getScalarSizeInBits() << ")"; return; } @@ -90,52 +91,6 @@ public: }; class InstructionMatcher; -class OperandPlaceholder { -private: - enum PlaceholderKind { - OP_MatchReference, - OP_Temporary, - } Kind; - - struct MatchReferenceData { - InstructionMatcher *InsnMatcher; - StringRef InsnVarName; - StringRef SymbolicName; - }; - - struct TemporaryData { - unsigned OpIdx; - }; - - union { - struct MatchReferenceData MatchReference; - struct TemporaryData Temporary; - }; - - OperandPlaceholder(PlaceholderKind Kind) : Kind(Kind) {} - -public: - ~OperandPlaceholder() {} - - static OperandPlaceholder - CreateMatchReference(InstructionMatcher *InsnMatcher, - StringRef InsnVarName, StringRef SymbolicName) { - OperandPlaceholder Result(OP_MatchReference); - Result.MatchReference.InsnMatcher = InsnMatcher; - Result.MatchReference.InsnVarName = InsnVarName; - Result.MatchReference.SymbolicName = SymbolicName; - return Result; - } - - static OperandPlaceholder CreateTemporary(unsigned OpIdx) { - OperandPlaceholder Result(OP_Temporary); - Result.Temporary.OpIdx = OpIdx; - return Result; - } - - void emitCxxValueExpr(raw_ostream &OS) const; -}; - /// Convert an MVT to an equivalent LLT if possible, or the invalid LLT() for /// MVTs that don't map cleanly to an LLT (e.g., iPTR, *any, ...). static Optional MVTToLLT(MVT::SimpleValueType SVT) { @@ -161,20 +116,6 @@ static std::string explainPredicates(const TreePatternNode *N) { return Explanation; } -static std::string explainRulePredicates(const ArrayRef Predicates) { - std::string Explanation = ""; - StringRef Separator = ""; - for (const auto *P : Predicates) { - Explanation += Separator; - - if (const DefInit *PDef = dyn_cast(P)) { - Explanation += PDef->getDef()->getName(); - } else - Explanation += ""; - } - return Explanation; -} - std::string explainOperator(Record *Operator) { if (Operator->isSubClassOf("SDNode")) return " (" + Operator->getValueAsString("Opcode") + ")"; @@ -238,6 +179,8 @@ class RuleMatcher { /// ID for the next instruction variable defined with defineInsnVar() unsigned NextInsnVarID; + std::vector RequiredFeatures; + public: RuleMatcher() : Matchers(), Actions(), InsnVariableNames(), NextInsnVarID(0) {} @@ -245,6 +188,7 @@ public: RuleMatcher &operator=(RuleMatcher &&Other) = default; InstructionMatcher &addInstructionMatcher(); + void addRequiredFeature(Record *Feature); template Kind &addAction(Args &&... args); @@ -255,7 +199,9 @@ public: void emitCxxCapturedInsnList(raw_ostream &OS); void emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr); - void emit(raw_ostream &OS); + void emit(raw_ostream &OS, + std::map + SubtargetFeatures); /// Compare the priority of this object and B. /// @@ -264,7 +210,10 @@ public: /// Report the maximum number of temporary operands needed by the rule /// matcher. - unsigned countTemporaryOperands() const; + unsigned countRendererFns() const; + + // FIXME: Remove this as soon as possible + InstructionMatcher &insnmatcher_front() const { return *Matchers.front(); } }; template class PredicateListMatcher { @@ -369,7 +318,7 @@ public: /// Report the maximum number of temporary operands needed by the predicate /// matcher. - virtual unsigned countTemporaryOperands() const { return 0; } + virtual unsigned countRendererFns() const { return 0; } }; /// Generates code to check that an operand is a particular LLT. @@ -399,10 +348,6 @@ protected: const OperandMatcher &Operand; const Record &TheDef; - unsigned getNumOperands() const { - return TheDef.getValueAsDag("Operands")->getNumArgs(); - } - unsigned getAllocatedTemporariesBaseID() const; public: @@ -417,17 +362,13 @@ public: void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, StringRef OperandExpr) const override { - OS << TheDef.getValueAsString("MatcherFn") << "(" << OperandExpr; - for (unsigned I = 0; I < getNumOperands(); ++I) { - OS << ", "; - OperandPlaceholder::CreateTemporary(getAllocatedTemporariesBaseID() + I) - .emitCxxValueExpr(OS); - } - OS << ")"; + unsigned ID = getAllocatedTemporariesBaseID(); + OS << "(Renderer" << ID << " = " << TheDef.getValueAsString("MatcherFn") + << "(" << OperandExpr << "))"; } - unsigned countTemporaryOperands() const override { - return getNumOperands(); + unsigned countRendererFns() const override { + return 1; } }; @@ -496,7 +437,7 @@ protected: /// The index of the first temporary variable allocated to this operand. The /// number of allocated temporaries can be found with - /// countTemporaryOperands(). + /// countRendererFns(). unsigned AllocatedTemporariesBaseID; public: @@ -577,12 +518,12 @@ public: /// Report the maximum number of temporary operands needed by the operand /// matcher. - unsigned countTemporaryOperands() const { + unsigned countRendererFns() const { return std::accumulate( predicates().begin(), predicates().end(), 0, [](unsigned A, const std::unique_ptr &Predicate) { - return A + Predicate->countTemporaryOperands(); + return A + Predicate->countRendererFns(); }); } @@ -631,7 +572,7 @@ public: /// Report the maximum number of temporary operands needed by the predicate /// matcher. - virtual unsigned countTemporaryOperands() const { return 0; } + virtual unsigned countRendererFns() const { return 0; } }; /// Generates code to check the opcode of an instruction. @@ -788,17 +729,17 @@ public: /// Report the maximum number of temporary operands needed by the instruction /// matcher. - unsigned countTemporaryOperands() const { + unsigned countRendererFns() const { return std::accumulate(predicates().begin(), predicates().end(), 0, [](unsigned A, const std::unique_ptr &Predicate) { - return A + Predicate->countTemporaryOperands(); + return A + Predicate->countRendererFns(); }) + std::accumulate( Operands.begin(), Operands.end(), 0, [](unsigned A, const std::unique_ptr &Operand) { - return A + Operand->countTemporaryOperands(); + return A + Operand->countRendererFns(); }); } }; @@ -853,18 +794,6 @@ public: }; //===- Actions ------------------------------------------------------------===// -void OperandPlaceholder::emitCxxValueExpr(raw_ostream &OS) const { - switch (Kind) { - case OP_MatchReference: - OS << MatchReference.InsnMatcher->getOperand(MatchReference.SymbolicName) - .getOperandExpr(MatchReference.InsnVarName); - break; - case OP_Temporary: - OS << "TempOp" << Temporary.OpIdx; - break; - } -} - class OperandRenderer { public: enum RendererKind { OR_Copy, OR_Imm, OR_Register, OR_ComplexPattern }; @@ -950,31 +879,33 @@ public: } }; +/// Adds operands by calling a renderer function supplied by the ComplexPattern +/// matcher function. class RenderComplexPatternOperand : public OperandRenderer { private: const Record &TheDef; - std::vector Sources; + /// The name of the operand. + const StringRef SymbolicName; + /// The renderer number. This must be unique within a rule since it's used to + /// identify a temporary variable to hold the renderer function. + unsigned RendererID; unsigned getNumOperands() const { return TheDef.getValueAsDag("Operands")->getNumArgs(); } public: - RenderComplexPatternOperand(const Record &TheDef, - const ArrayRef Sources) - : OperandRenderer(OR_ComplexPattern), TheDef(TheDef), Sources(Sources) {} + RenderComplexPatternOperand(const Record &TheDef, StringRef SymbolicName, + unsigned RendererID) + : OperandRenderer(OR_ComplexPattern), TheDef(TheDef), + SymbolicName(SymbolicName), RendererID(RendererID) {} static bool classof(const OperandRenderer *R) { return R->getKind() == OR_ComplexPattern; } void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override { - assert(Sources.size() == getNumOperands() && "Inconsistent number of operands"); - for (const auto &Source : Sources) { - OS << "MIB.add("; - Source.emitCxxValueExpr(OS); - OS << ");\n"; - } + OS << "Renderer" << RendererID << "(MIB);\n"; } }; @@ -1022,8 +953,9 @@ private: bool canMutate() const { for (const auto &Renderer : enumerate(OperandRenderers)) { if (const auto *Copy = dyn_cast(&*Renderer.value())) { - if (Matched.getOperand(Copy->getSymbolicName()).getOperandIndex() != - Renderer.index()) + const OperandMatcher &OM = Matched.getOperand(Copy->getSymbolicName()); + if (&Matched != &OM.getInstructionMatcher() || + OM.getOperandIndex() != Renderer.index()) return false; } else return false; @@ -1092,6 +1024,10 @@ InstructionMatcher &RuleMatcher::addInstructionMatcher() { return *Matchers.back(); } +void RuleMatcher::addRequiredFeature(Record *Feature) { + RequiredFeatures.push_back(Feature); +} + template Kind &RuleMatcher::addAction(Args &&... args) { Actions.emplace_back(llvm::make_unique(std::forward(args)...)); @@ -1135,7 +1071,9 @@ void RuleMatcher::emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr) { Matchers.front()->emitCxxCaptureStmts(OS, *this, InsnVarName); } -void RuleMatcher::emit(raw_ostream &OS) { +void RuleMatcher::emit(raw_ostream &OS, + std::map + SubtargetFeatures) { if (Matchers.empty()) llvm_unreachable("Unexpected empty matcher!"); @@ -1149,7 +1087,22 @@ void RuleMatcher::emit(raw_ostream &OS) { // %elt0(s32), %elt1(s32) = TGT_LOAD_PAIR %ptr // on some targets but we don't need to make use of that yet. assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet"); - OS << "if ([&]() {\n"; + + OS << "if ("; + OS << "[&]() {\n"; + if (!RequiredFeatures.empty()) { + OS << " PredicateBitset ExpectedFeatures = {"; + StringRef Separator = ""; + for (const auto &Predicate : RequiredFeatures) { + const auto &I = SubtargetFeatures.find(Predicate); + assert(I != SubtargetFeatures.end() && "Didn't import predicate?"); + OS << Separator << I->second.getEnumBitName(); + Separator = ", "; + } + OS << "};\n"; + OS << "if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures)\n" + << " return false;\n"; + } emitCxxCaptureStmts(OS, "I"); @@ -1235,11 +1188,11 @@ bool RuleMatcher::isHigherPriorityThan(const RuleMatcher &B) const { return false; } -unsigned RuleMatcher::countTemporaryOperands() const { +unsigned RuleMatcher::countRendererFns() const { return std::accumulate( Matchers.begin(), Matchers.end(), 0, [](unsigned A, const std::unique_ptr &Matcher) { - return A + Matcher->countTemporaryOperands(); + return A + Matcher->countRendererFns(); }); } @@ -1264,10 +1217,13 @@ private: /// GIComplexPatternEquiv. DenseMap ComplexPatternEquivs; + // Map of predicates to their subtarget features. + std::map SubtargetFeatures; + void gatherNodeEquivs(); const CodeGenInstruction *findNodeEquiv(Record *N) const; - Error importRulePredicates(RuleMatcher &M, ArrayRef Predicates) const; + Error importRulePredicates(RuleMatcher &M, ArrayRef Predicates); Expected createAndImportSelDAGMatcher(InstructionMatcher &InsnMatcher, const TreePatternNode *Src) const; @@ -1287,6 +1243,8 @@ private: /// Analyze pattern \p P, returning a matcher for it if possible. /// Otherwise, return an Error explaining why we don't support it. Expected runOnPattern(const PatternToMatch &P); + + void declareSubtargetFeature(Record *Predicate); }; void GlobalISelEmitter::gatherNodeEquivs() { @@ -1315,10 +1273,13 @@ GlobalISelEmitter::GlobalISelEmitter(RecordKeeper &RK) Error GlobalISelEmitter::importRulePredicates(RuleMatcher &M, - ArrayRef Predicates) const { - if (!Predicates.empty()) - return failedImport("Pattern has a rule predicate (" + - explainRulePredicates(Predicates) + ")"); + ArrayRef Predicates) { + for (const Init *Predicate : Predicates) { + const DefInit *PredicateDef = static_cast(Predicate); + declareSubtargetFeature(PredicateDef->getDef()); + M.addRequiredFeature(PredicateDef->getDef()); + } + return Error::success(); } @@ -1423,6 +1384,12 @@ Error GlobalISelEmitter::importChildMatcher(InstructionMatcher &InsnMatcher, return Error::success(); } + if (ChildRec->isSubClassOf("RegisterOperand")) { + OM.addPredicate( + Target.getRegisterClass(ChildRec->getValueAsDef("RegClass"))); + return Error::success(); + } + // Check for ComplexPattern's. if (ChildRec->isSubClassOf("ComplexPattern")) { const auto &ComplexPattern = ComplexPatternEquivs.find(ChildRec); @@ -1430,9 +1397,9 @@ Error GlobalISelEmitter::importChildMatcher(InstructionMatcher &InsnMatcher, return failedImport("SelectionDAG ComplexPattern (" + ChildRec->getName() + ") not mapped to GlobalISel"); - const auto &Predicate = OM.addPredicate( - OM, *ComplexPattern->second); - TempOpIdx += Predicate.countTemporaryOperands(); + OM.addPredicate(OM, + *ComplexPattern->second); + TempOpIdx++; return Error::success(); } @@ -1486,7 +1453,8 @@ Error GlobalISelEmitter::importExplicitUseRenderer( return Error::success(); } - if (ChildRec->isSubClassOf("RegisterClass")) { + if (ChildRec->isSubClassOf("RegisterClass") || + ChildRec->isSubClassOf("RegisterOperand")) { DstMIBuilder.addRenderer(InsnMatcher, DstChild->getName()); return Error::success(); } @@ -1497,13 +1465,10 @@ Error GlobalISelEmitter::importExplicitUseRenderer( return failedImport( "SelectionDAG ComplexPattern not mapped to GlobalISel"); - SmallVector RenderedOperands; const OperandMatcher &OM = InsnMatcher.getOperand(DstChild->getName()); - for (unsigned I = 0; I < OM.countTemporaryOperands(); ++I) - RenderedOperands.push_back(OperandPlaceholder::CreateTemporary( - OM.getAllocatedTemporariesBaseID() + I)); DstMIBuilder.addRenderer( - *ComplexPattern->second, RenderedOperands); + *ComplexPattern->second, DstChild->getName(), + OM.getAllocatedTemporariesBaseID()); return Error::success(); } @@ -1656,6 +1621,8 @@ Expected GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { const auto &DstIOperand = DstI.Operands[OpIdx]; Record *DstIOpRec = DstIOperand.Rec; + if (DstIOpRec->isSubClassOf("RegisterOperand")) + DstIOpRec = DstIOpRec->getValueAsDef("RegClass"); if (!DstIOpRec->isSubClassOf("RegisterClass")) return failedImport("Dst MI def isn't a register class"); @@ -1723,26 +1690,40 @@ void GlobalISelEmitter::run(raw_ostream &OS) { unsigned MaxTemporaries = 0; for (const auto &Rule : Rules) - MaxTemporaries = std::max(MaxTemporaries, Rule.countTemporaryOperands()); + MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns()); + + OS << "#ifdef GET_GLOBALISEL_PREDICATE_BITSET\n" + << "const unsigned MAX_SUBTARGET_PREDICATES = " << SubtargetFeatures.size() + << ";\n" + << "using PredicateBitset = " + "llvm::PredicateBitsetImpl;\n" + << "#endif // ifdef GET_GLOBALISEL_PREDICATE_BITSET\n\n"; OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n"; for (unsigned I = 0; I < MaxTemporaries; ++I) - OS << " mutable MachineOperand TempOp" << I << ";\n"; + OS << " mutable ComplexRendererFn Renderer" << I << ";\n"; OS << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n\n"; OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n"; for (unsigned I = 0; I < MaxTemporaries; ++I) - OS << ", TempOp" << I << "(MachineOperand::CreatePlaceholder())\n"; + OS << ", Renderer" << I << "(nullptr)\n"; OS << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n"; - OS << "#ifdef GET_GLOBALISEL_IMPL\n" - << "bool " << Target.getName() + OS << "#ifdef GET_GLOBALISEL_IMPL\n"; + SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures, + OS); + SubtargetFeatureInfo::emitNameTable(SubtargetFeatures, OS); + SubtargetFeatureInfo::emitComputeAvailableFeatures( + Target.getName(), "InstructionSelector", "computeAvailableFeatures", + SubtargetFeatures, OS); + + OS << "bool " << Target.getName() << "InstructionSelector::selectImpl(MachineInstr &I) const {\n" << " MachineFunction &MF = *I.getParent()->getParent();\n" << " const MachineRegisterInfo &MRI = MF.getRegInfo();\n"; for (auto &Rule : Rules) { - Rule.emit(OS); + Rule.emit(OS, SubtargetFeatures); ++NumPatternEmitted; } @@ -1751,6 +1732,12 @@ void GlobalISelEmitter::run(raw_ostream &OS) { << "#endif // ifdef GET_GLOBALISEL_IMPL\n"; } +void GlobalISelEmitter::declareSubtargetFeature(Record *Predicate) { + if (SubtargetFeatures.count(Predicate) == 0) + SubtargetFeatures.emplace( + Predicate, SubtargetFeatureInfo(Predicate, SubtargetFeatures.size())); +} + } // end anonymous namespace //===----------------------------------------------------------------------===// diff --git a/utils/TableGen/SubtargetFeatureInfo.cpp b/utils/TableGen/SubtargetFeatureInfo.cpp index 72a556182b1d..96418dc77d55 100644 --- a/utils/TableGen/SubtargetFeatureInfo.cpp +++ b/utils/TableGen/SubtargetFeatureInfo.cpp @@ -59,6 +59,20 @@ void SubtargetFeatureInfo::emitSubtargetFeatureFlagEnumeration( OS << "};\n\n"; } +void SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration( + std::map &SubtargetFeatures, + raw_ostream &OS) { + OS << "// Bits for subtarget features that participate in " + << "instruction matching.\n"; + OS << "enum SubtargetFeatureBits : " + << getMinimalTypeForRange(SubtargetFeatures.size()) << " {\n"; + for (const auto &SF : SubtargetFeatures) { + const SubtargetFeatureInfo &SFI = SF.second; + OS << " " << SFI.getEnumBitName() << " = " << SFI.Index << ",\n"; + } + OS << "};\n\n"; +} + void SubtargetFeatureInfo::emitNameTable( std::map &SubtargetFeatures, raw_ostream &OS) { @@ -90,6 +104,24 @@ void SubtargetFeatureInfo::emitComputeAvailableFeatures( StringRef TargetName, StringRef ClassName, StringRef FuncName, std::map &SubtargetFeatures, raw_ostream &OS) { + OS << "PredicateBitset " << TargetName << ClassName << "::\n" + << FuncName << "(const MachineFunction *MF, const " << TargetName + << "Subtarget *Subtarget) const {\n"; + OS << " PredicateBitset Features;\n"; + for (const auto &SF : SubtargetFeatures) { + const SubtargetFeatureInfo &SFI = SF.second; + + OS << " if (" << SFI.TheDef->getValueAsString("CondString") << ")\n"; + OS << " Features[" << SFI.getEnumBitName() << "] = 1;\n"; + } + OS << " return Features;\n"; + OS << "}\n\n"; +} + +void SubtargetFeatureInfo::emitComputeAssemblerAvailableFeatures( + StringRef TargetName, StringRef ClassName, StringRef FuncName, + std::map &SubtargetFeatures, + raw_ostream &OS) { OS << "uint64_t " << TargetName << ClassName << "::\n" << FuncName << "(const FeatureBitset& FB) const {\n"; OS << " uint64_t Features = 0;\n"; diff --git a/utils/TableGen/SubtargetFeatureInfo.h b/utils/TableGen/SubtargetFeatureInfo.h index 99f380f2a1d7..bbaf45259606 100644 --- a/utils/TableGen/SubtargetFeatureInfo.h +++ b/utils/TableGen/SubtargetFeatureInfo.h @@ -37,16 +37,34 @@ struct SubtargetFeatureInfo { return "Feature_" + TheDef->getName().str(); } + /// \brief The name of the enumerated constant identifying the bitnumber for + /// this feature. + std::string getEnumBitName() const { + return "Feature_" + TheDef->getName().str() + "Bit"; + } + void dump() const; static std::vector> getAll(const RecordKeeper &Records); /// Emit the subtarget feature flag definitions. + /// + /// This version emits the bit value for the feature and is therefore limited + /// to 64 feature bits. static void emitSubtargetFeatureFlagEnumeration( std::map &SubtargetFeatures, raw_ostream &OS); + /// Emit the subtarget feature flag definitions. + /// + /// This version emits the bit index for the feature and can therefore support + /// more than 64 feature bits. + static void emitSubtargetFeatureBitEnumeration( + std::map + &SubtargetFeatures, + raw_ostream &OS); + static void emitNameTable(std::map &SubtargetFeatures, raw_ostream &OS); @@ -54,6 +72,9 @@ struct SubtargetFeatureInfo { /// Emit the function to compute the list of available features given a /// subtarget. /// + /// This version is used for subtarget features defined using Predicate<> + /// and supports more than 64 feature bits. + /// /// \param TargetName The name of the target as used in class prefixes (e.g. /// Subtarget) /// \param ClassName The name of the class (without the prefix) @@ -66,6 +87,25 @@ struct SubtargetFeatureInfo { std::map &SubtargetFeatures, raw_ostream &OS); + + /// Emit the function to compute the list of available features given a + /// subtarget. + /// + /// This version is used for subtarget features defined using + /// AssemblerPredicate<> and supports up to 64 feature bits. + /// + /// \param TargetName The name of the target as used in class prefixes (e.g. + /// Subtarget) + /// \param ClassName The name of the class (without the prefix) + /// that will contain the generated functions. + /// \param FuncName The name of the function to emit. + /// \param SubtargetFeatures A map of TableGen records to the + /// SubtargetFeatureInfo equivalent. + static void emitComputeAssemblerAvailableFeatures( + StringRef TargetName, StringRef ClassName, StringRef FuncName, + std::map + &SubtargetFeatures, + raw_ostream &OS); }; } // end namespace llvm diff --git a/utils/TableGen/Types.cpp b/utils/TableGen/Types.cpp index 35458296f8fd..04d9e40f6743 100644 --- a/utils/TableGen/Types.cpp +++ b/utils/TableGen/Types.cpp @@ -40,5 +40,6 @@ const char *llvm::getMinimalTypeForEnumBitfield(uint64_t Size) { uint64_t MaxIndex = Size; if (MaxIndex > 0) MaxIndex--; + assert(MaxIndex <= 64 && "Too many bits"); return getMinimalTypeForRange(1ULL << MaxIndex); } diff --git a/utils/git-svn/git-llvm b/utils/git-svn/git-llvm index 3dd3ff7dc392..c2eaa5b6e640 100755 --- a/utils/git-svn/git-llvm +++ b/utils/git-svn/git-llvm @@ -51,6 +51,7 @@ GIT_TO_SVN_DIR.update({'clang': 'cfe/trunk'}) VERBOSE = False QUIET = False +dev_null_fd = None def eprint(*args, **kwargs): @@ -82,19 +83,33 @@ def first_dirname(d): d = head -def shell(cmd, strip=True, cwd=None, stdin=None, die_on_failure=True): +def get_dev_null(): + """Lazily create a /dev/null fd for use in shell()""" + global dev_null_fd + if dev_null_fd is None: + dev_null_fd = open(os.devnull, 'w') + return dev_null_fd + + +def shell(cmd, strip=True, cwd=None, stdin=None, die_on_failure=True, + ignore_errors=False): log_verbose('Running: %s' % ' '.join(cmd)) + err_pipe = subprocess.PIPE + if ignore_errors: + # Silence errors if requested. + err_pipe = get_dev_null() + start = time.time() - p = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, stdin=subprocess.PIPE) + p = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=err_pipe, + stdin=subprocess.PIPE) stdout, stderr = p.communicate(input=stdin) elapsed = time.time() - start log_verbose('Command took %0.1fs' % elapsed) - if p.returncode == 0: - if stderr: + if p.returncode == 0 or ignore_errors: + if stderr and not ignore_errors: eprint('`%s` printed to stderr:' % ' '.join(cmd)) eprint(stderr.rstrip()) if strip: @@ -115,7 +130,8 @@ def git(*cmd, **kwargs): def svn(cwd, *cmd, **kwargs): # TODO: Better way to do default arg when we have *cmd? - return shell(['svn'] + list(cmd), cwd=cwd, stdin=kwargs.get('stdin', None)) + return shell(['svn'] + list(cmd), cwd=cwd, stdin=kwargs.get('stdin', None), + ignore_errors=kwargs.get('ignore_errors', None)) def get_default_rev_range(): @@ -173,6 +189,43 @@ def svn_init(svn_root): die("Can't initialize svn staging dir (%s)" % svn_root) +def fix_eol_style_native(rev, sr, svn_sr_path): + """Fix line endings before applying patches with Unix endings + + SVN on Windows will check out files with CRLF for files with the + svn:eol-style property set to "native". This breaks `git apply`, which + typically works with Unix-line ending patches. Work around the problem here + by doing a dos2unix up front for files with svn:eol-style set to "native". + SVN will not commit a mass line ending re-doing because it detects the line + ending format for files with this property. + """ + files = git('diff-tree', '--no-commit-id', '--name-only', '-r', rev, '--', + sr).split('\n') + files = [f.split('/', 1)[1] for f in files] + # Use ignore_errors because 'svn propget' prints errors if the file doesn't + # have the named property. There doesn't seem to be a way to suppress that. + eol_props = svn(svn_sr_path, 'propget', 'svn:eol-style', *files, + ignore_errors=True).split('\n') + crlf_files = [] + for eol_prop in eol_props: + # Remove spare CR. + eol_prop = eol_prop.strip('\r') + if not eol_prop: + continue + prop_parts = eol_prop.rsplit(' - ', 1) + if len(prop_parts) != 2: + eprint("unable to parse svn propget line:") + eprint(eol_prop) + continue + (f, eol_style) = prop_parts + if eol_style == 'native': + crlf_files.append(f) + # Reformat all files with native SVN line endings to Unix format. SVN knows + # files with native line endings are text files. It will commit just the + # diff, and not a mass line ending change. + shell(['dos2unix', '-q'] + crlf_files, cwd=svn_sr_path) + + def svn_push_one_rev(svn_repo, rev, dry_run): files = git('diff-tree', '--no-commit-id', '--name-only', '-r', rev).split('\n') @@ -186,8 +239,10 @@ def svn_push_one_rev(svn_repo, rev, dry_run): (rev, status)) for sr in subrepos: - diff = git('show', '--binary', rev, '--', sr, strip=False) svn_sr_path = os.path.join(svn_repo, GIT_TO_SVN_DIR[sr]) + if os.name == 'nt': + fix_eol_style_native(rev, sr, svn_sr_path) + diff = git('show', '--binary', rev, '--', sr, strip=False) # git is the only thing that can handle its own patches... log_verbose('Apply patch: %s' % diff) try: -- cgit v1.3