Index: include/llvm/MC/MCSubtargetInfo.h =================================================================== --- include/llvm/MC/MCSubtargetInfo.h +++ include/llvm/MC/MCSubtargetInfo.h @@ -159,6 +159,13 @@ /// Initialize an InstrItineraryData instance. void initInstrItins(InstrItineraryData &InstrItins) const; + /// Resolve a variant scheduling class for the given MCInst and CPU. + virtual unsigned + resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI, + unsigned CPUID) const { + return 0; + } + /// Check whether the CPU string is valid. bool isCPUStringValid(StringRef CPU) const { auto Found = std::lower_bound(ProcDesc.begin(), ProcDesc.end(), CPU); Index: include/llvm/Target/Target.td =================================================================== --- include/llvm/Target/Target.td +++ include/llvm/Target/Target.td @@ -384,6 +384,11 @@ } //===----------------------------------------------------------------------===// +// Pull in the common support for machine instruction predicates. +// +include "llvm/Target/TargetInstrPredicate.td" + +//===----------------------------------------------------------------------===// // Pull in the common support for scheduling // include "llvm/Target/TargetSchedule.td" Index: include/llvm/Target/TargetInstrPredicate.td =================================================================== --- include/llvm/Target/TargetInstrPredicate.td +++ include/llvm/Target/TargetInstrPredicate.td @@ -0,0 +1,118 @@ +//===- TargetInstrPredicate.td - ---------------------------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines MCPredicate classes and its subclasses. +// +// MCPredicate is used to describe constraints on the opcode/operand(s) of +// an instruction. Each MCPredicate class has a well-known semantic, and it +// is used by a PredicateExpander to generate code for MachineInstr and/or +// MCInst. +// +// MCPredicate definitions can be used to construct MCSchedPredicate +// definitions. An MCSchedPredicate can be used in place of a SchedPredicate +// when defining SchedReadVariant and SchedWriteVariant used by a processor +// scheduling model. +// +//===----------------------------------------------------------------------===// + +// Forward declarations. +class Instruction; + +// A generic machine instruction predicate. +class MCPredicate; +class MCTrue : MCPredicate; +class MCFalse : MCPredicate; + +def TruePred : MCTrue; +def FalsePred : MCFalse; + +// Negates predicate P. +class CheckNot : MCPredicate { + MCPredicate Pred = P; +} + +// Operands are identified by an index. +class MCOperandPredicate : MCPredicate { + int OpIndex = Index; +} + +class CheckRegOperand : MCOperandPredicate; +class CheckImmOperand : MCOperandPredicate; + +// Check if operands at indices `First` and `Second` are the same register. +class CheckSameRegOperand : MCPredicate { + int FirstIndex = First; + int SecondIndex = Second; +} + +// Check that the operand at position `Index` is register R. +class CheckRegOperandValue + : MCOperandPredicate { + Register Reg = R; +} + +// Check that the operand at index `Index` is equal to literal number `Imm`. +class CheckImmOperandValue + : MCOperandPredicate { + int ImmVal = Imm; +} + +// Similar to CheckImmOperandValue, however the value is not a +// literal number. This can be used in cases where the operand immediate value +// is compared with an enum value. +class CheckImmOperandValue_s + : MCOperandPredicate { + string ImmVal = Value; +} + +// Special case of CheckMCImmOperand where the immediate value is zero. +class CheckZeroOperand : CheckImmOperandValue; + +// Check that the instruction has exactly `Val` operands. +class CheckNumOperands : MCPredicate { + int NumOps = Val; +} + +// Check that the instruction opcode is in set `Opcodes`. +class CheckOpcode Opcodes> : MCPredicate { + list ValidOpcodes = Opcodes; +} + +// A check for a pseudo instruction. This check always returns false if +// performed at MC level. +class CheckPseudo Opcodes> : CheckOpcode; + +// Only to use when a check is not portable and can be folded to 'false' when +// it is expanded for MCInst. +class NonPortableCheck : MCPredicate { + string CodeBlock = Code; +} + +// A generic predicate sequence. It is used as a base class for +// ALLOfMCPredicates and AnyOfMCPredicates. +class CheckPredicateSequence Preds> : MCPredicate { + list Predicates = Preds; +} + +// Check that all of the predicates in `Preds` are valid for the current +// machine instruction. +class CheckAllOf Sequence> + : CheckPredicateSequence; + +// Check that at least one of the predicates in `Preds` is valid for the machine +// instruction. +class CheckAnyOf Sequence> + : CheckPredicateSequence; + +// A call to a member of class "XXXGenInstrInfo" (where XXX is the target name). +class TIIPredicate : MCPredicate { + string TargetName = Target; + string FunctionName = Name; + MCPredicate Pred = P; +} Index: include/llvm/Target/TargetSchedule.td =================================================================== --- include/llvm/Target/TargetSchedule.td +++ include/llvm/Target/TargetSchedule.td @@ -355,13 +355,23 @@ code Code = c; } +// Base class for scheduling predicates. +class SchedPredicateBase; + +// A scheduling predicate whose logic is defined by a MCPredicate. +// This can directly be used by SchedWriteVariant definitions. +class MCSchedPredicate : SchedPredicateBase { + MCPredicate Pred = P; + SchedMachineModel SchedModel = ?; +} + // Define a predicate to determine which SchedVariant applies to a // particular MachineInstr. The code snippet is used as an // if-statement's expression. Available variables are MI, SchedModel, // and anything defined in a PredicateProlog. // // SchedModel silences warnings but is ignored. -class SchedPredicate { +class SchedPredicate : SchedPredicateBase { SchedMachineModel SchedModel = ?; code Predicate = pred; } @@ -376,8 +386,8 @@ // operands. In this case, latency is not additive. If the current Variant // is already part of a Sequence, then that entire chain leading up to // the Variant is distributed over the variadic operands. -class SchedVar selected> { - SchedPredicate Predicate = pred; +class SchedVar selected> { + SchedPredicateBase Predicate = pred; list Selected = selected; } Index: utils/TableGen/CMakeLists.txt =================================================================== --- utils/TableGen/CMakeLists.txt +++ utils/TableGen/CMakeLists.txt @@ -29,6 +29,7 @@ InstrDocsEmitter.cpp IntrinsicEmitter.cpp OptParserEmitter.cpp + PredicateExpander.cpp PseudoLoweringEmitter.cpp RISCVCompressInstEmitter.cpp RegisterBankEmitter.cpp Index: utils/TableGen/InstrInfoEmitter.cpp =================================================================== --- utils/TableGen/InstrInfoEmitter.cpp +++ utils/TableGen/InstrInfoEmitter.cpp @@ -16,6 +16,7 @@ #include "CodeGenInstruction.h" #include "CodeGenSchedule.h" #include "CodeGenTarget.h" +#include "PredicateExpander.h" #include "SequenceToOffsetTable.h" #include "TableGenBackends.h" #include "llvm/ADT/ArrayRef.h" @@ -59,6 +60,8 @@ typedef std::map, std::vector> OpNameMapTy; typedef std::map::iterator StrUintMapIter; + void emitTIIHelperMethods(raw_ostream &OS); + void emitMCIIHelperMethods(raw_ostream &OS, StringRef Target); void emitRecord(const CodeGenInstruction &Inst, unsigned Num, Record *InstrInfo, std::map, unsigned> &EL, @@ -339,6 +342,71 @@ OS << "#endif // GET_INSTRINFO_OPERAND_TYPES_ENUM\n\n"; } +void InstrInfoEmitter::emitMCIIHelperMethods(raw_ostream &OS, StringRef Target) { + RecVec TIIPredicates = Records.getAllDerivedDefinitions("TIIPredicate"); + if (TIIPredicates.empty()) + return; + + formatted_raw_ostream FOS(OS); + FOS << "#ifdef GET_GENINSTRINFO_MC_DECL\n"; + FOS << "#undef GET_GENINSTRINFO_MC_DECL\n\n"; + + FOS << "namespace llvm {\n"; + FOS << "class MCInst;\n\n"; + + FOS << "namespace " << Target << "_MC {\n\n"; + + for (const Record *Rec : TIIPredicates) { + FOS << "bool " << Rec->getValueAsString("FunctionName") + << "(const MCInst &MI);\n"; + } + + FOS << "\n} // end " << Target << "_MC namespace\n"; + FOS << "} // end llvm namespace\n\n"; + + FOS << "#endif // GET_GENINSTRINFO_MC_DECL\n\n"; + + FOS << "#ifdef GET_GENINSTRINFO_MC_HELPERS\n"; + FOS << "#undef GET_GENINSTRINFO_MC_HELPERS\n\n"; + + FOS << "namespace llvm {\n"; + FOS << "namespace " << Target << "_MC {\n\n"; + + PredicateExpander PE; + PE.setExpandForMC(true); + for (const Record *Rec : TIIPredicates) { + FOS << "bool " << Rec->getValueAsString("FunctionName"); + FOS << "(const MCInst &MI) {\n"; + FOS << " return "; + PE.expandPredicate(FOS, Rec->getValueAsDef("Pred")); + FOS << ";\n}\n"; + } + + FOS << "\n} // end " << Target << "_MC namespace\n"; + FOS << "} // end llvm namespace\n\n"; + + FOS << "#endif // GET_GENISTRINFO_MC_HELPERS\n"; +} + +void InstrInfoEmitter::emitTIIHelperMethods(raw_ostream &OS) { + RecVec TIIPredicates = Records.getAllDerivedDefinitions("TIIPredicate"); + if (TIIPredicates.empty()) + return; + + formatted_raw_ostream FOS(OS); + PredicateExpander PE; + PE.setExpandForMC(false); + PE.setIndentLevel(2); + + for (const Record *Rec : TIIPredicates) { + FOS << "\n static bool " << Rec->getValueAsString("FunctionName"); + FOS << "(const MachineInstr &MI) {\n"; + FOS << " return "; + PE.expandPredicate(FOS, Rec->getValueAsDef("Pred")); + FOS << ";\n }\n"; + } +} + //===----------------------------------------------------------------------===// // Main Output. //===----------------------------------------------------------------------===// @@ -435,9 +503,11 @@ OS << "struct " << ClassName << " : public TargetInstrInfo {\n" << " explicit " << ClassName << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1, int CatchRetOpcode = -1, int ReturnOpcode = -1);\n" - << " ~" << ClassName << "() override = default;\n" - << "};\n"; - OS << "} // end llvm namespace\n"; + << " ~" << ClassName << "() override = default;\n"; + + emitTIIHelperMethods(OS); + + OS << "\n};\n} // end llvm namespace\n"; OS << "#endif // GET_INSTRINFO_HEADER\n\n"; @@ -461,6 +531,8 @@ emitOperandNameMappings(OS, Target, NumberedInstructions); emitOperandTypesEnum(OS, Target); + + emitMCIIHelperMethods(OS, TargetName); } void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, Index: utils/TableGen/PredicateExpander.h =================================================================== --- utils/TableGen/PredicateExpander.h +++ utils/TableGen/PredicateExpander.h @@ -0,0 +1,79 @@ +//===--------------------- PredicateExpander.h ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// Functionalities used by the Tablegen backends to expand machine predicates. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_UTILS_TABLEGEN_PREDICATEEXPANDER_H +#define LLVM_UTILS_TABLEGEN_PREDICATEEXPANDER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/TableGen/Record.h" + +namespace llvm { + +class formatted_raw_ostream; + +class PredicateExpander { + bool EmitCallsByRef; + bool NegatePredicate; + bool ExpandForMC; + unsigned IndentLevel; + + PredicateExpander(const PredicateExpander &) = delete; + PredicateExpander &operator=(const PredicateExpander &) = delete; + +public: + PredicateExpander() + : EmitCallsByRef(true), NegatePredicate(false), ExpandForMC(false), + IndentLevel(1U) {} + bool isByRef() const { return EmitCallsByRef; } + bool shouldNegate() const { return NegatePredicate; } + bool shouldExpandForMC() const { return ExpandForMC; } + unsigned getIndentLevel() const { return IndentLevel; } + + void setByRef(bool Value) { EmitCallsByRef = Value; } + void flipNegatePredicate() { NegatePredicate = !NegatePredicate; } + void setNegatePredicate(bool Value) { NegatePredicate = Value; } + void setExpandForMC(bool Value) { ExpandForMC = Value; } + void increaseIndentLevel() { ++IndentLevel; } + void decreaseIndentLevel() { --IndentLevel; } + void setIndentLevel(unsigned Level) { IndentLevel = Level; } + + using RecVec = std::vector; + void expandTrue(formatted_raw_ostream &OS); + void expandFalse(formatted_raw_ostream &OS); + void expandCheckImmOperandValue(formatted_raw_ostream &OS, int OpIndex, + int ImmVal); + void expandCheckImmOperandValue(formatted_raw_ostream &OS, int OpIndex, + StringRef ImmVal); + void expandCheckRegOperandValue(formatted_raw_ostream &OS, int OpIndex, + const Record *Reg); + void expandCheckSameRegOperand(formatted_raw_ostream &OS, int First, + int Second); + void expandCheckNumOperands(formatted_raw_ostream &OS, int NumOps); + void expandCheckOpcode(formatted_raw_ostream &OS, const Record *Inst); + + void expandCheckPseudo(formatted_raw_ostream &OS, const RecVec &Opcodes); + void expandCheckOpcode(formatted_raw_ostream &OS, const RecVec &Opcodes); + void expandPredicateSequence(formatted_raw_ostream &OS, + const RecVec &Sequence, bool AllOf); + void expandTIIFunctionCall(formatted_raw_ostream &OS, StringRef TargetName, + StringRef MethodName); + void expandCheckRegOperand(formatted_raw_ostream &OS, int OpIndex); + void expandCheckImmOperand(formatted_raw_ostream &OS, int OpIndex); + void expandNonPortableCheck(formatted_raw_ostream &OS, StringRef CodeBlock); + void expandPredicate(formatted_raw_ostream &OS, const Record *Rec); +}; + +} // namespace llvm + +#endif Index: utils/TableGen/PredicateExpander.cpp =================================================================== --- utils/TableGen/PredicateExpander.cpp +++ utils/TableGen/PredicateExpander.cpp @@ -0,0 +1,241 @@ +//===--------------------- PredicateExpander.cpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// Functionalities used by the Tablegen backends to expand machine predicates. +// +//===----------------------------------------------------------------------===// + +#include "PredicateExpander.h" + +namespace llvm { + +void PredicateExpander::expandTrue(formatted_raw_ostream &OS) { OS << "true"; } +void PredicateExpander::expandFalse(formatted_raw_ostream &OS) { + OS << "false"; +} + +void PredicateExpander::expandCheckImmOperandValue(formatted_raw_ostream &OS, + int OpIndex, int ImmVal) { + OS << "MI.getOperand(" << OpIndex << ").getImm() " + << (shouldNegate() ? "!= " : "== ") << ImmVal; +} + +void PredicateExpander::expandCheckImmOperandValue(formatted_raw_ostream &OS, + int OpIndex, + StringRef ImmVal) { + OS << "MI.getOperand(" << OpIndex << ").getImm() " + << (shouldNegate() ? "!= " : "== ") << ImmVal; +} + +void PredicateExpander::expandCheckRegOperandValue(formatted_raw_ostream &OS, + int OpIndex, + const Record *Reg) { + assert(Reg->isSubClassOf("Register") && "Expected a register Record!"); + + OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex + << ").getReg() " << (shouldNegate() ? "!= " : "== "); + const StringRef Str = Reg->getValueAsString("Namespace"); + if (!Str.empty()) + OS << Str << "::"; + OS << Reg->getName(); +} + +void PredicateExpander::expandCheckSameRegOperand(formatted_raw_ostream &OS, + int First, int Second) { + OS << "MI" << (isByRef() ? "." : "->") << "getOperand(" << First + << ").getReg() " << (shouldNegate() ? "!=" : "==") << " MI" + << (isByRef() ? "." : "->") << "getOperand(" << Second << ").getReg()"; +} + +void PredicateExpander::expandCheckNumOperands(formatted_raw_ostream &OS, + int NumOps) { + OS << "MI" << (isByRef() ? "." : "->") << "getNumOperands() " + << (shouldNegate() ? "!= " : "== ") << NumOps; +} + +void PredicateExpander::expandCheckOpcode(formatted_raw_ostream &OS, + const Record *Inst) { + OS << "MI" << (isByRef() ? "." : "->") << "getOpcode() " + << (shouldNegate() ? "!= " : "== ") << Inst->getValueAsString("Namespace") + << "::" << Inst->getName(); +} + +void PredicateExpander::expandCheckOpcode(formatted_raw_ostream &OS, + const RecVec &Opcodes) { + assert(!Opcodes.empty() && "Expected at least one opcode to check!"); + bool First = true; + + if (Opcodes.size() == 1) { + OS << "( "; + expandCheckOpcode(OS, Opcodes[0]); + OS << " )"; + return; + } + + OS << '('; + increaseIndentLevel(); + for (const Record *Rec : Opcodes) { + OS << '\n'; + OS.PadToColumn(getIndentLevel() * 2); + if (!First) + OS << (shouldNegate() ? "&& " : "|| "); + + expandCheckOpcode(OS, Rec); + First = false; + } + + OS << '\n'; + decreaseIndentLevel(); + OS.PadToColumn(getIndentLevel() * 2); + OS << ')'; +} + +void PredicateExpander::expandCheckPseudo(formatted_raw_ostream &OS, + const RecVec &Opcodes) { + if (shouldExpandForMC()) + expandFalse(OS); + else + expandCheckOpcode(OS, Opcodes); +} + +void PredicateExpander::expandPredicateSequence(formatted_raw_ostream &OS, + const RecVec &Sequence, + bool AllOf) { + assert(!Sequence.empty() && "Found an invalid empty predicate set!"); + if (Sequence.size() == 1) + return expandPredicate(OS, Sequence[0]); + + // Okay, there is more than one predicate in the set. + bool First = true; + OS << (shouldNegate() ? "!(" : "("); + increaseIndentLevel(); + + bool OldValue = shouldNegate(); + setNegatePredicate(false); + for (const Record *Rec : Sequence) { + OS << '\n'; + OS.PadToColumn(getIndentLevel() * 2); + if (!First) + OS << (AllOf ? "&& " : "|| "); + expandPredicate(OS, Rec); + First = false; + } + OS << '\n'; + decreaseIndentLevel(); + OS.PadToColumn(getIndentLevel() * 2); + OS << ')'; + setNegatePredicate(OldValue); +} + +void PredicateExpander::expandTIIFunctionCall(formatted_raw_ostream &OS, + StringRef TargetName, + StringRef MethodName) { + OS << (shouldNegate() ? "!" : ""); + if (shouldExpandForMC()) + OS << TargetName << "_MC::"; + else + OS << TargetName << "Gen" + << "InstrInfo::"; + OS << MethodName << (isByRef() ? "(MI)" : "(*MI)"); +} + +void PredicateExpander::expandCheckRegOperand(formatted_raw_ostream &OS, + int OpIndex) { + OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->") + << "getOperand(" << OpIndex << ").isReg() "; +} + +void PredicateExpander::expandCheckImmOperand(formatted_raw_ostream &OS, + int OpIndex) { + OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->") + << "getOperand(" << OpIndex << ").isImm() "; +} + +void PredicateExpander::expandNonPortableCheck(formatted_raw_ostream &OS, + StringRef Code) { + if (shouldExpandForMC()) + return expandFalse(OS); + + OS << '(' << Code << ')'; +} + +void PredicateExpander::expandPredicate(formatted_raw_ostream &OS, + const Record *Rec) { + OS.flush(); + unsigned ColNum = getIndentLevel() * 2; + if (OS.getColumn() < ColNum) + OS.PadToColumn(ColNum); + + if (Rec->isSubClassOf("MCTrue")) { + if (shouldNegate()) + return expandFalse(OS); + return expandTrue(OS); + } + + if (Rec->isSubClassOf("MCFalse")) { + if (shouldNegate()) + return expandTrue(OS); + return expandFalse(OS); + } + + if (Rec->isSubClassOf("CheckNot")) { + flipNegatePredicate(); + expandPredicate(OS, Rec->getValueAsDef("Pred")); + flipNegatePredicate(); + return; + } + + if (Rec->isSubClassOf("CheckRegOperand")) + return expandCheckRegOperand(OS, Rec->getValueAsInt("OpIndex")); + + if (Rec->isSubClassOf("CheckImmOperand")) + return expandCheckImmOperand(OS, Rec->getValueAsInt("OpIndex")); + + if (Rec->isSubClassOf("CheckRegOperandValue")) + return expandCheckRegOperandValue(OS, Rec->getValueAsInt("OpIndex"), + Rec->getValueAsDef("Reg")); + + if (Rec->isSubClassOf("CheckImmOperandValue")) + return expandCheckImmOperandValue(OS, Rec->getValueAsInt("OpIndex"), + Rec->getValueAsInt("ImmVal")); + + if (Rec->isSubClassOf("CheckImmOperandValue_s")) + return expandCheckImmOperandValue(OS, Rec->getValueAsInt("OpIndex"), + Rec->getValueAsString("ImmVal")); + + if (Rec->isSubClassOf("CheckSameRegOperand")) + return expandCheckSameRegOperand(OS, Rec->getValueAsInt("FirstIndex"), + Rec->getValueAsInt("SecondIndex")); + + if (Rec->isSubClassOf("CheckNumOperands")) + return expandCheckNumOperands(OS, Rec->getValueAsInt("NumOps")); + + if (Rec->isSubClassOf("CheckPseudo")) + return expandCheckPseudo(OS, Rec->getValueAsListOfDefs("ValidOpcodes")); + + if (Rec->isSubClassOf("CheckOpcode")) + return expandCheckOpcode(OS, Rec->getValueAsListOfDefs("ValidOpcodes")); + + if (Rec->isSubClassOf("CheckAllOf")) + return expandPredicateSequence(OS, Rec->getValueAsListOfDefs("Predicates"), + /* AllOf */ true); + + if (Rec->isSubClassOf("CheckAnyOf")) + return expandPredicateSequence(OS, Rec->getValueAsListOfDefs("Predicates"), + /* AllOf */ false); + + if (Rec->isSubClassOf("NonPortableCheck")) + return expandNonPortableCheck(OS, Rec->getValueAsString("CodeBlock")); + + assert(Rec->isSubClassOf("TIIPredicate") && "Expected a MCPredicate!"); + return expandTIIFunctionCall(OS, Rec->getValueAsString("TargetName"), + Rec->getValueAsString("FunctionName")); +} + +} // namespace llvm Index: utils/TableGen/SubtargetEmitter.cpp =================================================================== --- utils/TableGen/SubtargetEmitter.cpp +++ utils/TableGen/SubtargetEmitter.cpp @@ -13,6 +13,7 @@ #include "CodeGenTarget.h" #include "CodeGenSchedule.h" +#include "PredicateExpander.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" @@ -112,6 +113,9 @@ void EmitProcessorModels(raw_ostream &OS); void EmitProcessorLookup(raw_ostream &OS); void EmitSchedModelHelpers(const std::string &ClassName, raw_ostream &OS); + void emitSchedModelHelpersImpl(bool OnlyExpandMCPredicates, raw_ostream &OS); + void emitGenMCSubtargetInfo(const std::string TargetName, raw_ostream &OS); + void EmitSchedModel(raw_ostream &OS); void EmitHwModeCheck(const std::string &ClassName, raw_ostream &OS); void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures, @@ -1460,35 +1464,37 @@ } static void emitPredicates(const CodeGenSchedTransition &T, - const CodeGenSchedClass &SC, unsigned ProcIdx, + const CodeGenSchedClass &SC, + PredicateExpander &PE, raw_ostream &OS) { - if (ProcIdx && !count(T.ProcIndices, ProcIdx)) - return; - std::string Buffer; - raw_string_ostream Stream(Buffer); - Stream << " if ("; + raw_string_ostream StringStream(Buffer); + formatted_raw_ostream FOS(StringStream); + + FOS.PadToColumn(6); + FOS << "if ("; for (RecIter RI = T.PredTerm.begin(), RE = T.PredTerm.end(); RI != RE; ++RI) { - if (RI != T.PredTerm.begin()) - Stream << "\n && "; - Stream << "(" << (*RI)->getValueAsString("Predicate") << ")"; + if (RI != T.PredTerm.begin()) { + FOS << "\n"; + FOS.PadToColumn(8); + FOS << "&& "; + } + const Record *Rec = *RI; + if (Rec->isSubClassOf("MCSchedPredicate")) + PE.expandPredicate(FOS, Rec->getValueAsDef("Pred")); + else + FOS << "(" << Rec->getValueAsString("Predicate") << ")"; } - Stream << ")\n" - << " return " << T.ToClassIdx << "; // " << SC.Name << '\n'; - Stream.flush(); + FOS << ")\n"; + FOS.PadToColumn(8); + FOS << "return " << T.ToClassIdx << "; // " << SC.Name << '\n'; + FOS.flush(); OS << Buffer; } -void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName, - raw_ostream &OS) { - OS << "unsigned " << ClassName - << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI," - << " const TargetSchedModel *SchedModel) const {\n"; - - // Emit the predicate prolog code. - emitPredicateProlog(Records, OS); - +void SubtargetEmitter::emitSchedModelHelpersImpl(bool OnlyExpandMCPredicates, + raw_ostream &OS) { // Collect Variant Classes. IdxVec VariantClasses; for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) { @@ -1502,24 +1508,44 @@ for (unsigned VC : VariantClasses) { // Emit code for each variant scheduling class. const CodeGenSchedClass &SC = SchedModels.getSchedClass(VC); - OS << " case " << VC << ": // " << SC.Name << '\n'; IdxVec ProcIndices; for (const CodeGenSchedTransition &T : SC.Transitions) { + if (OnlyExpandMCPredicates && + !all_of(T.PredTerm, [](const Record *Rec) { + return Rec->isSubClassOf("MCSchedPredicate"); + })) + continue; + IdxVec PI; std::set_union(T.ProcIndices.begin(), T.ProcIndices.end(), ProcIndices.begin(), ProcIndices.end(), std::back_inserter(PI)); ProcIndices.swap(PI); } + if (ProcIndices.empty()) + continue; + + OS << " case " << VC << ": // " << SC.Name << '\n'; + PredicateExpander PE; + PE.setByRef(false); + PE.setExpandForMC(OnlyExpandMCPredicates); for (unsigned PI : ProcIndices) { OS << " "; - if (PI != 0) - OS << "if (SchedModel->getProcessorID() == " << PI << ") "; - OS << "{ // " << (SchedModels.procModelBegin() + PI)->ModelName - << '\n'; + if (PI != 0) { + if (OnlyExpandMCPredicates) + OS << "if (CPUID == "; + else + OS << "if (SchedModel->getProcessorID() == "; + OS << PI << ") "; + } + OS << "{ // " << (SchedModels.procModelBegin() + PI)->ModelName << '\n'; - for (const CodeGenSchedTransition &T : SC.Transitions) - emitPredicates(T, SchedModels.getSchedClass(T.ToClassIdx), PI, OS); + for (const CodeGenSchedTransition &T : SC.Transitions) { + if (PI != 0 && !count(T.ProcIndices, PI)) + continue; + PE.setIndentLevel(4); + emitPredicates(T, SchedModels.getSchedClass(T.ToClassIdx), PE, OS); + } OS << " }\n"; if (PI == 0) @@ -1531,8 +1557,29 @@ } OS << " };\n"; } - OS << " report_fatal_error(\"Expected a variant SchedClass\");\n" - << "} // " << ClassName << "::resolveSchedClass\n"; + + if (OnlyExpandMCPredicates) { + OS << " // Don't know how to resolve this scheduling class.\n" + << " return 0;\n"; + return; + } + + OS << " report_fatal_error(\"Expected a variant SchedClass\");\n"; +} + +void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName, + raw_ostream &OS) { + OS << "unsigned " << ClassName + << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI," + << " const TargetSchedModel *SchedModel) const {\n"; + + // Emit the predicate prolog code. + emitPredicateProlog(Records, OS); + + // Emit target predicates. + emitSchedModelHelpersImpl(false, OS); + + OS << "} // " << ClassName << "::resolveSchedClass\n"; } void SubtargetEmitter::EmitHwModeCheck(const std::string &ClassName, @@ -1598,6 +1645,27 @@ OS << "}\n"; } +void SubtargetEmitter::emitGenMCSubtargetInfo(const std::string TargetName, + raw_ostream &OS) { + OS << "struct " << TargetName + << "GenMCSubtargetInfo : public MCSubtargetInfo {\n"; + OS << " " << TargetName << "GenMCSubtargetInfo(const Triple &TT, \n" + << " StringRef CPU, StringRef FS, ArrayRef PF,\n" + << " ArrayRef PD,\n" + << " const SubtargetInfoKV *ProcSched,\n" + << " const MCWriteProcResEntry *WPR,\n" + << " const MCWriteLatencyEntry *WL,\n" + << " const MCReadAdvanceEntry *RA, const InstrStage *IS,\n" + << " const unsigned *OC, const unsigned *FP) :\n" + << " MCSubtargetInfo(TT, CPU, FS, PF, PD, ProcSched,\n" + << " WPR, WL, RA, IS, OC, FP) { }\n\n" + << " unsigned resolveVariantSchedClass(unsigned SchedClass,\n" + << " const MCInst *MI, unsigned CPUID) const override {\n"; + emitSchedModelHelpersImpl(/* OnlyExpandMCPredicates */ true, OS); + OS << " }\n"; + OS << "};\n"; +} + // // SubtargetEmitter::run - Main subtarget enumeration emitter. // @@ -1630,10 +1698,12 @@ #endif // MCInstrInfo initialization routine. + emitGenMCSubtargetInfo(Target, OS); + OS << "\nstatic inline MCSubtargetInfo *create" << Target << "MCSubtargetInfoImpl(" << "const Triple &TT, StringRef CPU, StringRef FS) {\n"; - OS << " return new MCSubtargetInfo(TT, CPU, FS, "; + OS << " return new " << Target << "GenMCSubtargetInfo(TT, CPU, FS, "; if (NumFeatures) OS << Target << "FeatureKV, "; else