1*0fca6ea1SDimitry Andric //===- GlobalISelMatchTableExecutorEmitter.h ------------------------------===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric // 9*0fca6ea1SDimitry Andric /// \file 10*0fca6ea1SDimitry Andric /// This file contains common code related to emitting 11*0fca6ea1SDimitry Andric /// GIMatchTableExecutor-derived classes. 12*0fca6ea1SDimitry Andric /// 13*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 14*0fca6ea1SDimitry Andric 15*0fca6ea1SDimitry Andric #ifndef LLVM_UTILS_TABLEGEN_GLOBALISELMATCHTABLEEXECUTOREMITTER_H 16*0fca6ea1SDimitry Andric #define LLVM_UTILS_TABLEGEN_GLOBALISELMATCHTABLEEXECUTOREMITTER_H 17*0fca6ea1SDimitry Andric 18*0fca6ea1SDimitry Andric #include "Common/SubtargetFeatureInfo.h" 19*0fca6ea1SDimitry Andric #include "llvm/ADT/ArrayRef.h" 20*0fca6ea1SDimitry Andric #include "llvm/ADT/StringRef.h" 21*0fca6ea1SDimitry Andric #include "llvm/ADT/Twine.h" 22*0fca6ea1SDimitry Andric #include <functional> 23*0fca6ea1SDimitry Andric 24*0fca6ea1SDimitry Andric namespace llvm { 25*0fca6ea1SDimitry Andric class CodeGenTarget; 26*0fca6ea1SDimitry Andric 27*0fca6ea1SDimitry Andric namespace gi { 28*0fca6ea1SDimitry Andric class RuleMatcher; 29*0fca6ea1SDimitry Andric class LLTCodeGen; 30*0fca6ea1SDimitry Andric class MatchTable; 31*0fca6ea1SDimitry Andric } // namespace gi 32*0fca6ea1SDimitry Andric 33*0fca6ea1SDimitry Andric /// Abstract base class for TableGen backends that emit a 34*0fca6ea1SDimitry Andric /// `GIMatchTableExecutor`-derived class. 35*0fca6ea1SDimitry Andric class GlobalISelMatchTableExecutorEmitter { 36*0fca6ea1SDimitry Andric /// Emits logic to check features required by \p Rules using the 37*0fca6ea1SDimitry Andric 38*0fca6ea1SDimitry Andric /// SubtargetFeatures map. 39*0fca6ea1SDimitry Andric void emitSubtargetFeatureBitsetImpl(raw_ostream &OS, 40*0fca6ea1SDimitry Andric ArrayRef<gi::RuleMatcher> Rules); 41*0fca6ea1SDimitry Andric 42*0fca6ea1SDimitry Andric /// Emits an enum + an array that stores references to 43*0fca6ea1SDimitry Andric /// \p ComplexOperandMatchers. 44*0fca6ea1SDimitry Andric void emitComplexPredicates(raw_ostream &OS, 45*0fca6ea1SDimitry Andric ArrayRef<Record *> ComplexOperandMatchers); 46*0fca6ea1SDimitry Andric 47*0fca6ea1SDimitry Andric /// Emits an enum + an array that stores references to 48*0fca6ea1SDimitry Andric /// \p CustomOperandRenderers. 49*0fca6ea1SDimitry Andric void emitCustomOperandRenderers(raw_ostream &OS, 50*0fca6ea1SDimitry Andric ArrayRef<StringRef> CustomOperandRenderers); 51*0fca6ea1SDimitry Andric 52*0fca6ea1SDimitry Andric /// Emits an enum + an array to reference \p TypeObjects (LLTs) in the match 53*0fca6ea1SDimitry Andric /// table. 54*0fca6ea1SDimitry Andric void emitTypeObjects(raw_ostream &OS, ArrayRef<gi::LLTCodeGen> TypeObjects); 55*0fca6ea1SDimitry Andric 56*0fca6ea1SDimitry Andric /// Emits the getMatchTable function which contains all of the match table's 57*0fca6ea1SDimitry Andric /// opcodes. 58*0fca6ea1SDimitry Andric void emitMatchTable(raw_ostream &OS, const gi::MatchTable &Table); 59*0fca6ea1SDimitry Andric 60*0fca6ea1SDimitry Andric /// Helper function to emit `test` functions for the executor. This emits both 61*0fca6ea1SDimitry Andric /// an enum to reference predicates in the MatchTable, and a function to 62*0fca6ea1SDimitry Andric /// switch over the enum & execute the predicate's C++ code. 63*0fca6ea1SDimitry Andric /// 64*0fca6ea1SDimitry Andric /// \tparam PredicateObject An object representing a predicate to emit. 65*0fca6ea1SDimitry Andric /// \param OS Output stream 66*0fca6ea1SDimitry Andric /// \param TypeIdentifier Identifier used for the type of the predicate, 67*0fca6ea1SDimitry Andric /// e.g. `MI` for MachineInstrs. 68*0fca6ea1SDimitry Andric /// \param ArgType Full type of the argument, e.g. `const MachineInstr &` 69*0fca6ea1SDimitry Andric /// \param ArgName Name of the argument, e.g. `MI` for MachineInstrs. 70*0fca6ea1SDimitry Andric /// \param AdditionalArgs Optional additional argument declarations. 71*0fca6ea1SDimitry Andric /// \param AdditionalDeclarations Optional declarations to write at the start 72*0fca6ea1SDimitry Andric /// of the function, before switching over the predicates enum. 73*0fca6ea1SDimitry Andric /// \param Predicates Predicates to emit. 74*0fca6ea1SDimitry Andric /// \param GetPredEnumName Returns an enum name for a given predicate. 75*0fca6ea1SDimitry Andric /// \param GetPredCode Returns the C++ code of a given predicate. 76*0fca6ea1SDimitry Andric /// \param Comment Optional comment for the enum declaration. 77*0fca6ea1SDimitry Andric template <typename PredicateObject> emitCxxPredicateFns(raw_ostream & OS,StringRef TypeIdentifier,StringRef ArgType,StringRef ArgName,StringRef AdditionalArgs,StringRef AdditionalDeclarations,ArrayRef<PredicateObject> Predicates,std::function<StringRef (PredicateObject)> GetPredEnumName,std::function<StringRef (PredicateObject)> GetPredCode,StringRef Comment)78*0fca6ea1SDimitry Andric void emitCxxPredicateFns( 79*0fca6ea1SDimitry Andric raw_ostream &OS, StringRef TypeIdentifier, StringRef ArgType, 80*0fca6ea1SDimitry Andric StringRef ArgName, StringRef AdditionalArgs, 81*0fca6ea1SDimitry Andric StringRef AdditionalDeclarations, ArrayRef<PredicateObject> Predicates, 82*0fca6ea1SDimitry Andric std::function<StringRef(PredicateObject)> GetPredEnumName, 83*0fca6ea1SDimitry Andric std::function<StringRef(PredicateObject)> GetPredCode, 84*0fca6ea1SDimitry Andric StringRef Comment) { 85*0fca6ea1SDimitry Andric if (!Comment.empty()) 86*0fca6ea1SDimitry Andric OS << "// " << Comment << "\n"; 87*0fca6ea1SDimitry Andric if (!Predicates.empty()) { 88*0fca6ea1SDimitry Andric OS << "enum {\n"; 89*0fca6ea1SDimitry Andric StringRef EnumeratorSeparator = " = GICXXPred_Invalid + 1,\n"; 90*0fca6ea1SDimitry Andric for (const auto &Pred : Predicates) { 91*0fca6ea1SDimitry Andric OS << " GICXXPred_" << TypeIdentifier << "_Predicate_" 92*0fca6ea1SDimitry Andric << GetPredEnumName(Pred) << EnumeratorSeparator; 93*0fca6ea1SDimitry Andric EnumeratorSeparator = ",\n"; 94*0fca6ea1SDimitry Andric } 95*0fca6ea1SDimitry Andric OS << "};\n"; 96*0fca6ea1SDimitry Andric } 97*0fca6ea1SDimitry Andric 98*0fca6ea1SDimitry Andric OS << "bool " << getClassName() << "::test" << ArgName << "Predicate_" 99*0fca6ea1SDimitry Andric << TypeIdentifier << "(unsigned PredicateID, " << ArgType << " " 100*0fca6ea1SDimitry Andric << ArgName << AdditionalArgs << ") const {\n" 101*0fca6ea1SDimitry Andric << AdditionalDeclarations; 102*0fca6ea1SDimitry Andric if (!AdditionalDeclarations.empty()) 103*0fca6ea1SDimitry Andric OS << "\n"; 104*0fca6ea1SDimitry Andric if (!Predicates.empty()) { 105*0fca6ea1SDimitry Andric OS << " switch (PredicateID) {\n"; 106*0fca6ea1SDimitry Andric for (const auto &Pred : Predicates) { 107*0fca6ea1SDimitry Andric // Ensure all code is indented. 108*0fca6ea1SDimitry Andric const auto Code = join(split(GetPredCode(Pred).str(), "\n"), "\n "); 109*0fca6ea1SDimitry Andric OS << " case GICXXPred_" << TypeIdentifier << "_Predicate_" 110*0fca6ea1SDimitry Andric << GetPredEnumName(Pred) << ": {\n" 111*0fca6ea1SDimitry Andric << " " << Code << "\n"; 112*0fca6ea1SDimitry Andric if (!StringRef(Code).ltrim().starts_with("return")) { 113*0fca6ea1SDimitry Andric OS << " llvm_unreachable(\"" << GetPredEnumName(Pred) 114*0fca6ea1SDimitry Andric << " should have returned\");\n"; 115*0fca6ea1SDimitry Andric } 116*0fca6ea1SDimitry Andric OS << " }\n"; 117*0fca6ea1SDimitry Andric } 118*0fca6ea1SDimitry Andric OS << " }\n"; 119*0fca6ea1SDimitry Andric } 120*0fca6ea1SDimitry Andric OS << " llvm_unreachable(\"Unknown predicate\");\n" 121*0fca6ea1SDimitry Andric << " return false;\n" 122*0fca6ea1SDimitry Andric << "}\n"; 123*0fca6ea1SDimitry Andric } 124*0fca6ea1SDimitry Andric 125*0fca6ea1SDimitry Andric protected: 126*0fca6ea1SDimitry Andric /// Emits `testMIPredicate_MI`. 127*0fca6ea1SDimitry Andric /// \tparam PredicateObject An object representing a predicate to emit. 128*0fca6ea1SDimitry Andric /// \param OS Output stream 129*0fca6ea1SDimitry Andric /// \param AdditionalDecls Additional C++ variable declarations. 130*0fca6ea1SDimitry Andric /// \param Predicates Predicates to emit. 131*0fca6ea1SDimitry Andric /// \param GetPredEnumName Returns an enum name for a given predicate. 132*0fca6ea1SDimitry Andric /// \param GetPredCode Returns the C++ code of a given predicate. 133*0fca6ea1SDimitry Andric /// \param Comment Optional comment for the enum declaration. 134*0fca6ea1SDimitry Andric template <typename PredicateObject> 135*0fca6ea1SDimitry Andric void emitMIPredicateFnsImpl( 136*0fca6ea1SDimitry Andric raw_ostream &OS, StringRef AdditionalDecls, 137*0fca6ea1SDimitry Andric ArrayRef<PredicateObject> Predicates, 138*0fca6ea1SDimitry Andric std::function<StringRef(PredicateObject)> GetPredEnumName, 139*0fca6ea1SDimitry Andric std::function<StringRef(PredicateObject)> GetPredCode, 140*0fca6ea1SDimitry Andric StringRef Comment = "") { 141*0fca6ea1SDimitry Andric return emitCxxPredicateFns( 142*0fca6ea1SDimitry Andric OS, "MI", "const MachineInstr &", "MI", ", const MatcherState &State", 143*0fca6ea1SDimitry Andric AdditionalDecls, Predicates, GetPredEnumName, GetPredCode, Comment); 144*0fca6ea1SDimitry Andric } 145*0fca6ea1SDimitry Andric 146*0fca6ea1SDimitry Andric /// Helper function to emit the following executor functions: 147*0fca6ea1SDimitry Andric /// * testImmPredicate_I64 (TypeIdentifier=I64) 148*0fca6ea1SDimitry Andric /// * testImmPredicate_APInt (TypeIdentifier=APInt) 149*0fca6ea1SDimitry Andric /// * testImmPredicate_APFloat (TypeIdentifier=APFloat) 150*0fca6ea1SDimitry Andric /// 151*0fca6ea1SDimitry Andric /// \tparam PredicateObject An object representing a predicate to emit. 152*0fca6ea1SDimitry Andric /// \param OS Output stream 153*0fca6ea1SDimitry Andric /// \param TypeIdentifier Identifier used for the type of the predicate 154*0fca6ea1SDimitry Andric /// \param ArgType Full type of the argument 155*0fca6ea1SDimitry Andric /// \param Predicates Predicates to emit. 156*0fca6ea1SDimitry Andric /// \param GetPredEnumName Returns an enum name for a given predicate. 157*0fca6ea1SDimitry Andric /// \param GetPredCode Returns the C++ code of a given predicate. 158*0fca6ea1SDimitry Andric /// \param Comment Optional comment for the enum declaration. 159*0fca6ea1SDimitry Andric template <typename PredicateObject> 160*0fca6ea1SDimitry Andric void emitImmPredicateFnsImpl( 161*0fca6ea1SDimitry Andric raw_ostream &OS, StringRef TypeIdentifier, StringRef ArgType, 162*0fca6ea1SDimitry Andric ArrayRef<PredicateObject> Predicates, 163*0fca6ea1SDimitry Andric std::function<StringRef(PredicateObject)> GetPredEnumName, 164*0fca6ea1SDimitry Andric std::function<StringRef(PredicateObject)> GetPredCode, 165*0fca6ea1SDimitry Andric StringRef Comment = "") { 166*0fca6ea1SDimitry Andric return emitCxxPredicateFns(OS, TypeIdentifier, ArgType, "Imm", "", "", 167*0fca6ea1SDimitry Andric Predicates, GetPredEnumName, GetPredCode, 168*0fca6ea1SDimitry Andric Comment); 169*0fca6ea1SDimitry Andric } 170*0fca6ea1SDimitry Andric 171*0fca6ea1SDimitry Andric GlobalISelMatchTableExecutorEmitter() = default; 172*0fca6ea1SDimitry Andric 173*0fca6ea1SDimitry Andric public: 174*0fca6ea1SDimitry Andric virtual ~GlobalISelMatchTableExecutorEmitter() = default; 175*0fca6ea1SDimitry Andric 176*0fca6ea1SDimitry Andric virtual const CodeGenTarget &getTarget() const = 0; 177*0fca6ea1SDimitry Andric 178*0fca6ea1SDimitry Andric /// \returns the name of the class being emitted including any prefixes, e.g. 179*0fca6ea1SDimitry Andric /// `AMDGPUInstructionSelector`. 180*0fca6ea1SDimitry Andric virtual StringRef getClassName() const = 0; 181*0fca6ea1SDimitry Andric 182*0fca6ea1SDimitry Andric /// Emit additional content in emitExecutorImpl emitAdditionalImpl(raw_ostream & OS)183*0fca6ea1SDimitry Andric virtual void emitAdditionalImpl(raw_ostream &OS) {} 184*0fca6ea1SDimitry Andric 185*0fca6ea1SDimitry Andric /// Emit additional content in emitTemporariesInit. emitAdditionalTemporariesInit(raw_ostream & OS)186*0fca6ea1SDimitry Andric virtual void emitAdditionalTemporariesInit(raw_ostream &OS) {} 187*0fca6ea1SDimitry Andric 188*0fca6ea1SDimitry Andric /// Emit the `testMIPredicate_MI` function. 189*0fca6ea1SDimitry Andric /// Note: `emitMIPredicateFnsImpl` can be used to do most of the work. 190*0fca6ea1SDimitry Andric virtual void emitMIPredicateFns(raw_ostream &OS) = 0; 191*0fca6ea1SDimitry Andric 192*0fca6ea1SDimitry Andric /// Emit the `testImmPredicate_I64` function. 193*0fca6ea1SDimitry Andric /// Note: `emitImmPredicateFnsImpl` can be used to do most of the work. 194*0fca6ea1SDimitry Andric virtual void emitI64ImmPredicateFns(raw_ostream &OS) = 0; 195*0fca6ea1SDimitry Andric 196*0fca6ea1SDimitry Andric /// Emit the `testImmPredicate_APFloat` function. 197*0fca6ea1SDimitry Andric /// Note: `emitImmPredicateFnsImpl` can be used to do most of the work. 198*0fca6ea1SDimitry Andric virtual void emitAPFloatImmPredicateFns(raw_ostream &OS) = 0; 199*0fca6ea1SDimitry Andric 200*0fca6ea1SDimitry Andric /// Emit the `testImmPredicate_APInt` function. 201*0fca6ea1SDimitry Andric /// Note: `emitImmPredicateFnsImpl` can be used to do most of the work. 202*0fca6ea1SDimitry Andric virtual void emitAPIntImmPredicateFns(raw_ostream &OS) = 0; 203*0fca6ea1SDimitry Andric virtual void emitTestSimplePredicate(raw_ostream &OS) = 0; 204*0fca6ea1SDimitry Andric virtual void emitRunCustomAction(raw_ostream &OS) = 0; 205*0fca6ea1SDimitry Andric 206*0fca6ea1SDimitry Andric void emitExecutorImpl(raw_ostream &OS, const gi::MatchTable &Table, 207*0fca6ea1SDimitry Andric ArrayRef<gi::LLTCodeGen> TypeObjects, 208*0fca6ea1SDimitry Andric ArrayRef<gi::RuleMatcher> Rules, 209*0fca6ea1SDimitry Andric ArrayRef<Record *> ComplexOperandMatchers, 210*0fca6ea1SDimitry Andric ArrayRef<StringRef> CustomOperandRenderers, 211*0fca6ea1SDimitry Andric StringRef IfDefName); 212*0fca6ea1SDimitry Andric void emitPredicateBitset(raw_ostream &OS, StringRef IfDefName); 213*0fca6ea1SDimitry Andric void emitTemporariesDecl(raw_ostream &OS, StringRef IfDefName); 214*0fca6ea1SDimitry Andric void emitTemporariesInit(raw_ostream &OS, unsigned MaxTemporaries, 215*0fca6ea1SDimitry Andric StringRef IfDefName); 216*0fca6ea1SDimitry Andric void emitPredicatesDecl(raw_ostream &OS, StringRef IfDefName); 217*0fca6ea1SDimitry Andric void emitPredicatesInit(raw_ostream &OS, StringRef IfDefName); 218*0fca6ea1SDimitry Andric 219*0fca6ea1SDimitry Andric // Map of predicates to their subtarget features. 220*0fca6ea1SDimitry Andric SubtargetFeatureInfoMap SubtargetFeatures; 221*0fca6ea1SDimitry Andric 222*0fca6ea1SDimitry Andric std::map<std::string, unsigned> HwModes; 223*0fca6ea1SDimitry Andric }; 224*0fca6ea1SDimitry Andric } // namespace llvm 225*0fca6ea1SDimitry Andric 226*0fca6ea1SDimitry Andric #endif 227