LLVM  14.0.0git
JSONBackend.cpp
Go to the documentation of this file.
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/ADT/BitVector.h"
15 #include "llvm/Support/Debug.h"
16 #include "llvm/TableGen/Error.h"
17 #include "llvm/TableGen/Record.h"
19 #include "llvm/Support/JSON.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>(&I)) {
49  return nullptr;
50  } else if (auto *Bit = dyn_cast<BitInit>(&I)) {
51  return Bit->getValue() ? 1 : 0;
52  } else if (auto *Bits = dyn_cast<BitsInit>(&I)) {
53  json::Array array;
54  for (unsigned i = 0, limit = Bits->getNumBits(); i < limit; i++)
55  array.push_back(translateInit(*Bits->getBit(i)));
56  return std::move(array);
57  } else if (auto *Int = dyn_cast<IntInit>(&I)) {
58  return Int->getValue();
59  } else if (auto *Str = dyn_cast<StringInit>(&I)) {
60  return Str->getValue();
61  } else if (auto *List = dyn_cast<ListInit>(&I)) {
62  json::Array array;
63  for (auto val : *List)
64  array.push_back(translateInit(*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>(&I)) {
77  obj["kind"] = "def";
78  obj["def"] = Def->getDef()->getName();
79  return std::move(obj);
80  } else if (auto *Var = dyn_cast<VarInit>(&I)) {
81  obj["kind"] = "var";
82  obj["var"] = Var->getName();
83  return std::move(obj);
84  } else if (auto *VarBit = dyn_cast<VarBitInit>(&I)) {
85  if (auto *Var = dyn_cast<VarInit>(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>(&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 i = 0, limit = Dag->getNumArgs(); i < limit; ++i) {
98  json::Array arg;
99  arg.push_back(translateInit(*Dag->getArg(i)));
100  if (auto argname = Dag->getArgName(i))
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 
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  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  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(RV.getNameInit())) {
146  auto Name = RV.getNameInitAsString();
147  if (RV.isNonconcreteOK())
148  fields.push_back(Name);
149  obj[Name] = translateInit(*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(SuperPair.first->getNameInitAsString());
158  obj["!superclasses"] = std::move(superclasses);
159 
160  obj["!name"] = Name;
161  obj["!anonymous"] = Def.isAnonymous();
162 
163  root[Name] = std::move(obj);
164 
165  // Add this def to the instance list for each of its superclasses.
166  for (const auto &SuperPair : Def.getSuperClasses()) {
167  auto SuperName = SuperPair.first->getNameInitAsString();
168  instance_lists[SuperName].push_back(Name);
169  }
170  }
171 
172  // Make a JSON object from the std::map of instance lists.
173  json::Object instanceof;
174  for (auto kv: instance_lists)
175  instanceof[kv.first] = std::move(kv.second);
176  root["!instanceof"] = std::move(instanceof);
177 
178  // Done. Write the output.
179  OS << json::Value(std::move(root)) << "\n";
180 }
181 
182 namespace llvm {
183 
184 void EmitJSON(RecordKeeper &RK, raw_ostream &OS) { JSONEmitter(RK).run(OS); }
185 } // end namespace llvm
i
i
Definition: README.txt:29
llvm::json::Value
A Value is an JSON value of unknown type.
Definition: JSON.h:289
llvm
---------------------— PointerInfo ------------------------------------—
Definition: AllocatorList.h:23
llvm::tgtok::Def
@ Def
Definition: TGLexer.h:50
llvm::RecordKeeper
Definition: Record.h:1771
llvm::tgtok::Bits
@ Bits
Definition: TGLexer.h:50
llvm::json::Array::push_back
void push_back(const Value &E)
Definition: JSON.h:190
llvm::RISCVFenceField::R
@ R
Definition: RISCVBaseInfo.h:198
TableGenBackend.h
llvm::tgtok::Dag
@ Dag
Definition: TGLexer.h:50
C
(vector float) vec_cmpeq(*A, *B) C
Definition: README_ALTIVEC.txt:86
llvm::json::Array
An Array is a JSON array, which contains heterogeneous JSON values.
Definition: JSON.h:156
llvm::raw_ostream
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
BitVector.h
JSON.h
Error.h
val
The initial backend is deliberately restricted to z10 We should add support for later architectures at some point If an asm ties an i32 r result to an i64 the input will be treated as an leaving the upper bits uninitialised For i64 store i32 val
Definition: README.txt:15
D
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
llvm::tgtok::Int
@ Int
Definition: TGLexer.h:51
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
I
#define I(x, y, z)
Definition: MD5.cpp:59
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::EmitJSON
void EmitJSON(RecordKeeper &RK, raw_ostream &OS)
Definition: JSONBackend.cpp:184
llvm::Init
Definition: Record.h:271
name
static const char * name
Definition: SVEIntrinsicOpts.cpp:78
llvm::GraphProgram::Name
Name
Definition: GraphWriter.h:52
llvm::TargetStackID::Value
Value
Definition: TargetFrameLowering.h:27
List
const NodeList & List
Definition: RDFGraph.cpp:201
llvm::tgtok::Bit
@ Bit
Definition: TGLexer.h:50
llvm::json::Object
An Object is a JSON object, which maps strings to heterogenous JSON values.
Definition: JSON.h:90
llvm::RecordVal
This class represents a field in a record, including its name, type, value, and source location.
Definition: Record.h:1402
Record.h
Debug.h