diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td index 68d88ae0063d..4bfa655cc588 100644 --- a/llvm/include/llvm/Target/Target.td +++ b/llvm/include/llvm/Target/Target.td @@ -383,6 +383,11 @@ class DwarfRegAlias { Register DwarfAlias = reg; } +//===----------------------------------------------------------------------===// +// Pull in the common support for MCPredicate (portable scheduling predicates). +// +include "llvm/Target/TargetInstrPredicate.td" + //===----------------------------------------------------------------------===// // Pull in the common support for scheduling // diff --git a/llvm/include/llvm/Target/TargetInstrPredicate.td b/llvm/include/llvm/Target/TargetInstrPredicate.td new file mode 100644 index 000000000000..e6e5c06cd038 --- /dev/null +++ b/llvm/include/llvm/Target/TargetInstrPredicate.td @@ -0,0 +1,194 @@ +//===- 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 MCInstPredicate classes and its subclasses. +// +// MCInstPredicate is used to describe constraints on the opcode/operand(s) of +// an instruction. Each MCInstPredicate class has a well-known semantic, and it +// is used by a PredicateExpander to generate code for MachineInstr and/or +// MCInst. +// +// MCInstPredicate 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. +// +// Here is an example of MCInstPredicate definition: +// +// def MCInstPredicateExample : CheckAll<[ +// CheckOpcode<[BLR]>, +// CheckIsRegOperand<0>, +// CheckNot>]>; +// +// Predicate `MCInstPredicateExample` checks that the machine instruction in +// input is a BLR, and that operand at index 0 is register `LR`. +// +// That predicate could be used to rewrite the following definition (from +// AArch64SchedExynosM3.td): +// +// def M3BranchLinkFastPred : SchedPredicate<[{ +// MI->getOpcode() == AArch64::BLR && +// MI->getOperand(0).isReg() && +// MI->getOperand(0).getReg() != AArch64::LR}]>; +// +// MCInstPredicate definitions are used to construct MCSchedPredicate (see the +// definition of class MCSchedPredicate in llvm/Target/TargetSchedule.td). An +// MCSchedPredicate can be used by a `SchedVar` to associate a predicate with a +// list of SchedReadWrites. Note that `SchedVar` are used to create SchedVariant +// definitions. +// +// Each MCInstPredicate class has a well known semantic. For example, +// `CheckOpcode` is only used to check the instruction opcode value. +// +// MCInstPredicate classes allow the definition of predicates in a declarative +// way. These predicates don't require a custom block of C++, and can be used +// to define conditions on instructions without being bound to a particular +// representation (i.e. MachineInstr vs MCInst). +// +// It also means that tablegen backends must know how to parse and expand them +// into code that works on MCInst (or MachineInst). +// +// Instances of class PredicateExpander (see utils/Tablegen/PredicateExpander.h) +// know how to expand a predicate. For each MCInstPredicate class, there must be +// an "expand" method available in the PredicateExpander interface. +// +// For example, a `CheckOpcode` predicate is expanded using method +// `PredicateExpander::expandCheckOpcode()`. +// +// New MCInstPredicate classes must be added to this file. For each new class +// XYZ, an "expandXYZ" method must be added to the PredicateExpander. +// +//===----------------------------------------------------------------------===// + +// Forward declarations. +class Instruction; + +// A generic machine instruction predicate. +class MCInstPredicate; + +class MCTrue : MCInstPredicate; // A predicate that always evaluates to True. +class MCFalse : MCInstPredicate; // A predicate that always evaluates to False. +def TruePred : MCTrue; +def FalsePred : MCFalse; + +// A predicate used to negate the outcome of another predicate. +// It allows to easily express "set difference" operations. For example, it +// makes it easy to describe a check that tests if an opcode is not part of a +// set of opcodes. +class CheckNot : MCInstPredicate { + MCInstPredicate Pred = P; +} + +// This class is used as a building block to define predicates on instruction +// operands. It is used to reference a specific machine operand. +class MCOperandPredicate : MCInstPredicate { + int OpIndex = Index; +} + +// Return true if machine operand at position `Index` is a register operand. +class CheckIsRegOperand : MCOperandPredicate; + +// Return true if machine operand at position `Index` is an immediate operand. +class CheckIsImmOperand : MCOperandPredicate; + +// Check if machine operands at index `First` and index `Second` both reference +// the same register. +class CheckSameRegOperand : MCInstPredicate { + int FirstIndex = First; + int SecondIndex = Second; +} + +// Check that the machine register operand at position `Index` references +// register R. This predicate assumes that we already checked that the machine +// operand at position `Index` is a register operand. +class CheckRegOperand : MCOperandPredicate { + Register Reg = R; +} + +// Check that the operand at position `Index` is immediate `Imm`. +class CheckImmOperand : MCOperandPredicate { + int ImmVal = Imm; +} + +// Similar to CheckImmOperand, however the immediate is not a literal number. +// This is useful when we want to compare the value of an operand against an +// enum value, and we know the actual integer value of that enum. +class CheckImmOperand_s : MCOperandPredicate { + string ImmVal = Value; +} + +// Check that the operand at position `Index` is immediate value zero. +class CheckZeroOperand : CheckImmOperand; + +// Check that the instruction has exactly `Num` operands. +class CheckNumOperands : MCInstPredicate { + int NumOps = Num; +} + +// Check that the instruction opcode is one of the opcodes in set `Opcodes`. +// This is a simple set membership query. The easier way to check if an opcode +// is not a member of the set is by using a `CheckNot>` +// sequence. +class CheckOpcode Opcodes> : MCInstPredicate { + list ValidOpcodes = Opcodes; +} + +// Check that the instruction opcode is a pseudo opcode member of the set +// `Opcodes`. This check is always expanded to "false" if we are generating +// code for MCInst. +class CheckPseudo Opcodes> : CheckOpcode; + +// A non-portable predicate. Only to use as a last resort when a block of code +// cannot possibly be converted in a declarative way using other MCInstPredicate +// classes. This check is always expanded to "false" when generating code for +// MCInst. +class CheckNonPortable : MCInstPredicate { + string CodeBlock = Code; +} + +// A sequence of predicates. It is used as the base class for CheckAll, and +// CheckAny. It allows to describe compositions of predicates. +class CheckPredicateSequence Preds> : MCInstPredicate { + list Predicates = Preds; +} + +// Check that all of the predicates in `Preds` evaluate to true. +class CheckAll Sequence> + : CheckPredicateSequence; + +// Check that at least one of the predicates in `Preds` evaluates to true. +class CheckAny Sequence> + : CheckPredicateSequence; + +// Check that a call to method `Name` in class "XXXGenInstrInfo" (where XXX is +// the `Target` name) returns true. +// +// TIIPredicate definitions are used to model calls to the target-specific +// InstrInfo. A TIIPredicate is treated specially by the InstrInfoEmitter +// tablegen backend, which will use it to automatically generate a definition in +// the target specific `GenInstrInfo` class. +class TIIPredicate : MCInstPredicate { + string TargetName = Target; + string FunctionName = Name; + MCInstPredicate Pred = P; +} + +// A function predicate that takes as input a machine instruction, and returns +// a boolean value. +// +// This predicate is expanded into a function call by the PredicateExpander. +// In particular, the PredicateExpander would either expand this predicate into +// a call to `MCInstFn`, or into a call to`MachineInstrFn` depending on whether +// it is lowering predicates for MCInst or MachineInstr. +// +// In this context, `MCInstFn` and `MachineInstrFn` are both function names. +class CheckFunctionPredicate : MCInstPredicate { + string MCInstFnName = MCInstFn; + string MachineInstrFnName = MachineInstrFn; +} diff --git a/llvm/include/llvm/Target/TargetSchedule.td b/llvm/include/llvm/Target/TargetSchedule.td index 289892ab4014..554f83b5a565 100644 --- a/llvm/include/llvm/Target/TargetSchedule.td +++ b/llvm/include/llvm/Target/TargetSchedule.td @@ -355,13 +355,23 @@ class PredicateProlog { code Code = c; } +// Base class for scheduling predicates. +class SchedPredicateBase; + +// A scheduling predicate whose logic is defined by a MCInstPredicate. +// This can directly be used by SchedWriteVariant definitions. +class MCSchedPredicate : SchedPredicateBase { + MCInstPredicate 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 @@ def NoSchedPred : SchedPredicate<[{true}]>; // 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; } diff --git a/llvm/utils/TableGen/CMakeLists.txt b/llvm/utils/TableGen/CMakeLists.txt index bd7eca4885db..0428249f9179 100644 --- a/llvm/utils/TableGen/CMakeLists.txt +++ b/llvm/utils/TableGen/CMakeLists.txt @@ -29,6 +29,7 @@ add_tablegen(llvm-tblgen LLVM InstrDocsEmitter.cpp IntrinsicEmitter.cpp OptParserEmitter.cpp + PredicateExpander.cpp PseudoLoweringEmitter.cpp RISCVCompressInstEmitter.cpp RegisterBankEmitter.cpp diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp index 85666af6be20..61c3f1d2bb4b 100644 --- a/llvm/utils/TableGen/InstrInfoEmitter.cpp +++ b/llvm/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,13 @@ private: typedef std::map, std::vector> OpNameMapTy; typedef std::map::iterator StrUintMapIter; + + /// Generate member functions in the target-specific GenInstrInfo class. + /// + /// This method is used to custom expand TIIPredicate definitions. + /// See file llvm/Target/TargetInstPredicates.td for a description of what is + /// a TIIPredicate and how to use it. + void emitTIIHelperMethods(raw_ostream &OS); void emitRecord(const CodeGenInstruction &Inst, unsigned Num, Record *InstrInfo, std::map, unsigned> &EL, @@ -339,6 +347,25 @@ void InstrInfoEmitter::emitOperandTypesEnum(raw_ostream &OS, OS << "#endif // GET_INSTRINFO_OPERAND_TYPES_ENUM\n\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 +462,11 @@ void InstrInfoEmitter::run(raw_ostream &OS) { 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"; diff --git a/llvm/utils/TableGen/PredicateExpander.cpp b/llvm/utils/TableGen/PredicateExpander.cpp new file mode 100644 index 000000000000..62a01dc88548 --- /dev/null +++ b/llvm/utils/TableGen/PredicateExpander.cpp @@ -0,0 +1,253 @@ +//===--------------------- 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::expandCheckImmOperand(formatted_raw_ostream &OS, + int OpIndex, int ImmVal) { + OS << "MI.getOperand(" << OpIndex << ").getImm() " + << (shouldNegate() ? "!= " : "== ") << ImmVal; +} + +void PredicateExpander::expandCheckImmOperand(formatted_raw_ostream &OS, + int OpIndex, StringRef ImmVal) { + OS << "MI.getOperand(" << OpIndex << ").getImm() " + << (shouldNegate() ? "!= " : "== ") << ImmVal; +} + +void PredicateExpander::expandCheckRegOperand(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 IsCheckAll) { + 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 << (IsCheckAll ? "&& " : "|| "); + 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::expandCheckIsRegOperand(formatted_raw_ostream &OS, + int OpIndex) { + OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->") + << "getOperand(" << OpIndex << ").isReg() "; +} + +void PredicateExpander::expandCheckIsImmOperand(formatted_raw_ostream &OS, + int OpIndex) { + OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->") + << "getOperand(" << OpIndex << ").isImm() "; +} + +void PredicateExpander::expandCheckFunctionPredicate(formatted_raw_ostream &OS, + StringRef MCInstFn, + StringRef MachineInstrFn) { + OS << (shouldExpandForMC() ? MCInstFn : MachineInstrFn) + << (isByRef() ? "(MI)" : "(*MI)"); +} + +void PredicateExpander::expandCheckNonPortable(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("CheckIsRegOperand")) + return expandCheckIsRegOperand(OS, Rec->getValueAsInt("OpIndex")); + + if (Rec->isSubClassOf("CheckIsImmOperand")) + return expandCheckIsImmOperand(OS, Rec->getValueAsInt("OpIndex")); + + if (Rec->isSubClassOf("CheckRegOperand")) + return expandCheckRegOperand(OS, Rec->getValueAsInt("OpIndex"), + Rec->getValueAsDef("Reg")); + + if (Rec->isSubClassOf("CheckImmOperand")) + return expandCheckImmOperand(OS, Rec->getValueAsInt("OpIndex"), + Rec->getValueAsInt("ImmVal")); + + if (Rec->isSubClassOf("CheckImmOperand_s")) + return expandCheckImmOperand(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("CheckAll")) + return expandPredicateSequence(OS, Rec->getValueAsListOfDefs("Predicates"), + /* AllOf */ true); + + if (Rec->isSubClassOf("CheckAny")) + return expandPredicateSequence(OS, Rec->getValueAsListOfDefs("Predicates"), + /* AllOf */ false); + + if (Rec->isSubClassOf("CheckFunctionPredicate")) + return expandCheckFunctionPredicate( + OS, Rec->getValueAsString("MCInstFnName"), + Rec->getValueAsString("MachineInstrFnName")); + + if (Rec->isSubClassOf("CheckNonPortable")) + return expandCheckNonPortable(OS, Rec->getValueAsString("CodeBlock")); + + if (Rec->isSubClassOf("TIIPredicate")) + return expandTIIFunctionCall(OS, Rec->getValueAsString("TargetName"), + Rec->getValueAsString("FunctionName")); + + llvm_unreachable("No known rules to expand this MCInstPredicate"); +} + +} // namespace llvm diff --git a/llvm/utils/TableGen/PredicateExpander.h b/llvm/utils/TableGen/PredicateExpander.h new file mode 100644 index 000000000000..bc4de902fcc2 --- /dev/null +++ b/llvm/utils/TableGen/PredicateExpander.h @@ -0,0 +1,85 @@ +//===--------------------- 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. +/// +/// See file llvm/Target/TargetInstrPredicate.td for a full list and description +/// of all the supported MCInstPredicate classes. +// +//===----------------------------------------------------------------------===// + +#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 expandCheckImmOperand(formatted_raw_ostream &OS, int OpIndex, + int ImmVal); + void expandCheckImmOperand(formatted_raw_ostream &OS, int OpIndex, + StringRef ImmVal); + void expandCheckRegOperand(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 IsCheckAll); + void expandTIIFunctionCall(formatted_raw_ostream &OS, StringRef TargetName, + StringRef MethodName); + void expandCheckIsRegOperand(formatted_raw_ostream &OS, int OpIndex); + void expandCheckIsImmOperand(formatted_raw_ostream &OS, int OpIndex); + void expandCheckFunctionPredicate(formatted_raw_ostream &OS, + StringRef MCInstFn, + StringRef MachineInstrFn); + void expandCheckNonPortable(formatted_raw_ostream &OS, StringRef CodeBlock); + void expandPredicate(formatted_raw_ostream &OS, const Record *Rec); +}; + +} // namespace llvm + +#endif diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp index 5fd145fe63b8..d110f80766d2 100644 --- a/llvm/utils/TableGen/SubtargetEmitter.cpp +++ b/llvm/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 @@ class SubtargetEmitter { void EmitProcessorModels(raw_ostream &OS); void EmitProcessorLookup(raw_ostream &OS); void EmitSchedModelHelpers(const std::string &ClassName, raw_ostream &OS); + void emitSchedModelHelpersImpl(raw_ostream &OS, + bool OnlyExpandMCInstPredicates = false); + void EmitSchedModel(raw_ostream &OS); void EmitHwModeCheck(const std::string &ClassName, raw_ostream &OS); void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures, @@ -1461,35 +1465,37 @@ static void emitPredicateProlog(const RecordKeeper &Records, raw_ostream &OS) { } 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( + raw_ostream &OS, bool OnlyExpandMCInstPredicates) { // Collect Variant Classes. IdxVec VariantClasses; for (const CodeGenSchedClass &SC : SchedModels.schedClasses()) { @@ -1503,24 +1509,43 @@ void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName, 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 (OnlyExpandMCInstPredicates && + !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(OnlyExpandMCInstPredicates); for (unsigned PI : ProcIndices) { OS << " "; - if (PI != 0) - OS << "if (SchedModel->getProcessorID() == " << PI << ") "; - OS << "{ // " << (SchedModels.procModelBegin() + PI)->ModelName - << '\n'; + if (PI != 0) { + OS << (OnlyExpandMCInstPredicates + ? "if (CPUID == " + : "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) @@ -1532,8 +1557,29 @@ void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName, } OS << " };\n"; } - OS << " report_fatal_error(\"Expected a variant SchedClass\");\n" - << "} // " << ClassName << "::resolveSchedClass\n"; + + if (OnlyExpandMCInstPredicates) { + 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(OS); + + OS << "} // " << ClassName << "::resolveSchedClass\n"; } void SubtargetEmitter::EmitHwModeCheck(const std::string &ClassName,