diff --git a/llvm/include/llvm/Target/TargetSchedule.td b/llvm/include/llvm/Target/TargetSchedule.td index f55bff16dcecd..d6a40598a7ea2 100644 --- a/llvm/include/llvm/Target/TargetSchedule.td +++ b/llvm/include/llvm/Target/TargetSchedule.td @@ -377,6 +377,12 @@ class MCSchedPredicate : SchedPredicateBase { SchedMachineModel SchedModel = ?; } +// A scheduling predicate whose logic depends on a SubtargetFeature. +class FeatureSchedPredicate : SchedPredicateBase { + SubtargetFeature Feature = SF; + 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, diff --git a/llvm/test/TableGen/ResolveSchedClass.td b/llvm/test/TableGen/ResolveSchedClass.td index 8c9ef1eab3566..c1cadb359ca03 100644 --- a/llvm/test/TableGen/ResolveSchedClass.td +++ b/llvm/test/TableGen/ResolveSchedClass.td @@ -8,11 +8,57 @@ def TestTarget : Target { let InstructionSet = TestTargetInstrInfo; } +def FeatureFoo : SubtargetFeature<"foo", "HasFoo", "true", "enable foo">; + +def ResX0 : ProcResource<1>; + +let OutOperandList = (outs), InOperandList = (ins) in +def Inst_A : Instruction; + +def SchedModel_A: SchedMachineModel { + let CompleteModel = false; +} + +let SchedModel = SchedModel_A in { +def SchedWriteResA : SchedWriteRes<[ResX0]> { + let Latency = 2; +} +def SchedWriteResB : SchedWriteRes<[ResX0]> { + let Latency = 4; +} + +// Check SchedPredicate with subtarget feature. +def FeatureFooPred : FeatureSchedPredicate; + +def Variant : SchedWriteVariant<[ + SchedVar, + SchedVar +]>; + +def : InstRW<[Variant], (instrs Inst_A)>; +} + +def ProcessorA: ProcessorModel<"ProcessorA", SchedModel_A, []>; + // CHECK: unsigned resolveVariantSchedClassImpl(unsigned SchedClass, // CHECK-NEXT: const MCInst *MI, const MCInstrInfo *MCII, const MCSubtargetInfo &STI, unsigned CPUID) +// CHECK: case {{.*}}: // Inst_A +// CHECK-NEXT: if (CPUID == {{.*}}) { // SchedModel_A +// CHECK-NEXT: if (STI.hasFeature(TestTarget::FeatureFoo)) +// CHECK-NEXT: return {{.*}}; // SchedWriteResA +// CHECK-NEXT: return {{.*}}; // SchedWriteResB // CHECK: unsigned resolveVariantSchedClass(unsigned SchedClass, // CHECK-NEXT: const MCInst *MI, const MCInstrInfo *MCII, // CHECK-NEXT: unsigned CPUID) const override { // CHECK-NEXT: return TestTarget_MC::resolveVariantSchedClassImpl(SchedClass, MI, MCII, *this, CPUID); // CHECK-NEXT: } + +// CHECK: unsigned TestTargetGenSubtargetInfo +// CHECK-NEXT: ::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI, const TargetSchedModel *SchedModel) const { +// CHECK-NEXT: switch (SchedClass) { +// CHECK-NEXT: case {{.*}}: // Inst_A +// CHECK-NEXT: if (SchedModel->getProcessorID() == {{.*}}) { // SchedModel_A +// CHECK-NEXT: if (this->hasFeature(TestTarget::FeatureFoo)) +// CHECK-NEXT: return {{.*}}; // SchedWriteResA +// CHECK-NEXT: return {{.*}}; // SchedWriteResB diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp index b0a309cdbfef8..2f15cc8c76548 100644 --- a/llvm/utils/TableGen/SubtargetEmitter.cpp +++ b/llvm/utils/TableGen/SubtargetEmitter.cpp @@ -1586,6 +1586,24 @@ static void emitPredicates(const CodeGenSchedTransition &T, continue; } + if (Rec->isSubClassOf("FeatureSchedPredicate")) { + const Record *FR = Rec->getValueAsDef("Feature"); + if (PE.shouldExpandForMC()) { + // MC version of this predicate will be emitted into + // resolveVariantSchedClassImpl, which accesses MCSubtargetInfo + // through argument STI. + SS << "STI."; + } else { + // Otherwise, this predicate will be emitted directly into + // TargetGenSubtargetInfo::resolveSchedClass, which can just access + // TargetSubtargetInfo / MCSubtargetInfo through `this`. + SS << "this->"; + } + SS << "hasFeature(" << PE.getTargetName() << "::" << FR->getName() + << ")"; + continue; + } + // Expand this legacy predicate and wrap it around braces if there is more // than one predicate to expand. SS << ((NumNonTruePreds > 1) ? "(" : "") @@ -1618,7 +1636,8 @@ static void emitSchedModelHelperEpilogue(raw_ostream &OS, static bool hasMCSchedPredicates(const CodeGenSchedTransition &T) { return all_of(T.PredTerm, [](const Record *Rec) { - return Rec->isSubClassOf("MCSchedPredicate"); + return Rec->isSubClassOf("MCSchedPredicate") || + Rec->isSubClassOf("FeatureSchedPredicate"); }); }