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