1 //===- JSONBackend.cpp - Generate a JSON dump of all records. -*- C++ -*-=====// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This TableGen back end generates a machine-readable representation 10 // of all the classes and records defined by the input, in JSON format. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/Support/Casting.h" 15 #include "llvm/Support/Debug.h" 16 #include "llvm/Support/JSON.h" 17 #include "llvm/TableGen/Error.h" 18 #include "llvm/TableGen/Record.h" 19 20 #define DEBUG_TYPE "json-emitter" 21 22 using namespace llvm; 23 24 namespace { 25 26 class JSONEmitter { 27 private: 28 const RecordKeeper &Records; 29 30 json::Value translateInit(const Init &I); 31 32 public: 33 explicit JSONEmitter(const RecordKeeper &R) : Records(R) {} 34 35 void run(raw_ostream &OS); 36 }; 37 38 } // end anonymous namespace 39 40 json::Value JSONEmitter::translateInit(const Init &I) { 41 // Init subclasses that we return as JSON primitive values of one 42 // kind or another. 43 44 if (isa<UnsetInit>(&I)) 45 return nullptr; 46 if (const auto *Bit = dyn_cast<BitInit>(&I)) 47 return Bit->getValue() ? 1 : 0; 48 if (const auto *Bits = dyn_cast<BitsInit>(&I)) { 49 json::Array Array; 50 for (unsigned Idx = 0, E = Bits->getNumBits(); Idx < E; ++Idx) 51 Array.push_back(translateInit(*Bits->getBit(Idx))); 52 return std::move(Array); 53 } 54 if (const auto *Int = dyn_cast<IntInit>(&I)) 55 return Int->getValue(); 56 if (const auto *Str = dyn_cast<StringInit>(&I)) 57 return Str->getValue(); 58 if (const auto *List = dyn_cast<ListInit>(&I)) { 59 json::Array Array; 60 for (const auto *Val : *List) 61 Array.push_back(translateInit(*Val)); 62 return std::move(Array); 63 } 64 65 // Init subclasses that we return as JSON objects containing a 66 // 'kind' discriminator. For these, we also provide the same 67 // translation back into TableGen input syntax that -print-records 68 // would give. 69 70 json::Object Obj; 71 Obj["printable"] = I.getAsString(); 72 73 if (const auto *Def = dyn_cast<DefInit>(&I)) { 74 Obj["kind"] = "def"; 75 Obj["def"] = Def->getDef()->getName(); 76 return std::move(Obj); 77 } 78 if (const auto *Var = dyn_cast<VarInit>(&I)) { 79 Obj["kind"] = "var"; 80 Obj["var"] = Var->getName(); 81 return std::move(Obj); 82 } 83 if (const auto *VarBit = dyn_cast<VarBitInit>(&I)) { 84 if (const auto *Var = dyn_cast<VarInit>(VarBit->getBitVar())) { 85 Obj["kind"] = "varbit"; 86 Obj["var"] = Var->getName(); 87 Obj["index"] = VarBit->getBitNum(); 88 return std::move(Obj); 89 } 90 } 91 if (const auto *Dag = dyn_cast<DagInit>(&I)) { 92 Obj["kind"] = "dag"; 93 Obj["operator"] = translateInit(*Dag->getOperator()); 94 if (auto name = Dag->getName()) 95 Obj["name"] = name->getAsUnquotedString(); 96 json::Array Args; 97 for (unsigned Idx = 0, E = Dag->getNumArgs(); Idx < E; ++Idx) { 98 json::Array Arg; 99 Arg.push_back(translateInit(*Dag->getArg(Idx))); 100 if (const auto ArgName = Dag->getArgName(Idx)) 101 Arg.push_back(ArgName->getAsUnquotedString()); 102 else 103 Arg.push_back(nullptr); 104 Args.push_back(std::move(Arg)); 105 } 106 Obj["args"] = std::move(Args); 107 return std::move(Obj); 108 } 109 110 // Final fallback: anything that gets past here is simply given a 111 // kind field of 'complex', and the only other field is the standard 112 // 'printable' representation. 113 assert(!I.isConcrete()); 114 Obj["kind"] = "complex"; 115 return std::move(Obj); 116 } 117 118 void JSONEmitter::run(raw_ostream &OS) { 119 json::Object Root; 120 121 Root["!tablegen_json_version"] = 1; 122 123 // Prepare the arrays that will list the instances of every class. 124 // We mostly fill those in by iterating over the superclasses of 125 // each def, but we also want to ensure we store an empty list for a 126 // class with no instances at all, so we do a preliminary iteration 127 // over the classes, invoking std::map::operator[] to default- 128 // construct the array for each one. 129 std::map<std::string, json::Array> InstanceLists; 130 for (const auto &[ClassName, ClassRec] : Records.getClasses()) 131 InstanceLists.emplace(ClassRec->getNameInitAsString(), json::Array()); 132 133 // Main iteration over the defs. 134 for (const auto &[DefName, Def] : Records.getDefs()) { 135 const std::string Name = Def->getNameInitAsString(); 136 137 json::Object Obj; 138 json::Array Fields; 139 140 for (const RecordVal &RV : Def->getValues()) { 141 if (!Def->isTemplateArg(RV.getNameInit())) { 142 auto Name = RV.getNameInitAsString(); 143 if (RV.isNonconcreteOK()) 144 Fields.push_back(Name); 145 Obj[Name] = translateInit(*RV.getValue()); 146 } 147 } 148 149 Obj["!fields"] = std::move(Fields); 150 151 json::Array SuperClasses; 152 // Add this def to the instance list for each of its superclasses. 153 for (const Record *SuperClass : Def->getSuperClasses()) { 154 std::string SuperName = SuperClass->getNameInitAsString(); 155 SuperClasses.push_back(SuperName); 156 InstanceLists[SuperName].push_back(Name); 157 } 158 159 Obj["!superclasses"] = std::move(SuperClasses); 160 161 Obj["!name"] = Name; 162 Obj["!anonymous"] = Def->isAnonymous(); 163 164 json::Array Locs; 165 for (const SMLoc Loc : Def->getLoc()) 166 Locs.push_back(SrcMgr.getFormattedLocationNoOffset(Loc)); 167 Obj["!locs"] = std::move(Locs); 168 169 Root[Name] = std::move(Obj); 170 } 171 172 // Make a JSON object from the std::map of instance lists. 173 json::Object InstanceOf; 174 for (auto &[ClassName, Instances] : InstanceLists) 175 InstanceOf[ClassName] = std::move(Instances); 176 Root["!instanceof"] = std::move(InstanceOf); 177 178 // Done. Write the output. 179 OS << json::Value(std::move(Root)) << "\n"; 180 } 181 182 void llvm::EmitJSON(const RecordKeeper &RK, raw_ostream &OS) { 183 JSONEmitter(RK).run(OS); 184 } 185