diff options
Diffstat (limited to 'contrib/llvm-project/llvm/include/llvm/TableGen/Record.h')
-rw-r--r-- | contrib/llvm-project/llvm/include/llvm/TableGen/Record.h | 362 |
1 files changed, 214 insertions, 148 deletions
diff --git a/contrib/llvm-project/llvm/include/llvm/TableGen/Record.h b/contrib/llvm-project/llvm/include/llvm/TableGen/Record.h index a082fe5d74a1..b71aa0a89056 100644 --- a/contrib/llvm-project/llvm/include/llvm/TableGen/Record.h +++ b/contrib/llvm-project/llvm/include/llvm/TableGen/Record.h @@ -20,10 +20,12 @@ #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SMLoc.h" +#include "llvm/Support/Timer.h" #include "llvm/Support/TrailingObjects.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -57,7 +59,6 @@ public: enum RecTyKind { BitRecTyKind, BitsRecTyKind, - CodeRecTyKind, IntRecTyKind, StringRecTyKind, ListRecTyKind, @@ -67,6 +68,7 @@ public: private: RecTyKind Kind; + /// ListRecTy of the list that has elements of this type. ListRecTy *ListTy = nullptr; public: @@ -87,7 +89,7 @@ public: /// a bit set is not an int, but they are convertible. virtual bool typeIsA(const RecTy *RHS) const; - /// Returns the type representing list<this>. + /// Returns the type representing list<thistype>. ListRecTy *getListTy(); }; @@ -136,24 +138,6 @@ public: bool typeIsA(const RecTy *RHS) const override; }; -/// 'code' - Represent a code fragment -class CodeRecTy : public RecTy { - static CodeRecTy Shared; - - CodeRecTy() : RecTy(CodeRecTyKind) {} - -public: - static bool classof(const RecTy *RT) { - return RT->getRecTyKind() == CodeRecTyKind; - } - - static CodeRecTy *get() { return &Shared; } - - std::string getAsString() const override { return "code"; } - - bool typeIsConvertibleTo(const RecTy *RHS) const override; -}; - /// 'int' - Represent an integer value of no particular size class IntRecTy : public RecTy { static IntRecTy Shared; @@ -190,14 +174,14 @@ public: bool typeIsConvertibleTo(const RecTy *RHS) const override; }; -/// 'list<Ty>' - Represent a list of values, all of which must be of -/// the specified type. +/// 'list<Ty>' - Represent a list of element values, all of which must be of +/// the specified type. The type is stored in ElementTy. class ListRecTy : public RecTy { friend ListRecTy *RecTy::getListTy(); - RecTy *Ty; + RecTy *ElementTy; - explicit ListRecTy(RecTy *T) : RecTy(ListRecTyKind), Ty(T) {} + explicit ListRecTy(RecTy *T) : RecTy(ListRecTyKind), ElementTy(T) {} public: static bool classof(const RecTy *RT) { @@ -205,7 +189,7 @@ public: } static ListRecTy *get(RecTy *T) { return T->getListTy(); } - RecTy *getElementType() const { return Ty; } + RecTy *getElementType() const { return ElementTy; } std::string getAsString() const override; @@ -304,7 +288,6 @@ protected: IK_FirstTypedInit, IK_BitInit, IK_BitsInit, - IK_CodeInit, IK_DagInit, IK_DefInit, IK_FieldInit, @@ -337,6 +320,7 @@ private: virtual void anchor(); public: + /// Get the kind (type) of the value. InitKind getKind() const { return Kind; } protected: @@ -347,63 +331,61 @@ public: Init &operator=(const Init &) = delete; virtual ~Init() = default; - /// This virtual method should be overridden by values that may - /// not be completely specified yet. + /// Is this a complete value with no unset (uninitialized) subvalues? virtual bool isComplete() const { return true; } /// Is this a concrete and fully resolved value without any references or /// stuck operations? Unset values are concrete. virtual bool isConcrete() const { return false; } - /// Print out this value. + /// Print this value. void print(raw_ostream &OS) const { OS << getAsString(); } - /// Convert this value to a string form. + /// Convert this value to a literal form. virtual std::string getAsString() const = 0; - /// Convert this value to a string form, - /// without adding quote markers. This primaruly affects - /// StringInits where we will not surround the string value with - /// quotes. + + /// Convert this value to a literal form, + /// without adding quotes around a string. virtual std::string getAsUnquotedString() const { return getAsString(); } - /// Debugging method that may be called through a debugger, just + /// Debugging method that may be called through a debugger; just /// invokes print on stderr. void dump() const; - /// If this initializer is convertible to Ty, return an initializer whose - /// type is-a Ty, generating a !cast operation if required. Otherwise, return - /// nullptr. + /// If this value is convertible to type \p Ty, return a value whose + /// type is \p Ty, generating a !cast operation if required. + /// Otherwise, return null. virtual Init *getCastTo(RecTy *Ty) const = 0; - /// Convert to an initializer whose type is-a Ty, or return nullptr if this - /// is not possible (this can happen if the initializer's type is convertible - /// to Ty, but there are unresolved references). + /// Convert to a value whose type is \p Ty, or return null if this + /// is not possible. This can happen if the value's type is convertible + /// to \p Ty, but there are unresolved references. virtual Init *convertInitializerTo(RecTy *Ty) const = 0; - /// This method is used to implement the bitrange - /// selection operator. Given an initializer, it selects the specified bits - /// out, returning them as a new init of bits type. If it is not legal to use - /// the bit subscript operator on this initializer, return null. + /// This function is used to implement the bit range + /// selection operator. Given a value, it selects the specified bits, + /// returning them as a new \p Init of type \p bits. If it is not legal + /// to use the bit selection operator on this value, null is returned. virtual Init *convertInitializerBitRange(ArrayRef<unsigned> Bits) const { return nullptr; } - /// This method is used to implement the list slice - /// selection operator. Given an initializer, it selects the specified list - /// elements, returning them as a new init of list type. If it is not legal - /// to take a slice of this, return null. + /// This function is used to implement the list slice + /// selection operator. Given a value, it selects the specified list + /// elements, returning them as a new \p Init of type \p list. If it + /// is not legal to use the slice operator, null is returned. virtual Init *convertInitListSlice(ArrayRef<unsigned> Elements) const { return nullptr; } - /// This method is used to implement the FieldInit class. - /// Implementors of this method should return the type of the named field if - /// they are of record type. + /// This function is used to implement the FieldInit class. + /// Implementors of this method should return the type of the named + /// field if they are of type record. virtual RecTy *getFieldType(StringInit *FieldName) const { return nullptr; } - /// This method is used by classes that refer to other + /// This function is used by classes that refer to other /// variables which may not be defined at the time the expression is formed. /// If a value is set for the variable later, this method will be called on /// users of the value to allow the value to propagate out. @@ -411,8 +393,7 @@ public: return const_cast<Init *>(this); } - /// This method is used to return the initializer for the specified - /// bit. + /// Get the \p Init value of the specified bit. virtual Init *getBit(unsigned Bit) const = 0; }; @@ -420,14 +401,14 @@ inline raw_ostream &operator<<(raw_ostream &OS, const Init &I) { I.print(OS); return OS; } -/// This is the common super-class of types that have a specific, -/// explicit, type. +/// This is the common superclass of types that have a specific, +/// explicit type, stored in ValueTy. class TypedInit : public Init { - RecTy *Ty; + RecTy *ValueTy; protected: explicit TypedInit(InitKind K, RecTy *T, uint8_t Opc = 0) - : Init(K, Opc), Ty(T) {} + : Init(K, Opc), ValueTy(T) {} public: TypedInit(const TypedInit &) = delete; @@ -438,7 +419,8 @@ public: I->getKind() <= IK_LastTypedInit; } - RecTy *getType() const { return Ty; } + /// Get the type of the Init as a RecTy. + RecTy *getType() const { return ValueTy; } Init *getCastTo(RecTy *Ty) const override; Init *convertInitializerTo(RecTy *Ty) const override; @@ -448,12 +430,11 @@ public: /// This method is used to implement the FieldInit class. /// Implementors of this method should return the type of the named field if - /// they are of record type. - /// + /// they are of type record. RecTy *getFieldType(StringInit *FieldName) const override; }; -/// '?' - Represents an uninitialized value +/// '?' - Represents an uninitialized value. class UnsetInit : public Init { UnsetInit() : Init(IK_UnsetInit) {} @@ -465,6 +446,7 @@ public: return I->getKind() == IK_UnsetInit; } + /// Get the singleton unset Init. static UnsetInit *get(); Init *getCastTo(RecTy *Ty) const override; @@ -474,8 +456,12 @@ public: return const_cast<UnsetInit*>(this); } + /// Is this a complete value with no unset (uninitialized) subvalues? bool isComplete() const override { return false; } + bool isConcrete() const override { return true; } + + /// Get the string representation of the Init. std::string getAsString() const override { return "?"; } }; @@ -592,10 +578,18 @@ public: /// "foo" - Represent an initialization by a string value. class StringInit : public TypedInit { +public: + enum StringFormat { + SF_String, // Format as "text" + SF_Code, // Format as [{text}] + }; + +private: StringRef Value; + StringFormat Format; - explicit StringInit(StringRef V) - : TypedInit(IK_StringInit, StringRecTy::get()), Value(V) {} + explicit StringInit(StringRef V, StringFormat Fmt) + : TypedInit(IK_StringInit, StringRecTy::get()), Value(V), Format(Fmt) {} public: StringInit(const StringInit &) = delete; @@ -605,50 +599,25 @@ public: return I->getKind() == IK_StringInit; } - static StringInit *get(StringRef); - - StringRef getValue() const { return Value; } - - Init *convertInitializerTo(RecTy *Ty) const override; - - bool isConcrete() const override { return true; } - std::string getAsString() const override { return "\"" + Value.str() + "\""; } - - std::string getAsUnquotedString() const override { - return std::string(Value); - } - - Init *getBit(unsigned Bit) const override { - llvm_unreachable("Illegal bit reference off string"); - } -}; - -class CodeInit : public TypedInit { - StringRef Value; - SMLoc Loc; - - explicit CodeInit(StringRef V, const SMLoc &Loc) - : TypedInit(IK_CodeInit, static_cast<RecTy *>(CodeRecTy::get())), - Value(V), Loc(Loc) {} - -public: - CodeInit(const StringInit &) = delete; - CodeInit &operator=(const StringInit &) = delete; + static StringInit *get(StringRef, StringFormat Fmt = SF_String); - static bool classof(const Init *I) { - return I->getKind() == IK_CodeInit; + static StringFormat determineFormat(StringFormat Fmt1, StringFormat Fmt2) { + return (Fmt1 == SF_Code || Fmt2 == SF_Code) ? SF_Code : SF_String; } - static CodeInit *get(StringRef, const SMLoc &Loc); - StringRef getValue() const { return Value; } - const SMLoc &getLoc() const { return Loc; } + StringFormat getFormat() const { return Format; } + bool hasCodeFormat() const { return Format == SF_Code; } Init *convertInitializerTo(RecTy *Ty) const override; bool isConcrete() const override { return true; } + std::string getAsString() const override { - return "[{" + Value.str() + "}]"; + if (Format == SF_String) + return "\"" + Value.str() + "\""; + else + return "[{" + Value.str() + "}]"; } std::string getAsUnquotedString() const override { @@ -755,7 +724,7 @@ public: /// class UnOpInit : public OpInit, public FoldingSetNode { public: - enum UnaryOp : uint8_t { CAST, HEAD, TAIL, SIZE, EMPTY, GETOP }; + enum UnaryOp : uint8_t { CAST, NOT, HEAD, TAIL, SIZE, EMPTY, GETDAGOP }; private: Init *LHS; @@ -804,9 +773,9 @@ public: /// !op (X, Y) - Combine two inits. class BinOpInit : public OpInit, public FoldingSetNode { public: - enum BinaryOp : uint8_t { ADD, MUL, AND, OR, SHL, SRA, SRL, LISTCONCAT, - LISTSPLAT, STRCONCAT, CONCAT, EQ, NE, LE, LT, GE, - GT, SETOP }; + enum BinaryOp : uint8_t { ADD, SUB, MUL, AND, OR, XOR, SHL, SRA, SRL, LISTCONCAT, + LISTSPLAT, STRCONCAT, INTERLEAVE, CONCAT, EQ, + NE, LE, LT, GE, GT, SETDAGOP }; private: Init *LHS, *RHS; @@ -826,7 +795,6 @@ public: RecTy *Type); static Init *getStrConcat(Init *lhs, Init *rhs); static Init *getListConcat(TypedInit *lhs, Init *rhs); - static Init *getListSplat(TypedInit *lhs, Init *rhs); void Profile(FoldingSetNodeID &ID) const; @@ -862,7 +830,7 @@ public: /// !op (X, Y, Z) - Combine two inits. class TernOpInit : public OpInit, public FoldingSetNode { public: - enum TernaryOp : uint8_t { SUBST, FOREACH, IF, DAG }; + enum TernaryOp : uint8_t { SUBST, FOREACH, FILTER, IF, DAG, SUBSTR }; private: Init *LHS, *MHS, *RHS; @@ -1397,30 +1365,70 @@ public: // High-Level Classes //===----------------------------------------------------------------------===// +/// This class represents a field in a record, including its name, type, +/// value, and source location. class RecordVal { friend class Record; +public: + enum FieldKind { + FK_Normal, // A normal record field. + FK_NonconcreteOK, // A field that can be nonconcrete ('field' keyword). + FK_TemplateArg, // A template argument. + }; + +private: Init *Name; - PointerIntPair<RecTy *, 1, bool> TyAndPrefix; + SMLoc Loc; // Source location of definition of name. + PointerIntPair<RecTy *, 2, FieldKind> TyAndKind; Init *Value; public: - RecordVal(Init *N, RecTy *T, bool P); + RecordVal(Init *N, RecTy *T, FieldKind K); + RecordVal(Init *N, SMLoc Loc, RecTy *T, FieldKind K); + /// Get the name of the field as a StringRef. StringRef getName() const; + + /// Get the name of the field as an Init. Init *getNameInit() const { return Name; } + /// Get the name of the field as a std::string. std::string getNameInitAsString() const { return getNameInit()->getAsUnquotedString(); } - bool getPrefix() const { return TyAndPrefix.getInt(); } - RecTy *getType() const { return TyAndPrefix.getPointer(); } + /// Get the source location of the point where the field was defined. + const SMLoc &getLoc() const { return Loc; } + + /// Is this a field where nonconcrete values are okay? + bool isNonconcreteOK() const { + return TyAndKind.getInt() == FK_NonconcreteOK; + } + + /// Is this a template argument? + bool isTemplateArg() const { + return TyAndKind.getInt() == FK_TemplateArg; + } + + /// Get the type of the field value as a RecTy. + RecTy *getType() const { return TyAndKind.getPointer(); } + + /// Get the type of the field for printing purposes. + std::string getPrintType() const; + + /// Get the value of the field as an Init. Init *getValue() const { return Value; } + /// Set the value of the field from an Init. bool setValue(Init *V); + /// Set the value and source location of the field. + bool setValue(Init *V, SMLoc NewLoc); + void dump() const; + + /// Print the value to an output stream, possibly with a semicolon. void print(raw_ostream &OS, bool PrintSem = true) const; }; @@ -1438,15 +1446,18 @@ class Record { SmallVector<SMLoc, 4> Locs; SmallVector<Init *, 0> TemplateArgs; SmallVector<RecordVal, 0> Values; + // Vector of [source location, condition Init, message Init]. + SmallVector<std::tuple<SMLoc, Init *, Init *>, 0> Assertions; - // All superclasses in the inheritance forest in reverse preorder (yes, it + // All superclasses in the inheritance forest in post-order (yes, it // must be a forest; diamond-shaped inheritance is not allowed). SmallVector<std::pair<Record *, SMRange>, 0> SuperClasses; // Tracks Record instances. Not owned by Record. RecordKeeper &TrackedRecords; - DefInit *TheInit = nullptr; + // The DefInit corresponding to this record. + DefInit *CorrespondingDefInit = nullptr; // Unique record ID. unsigned ID; @@ -1470,8 +1481,8 @@ public: : Record(StringInit::get(N), locs, records, false, Class) {} // When copy-constructing a Record, we must still guarantee a globally unique - // ID number. Don't copy TheInit either since it's owned by the original - // record. All other fields can be copied normally. + // ID number. Don't copy CorrespondingDefInit either, since it's owned by the + // original record. All other fields can be copied normally. Record(const Record &O) : Name(O.Name), Locs(O.Locs), TemplateArgs(O.TemplateArgs), Values(O.Values), SuperClasses(O.SuperClasses), @@ -1511,11 +1522,18 @@ public: ArrayRef<RecordVal> getValues() const { return Values; } + ArrayRef<std::tuple<SMLoc, Init *, Init *>> getAssertions() const { + return Assertions; + } + ArrayRef<std::pair<Record *, SMRange>> getSuperClasses() const { return SuperClasses; } - /// Append the direct super classes of this record to Classes. + /// Determine whether this record has the specified direct superclass. + bool hasDirectSuperClass(const Record *SuperClass) const; + + /// Append the direct superclasses of this record to Classes. void getDirectSuperClasses(SmallVectorImpl<Record *> &Classes) const; bool isTemplateArg(Init *Name) const { @@ -1565,6 +1583,10 @@ public: removeValue(StringInit::get(Name)); } + void addAssertion(SMLoc Loc, Init *Condition, Init *Message) { + Assertions.push_back(std::make_tuple(Loc, Condition, Message)); + } + bool isSubClassOf(const Record *R) const { for (const auto &SCPair : SuperClasses) if (SCPair.first == R) @@ -1585,7 +1607,8 @@ public: } void addSuperClass(Record *R, SMRange Range) { - assert(!TheInit && "changing type of record after it has been referenced"); + assert(!CorrespondingDefInit && + "changing type of record after it has been referenced"); assert(!isSubClassOf(R) && "Already subclassing record!"); SuperClasses.push_back(std::make_pair(R, Range)); } @@ -1612,13 +1635,15 @@ public: return IsAnonymous; } - void print(raw_ostream &OS) const; void dump() const; //===--------------------------------------------------------------------===// // High-level methods useful to tablegen back-ends // + ///Return the source location for the named field. + SMLoc getFieldLoc(StringRef FieldName) const; + /// Return the initializer for a value with the specified name, /// or throw an exception if the field does not exist. Init *getValueInit(StringRef FieldName) const; @@ -1634,6 +1659,11 @@ public: StringRef getValueAsString(StringRef FieldName) const; /// This method looks up the specified field and returns + /// its value as a string, throwing an exception if the field if the value is + /// not a string and llvm::Optional() if the field does not exist. + llvm::Optional<StringRef> getValueAsOptionalString(StringRef FieldName) const; + + /// This method looks up the specified field and returns /// its value as a BitsInit, throwing an exception if the field does not exist /// or if the value is not the right type. BitsInit *getValueAsBitsInit(StringRef FieldName) const; @@ -1694,26 +1724,50 @@ raw_ostream &operator<<(raw_ostream &OS, const Record &R); class RecordKeeper { friend class RecordRecTy; + using RecordMap = std::map<std::string, std::unique_ptr<Record>, std::less<>>; + using GlobalMap = std::map<std::string, Init *, std::less<>>; + + std::string InputFilename; RecordMap Classes, Defs; + mutable StringMap<std::vector<Record *>> ClassRecordsMap; FoldingSet<RecordRecTy> RecordTypePool; std::map<std::string, Init *, std::less<>> ExtraGlobals; unsigned AnonCounter = 0; + // These members are for the phase timing feature. We need a timer group, + // the last timer started, and a flag to say whether the last timer + // is the special "backend overall timer." + TimerGroup *TimingGroup = nullptr; + Timer *LastTimer = nullptr; + bool BackendTimer = false; + public: + /// Get the main TableGen input file's name. + const std::string getInputFilename() const { return InputFilename; } + + /// Get the map of classes. const RecordMap &getClasses() const { return Classes; } + + /// Get the map of records (defs). const RecordMap &getDefs() const { return Defs; } + /// Get the map of global variables. + const GlobalMap &getGlobals() const { return ExtraGlobals; } + + /// Get the class with the specified name. Record *getClass(StringRef Name) const { auto I = Classes.find(Name); return I == Classes.end() ? nullptr : I->second.get(); } + /// Get the concrete record with the specified name. Record *getDef(StringRef Name) const { auto I = Defs.find(Name); return I == Defs.end() ? nullptr : I->second.get(); } + /// Get the \p Init value of the specified global variable. Init *getGlobal(StringRef Name) const { if (Record *R = getDef(Name)) return R->getDefInit(); @@ -1721,6 +1775,10 @@ public: return It == ExtraGlobals.end() ? nullptr : It->second; } + void saveInputFilename(std::string Filename) { + InputFilename = Filename; + } + void addClass(std::unique_ptr<Record> R) { bool Ins = Classes.insert(std::make_pair(std::string(R->getName()), std::move(R))).second; @@ -1744,14 +1802,42 @@ public: Init *getNewAnonymousName(); + /// Start phase timing; called if the --time-phases option is specified. + void startPhaseTiming() { + TimingGroup = new TimerGroup("TableGen", "TableGen Phase Timing"); + } + + /// Start timing a phase. Automatically stops any previous phase timer. + void startTimer(StringRef Name); + + /// Stop timing a phase. + void stopTimer(); + + /// Start timing the overall backend. If the backend itself starts a timer, + /// then this timer is cleared. + void startBackendTimer(StringRef Name); + + /// Stop timing the overall backend. + void stopBackendTimer(); + + /// Stop phase timing and print the report. + void stopPhaseTiming() { + if (TimingGroup) + delete TimingGroup; + } + //===--------------------------------------------------------------------===// - // High-level helper methods, useful for tablegen backends... + // High-level helper methods, useful for tablegen backends. - /// This method returns all concrete definitions - /// that derive from the specified class name. A class with the specified - /// name must exist. + /// Get all the concrete records that inherit from the one specified + /// class. The class must be defined. std::vector<Record *> getAllDerivedDefinitions(StringRef ClassName) const; + /// Get all the concrete records that inherit from all the specified + /// classes. The classes must be defined. + std::vector<Record *> getAllDerivedDefinitions( + ArrayRef<StringRef> ClassNames) const; + void dump() const; }; @@ -1781,8 +1867,6 @@ struct LessRecordFieldName { }; struct LessRecordRegister { - static bool ascii_isdigit(char x) { return x >= '0' && x <= '9'; } - struct RecordParts { SmallVector<std::pair< bool, StringRef>, 4> Parts; @@ -1793,18 +1877,18 @@ struct LessRecordRegister { size_t Len = 0; const char *Start = Rec.data(); const char *Curr = Start; - bool isDigitPart = ascii_isdigit(Curr[0]); + bool IsDigitPart = isDigit(Curr[0]); for (size_t I = 0, E = Rec.size(); I != E; ++I, ++Len) { - bool isDigit = ascii_isdigit(Curr[I]); - if (isDigit != isDigitPart) { - Parts.push_back(std::make_pair(isDigitPart, StringRef(Start, Len))); + bool IsDigit = isDigit(Curr[I]); + if (IsDigit != IsDigitPart) { + Parts.push_back(std::make_pair(IsDigitPart, StringRef(Start, Len))); Len = 0; Start = &Curr[I]; - isDigitPart = ascii_isdigit(Curr[I]); + IsDigitPart = isDigit(Curr[I]); } } // Push the last part. - Parts.push_back(std::make_pair(isDigitPart, StringRef(Start, Len))); + Parts.push_back(std::make_pair(IsDigitPart, StringRef(Start, Len))); } size_t size() { return Parts.size(); } @@ -1927,25 +2011,6 @@ public: bool keepUnsetBits() const override { return true; } }; -/// Resolve all references to a specific RecordVal. -// -// TODO: This is used for resolving references to template arguments, in a -// rather inefficient way. Change those uses to resolve all template -// arguments simultaneously and get rid of this class. -class RecordValResolver final : public Resolver { - const RecordVal *RV; - -public: - explicit RecordValResolver(Record &R, const RecordVal *RV) - : Resolver(&R), RV(RV) {} - - Init *resolve(Init *VarName) override { - if (VarName == RV->getNameInit()) - return RV->getValue(); - return nullptr; - } -}; - /// Delegate resolving to a sub-resolver, but shadow some variable names. class ShadowResolver final : public Resolver { Resolver &R; @@ -1996,6 +2061,7 @@ public: Init *resolve(Init *VarName) override; }; +void EmitDetailedRecords(RecordKeeper &RK, raw_ostream &OS); void EmitJSON(RecordKeeper &RK, raw_ostream &OS); } // end namespace llvm |