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/ErrorHandling.h" |
17 | #include "llvm/Support/JSON.h" |
18 | #include "llvm/TableGen/Error.h" |
19 | #include "llvm/TableGen/Record.h" |
20 | |
21 | #define DEBUG_TYPE "json-emitter" |
22 | |
23 | using namespace llvm; |
24 | |
25 | namespace { |
26 | |
27 | class JSONEmitter { |
28 | private: |
29 | RecordKeeper &Records; |
30 | |
31 | json::Value translateInit(const Init &I); |
32 | |
33 | public: |
34 | JSONEmitter(RecordKeeper &R); |
35 | |
36 | void run(raw_ostream &OS); |
37 | }; |
38 | |
39 | } // end anonymous namespace |
40 | |
41 | JSONEmitter::JSONEmitter(RecordKeeper &R) : Records(R) {} |
42 | |
43 | json::Value JSONEmitter::translateInit(const Init &I) { |
44 | |
45 | // Init subclasses that we return as JSON primitive values of one |
46 | // kind or another. |
47 | |
48 | if (isa<UnsetInit>(Val: &I)) { |
49 | return nullptr; |
50 | } else if (auto *Bit = dyn_cast<BitInit>(Val: &I)) { |
51 | return Bit->getValue() ? 1 : 0; |
52 | } else if (auto *Bits = dyn_cast<BitsInit>(Val: &I)) { |
53 | json::Array array; |
54 | for (unsigned i = 0, limit = Bits->getNumBits(); i < limit; i++) |
55 | array.push_back(E: translateInit(I: *Bits->getBit(Bit: i))); |
56 | return std::move(array); |
57 | } else if (auto *Int = dyn_cast<IntInit>(Val: &I)) { |
58 | return Int->getValue(); |
59 | } else if (auto *Str = dyn_cast<StringInit>(Val: &I)) { |
60 | return Str->getValue(); |
61 | } else if (auto *List = dyn_cast<ListInit>(Val: &I)) { |
62 | json::Array array; |
63 | for (auto *val : *List) |
64 | array.push_back(E: translateInit(I: *val)); |
65 | return std::move(array); |
66 | } |
67 | |
68 | // Init subclasses that we return as JSON objects containing a |
69 | // 'kind' discriminator. For these, we also provide the same |
70 | // translation back into TableGen input syntax that -print-records |
71 | // would give. |
72 | |
73 | json::Object obj; |
74 | obj["printable" ] = I.getAsString(); |
75 | |
76 | if (auto *Def = dyn_cast<DefInit>(Val: &I)) { |
77 | obj["kind" ] = "def" ; |
78 | obj["def" ] = Def->getDef()->getName(); |
79 | return std::move(obj); |
80 | } else if (auto *Var = dyn_cast<VarInit>(Val: &I)) { |
81 | obj["kind" ] = "var" ; |
82 | obj["var" ] = Var->getName(); |
83 | return std::move(obj); |
84 | } else if (auto *VarBit = dyn_cast<VarBitInit>(Val: &I)) { |
85 | if (auto *Var = dyn_cast<VarInit>(Val: VarBit->getBitVar())) { |
86 | obj["kind" ] = "varbit" ; |
87 | obj["var" ] = Var->getName(); |
88 | obj["index" ] = VarBit->getBitNum(); |
89 | return std::move(obj); |
90 | } |
91 | } else if (auto *Dag = dyn_cast<DagInit>(Val: &I)) { |
92 | obj["kind" ] = "dag" ; |
93 | obj["operator" ] = translateInit(I: *Dag->getOperator()); |
94 | if (auto name = Dag->getName()) |
95 | obj["name" ] = name->getAsUnquotedString(); |
96 | json::Array args; |
97 | for (unsigned i = 0, limit = Dag->getNumArgs(); i < limit; ++i) { |
98 | json::Array arg; |
99 | arg.push_back(E: translateInit(I: *Dag->getArg(Num: i))); |
100 | if (auto argname = Dag->getArgName(Num: i)) |
101 | arg.push_back(E: argname->getAsUnquotedString()); |
102 | else |
103 | arg.push_back(E: nullptr); |
104 | args.push_back(E: 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 | |
114 | assert(!I.isConcrete()); |
115 | obj["kind" ] = "complex" ; |
116 | return std::move(obj); |
117 | } |
118 | |
119 | void JSONEmitter::run(raw_ostream &OS) { |
120 | json::Object root; |
121 | |
122 | root["!tablegen_json_version" ] = 1; |
123 | |
124 | // Prepare the arrays that will list the instances of every class. |
125 | // We mostly fill those in by iterating over the superclasses of |
126 | // each def, but we also want to ensure we store an empty list for a |
127 | // class with no instances at all, so we do a preliminary iteration |
128 | // over the classes, invoking std::map::operator[] to default- |
129 | // construct the array for each one. |
130 | std::map<std::string, json::Array> instance_lists; |
131 | for (const auto &C : Records.getClasses()) { |
132 | const auto Name = C.second->getNameInitAsString(); |
133 | (void)instance_lists[Name]; |
134 | } |
135 | |
136 | // Main iteration over the defs. |
137 | for (const auto &D : Records.getDefs()) { |
138 | const auto Name = D.second->getNameInitAsString(); |
139 | auto &Def = *D.second; |
140 | |
141 | json::Object obj; |
142 | json::Array fields; |
143 | |
144 | for (const RecordVal &RV : Def.getValues()) { |
145 | if (!Def.isTemplateArg(Name: RV.getNameInit())) { |
146 | auto Name = RV.getNameInitAsString(); |
147 | if (RV.isNonconcreteOK()) |
148 | fields.push_back(E: Name); |
149 | obj[Name] = translateInit(I: *RV.getValue()); |
150 | } |
151 | } |
152 | |
153 | obj["!fields" ] = std::move(fields); |
154 | |
155 | json::Array superclasses; |
156 | for (const auto &SuperPair : Def.getSuperClasses()) |
157 | superclasses.push_back(E: SuperPair.first->getNameInitAsString()); |
158 | obj["!superclasses" ] = std::move(superclasses); |
159 | |
160 | obj["!name" ] = Name; |
161 | obj["!anonymous" ] = Def.isAnonymous(); |
162 | |
163 | json::Array locs; |
164 | for (const SMLoc Loc : Def.getLoc()) |
165 | locs.push_back(E: SrcMgr.getFormattedLocationNoOffset(Loc)); |
166 | obj["!locs" ] = std::move(locs); |
167 | |
168 | root[Name] = std::move(obj); |
169 | |
170 | // Add this def to the instance list for each of its superclasses. |
171 | for (const auto &SuperPair : Def.getSuperClasses()) { |
172 | auto SuperName = SuperPair.first->getNameInitAsString(); |
173 | instance_lists[SuperName].push_back(E: Name); |
174 | } |
175 | } |
176 | |
177 | // Make a JSON object from the std::map of instance lists. |
178 | json::Object instanceof; |
179 | for (auto kv: instance_lists) |
180 | instanceof[kv.first] = std::move(kv.second); |
181 | root["!instanceof" ] = std::move(instanceof); |
182 | |
183 | // Done. Write the output. |
184 | OS << json::Value(std::move(root)) << "\n" ; |
185 | } |
186 | |
187 | namespace llvm { |
188 | |
189 | void EmitJSON(RecordKeeper &RK, raw_ostream &OS) { JSONEmitter(RK).run(OS); } |
190 | } // end namespace llvm |
191 | |