16a8c6cadSSimon Tatham //===- JSONBackend.cpp - Generate a JSON dump of all records. -*- C++ -*-=====// 26a8c6cadSSimon Tatham // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 66a8c6cadSSimon Tatham // 76a8c6cadSSimon Tatham //===----------------------------------------------------------------------===// 86a8c6cadSSimon Tatham // 96a8c6cadSSimon Tatham // This TableGen back end generates a machine-readable representation 106a8c6cadSSimon Tatham // of all the classes and records defined by the input, in JSON format. 116a8c6cadSSimon Tatham // 126a8c6cadSSimon Tatham //===----------------------------------------------------------------------===// 136a8c6cadSSimon Tatham 1492f49b89Sserge-sans-paille #include "llvm/Support/Casting.h" 156a8c6cadSSimon Tatham #include "llvm/Support/Debug.h" 1692f49b89Sserge-sans-paille #include "llvm/Support/ErrorHandling.h" 176a8c6cadSSimon Tatham #include "llvm/Support/JSON.h" 1856602a48Sostannard #include "llvm/TableGen/Error.h" 1992f49b89Sserge-sans-paille #include "llvm/TableGen/Record.h" 206a8c6cadSSimon Tatham 216a8c6cadSSimon Tatham #define DEBUG_TYPE "json-emitter" 226a8c6cadSSimon Tatham 236a8c6cadSSimon Tatham using namespace llvm; 246a8c6cadSSimon Tatham 256a8c6cadSSimon Tatham namespace { 266a8c6cadSSimon Tatham 276a8c6cadSSimon Tatham class JSONEmitter { 286a8c6cadSSimon Tatham private: 29*bcde45baSRahul Joshi const RecordKeeper &Records; 306a8c6cadSSimon Tatham 316a8c6cadSSimon Tatham json::Value translateInit(const Init &I); 326a8c6cadSSimon Tatham 336a8c6cadSSimon Tatham public: 34*bcde45baSRahul Joshi explicit JSONEmitter(const RecordKeeper &R) : Records(R) {} 356a8c6cadSSimon Tatham 366a8c6cadSSimon Tatham void run(raw_ostream &OS); 376a8c6cadSSimon Tatham }; 386a8c6cadSSimon Tatham 396a8c6cadSSimon Tatham } // end anonymous namespace 406a8c6cadSSimon Tatham 416a8c6cadSSimon Tatham json::Value JSONEmitter::translateInit(const Init &I) { 426a8c6cadSSimon Tatham // Init subclasses that we return as JSON primitive values of one 436a8c6cadSSimon Tatham // kind or another. 446a8c6cadSSimon Tatham 45*bcde45baSRahul Joshi if (isa<UnsetInit>(&I)) 466a8c6cadSSimon Tatham return nullptr; 47*bcde45baSRahul Joshi if (const auto *Bit = dyn_cast<BitInit>(&I)) 486a8c6cadSSimon Tatham return Bit->getValue() ? 1 : 0; 49*bcde45baSRahul Joshi if (const auto *Bits = dyn_cast<BitsInit>(&I)) { 50*bcde45baSRahul Joshi json::Array Array; 51*bcde45baSRahul Joshi for (unsigned Idx = 0, E = Bits->getNumBits(); Idx < E; ++Idx) 52*bcde45baSRahul Joshi Array.push_back(translateInit(*Bits->getBit(Idx))); 53*bcde45baSRahul Joshi return std::move(Array); 54*bcde45baSRahul Joshi } 55*bcde45baSRahul Joshi if (const auto *Int = dyn_cast<IntInit>(&I)) 566a8c6cadSSimon Tatham return Int->getValue(); 57*bcde45baSRahul Joshi if (const auto *Str = dyn_cast<StringInit>(&I)) 586a8c6cadSSimon Tatham return Str->getValue(); 59*bcde45baSRahul Joshi if (const auto *List = dyn_cast<ListInit>(&I)) { 60*bcde45baSRahul Joshi json::Array Array; 61*bcde45baSRahul Joshi for (const auto *Val : *List) 62*bcde45baSRahul Joshi Array.push_back(translateInit(*Val)); 63*bcde45baSRahul Joshi return std::move(Array); 646a8c6cadSSimon Tatham } 656a8c6cadSSimon Tatham 666a8c6cadSSimon Tatham // Init subclasses that we return as JSON objects containing a 676a8c6cadSSimon Tatham // 'kind' discriminator. For these, we also provide the same 686a8c6cadSSimon Tatham // translation back into TableGen input syntax that -print-records 696a8c6cadSSimon Tatham // would give. 706a8c6cadSSimon Tatham 71*bcde45baSRahul Joshi json::Object Obj; 72*bcde45baSRahul Joshi Obj["printable"] = I.getAsString(); 736a8c6cadSSimon Tatham 74*bcde45baSRahul Joshi if (const auto *Def = dyn_cast<DefInit>(&I)) { 75*bcde45baSRahul Joshi Obj["kind"] = "def"; 76*bcde45baSRahul Joshi Obj["def"] = Def->getDef()->getName(); 77*bcde45baSRahul Joshi return std::move(Obj); 786a8c6cadSSimon Tatham } 79*bcde45baSRahul Joshi if (const auto *Var = dyn_cast<VarInit>(&I)) { 80*bcde45baSRahul Joshi Obj["kind"] = "var"; 81*bcde45baSRahul Joshi Obj["var"] = Var->getName(); 82*bcde45baSRahul Joshi return std::move(Obj); 83*bcde45baSRahul Joshi } 84*bcde45baSRahul Joshi if (const auto *VarBit = dyn_cast<VarBitInit>(&I)) { 85*bcde45baSRahul Joshi if (const auto *Var = dyn_cast<VarInit>(VarBit->getBitVar())) { 86*bcde45baSRahul Joshi Obj["kind"] = "varbit"; 87*bcde45baSRahul Joshi Obj["var"] = Var->getName(); 88*bcde45baSRahul Joshi Obj["index"] = VarBit->getBitNum(); 89*bcde45baSRahul Joshi return std::move(Obj); 90*bcde45baSRahul Joshi } 91*bcde45baSRahul Joshi } 92*bcde45baSRahul Joshi if (const auto *Dag = dyn_cast<DagInit>(&I)) { 93*bcde45baSRahul Joshi Obj["kind"] = "dag"; 94*bcde45baSRahul Joshi Obj["operator"] = translateInit(*Dag->getOperator()); 956a8c6cadSSimon Tatham if (auto name = Dag->getName()) 96*bcde45baSRahul Joshi Obj["name"] = name->getAsUnquotedString(); 97*bcde45baSRahul Joshi json::Array Args; 98*bcde45baSRahul Joshi for (unsigned Idx = 0, E = Dag->getNumArgs(); Idx < E; ++Idx) { 99*bcde45baSRahul Joshi json::Array Arg; 100*bcde45baSRahul Joshi Arg.push_back(translateInit(*Dag->getArg(Idx))); 101*bcde45baSRahul Joshi if (const auto ArgName = Dag->getArgName(Idx)) 102*bcde45baSRahul Joshi Arg.push_back(ArgName->getAsUnquotedString()); 1036a8c6cadSSimon Tatham else 104*bcde45baSRahul Joshi Arg.push_back(nullptr); 105*bcde45baSRahul Joshi Args.push_back(std::move(Arg)); 1066a8c6cadSSimon Tatham } 107*bcde45baSRahul Joshi Obj["args"] = std::move(Args); 108*bcde45baSRahul Joshi return std::move(Obj); 1096a8c6cadSSimon Tatham } 1106a8c6cadSSimon Tatham 1116a8c6cadSSimon Tatham // Final fallback: anything that gets past here is simply given a 1126a8c6cadSSimon Tatham // kind field of 'complex', and the only other field is the standard 1136a8c6cadSSimon Tatham // 'printable' representation. 1146a8c6cadSSimon Tatham assert(!I.isConcrete()); 115*bcde45baSRahul Joshi Obj["kind"] = "complex"; 116*bcde45baSRahul Joshi return std::move(Obj); 1176a8c6cadSSimon Tatham } 1186a8c6cadSSimon Tatham 1196a8c6cadSSimon Tatham void JSONEmitter::run(raw_ostream &OS) { 120*bcde45baSRahul Joshi json::Object Root; 1216a8c6cadSSimon Tatham 122*bcde45baSRahul Joshi Root["!tablegen_json_version"] = 1; 1236a8c6cadSSimon Tatham 1246a8c6cadSSimon Tatham // Prepare the arrays that will list the instances of every class. 1256a8c6cadSSimon Tatham // We mostly fill those in by iterating over the superclasses of 1266a8c6cadSSimon Tatham // each def, but we also want to ensure we store an empty list for a 1276a8c6cadSSimon Tatham // class with no instances at all, so we do a preliminary iteration 1286a8c6cadSSimon Tatham // over the classes, invoking std::map::operator[] to default- 1296a8c6cadSSimon Tatham // construct the array for each one. 130*bcde45baSRahul Joshi std::map<std::string, json::Array> InstanceLists; 131*bcde45baSRahul Joshi for (const auto &[ClassName, ClassRec] : Records.getClasses()) 132*bcde45baSRahul Joshi InstanceLists.emplace(ClassRec->getNameInitAsString(), json::Array()); 1336a8c6cadSSimon Tatham 1346a8c6cadSSimon Tatham // Main iteration over the defs. 135*bcde45baSRahul Joshi for (const auto &[DefName, Def] : Records.getDefs()) { 136*bcde45baSRahul Joshi const std::string Name = Def->getNameInitAsString(); 1376a8c6cadSSimon Tatham 138*bcde45baSRahul Joshi json::Object Obj; 139*bcde45baSRahul Joshi json::Array Fields; 1406a8c6cadSSimon Tatham 141*bcde45baSRahul Joshi for (const RecordVal &RV : Def->getValues()) { 142*bcde45baSRahul Joshi if (!Def->isTemplateArg(RV.getNameInit())) { 1436a8c6cadSSimon Tatham auto Name = RV.getNameInitAsString(); 144aa7968a8SPaul C. Anagnostopoulos if (RV.isNonconcreteOK()) 145*bcde45baSRahul Joshi Fields.push_back(Name); 146*bcde45baSRahul Joshi Obj[Name] = translateInit(*RV.getValue()); 1476a8c6cadSSimon Tatham } 1486a8c6cadSSimon Tatham } 1496a8c6cadSSimon Tatham 150*bcde45baSRahul Joshi Obj["!fields"] = std::move(Fields); 1516a8c6cadSSimon Tatham 152*bcde45baSRahul Joshi json::Array SuperClasses; 1536a8c6cadSSimon Tatham // Add this def to the instance list for each of its superclasses. 154*bcde45baSRahul Joshi for (const auto &[SuperClass, Loc] : Def->getSuperClasses()) { 155*bcde45baSRahul Joshi std::string SuperName = SuperClass->getNameInitAsString(); 156*bcde45baSRahul Joshi SuperClasses.push_back(SuperName); 157*bcde45baSRahul Joshi InstanceLists[SuperName].push_back(Name); 1586a8c6cadSSimon Tatham } 159*bcde45baSRahul Joshi 160*bcde45baSRahul Joshi Obj["!superclasses"] = std::move(SuperClasses); 161*bcde45baSRahul Joshi 162*bcde45baSRahul Joshi Obj["!name"] = Name; 163*bcde45baSRahul Joshi Obj["!anonymous"] = Def->isAnonymous(); 164*bcde45baSRahul Joshi 165*bcde45baSRahul Joshi json::Array Locs; 166*bcde45baSRahul Joshi for (const SMLoc Loc : Def->getLoc()) 167*bcde45baSRahul Joshi Locs.push_back(SrcMgr.getFormattedLocationNoOffset(Loc)); 168*bcde45baSRahul Joshi Obj["!locs"] = std::move(Locs); 169*bcde45baSRahul Joshi 170*bcde45baSRahul Joshi Root[Name] = std::move(Obj); 1716a8c6cadSSimon Tatham } 1726a8c6cadSSimon Tatham 1736a8c6cadSSimon Tatham // Make a JSON object from the std::map of instance lists. 174*bcde45baSRahul Joshi json::Object InstanceOf; 175*bcde45baSRahul Joshi for (auto &[ClassName, Instances] : InstanceLists) 176*bcde45baSRahul Joshi InstanceOf[ClassName] = std::move(Instances); 177*bcde45baSRahul Joshi Root["!instanceof"] = std::move(InstanceOf); 1786a8c6cadSSimon Tatham 1796a8c6cadSSimon Tatham // Done. Write the output. 180*bcde45baSRahul Joshi OS << json::Value(std::move(Root)) << "\n"; 1816a8c6cadSSimon Tatham } 1826a8c6cadSSimon Tatham 183*bcde45baSRahul Joshi void llvm::EmitJSON(const RecordKeeper &RK, raw_ostream &OS) { 184*bcde45baSRahul Joshi JSONEmitter(RK).run(OS); 185*bcde45baSRahul Joshi } 186