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 146a8c6cadSSimon Tatham #include "llvm/ADT/BitVector.h" 156a8c6cadSSimon Tatham #include "llvm/Support/Debug.h" 166a8c6cadSSimon Tatham #include "llvm/TableGen/Error.h" 176a8c6cadSSimon Tatham #include "llvm/TableGen/Record.h" 186a8c6cadSSimon Tatham #include "llvm/TableGen/TableGenBackend.h" 196a8c6cadSSimon Tatham #include "llvm/Support/JSON.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: 296a8c6cadSSimon Tatham RecordKeeper &Records; 306a8c6cadSSimon Tatham 316a8c6cadSSimon Tatham json::Value translateInit(const Init &I); 326a8c6cadSSimon Tatham json::Array listSuperclasses(const Record &R); 336a8c6cadSSimon Tatham 346a8c6cadSSimon Tatham public: 356a8c6cadSSimon Tatham JSONEmitter(RecordKeeper &R); 366a8c6cadSSimon Tatham 376a8c6cadSSimon Tatham void run(raw_ostream &OS); 386a8c6cadSSimon Tatham }; 396a8c6cadSSimon Tatham 406a8c6cadSSimon Tatham } // end anonymous namespace 416a8c6cadSSimon Tatham 426a8c6cadSSimon Tatham JSONEmitter::JSONEmitter(RecordKeeper &R) : Records(R) {} 436a8c6cadSSimon Tatham 446a8c6cadSSimon Tatham json::Value JSONEmitter::translateInit(const Init &I) { 456a8c6cadSSimon Tatham 466a8c6cadSSimon Tatham // Init subclasses that we return as JSON primitive values of one 476a8c6cadSSimon Tatham // kind or another. 486a8c6cadSSimon Tatham 496a8c6cadSSimon Tatham if (isa<UnsetInit>(&I)) { 506a8c6cadSSimon Tatham return nullptr; 516a8c6cadSSimon Tatham } else if (auto *Bit = dyn_cast<BitInit>(&I)) { 526a8c6cadSSimon Tatham return Bit->getValue() ? 1 : 0; 536a8c6cadSSimon Tatham } else if (auto *Bits = dyn_cast<BitsInit>(&I)) { 546a8c6cadSSimon Tatham json::Array array; 556a8c6cadSSimon Tatham for (unsigned i = 0, limit = Bits->getNumBits(); i < limit; i++) 566a8c6cadSSimon Tatham array.push_back(translateInit(*Bits->getBit(i))); 57*c55cf4afSBill Wendling return std::move(array); 586a8c6cadSSimon Tatham } else if (auto *Int = dyn_cast<IntInit>(&I)) { 596a8c6cadSSimon Tatham return Int->getValue(); 606a8c6cadSSimon Tatham } else if (auto *Str = dyn_cast<StringInit>(&I)) { 616a8c6cadSSimon Tatham return Str->getValue(); 626a8c6cadSSimon Tatham } else if (auto *Code = dyn_cast<CodeInit>(&I)) { 636a8c6cadSSimon Tatham return Code->getValue(); 646a8c6cadSSimon Tatham } else if (auto *List = dyn_cast<ListInit>(&I)) { 656a8c6cadSSimon Tatham json::Array array; 666a8c6cadSSimon Tatham for (auto val : *List) 676a8c6cadSSimon Tatham array.push_back(translateInit(*val)); 68*c55cf4afSBill Wendling return std::move(array); 696a8c6cadSSimon Tatham } 706a8c6cadSSimon Tatham 716a8c6cadSSimon Tatham // Init subclasses that we return as JSON objects containing a 726a8c6cadSSimon Tatham // 'kind' discriminator. For these, we also provide the same 736a8c6cadSSimon Tatham // translation back into TableGen input syntax that -print-records 746a8c6cadSSimon Tatham // would give. 756a8c6cadSSimon Tatham 766a8c6cadSSimon Tatham json::Object obj; 776a8c6cadSSimon Tatham obj["printable"] = I.getAsString(); 786a8c6cadSSimon Tatham 796a8c6cadSSimon Tatham if (auto *Def = dyn_cast<DefInit>(&I)) { 806a8c6cadSSimon Tatham obj["kind"] = "def"; 816a8c6cadSSimon Tatham obj["def"] = Def->getDef()->getName(); 82*c55cf4afSBill Wendling return std::move(obj); 836a8c6cadSSimon Tatham } else if (auto *Var = dyn_cast<VarInit>(&I)) { 846a8c6cadSSimon Tatham obj["kind"] = "var"; 856a8c6cadSSimon Tatham obj["var"] = Var->getName(); 86*c55cf4afSBill Wendling return std::move(obj); 876a8c6cadSSimon Tatham } else if (auto *VarBit = dyn_cast<VarBitInit>(&I)) { 886a8c6cadSSimon Tatham if (auto *Var = dyn_cast<VarInit>(VarBit->getBitVar())) { 896a8c6cadSSimon Tatham obj["kind"] = "varbit"; 906a8c6cadSSimon Tatham obj["var"] = Var->getName(); 916a8c6cadSSimon Tatham obj["index"] = VarBit->getBitNum(); 92*c55cf4afSBill Wendling return std::move(obj); 936a8c6cadSSimon Tatham } 946a8c6cadSSimon Tatham } else if (auto *Dag = dyn_cast<DagInit>(&I)) { 956a8c6cadSSimon Tatham obj["kind"] = "dag"; 966a8c6cadSSimon Tatham obj["operator"] = translateInit(*Dag->getOperator()); 976a8c6cadSSimon Tatham if (auto name = Dag->getName()) 986a8c6cadSSimon Tatham obj["name"] = name->getAsUnquotedString(); 996a8c6cadSSimon Tatham json::Array args; 1006a8c6cadSSimon Tatham for (unsigned i = 0, limit = Dag->getNumArgs(); i < limit; ++i) { 1016a8c6cadSSimon Tatham json::Array arg; 1026a8c6cadSSimon Tatham arg.push_back(translateInit(*Dag->getArg(i))); 1036a8c6cadSSimon Tatham if (auto argname = Dag->getArgName(i)) 1046a8c6cadSSimon Tatham arg.push_back(argname->getAsUnquotedString()); 1056a8c6cadSSimon Tatham else 1066a8c6cadSSimon Tatham arg.push_back(nullptr); 1076a8c6cadSSimon Tatham args.push_back(std::move(arg)); 1086a8c6cadSSimon Tatham } 1096a8c6cadSSimon Tatham obj["args"] = std::move(args); 110*c55cf4afSBill Wendling return std::move(obj); 1116a8c6cadSSimon Tatham } 1126a8c6cadSSimon Tatham 1136a8c6cadSSimon Tatham // Final fallback: anything that gets past here is simply given a 1146a8c6cadSSimon Tatham // kind field of 'complex', and the only other field is the standard 1156a8c6cadSSimon Tatham // 'printable' representation. 1166a8c6cadSSimon Tatham 1176a8c6cadSSimon Tatham assert(!I.isConcrete()); 1186a8c6cadSSimon Tatham obj["kind"] = "complex"; 119*c55cf4afSBill Wendling return std::move(obj); 1206a8c6cadSSimon Tatham } 1216a8c6cadSSimon Tatham 1226a8c6cadSSimon Tatham void JSONEmitter::run(raw_ostream &OS) { 1236a8c6cadSSimon Tatham json::Object root; 1246a8c6cadSSimon Tatham 1256a8c6cadSSimon Tatham root["!tablegen_json_version"] = 1; 1266a8c6cadSSimon Tatham 1276a8c6cadSSimon Tatham // Prepare the arrays that will list the instances of every class. 1286a8c6cadSSimon Tatham // We mostly fill those in by iterating over the superclasses of 1296a8c6cadSSimon Tatham // each def, but we also want to ensure we store an empty list for a 1306a8c6cadSSimon Tatham // class with no instances at all, so we do a preliminary iteration 1316a8c6cadSSimon Tatham // over the classes, invoking std::map::operator[] to default- 1326a8c6cadSSimon Tatham // construct the array for each one. 1336a8c6cadSSimon Tatham std::map<std::string, json::Array> instance_lists; 1346a8c6cadSSimon Tatham for (const auto &C : Records.getClasses()) { 1356a8c6cadSSimon Tatham auto &Name = C.second->getNameInitAsString(); 1366a8c6cadSSimon Tatham (void)instance_lists[Name]; 1376a8c6cadSSimon Tatham } 1386a8c6cadSSimon Tatham 1396a8c6cadSSimon Tatham // Main iteration over the defs. 1406a8c6cadSSimon Tatham for (const auto &D : Records.getDefs()) { 1416a8c6cadSSimon Tatham auto &Name = D.second->getNameInitAsString(); 1426a8c6cadSSimon Tatham auto &Def = *D.second; 1436a8c6cadSSimon Tatham 1446a8c6cadSSimon Tatham json::Object obj; 1456a8c6cadSSimon Tatham json::Array fields; 1466a8c6cadSSimon Tatham 1476a8c6cadSSimon Tatham for (const RecordVal &RV : Def.getValues()) { 1486a8c6cadSSimon Tatham if (!Def.isTemplateArg(RV.getNameInit())) { 1496a8c6cadSSimon Tatham auto Name = RV.getNameInitAsString(); 1506a8c6cadSSimon Tatham if (RV.getPrefix()) 1516a8c6cadSSimon Tatham fields.push_back(Name); 1526a8c6cadSSimon Tatham obj[Name] = translateInit(*RV.getValue()); 1536a8c6cadSSimon Tatham } 1546a8c6cadSSimon Tatham } 1556a8c6cadSSimon Tatham 1566a8c6cadSSimon Tatham obj["!fields"] = std::move(fields); 1576a8c6cadSSimon Tatham 1586a8c6cadSSimon Tatham json::Array superclasses; 1596a8c6cadSSimon Tatham for (const auto &SuperPair : Def.getSuperClasses()) 1606a8c6cadSSimon Tatham superclasses.push_back(SuperPair.first->getNameInitAsString()); 1616a8c6cadSSimon Tatham obj["!superclasses"] = std::move(superclasses); 1626a8c6cadSSimon Tatham 1636a8c6cadSSimon Tatham obj["!name"] = Name; 1646a8c6cadSSimon Tatham obj["!anonymous"] = Def.isAnonymous(); 1656a8c6cadSSimon Tatham 1666a8c6cadSSimon Tatham root[Name] = std::move(obj); 1676a8c6cadSSimon Tatham 1686a8c6cadSSimon Tatham // Add this def to the instance list for each of its superclasses. 1696a8c6cadSSimon Tatham for (const auto &SuperPair : Def.getSuperClasses()) { 1706a8c6cadSSimon Tatham auto SuperName = SuperPair.first->getNameInitAsString(); 1716a8c6cadSSimon Tatham instance_lists[SuperName].push_back(Name); 1726a8c6cadSSimon Tatham } 1736a8c6cadSSimon Tatham } 1746a8c6cadSSimon Tatham 1756a8c6cadSSimon Tatham // Make a JSON object from the std::map of instance lists. 1766a8c6cadSSimon Tatham json::Object instanceof; 1776a8c6cadSSimon Tatham for (auto kv: instance_lists) 1786a8c6cadSSimon Tatham instanceof[kv.first] = std::move(kv.second); 1796a8c6cadSSimon Tatham root["!instanceof"] = std::move(instanceof); 1806a8c6cadSSimon Tatham 1816a8c6cadSSimon Tatham // Done. Write the output. 1826a8c6cadSSimon Tatham OS << json::Value(std::move(root)) << "\n"; 1836a8c6cadSSimon Tatham } 1846a8c6cadSSimon Tatham 1856a8c6cadSSimon Tatham namespace llvm { 1866a8c6cadSSimon Tatham 1876a8c6cadSSimon Tatham void EmitJSON(RecordKeeper &RK, raw_ostream &OS) { JSONEmitter(RK).run(OS); } 1886a8c6cadSSimon Tatham } // end namespace llvm 189