Coverage Report

Created: 2020-10-24 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/utils/TableGen/ClangOpcodesEmitter.cpp
Line
Count
Source (jump to first uncovered line)
1
//=== ClangOpcodesEmitter.cpp - constexpr interpreter opcodes ---*- 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
// These tablegen backends emit Clang AST node tables
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "TableGenBackends.h"
14
#include "llvm/TableGen/Error.h"
15
#include "llvm/TableGen/Record.h"
16
#include "llvm/TableGen/StringMatcher.h"
17
#include "llvm/TableGen/TableGenBackend.h"
18
19
using namespace llvm;
20
21
namespace {
22
class ClangOpcodesEmitter {
23
  RecordKeeper &Records;
24
  Record Root;
25
  unsigned NumTypes;
26
27
public:
28
  ClangOpcodesEmitter(RecordKeeper &R)
29
    : Records(R), Root("Opcode", SMLoc(), R),
30
0
      NumTypes(Records.getAllDerivedDefinitions("Type").size()) {}
31
32
  void run(raw_ostream &OS);
33
34
private:
35
  /// Emits the opcode name for the opcode enum.
36
  /// The name is obtained by concatenating the name with the list of types.
37
  void EmitEnum(raw_ostream &OS, StringRef N, Record *R);
38
39
  /// Emits the switch case and the invocation in the interpreter.
40
  void EmitInterp(raw_ostream &OS, StringRef N, Record *R);
41
42
  /// Emits the disassembler.
43
  void EmitDisasm(raw_ostream &OS, StringRef N, Record *R);
44
45
  /// Emits the byte code emitter method.
46
  void EmitEmitter(raw_ostream &OS, StringRef N, Record *R);
47
48
  /// Emits the prototype.
49
  void EmitProto(raw_ostream &OS, StringRef N, Record *R);
50
51
  /// Emits the prototype to dispatch from a type.
52
  void EmitGroup(raw_ostream &OS, StringRef N, Record *R);
53
54
  /// Emits the evaluator method.
55
  void EmitEval(raw_ostream &OS, StringRef N, Record *R);
56
57
  void PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types);
58
};
59
60
void Enumerate(const Record *R,
61
               StringRef N,
62
0
               std::function<void(ArrayRef<Record *>, Twine)> &&F) {
63
0
  llvm::SmallVector<Record *, 2> TypePath;
64
0
  auto *Types = R->getValueAsListInit("Types");
65
66
0
  std::function<void(size_t, const Twine &)> Rec;
67
0
  Rec = [&TypePath, Types, &Rec, &F](size_t I, const Twine &ID) {
68
0
    if (I >= Types->size()) {
69
0
      F(TypePath, ID);
70
0
      return;
71
0
    }
72
73
0
    if (auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) {
74
0
      for (auto *Type : TypeClass->getDef()->getValueAsListOfDefs("Types")) {
75
0
        TypePath.push_back(Type);
76
0
        Rec(I + 1, ID + Type->getName());
77
0
        TypePath.pop_back();
78
0
      }
79
0
    } else {
80
0
      PrintFatalError("Expected a type class");
81
0
    }
82
0
  };
83
0
  Rec(0, N);
84
0
}
85
86
} // namespace
87
88
0
void ClangOpcodesEmitter::run(raw_ostream &OS) {
89
0
  for (auto *Opcode : Records.getAllDerivedDefinitions(Root.getName())) {
90
    // The name is the record name, unless overriden.
91
0
    StringRef N = Opcode->getValueAsString("Name");
92
0
    if (N.empty())
93
0
      N = Opcode->getName();
94
95
0
    EmitEnum(OS, N, Opcode);
96
0
    EmitInterp(OS, N, Opcode);
97
0
    EmitDisasm(OS, N, Opcode);
98
0
    EmitProto(OS, N, Opcode);
99
0
    EmitGroup(OS, N, Opcode);
100
0
    EmitEmitter(OS, N, Opcode);
101
0
    EmitEval(OS, N, Opcode);
102
0
  }
103
0
}
104
105
0
void ClangOpcodesEmitter::EmitEnum(raw_ostream &OS, StringRef N, Record *R) {
106
0
  OS << "#ifdef GET_OPCODE_NAMES\n";
107
0
  Enumerate(R, N, [&OS](ArrayRef<Record *>, const Twine &ID) {
108
0
    OS << "OP_" << ID << ",\n";
109
0
  });
110
0
  OS << "#endif\n";
111
0
}
112
113
0
void ClangOpcodesEmitter::EmitInterp(raw_ostream &OS, StringRef N, Record *R) {
114
0
  OS << "#ifdef GET_INTERP\n";
115
116
0
  Enumerate(R, N, [this, R, &OS, &N](ArrayRef<Record *> TS, const Twine &ID) {
117
0
    bool CanReturn = R->getValueAsBit("CanReturn");
118
0
    bool ChangesPC = R->getValueAsBit("ChangesPC");
119
0
    auto Args = R->getValueAsListOfDefs("Args");
120
121
0
    OS << "case OP_" << ID << ": {\n";
122
123
    // Emit calls to read arguments.
124
0
    for (size_t I = 0, N = Args.size(); I < N; ++I) {
125
0
      OS << "\tauto V" << I;
126
0
      OS << " = ";
127
0
      OS << "PC.read<" << Args[I]->getValueAsString("Name") << ">();\n";
128
0
    }
129
130
    // Emit a call to the template method and pass arguments.
131
0
    OS << "\tif (!" << N;
132
0
    PrintTypes(OS, TS);
133
0
    OS << "(S";
134
0
    if (ChangesPC)
135
0
      OS << ", PC";
136
0
    else
137
0
      OS << ", OpPC";
138
0
    if (CanReturn)
139
0
      OS << ", Result";
140
0
    for (size_t I = 0, N = Args.size(); I < N; ++I)
141
0
      OS << ", V" << I;
142
0
    OS << "))\n";
143
0
    OS << "\t\treturn false;\n";
144
145
    // Bail out if interpreter returned.
146
0
    if (CanReturn) {
147
0
      OS << "\tif (!S.Current || S.Current->isRoot())\n";
148
0
      OS << "\t\treturn true;\n";
149
0
    }
150
151
0
    OS << "\tcontinue;\n";
152
0
    OS << "}\n";
153
0
  });
154
0
  OS << "#endif\n";
155
0
}
156
157
0
void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N, Record *R) {
158
0
  OS << "#ifdef GET_DISASM\n";
159
0
  Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) {
160
0
    OS << "case OP_" << ID << ":\n";
161
0
    OS << "\tPrintName(\"" << ID << "\");\n";
162
0
    OS << "\tOS << \"\\t\"";
163
164
0
    for (auto *Arg : R->getValueAsListOfDefs("Args"))
165
0
      OS << " << PC.read<" << Arg->getValueAsString("Name") << ">() << \" \"";
166
167
0
    OS << "<< \"\\n\";\n";
168
0
    OS << "\tcontinue;\n";
169
0
  });
170
0
  OS << "#endif\n";
171
0
}
172
173
0
void ClangOpcodesEmitter::EmitEmitter(raw_ostream &OS, StringRef N, Record *R) {
174
0
  if (R->getValueAsBit("HasCustomLink"))
175
0
    return;
176
177
0
  OS << "#ifdef GET_LINK_IMPL\n";
178
0
  Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) {
179
0
    auto Args = R->getValueAsListOfDefs("Args");
180
181
    // Emit the list of arguments.
182
0
    OS << "bool ByteCodeEmitter::emit" << ID << "(";
183
0
    for (size_t I = 0, N = Args.size(); I < N; ++I)
184
0
      OS << Args[I]->getValueAsString("Name") << " A" << I << ",";
185
0
    OS << "const SourceInfo &L) {\n";
186
187
    // Emit a call to write the opcodes.
188
0
    OS << "\treturn emitOp<";
189
0
    for (size_t I = 0, N = Args.size(); I < N; ++I) {
190
0
      if (I != 0)
191
0
        OS << ", ";
192
0
      OS << Args[I]->getValueAsString("Name");
193
0
    }
194
0
    OS << ">(OP_" << ID;
195
0
    for (size_t I = 0, N = Args.size(); I < N; ++I)
196
0
      OS << ", A" << I;
197
0
    OS << ", L);\n";
198
0
    OS << "}\n";
199
0
  });
200
0
  OS << "#endif\n";
201
0
}
202
203
0
void ClangOpcodesEmitter::EmitProto(raw_ostream &OS, StringRef N, Record *R) {
204
0
  OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
205
0
  auto Args = R->getValueAsListOfDefs("Args");
206
0
  Enumerate(R, N, [&OS, &Args](ArrayRef<Record *> TS, const Twine &ID) {
207
0
    OS << "bool emit" << ID << "(";
208
0
    for (auto *Arg : Args)
209
0
      OS << Arg->getValueAsString("Name") << ", ";
210
0
    OS << "const SourceInfo &);\n";
211
0
  });
212
213
  // Emit a template method for custom emitters to have less to implement.
214
0
  auto TypeCount = R->getValueAsListInit("Types")->size();
215
0
  if (R->getValueAsBit("HasCustomEval") && TypeCount) {
216
0
    OS << "#if defined(GET_EVAL_PROTO)\n";
217
0
    OS << "template<";
218
0
    for (size_t I = 0; I < TypeCount; ++I) {
219
0
      if (I != 0)
220
0
        OS << ", ";
221
0
      OS << "PrimType";
222
0
    }
223
0
    OS << ">\n";
224
0
    OS << "bool emit" << N << "(";
225
0
    for (auto *Arg : Args)
226
0
      OS << Arg->getValueAsString("Name") << ", ";
227
0
    OS << "const SourceInfo &);\n";
228
0
    OS << "#endif\n";
229
0
  }
230
231
0
  OS << "#endif\n";
232
0
}
233
234
0
void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N, Record *R) {
235
0
  if (!R->getValueAsBit("HasGroup"))
236
0
    return;
237
238
0
  auto *Types = R->getValueAsListInit("Types");
239
0
  auto Args = R->getValueAsListOfDefs("Args");
240
241
  // Emit the prototype of the group emitter in the header.
242
0
  OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
243
0
  OS << "bool emit" << N << "(";
244
0
  for (size_t I = 0, N = Types->size(); I < N; ++I)
245
0
    OS << "PrimType, ";
246
0
  for (auto *Arg : Args)
247
0
    OS << Arg->getValueAsString("Name") << ", ";
248
0
  OS << "const SourceInfo &I);\n";
249
0
  OS << "#endif\n";
250
251
  // Emit the dispatch implementation in the source.
252
0
  OS << "#if defined(GET_EVAL_IMPL) || defined(GET_LINK_IMPL)\n";
253
0
  OS << "bool \n";
254
0
  OS << "#if defined(GET_EVAL_IMPL)\n";
255
0
  OS << "EvalEmitter\n";
256
0
  OS << "#else\n";
257
0
  OS << "ByteCodeEmitter\n";
258
0
  OS << "#endif\n";
259
0
  OS << "::emit" << N << "(";
260
0
  for (size_t I = 0, N = Types->size(); I < N; ++I)
261
0
    OS << "PrimType T" << I << ", ";
262
0
  for (size_t I = 0, N = Args.size(); I < N; ++I)
263
0
    OS << Args[I]->getValueAsString("Name") << " A" << I << ", ";
264
0
  OS << "const SourceInfo &I) {\n";
265
266
0
  std::function<void(size_t, const Twine &)> Rec;
267
0
  llvm::SmallVector<Record *, 2> TS;
268
0
  Rec = [this, &Rec, &OS, Types, &Args, R, &TS, N](size_t I, const Twine &ID) {
269
0
    if (I >= Types->size()) {
270
      // Print a call to the emitter method.
271
      // Custom evaluator methods dispatch to template methods.
272
0
      if (R->getValueAsBit("HasCustomEval")) {
273
0
        OS << "#ifdef GET_LINK_IMPL\n";
274
0
        OS << "return emit" << ID << "\n";
275
0
        OS << "#else\n";
276
0
        OS << "return emit" << N;
277
0
        PrintTypes(OS, TS);
278
0
        OS << "\n#endif\n";
279
0
      } else {
280
0
        OS << "return emit" << ID;
281
0
      }
282
283
0
      OS << "(";
284
0
      for (size_t I = 0; I < Args.size(); ++I) {
285
0
        OS << "A" << I << ", ";
286
0
      }
287
0
      OS << "I);\n";
288
0
      return;
289
0
    }
290
291
    // Print a switch statement selecting T.
292
0
    if (auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) {
293
0
      OS << "switch (T" << I << "){\n";
294
0
      auto Cases = TypeClass->getDef()->getValueAsListOfDefs("Types");
295
0
      for (auto *Case : Cases) {
296
0
        OS << "case PT_" << Case->getName() << ":\n";
297
0
        TS.push_back(Case);
298
0
        Rec(I + 1, ID + Case->getName());
299
0
        TS.pop_back();
300
0
      }
301
      // Emit a default case if not all types are present.
302
0
      if (Cases.size() < NumTypes)
303
0
        OS << "default: llvm_unreachable(\"invalid type\");\n";
304
0
      OS << "}\n";
305
0
      OS << "llvm_unreachable(\"invalid enum value\");\n";
306
0
    } else {
307
0
      PrintFatalError("Expected a type class");
308
0
    }
309
0
  };
310
0
  Rec(0, N);
311
312
0
  OS << "}\n";
313
0
  OS << "#endif\n";
314
0
}
315
316
0
void ClangOpcodesEmitter::EmitEval(raw_ostream &OS, StringRef N, Record *R) {
317
0
  if (R->getValueAsBit("HasCustomEval"))
318
0
    return;
319
320
0
  OS << "#ifdef GET_EVAL_IMPL\n";
321
0
  Enumerate(R, N, [this, R, &N, &OS](ArrayRef<Record *> TS, const Twine &ID) {
322
0
    auto Args = R->getValueAsListOfDefs("Args");
323
324
0
    OS << "bool EvalEmitter::emit" << ID << "(";
325
0
    for (size_t I = 0, N = Args.size(); I < N; ++I)
326
0
      OS << Args[I]->getValueAsString("Name") << " A" << I << ",";
327
0
    OS << "const SourceInfo &L) {\n";
328
0
    OS << "if (!isActive()) return true;\n";
329
0
    OS << "CurrentSource = L;\n";
330
331
0
    OS << "return " << N;
332
0
    PrintTypes(OS, TS);
333
0
    OS << "(S, OpPC";
334
0
    for (size_t I = 0, N = Args.size(); I < N; ++I)
335
0
      OS << ", A" << I;
336
0
    OS << ");\n";
337
0
    OS << "}\n";
338
0
  });
339
340
0
  OS << "#endif\n";
341
0
}
342
343
0
void ClangOpcodesEmitter::PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types) {
344
0
  if (Types.empty())
345
0
    return;
346
0
  OS << "<";
347
0
  for (size_t I = 0, N = Types.size(); I < N; ++I) {
348
0
    if (I != 0)
349
0
      OS << ", ";
350
0
    OS << "PT_" << Types[I]->getName();
351
0
  }
352
0
  OS << ">";
353
0
}
354
355
0
void clang::EmitClangOpcodes(RecordKeeper &Records, raw_ostream &OS) {
356
0
  ClangOpcodesEmitter(Records).run(OS);
357
0
}