diff options
author | Wang Pengcheng <wangpengcheng.pp@bytedance.com> | 2024-01-05 22:44:04 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-05 22:44:04 +0800 |
commit | a0e6b7c0429204ac42095be09bd1d5dcad4a052a (patch) | |
tree | d8a4c14ff6bf4194bc7f222f95e01f39d42e65a6 | |
parent | 65df69619c49717da64140baddda0f04ed62ffdf (diff) |
[TableGen] Add a backend to generate MacroFusion predicators (#72222)
`FusionPredicate` is used to predicate if target instruction matches
the requirement. The targets can be firstMI, secondMI or both.
The `Fusion` contains a list of `FusionPredicate`. The generated code
will be like:
```
bool isNAME(const TargetInstrInfo &TII,
const TargetSubtargetInfo &STI,
const MachineInstr *FirstMI,
const MachineInstr &SecondMI) {
auto &MRI = SecondMI.getMF()->getRegInfo();
/* Predicates */
return true;
}
```
A boilerplate class called `SimpleFusion` is added. `SimpleFusion` has
a predefined structure of predicates and accepts predicate for
`firstMI`, predicate for `secondMI` and epilog/prolog as arguments.
The generated code for `SimpleFusion` will be like:
```
bool isNAME(const TargetInstrInfo &TII,
const TargetSubtargetInfo &STI,
const MachineInstr *FirstMI,
const MachineInstr &SecondMI) {
auto &MRI = SecondMI.getMF()->getRegInfo();
/* Prolog */
/* Predicate for `SecondMI` */
/* Wildcard */
/* Predicate for `FirstMI` */
/* Check One Use */
/* Tie registers */
/* Epilog */
return true;
}
```
-rw-r--r-- | llvm/include/llvm/Target/TargetInstrPredicate.td | 6 | ||||
-rw-r--r-- | llvm/include/llvm/Target/TargetSchedule.td | 113 | ||||
-rw-r--r-- | llvm/test/TableGen/MacroFusion.td | 97 | ||||
-rw-r--r-- | llvm/utils/TableGen/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp | 236 | ||||
-rw-r--r-- | llvm/utils/TableGen/PredicateExpander.cpp | 8 | ||||
-rw-r--r-- | llvm/utils/TableGen/PredicateExpander.h | 1 |
7 files changed, 462 insertions, 0 deletions
diff --git a/llvm/include/llvm/Target/TargetInstrPredicate.td b/llvm/include/llvm/Target/TargetInstrPredicate.td index 9f2cde9d9230..82c4c7b23a49 100644 --- a/llvm/include/llvm/Target/TargetInstrPredicate.td +++ b/llvm/include/llvm/Target/TargetInstrPredicate.td @@ -95,6 +95,12 @@ class MCOperandPredicate<int Index> : MCInstPredicate { // Return true if machine operand at position `Index` is a register operand. class CheckIsRegOperand<int Index> : MCOperandPredicate<Index>; +// Return true if machine operand at position `Index` is a virtual register operand. +class CheckIsVRegOperand<int Index> : MCOperandPredicate<Index>; + +// Return true if machine operand at position `Index` is not a virtual register operand. +class CheckIsNotVRegOperand<int Index> : CheckNot<CheckIsVRegOperand<Index>>; + // Return true if machine operand at position `Index` is an immediate operand. class CheckIsImmOperand<int Index> : MCOperandPredicate<Index>; diff --git a/llvm/include/llvm/Target/TargetSchedule.td b/llvm/include/llvm/Target/TargetSchedule.td index 949baa5d2105..2016d452afb6 100644 --- a/llvm/include/llvm/Target/TargetSchedule.td +++ b/llvm/include/llvm/Target/TargetSchedule.td @@ -584,3 +584,116 @@ class MemoryQueue<ProcResourceKind PR> { class LoadQueue<ProcResourceKind LDQueue> : MemoryQueue<LDQueue>; class StoreQueue<ProcResourceKind STQueue> : MemoryQueue<STQueue>; + +// The target instruction that FusionPredicate will be evaluated on. +class FusionTarget; +def first_fusion_target : FusionTarget; +def second_fusion_target : FusionTarget; +def both_fusion_target : FusionTarget; + +// Base class of FusionPredicate, etc. The avaliable variables are: +// * const TargetInstrInfo &TII +// * const TargetSubtargetInfo &STI +// * const MachineRegisterInfo &MRI +// * const MachineInstr *FirstMI +// * const MachineInstr &SecondMI +class FusionPredicate<FusionTarget target> { + FusionTarget Target = target; +} +class FirstFusionPredicate: FusionPredicate<first_fusion_target>; +class SecondFusionPredicate: FusionPredicate<second_fusion_target>; +class BothFusionPredicate: FusionPredicate<both_fusion_target>; + +// FusionPredicate with raw code predicate. +class FusionPredicateWithCode<code pred> : FusionPredicate<both_fusion_target> { + code Predicate = pred; +} + +// FusionPredicate with MCInstPredicate. +class FusionPredicateWithMCInstPredicate<FusionTarget target, MCInstPredicate pred> + : FusionPredicate<target> { + MCInstPredicate Predicate = pred; +} +class FirstFusionPredicateWithMCInstPredicate<MCInstPredicate pred> + : FusionPredicateWithMCInstPredicate<first_fusion_target, pred>; +class SecondFusionPredicateWithMCInstPredicate<MCInstPredicate pred> + : FusionPredicateWithMCInstPredicate<second_fusion_target, pred>; +// The pred will be applied on both firstMI and secondMI. +class BothFusionPredicateWithMCInstPredicate<MCInstPredicate pred> + : FusionPredicateWithMCInstPredicate<second_fusion_target, pred>; + +// Tie firstOpIdx and secondOpIdx. The operand of `FirstMI` at position +// `firstOpIdx` should be the same as the operand of `SecondMI` at position +// `secondOpIdx`. +class TieReg<int firstOpIdx, int secondOpIdx> : BothFusionPredicate { + int FirstOpIdx = firstOpIdx; + int SecondOpIdx = secondOpIdx; +} + +// A predicate for wildcard. The generated code will be like: +// ``` +// if (!FirstMI) +// return ReturnValue; +// ``` +class WildcardPred<bit ret> : FirstFusionPredicate { + bit ReturnValue = ret; +} +def WildcardFalse : WildcardPred<0>; +def WildcardTrue : WildcardPred<1>; + +// Indicates that the destination register of `FirstMI` should have one use if +// it is a virtual register. +class OneUsePred : FirstFusionPredicate; +def OneUse : OneUsePred; + +// Handled by MacroFusionPredicatorEmitter backend. +// The generated predicator will be like: +// ``` +// bool isNAME(const TargetInstrInfo &TII, +// const TargetSubtargetInfo &STI, +// const MachineInstr *FirstMI, +// const MachineInstr &SecondMI) { +// auto &MRI = SecondMI.getMF()->getRegInfo(); +// /* Predicates */ +// return true; +// } +// ``` +class Fusion<list<FusionPredicate> predicates> { + list<FusionPredicate> Predicates = predicates; +} + +// The generated predicator will be like: +// ``` +// bool isNAME(const TargetInstrInfo &TII, +// const TargetSubtargetInfo &STI, +// const MachineInstr *FirstMI, +// const MachineInstr &SecondMI) { +// auto &MRI = SecondMI.getMF()->getRegInfo(); +// /* Prolog */ +// /* Predicate for `SecondMI` */ +// /* Wildcard */ +// /* Predicate for `FirstMI` */ +// /* Check One Use */ +// /* Tie registers */ +// /* Epilog */ +// return true; +// } +// ``` +class SimpleFusion<MCInstPredicate firstPred, MCInstPredicate secondPred, + list<FusionPredicate> prolog = [], + list<FusionPredicate> epilog = []> + : Fusion<!listconcat( + prolog, + [ + SecondFusionPredicateWithMCInstPredicate<secondPred>, + WildcardTrue, + FirstFusionPredicateWithMCInstPredicate<firstPred>, + SecondFusionPredicateWithMCInstPredicate< + CheckAny<[ + CheckIsVRegOperand<0>, + CheckSameRegOperand<0, 1> + ]>>, + OneUse, + TieReg<0, 1>, + ], + epilog)>; diff --git a/llvm/test/TableGen/MacroFusion.td b/llvm/test/TableGen/MacroFusion.td new file mode 100644 index 000000000000..f984a142839c --- /dev/null +++ b/llvm/test/TableGen/MacroFusion.td @@ -0,0 +1,97 @@ +// RUN: llvm-tblgen -gen-macro-fusion-pred -I %p/../../include %s | FileCheck %s --check-prefix=CHECK-PREDICATOR + +include "llvm/Target/Target.td" + +def TestInstrInfo : InstrInfo { } +def TestAsmWriter : AsmWriter { + int PassSubtarget = 1; +} + +def Test : Target { + let InstructionSet = TestInstrInfo; + let AssemblyWriters = [TestAsmWriter]; +} + +let Namespace = "Test" in { + foreach i = 0-32 in { + def X#i : Register<"x"#i>; + } + + def GPR : RegisterClass<"GPR", [i32], 32, (sequence "X%u", 0, 32)>; + + class TestInst<int Opc> : Instruction { + field bits<32> Inst; + field bits<32> SoftFail = 0; + let Size = 4; + let Inst = Opc; + let OutOperandList = (outs); + let InOperandList = (ins); + let AsmString = NAME; + } +} + +def Inst0 : TestInst<0>; +def Inst1 : TestInst<1>; + +def TestFusion: SimpleFusion<CheckOpcode<[Inst0]>, + CheckAll<[ + CheckOpcode<[Inst1]>, + CheckRegOperand<0, X0> + ]>>; + +// CHECK-PREDICATOR: #ifdef GET_Test_MACRO_FUSION_PRED_DECL +// CHECK-PREDICATOR-NEXT: #undef GET_Test_MACRO_FUSION_PRED_DECL +// CHECK-PREDICATOR-EMPTY: +// CHECK-PREDICATOR-NEXT: namespace llvm { +// CHECK-PREDICATOR-NEXT: bool isTestFusion(const TargetInstrInfo &, const TargetSubtargetInfo &, const MachineInstr *, const MachineInstr &); +// CHECK-PREDICATOR-NEXT: } // end namespace llvm +// CHECK-PREDICATOR-EMPTY: +// CHECK-PREDICATOR-NEXT: #endif + +// CHECK-PREDICATOR: #ifdef GET_Test_MACRO_FUSION_PRED_IMPL +// CHECK-PREDICATOR-NEXT: #undef GET_Test_MACRO_FUSION_PRED_IMPL +// CHECK-PREDICATOR-EMPTY: +// CHECK-PREDICATOR-NEXT: namespace llvm { +// CHECK-PREDICATOR-NEXT: bool isTestFusion( +// CHECK-PREDICATOR-NEXT: const TargetInstrInfo &TII, +// CHECK-PREDICATOR-NEXT: const TargetSubtargetInfo &STI, +// CHECK-PREDICATOR-NEXT: const MachineInstr *FirstMI, +// CHECK-PREDICATOR-NEXT: const MachineInstr &SecondMI) { +// CHECK-PREDICATOR-NEXT: auto &MRI = SecondMI.getMF()->getRegInfo(); +// CHECK-PREDICATOR-NEXT: { +// CHECK-PREDICATOR-NEXT: const MachineInstr *MI = &SecondMI; +// CHECK-PREDICATOR-NEXT: if (!( +// CHECK-PREDICATOR-NEXT: ( MI->getOpcode() == Test::Inst1 ) +// CHECK-PREDICATOR-NEXT: && MI->getOperand(0).getReg() == Test::X0 +// CHECK-PREDICATOR-NEXT: )) +// CHECK-PREDICATOR-NEXT: return false; +// CHECK-PREDICATOR-NEXT: } +// CHECK-PREDICATOR-NEXT: if (!FirstMI) +// CHECK-PREDICATOR-NEXT: return true; +// CHECK-PREDICATOR-NEXT: { +// CHECK-PREDICATOR-NEXT: const MachineInstr *MI = FirstMI; +// CHECK-PREDICATOR-NEXT: if (( MI->getOpcode() != Test::Inst0 )) +// CHECK-PREDICATOR-NEXT: return false; +// CHECK-PREDICATOR-NEXT: } +// CHECK-PREDICATOR-NEXT: { +// CHECK-PREDICATOR-NEXT: const MachineInstr *MI = &SecondMI; +// CHECK-PREDICATOR-NEXT: if (!( +// CHECK-PREDICATOR-NEXT: MI->getOperand(0).getReg().isVirtual() +// CHECK-PREDICATOR-NEXT: || MI->getOperand(0).getReg() == MI->getOperand(1).getReg() +// CHECK-PREDICATOR-NEXT: )) +// CHECK-PREDICATOR-NEXT: return false; +// CHECK-PREDICATOR-NEXT: } +// CHECK-PREDICATOR-NEXT: { +// CHECK-PREDICATOR-NEXT: Register FirstDest = FirstMI->getOperand(0).getReg(); +// CHECK-PREDICATOR-NEXT: if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest)) +// CHECK-PREDICATOR-NEXT: return false; +// CHECK-PREDICATOR-NEXT: } +// CHECK-PREDICATOR-NEXT: if (!(FirstMI->getOperand(0).isReg() && +// CHECK-PREDICATOR-NEXT: SecondMI.getOperand(1).isReg() && +// CHECK-PREDICATOR-NEXT: FirstMI->getOperand(0).getReg() == SecondMI.getOperand(1).getReg())) +// CHECK-PREDICATOR-NEXT: return false; +// CHECK-PREDICATOR-NEXT: return true; +// CHECK-PREDICATOR-NEXT: } +// CHECK-PREDICATOR-NEXT: } // end namespace llvm +// CHECK-PREDICATOR-EMPTY: +// CHECK-PREDICATOR-NEXT: #endif diff --git a/llvm/utils/TableGen/CMakeLists.txt b/llvm/utils/TableGen/CMakeLists.txt index 071ea3bc0705..f765cc36d3be 100644 --- a/llvm/utils/TableGen/CMakeLists.txt +++ b/llvm/utils/TableGen/CMakeLists.txt @@ -72,6 +72,7 @@ add_tablegen(llvm-tblgen LLVM PredicateExpander.cpp PseudoLoweringEmitter.cpp CompressInstEmitter.cpp + MacroFusionPredicatorEmitter.cpp RegisterBankEmitter.cpp RegisterInfoEmitter.cpp SearchableTableEmitter.cpp diff --git a/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp b/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp new file mode 100644 index 000000000000..78dcd4471ae7 --- /dev/null +++ b/llvm/utils/TableGen/MacroFusionPredicatorEmitter.cpp @@ -0,0 +1,236 @@ +//===------ MacroFusionPredicatorEmitter.cpp - Generator for Fusion ------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// MacroFusionPredicatorEmitter implements a TableGen-driven predicators +// generator for macro-op fusions. +// +// This TableGen backend processes `Fusion` definitions and generates +// predicators for checking if input instructions can be fused. These +// predicators can used in `MacroFusion` DAG mutation. +// +// The generated header file contains two parts: one for predicator +// declarations and one for predicator implementations. The user can get them +// by defining macro `GET_<TargetName>_MACRO_FUSION_PRED_DECL` or +// `GET_<TargetName>_MACRO_FUSION_PRED_IMPL` and then including the generated +// header file. +// +// The generated predicator will be like: +// +// ``` +// bool isNAME(const TargetInstrInfo &TII, +// const TargetSubtargetInfo &STI, +// const MachineInstr *FirstMI, +// const MachineInstr &SecondMI) { +// auto &MRI = SecondMI.getMF()->getRegInfo(); +// /* Predicates */ +// return true; +// } +// ``` +// +// The `Predicates` part is generated from a list of `FusionPredicate`, which +// can be predefined predicates, a raw code string or `MCInstPredicate` defined +// in TargetInstrPredicate.td. +// +//===---------------------------------------------------------------------===// + +#include "CodeGenTarget.h" +#include "PredicateExpander.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Debug.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <set> +#include <vector> + +using namespace llvm; + +#define DEBUG_TYPE "macro-fusion-predicator" + +namespace { +class MacroFusionPredicatorEmitter { + RecordKeeper &Records; + CodeGenTarget Target; + + void emitMacroFusionDecl(std::vector<Record *> Fusions, PredicateExpander &PE, + raw_ostream &OS); + void emitMacroFusionImpl(std::vector<Record *> Fusions, PredicateExpander &PE, + raw_ostream &OS); + void emitPredicates(std::vector<Record *> &FirstPredicate, + PredicateExpander &PE, raw_ostream &OS); + void emitFirstPredicate(Record *SecondPredicate, PredicateExpander &PE, + raw_ostream &OS); + void emitSecondPredicate(Record *SecondPredicate, PredicateExpander &PE, + raw_ostream &OS); + void emitBothPredicate(Record *Predicates, PredicateExpander &PE, + raw_ostream &OS); + +public: + MacroFusionPredicatorEmitter(RecordKeeper &R) : Records(R), Target(R) {} + + void run(raw_ostream &OS); +}; +} // End anonymous namespace. + +void MacroFusionPredicatorEmitter::emitMacroFusionDecl( + std::vector<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) { + OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n"; + OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_DECL\n\n"; + OS << "namespace llvm {\n"; + + for (Record *Fusion : Fusions) { + OS << "bool is" << Fusion->getName() << "(const TargetInstrInfo &, " + << "const TargetSubtargetInfo &, " + << "const MachineInstr *, " + << "const MachineInstr &);\n"; + } + + OS << "} // end namespace llvm\n"; + OS << "\n#endif\n"; +} + +void MacroFusionPredicatorEmitter::emitMacroFusionImpl( + std::vector<Record *> Fusions, PredicateExpander &PE, raw_ostream &OS) { + OS << "#ifdef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n"; + OS << "#undef GET_" << Target.getName() << "_MACRO_FUSION_PRED_IMPL\n\n"; + OS << "namespace llvm {\n"; + + for (Record *Fusion : Fusions) { + std::vector<Record *> Predicates = + Fusion->getValueAsListOfDefs("Predicates"); + + OS << "bool is" << Fusion->getName() << "(\n"; + OS.indent(4) << "const TargetInstrInfo &TII,\n"; + OS.indent(4) << "const TargetSubtargetInfo &STI,\n"; + OS.indent(4) << "const MachineInstr *FirstMI,\n"; + OS.indent(4) << "const MachineInstr &SecondMI) {\n"; + OS.indent(2) << "auto &MRI = SecondMI.getMF()->getRegInfo();\n"; + + emitPredicates(Predicates, PE, OS); + + OS.indent(2) << "return true;\n"; + OS << "}\n"; + } + + OS << "} // end namespace llvm\n"; + OS << "\n#endif\n"; +} + +void MacroFusionPredicatorEmitter::emitPredicates( + std::vector<Record *> &Predicates, PredicateExpander &PE, raw_ostream &OS) { + for (Record *Predicate : Predicates) { + Record *Target = Predicate->getValueAsDef("Target"); + if (Target->getName() == "first_fusion_target") + emitFirstPredicate(Predicate, PE, OS); + else if (Target->getName() == "second_fusion_target") + emitSecondPredicate(Predicate, PE, OS); + else if (Target->getName() == "both_fusion_target") + emitBothPredicate(Predicate, PE, OS); + else + PrintFatalError(Target->getLoc(), + "Unsupported 'FusionTarget': " + Target->getName()); + } +} + +void MacroFusionPredicatorEmitter::emitFirstPredicate(Record *Predicate, + PredicateExpander &PE, + raw_ostream &OS) { + if (Predicate->isSubClassOf("WildcardPred")) { + OS.indent(2) << "if (!FirstMI)\n"; + OS.indent(2) << " return " + << (Predicate->getValueAsBit("ReturnValue") ? "true" : "false") + << ";\n"; + } else if (Predicate->isSubClassOf("OneUsePred")) { + OS.indent(2) << "{\n"; + OS.indent(4) << "Register FirstDest = FirstMI->getOperand(0).getReg();\n"; + OS.indent(4) + << "if (FirstDest.isVirtual() && !MRI.hasOneNonDBGUse(FirstDest))\n"; + OS.indent(4) << " return false;\n"; + OS.indent(2) << "}\n"; + } else if (Predicate->isSubClassOf( + "FirstFusionPredicateWithMCInstPredicate")) { + OS.indent(2) << "{\n"; + OS.indent(4) << "const MachineInstr *MI = FirstMI;\n"; + OS.indent(4) << "if ("; + PE.setNegatePredicate(true); + PE.setIndentLevel(3); + PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate")); + OS << ")\n"; + OS.indent(4) << " return false;\n"; + OS.indent(2) << "}\n"; + } else { + PrintFatalError(Predicate->getLoc(), + "Unsupported predicate for first instruction: " + + Predicate->getType()->getAsString()); + } +} + +void MacroFusionPredicatorEmitter::emitSecondPredicate(Record *Predicate, + PredicateExpander &PE, + raw_ostream &OS) { + if (Predicate->isSubClassOf("SecondFusionPredicateWithMCInstPredicate")) { + OS.indent(2) << "{\n"; + OS.indent(4) << "const MachineInstr *MI = &SecondMI;\n"; + OS.indent(4) << "if ("; + PE.setNegatePredicate(true); + PE.setIndentLevel(3); + PE.expandPredicate(OS, Predicate->getValueAsDef("Predicate")); + OS << ")\n"; + OS.indent(4) << " return false;\n"; + OS.indent(2) << "}\n"; + } else { + PrintFatalError(Predicate->getLoc(), + "Unsupported predicate for first instruction: " + + Predicate->getType()->getAsString()); + } +} + +void MacroFusionPredicatorEmitter::emitBothPredicate(Record *Predicate, + PredicateExpander &PE, + raw_ostream &OS) { + if (Predicate->isSubClassOf("FusionPredicateWithCode")) + OS << Predicate->getValueAsString("Predicate"); + else if (Predicate->isSubClassOf("BothFusionPredicateWithMCInstPredicate")) { + Record *MCPred = Predicate->getValueAsDef("Predicate"); + emitFirstPredicate(MCPred, PE, OS); + emitSecondPredicate(MCPred, PE, OS); + } else if (Predicate->isSubClassOf("TieReg")) { + int FirstOpIdx = Predicate->getValueAsInt("FirstOpIdx"); + int SecondOpIdx = Predicate->getValueAsInt("SecondOpIdx"); + OS.indent(2) << "if (!(FirstMI->getOperand(" << FirstOpIdx + << ").isReg() &&\n"; + OS.indent(2) << " SecondMI.getOperand(" << SecondOpIdx + << ").isReg() &&\n"; + OS.indent(2) << " FirstMI->getOperand(" << FirstOpIdx + << ").getReg() == SecondMI.getOperand(" << SecondOpIdx + << ").getReg()))\n"; + OS.indent(2) << " return false;\n"; + } else + PrintFatalError(Predicate->getLoc(), + "Unsupported predicate for both instruction: " + + Predicate->getType()->getAsString()); +} + +void MacroFusionPredicatorEmitter::run(raw_ostream &OS) { + // Emit file header. + emitSourceFileHeader("Macro Fusion Predicators", OS); + + PredicateExpander PE(Target.getName()); + PE.setByRef(false); + PE.setExpandForMC(false); + + std::vector<Record *> Fusions = Records.getAllDerivedDefinitions("Fusion"); + // Sort macro fusions by name. + sort(Fusions, LessRecord()); + emitMacroFusionDecl(Fusions, PE, OS); + OS << "\n"; + emitMacroFusionImpl(Fusions, PE, OS); +} + +static TableGen::Emitter::OptClass<MacroFusionPredicatorEmitter> + X("gen-macro-fusion-pred", "Generate macro fusion predicators."); diff --git a/llvm/utils/TableGen/PredicateExpander.cpp b/llvm/utils/TableGen/PredicateExpander.cpp index 8f96d3307ded..d3a73e02cd91 100644 --- a/llvm/utils/TableGen/PredicateExpander.cpp +++ b/llvm/utils/TableGen/PredicateExpander.cpp @@ -194,6 +194,11 @@ void PredicateExpander::expandCheckIsRegOperand(raw_ostream &OS, int OpIndex) { << "getOperand(" << OpIndex << ").isReg() "; } +void PredicateExpander::expandCheckIsVRegOperand(raw_ostream &OS, int OpIndex) { + OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->") + << "getOperand(" << OpIndex << ").getReg().isVirtual()"; +} + void PredicateExpander::expandCheckIsImmOperand(raw_ostream &OS, int OpIndex) { OS << (shouldNegate() ? "!" : "") << "MI" << (isByRef() ? "." : "->") << "getOperand(" << OpIndex << ").isImm() "; @@ -319,6 +324,9 @@ void PredicateExpander::expandPredicate(raw_ostream &OS, const Record *Rec) { if (Rec->isSubClassOf("CheckIsRegOperand")) return expandCheckIsRegOperand(OS, Rec->getValueAsInt("OpIndex")); + if (Rec->isSubClassOf("CheckIsVRegOperand")) + return expandCheckIsVRegOperand(OS, Rec->getValueAsInt("OpIndex")); + if (Rec->isSubClassOf("CheckIsImmOperand")) return expandCheckIsImmOperand(OS, Rec->getValueAsInt("OpIndex")); diff --git a/llvm/utils/TableGen/PredicateExpander.h b/llvm/utils/TableGen/PredicateExpander.h index 27f049a715aa..cfb0a3d51e67 100644 --- a/llvm/utils/TableGen/PredicateExpander.h +++ b/llvm/utils/TableGen/PredicateExpander.h @@ -75,6 +75,7 @@ public: bool IsCheckAll); void expandTIIFunctionCall(raw_ostream &OS, StringRef MethodName); void expandCheckIsRegOperand(raw_ostream &OS, int OpIndex); + void expandCheckIsVRegOperand(raw_ostream &OS, int OpIndex); void expandCheckIsImmOperand(raw_ostream &OS, int OpIndex); void expandCheckInvalidRegOperand(raw_ostream &OS, int OpIndex); void expandCheckFunctionPredicate(raw_ostream &OS, StringRef MCInstFn, |