-
Notifications
You must be signed in to change notification settings - Fork 437
Expand file tree
/
Copy pathImportVerilogInternals.h
More file actions
377 lines (315 loc) · 15.6 KB
/
ImportVerilogInternals.h
File metadata and controls
377 lines (315 loc) · 15.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
//===- ImportVerilogInternals.h - Internal implementation details ---------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// NOLINTNEXTLINE(llvm-header-guard)
#ifndef CONVERSION_IMPORTVERILOG_IMPORTVERILOGINTERNALS_H
#define CONVERSION_IMPORTVERILOG_IMPORTVERILOGINTERNALS_H
#include "circt/Conversion/ImportVerilog.h"
#include "circt/Dialect/Debug/DebugOps.h"
#include "circt/Dialect/HW/HWOps.h"
#include "circt/Dialect/LTL/LTLOps.h"
#include "circt/Dialect/Moore/MooreOps.h"
#include "circt/Dialect/SV/SVOps.h"
#include "circt/Dialect/Verif/VerifOps.h"
#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "slang/ast/ASTVisitor.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/Support/Debug.h"
#include <map>
#include <queue>
#define DEBUG_TYPE "import-verilog"
namespace circt {
namespace ImportVerilog {
using moore::Domain;
/// Port lowering information.
struct PortLowering {
const slang::ast::PortSymbol *
Location loc;
BlockArgument arg;
};
/// Module lowering information.
struct ModuleLowering {
moore::SVModuleOp op;
SmallVector<PortLowering> ports;
DenseMap<const slang::syntax::SyntaxNode *, const slang::ast::PortSymbol *>
portsBySyntaxNode;
};
/// Interface lowering information.
struct InterfaceLowering {
sv::InterfaceOp op;
sv::InterfaceType type;
DenseMap<const slang::ast::ValueSymbol *, mlir::FlatSymbolRefAttr> signalRefs;
DenseMap<mlir::StringAttr, mlir::FlatSymbolRefAttr> signalRefsByName;
};
/// Function lowering information.
struct FunctionLowering {
mlir::func::FuncOp op;
llvm::SmallVector<Value, 4> captures;
llvm::DenseMap<Value, unsigned> captureIndex;
bool capturesFinalized = false;
bool isConverting = false;
};
// Class lowering information.
struct ClassLowering {
circt::moore::ClassDeclOp op;
bool methodsFinalized = false;
};
/// Information about a loops continuation and exit blocks relevant while
/// lowering the loop's body statements.
struct LoopFrame {
/// The block to jump to from a `continue` statement.
Block *continueBlock;
/// The block to jump to from a `break` statement.
Block *breakBlock;
};
/// Hierarchical path information.
/// The "hierName" means a different hierarchical name at different module
/// levels.
/// The "idx" means where the current hierarchical name is on the portlists.
/// The "direction" means hierarchical names whether downward(In) or
/// upward(Out).
struct HierPathInfo {
mlir::StringAttr hierName;
std::optional<unsigned int> idx;
slang::ast::ArgumentDirection direction;
const slang::ast::ValueSymbol *valueSym;
};
/// A helper class to facilitate the conversion from a Slang AST to MLIR
/// operations. Keeps track of the destination MLIR module, builders, and
/// various worklists and utilities needed for conversion.
struct Context {
Context(const ImportVerilogOptions &options,
slang::ast::Compilation &compilation, mlir::ModuleOp intoModuleOp,
const slang::SourceManager &sourceManager)
: options(options), compilation(compilation), intoModuleOp(intoModuleOp),
sourceManager(sourceManager),
builder(OpBuilder::atBlockEnd(intoModuleOp.getBody())),
symbolTable(intoModuleOp) {}
Context(const Context &) = delete;
/// Return the MLIR context.
MLIRContext *getContext() { return intoModuleOp.getContext(); }
/// Convert a slang `SourceLocation` into an MLIR `Location`.
Location convertLocation(slang::SourceLocation loc);
/// Convert a slang `SourceRange` into an MLIR `Location`.
Location convertLocation(slang::SourceRange range);
/// Convert a slang type into an MLIR type. Returns null on failure. Uses the
/// provided location for error reporting, or tries to guess one from the
/// given type. Types tend to have unreliable location information, so it's
/// generally a good idea to pass in a location.
Type convertType(const slang::ast::Type &type, LocationAttr loc = {});
Type convertType(const slang::ast::DeclaredType &type);
/// Convert hierarchy and structure AST nodes to MLIR ops.
LogicalResult convertCompilation();
ModuleLowering *
convertModuleHeader(const slang::ast::InstanceBodySymbol *module);
LogicalResult convertModuleBody(const slang::ast::InstanceBodySymbol *module);
InterfaceLowering *
convertInterface(const slang::ast::InstanceBodySymbol *interface);
LogicalResult convertPackage(const slang::ast::PackageSymbol &package);
FunctionLowering *
declareFunction(const slang::ast::SubroutineSymbol &subroutine);
LogicalResult convertFunction(const slang::ast::SubroutineSymbol &subroutine);
LogicalResult finalizeFunctionBodyCaptures(FunctionLowering &lowering);
ClassLowering *declareClass(const slang::ast::ClassType &cls);
LogicalResult buildClassProperties(const slang::ast::ClassType &classdecl);
LogicalResult materializeClassMethods(const slang::ast::ClassType &classdecl);
LogicalResult convertGlobalVariable(const slang::ast::VariableSymbol &var);
/// Checks whether one class (actualTy) is derived from another class
/// (baseTy). True if it's a subclass, false otherwise.
bool isClassDerivedFrom(const moore::ClassHandleType &actualTy,
const moore::ClassHandleType &baseTy);
/// Tries to find the closest base class of actualTy that carries a property
/// with name fieldName. The location is used for error reporting.
moore::ClassHandleType
getAncestorClassWithProperty(const moore::ClassHandleType &actualTy,
StringRef fieldName, Location loc);
Value getImplicitThisRef() const {
return currentThisRef; // block arg added in declareFunction
}
Value getIndexedQueue() const { return currentQueue; }
// Convert a statement AST node to MLIR ops.
LogicalResult convertStatement(const slang::ast::Statement &stmt);
// Convert an expression AST node to MLIR ops.
Value convertRvalueExpression(const slang::ast::Expression &expr,
Type requiredType = {});
Value convertLvalueExpression(const slang::ast::Expression &expr);
// Convert an assertion expression AST node to MLIR ops.
Value convertAssertionExpression(const slang::ast::AssertionExpr &expr,
Location loc);
// Convert an assertion expression AST node to MLIR ops.
Value convertAssertionCallExpression(
const slang::ast::CallExpression &expr,
const slang::ast::CallExpression::SystemCallInfo &info, Location loc);
// Traverse the whole AST to collect hierarchical names.
LogicalResult
collectHierarchicalValues(const slang::ast::Expression &expr,
const slang::ast::Symbol &outermostModule);
LogicalResult traverseInstanceBody(const slang::ast::Symbol &symbol);
// Convert timing controls into a corresponding set of ops that delay
// execution of the current block. Produces an error if the implicit event
// control `@*` or `@(*)` is used.
LogicalResult convertTimingControl(const slang::ast::TimingControl &ctrl);
// Convert timing controls into a corresponding set of ops that delay
// execution of the current block. Then converts the given statement, taking
// note of the rvalues it reads and adding them to a wait op in case an
// implicit event control `@*` or `@(*)` is used.
LogicalResult convertTimingControl(const slang::ast::TimingControl &ctrl,
const slang::ast::Statement &stmt);
/// Helper function to convert a value to a MLIR I1 value.
Value convertToI1(Value value);
// Convert a slang timing control for LTL
Value convertLTLTimingControl(const slang::ast::TimingControl &ctrl,
const Value &seqOrPro);
/// Helper function to convert a value to its "truthy" boolean value.
Value convertToBool(Value value);
/// Helper function to convert a value to its "truthy" boolean value and
/// convert it to the given domain.
Value convertToBool(Value value, Domain domain);
/// Helper function to convert a value to its simple bit vector
/// representation, if it has one. Otherwise returns null. Also returns null
/// if the given value is null.
Value convertToSimpleBitVector(Value value);
/// Helper function to insert the necessary operations to cast a value from
/// one type to another.
Value materializeConversion(Type type, Value value, bool isSigned,
Location loc);
/// Helper function to materialize an `SVInt` as an SSA value.
Value materializeSVInt(const slang::SVInt &svint,
const slang::ast::Type &type, Location loc);
/// Helper function to materialize a real value as an SSA value.
Value materializeSVReal(const slang::ConstantValue &svreal,
const slang::ast::Type &type, Location loc);
/// Helper function to materialize a string as an SSA value.
Value materializeString(const slang::ConstantValue &string,
const slang::ast::Type &astType, Location loc);
/// Helper function to materialize an unpacked array of `SVInt`s as an SSA
/// value.
Value materializeFixedSizeUnpackedArrayType(
const slang::ConstantValue &constant,
const slang::ast::FixedSizeUnpackedArrayType &astType, Location loc);
/// Helper function to materialize a `ConstantValue` as an SSA value. Returns
/// null if the constant cannot be materialized.
Value materializeConstant(const slang::ConstantValue &constant,
const slang::ast::Type &type, Location loc);
/// Convert a list of string literal arguments with formatting specifiers and
/// arguments to be interpolated into a `!moore.format_string` value. Returns
/// failure if an error occurs. Returns a null value if the formatted string
/// is trivially empty. Otherwise returns the formatted string.
FailureOr<Value> convertFormatString(
std::span<const slang::ast::Expression *const> arguments, Location loc,
moore::IntFormat defaultFormat = moore::IntFormat::Decimal,
bool appendNewline = false);
/// Convert system function calls only have arity-0.
FailureOr<Value>
convertSystemCallArity0(const slang::ast::SystemSubroutine &subroutine,
Location loc);
/// Convert system function calls only have arity-1.
FailureOr<Value>
convertSystemCallArity1(const slang::ast::SystemSubroutine &subroutine,
Location loc, Value value);
/// Convert system function calls with arity-2.
FailureOr<Value>
convertSystemCallArity2(const slang::ast::SystemSubroutine &subroutine,
Location loc, Value value1, Value value2);
/// Convert system function calls within properties and assertion with a
/// single argument.
FailureOr<Value> convertAssertionSystemCallArity1(
const slang::ast::SystemSubroutine &subroutine, Location loc, Value value,
Type originalType);
/// Evaluate the constant value of an expression.
slang::ConstantValue evaluateConstant(const slang::ast::Expression &expr);
const ImportVerilogOptions &options;
slang::ast::Compilation &compilation;
mlir::ModuleOp intoModuleOp;
const slang::SourceManager &sourceManager;
/// The builder used to create IR operations.
OpBuilder builder;
/// A symbol table of the MLIR module we are emitting into.
SymbolTable symbolTable;
/// The top-level operations ordered by their Slang source location. This is
/// used to produce IR that follows the source file order.
std::map<slang::SourceLocation, Operation *> orderedRootOps;
/// How we have lowered modules to MLIR.
DenseMap<const slang::ast::InstanceBodySymbol *,
std::unique_ptr<ModuleLowering>>
modules;
/// How we have lowered interfaces to MLIR.
DenseMap<const slang::ast::InstanceBodySymbol *,
std::unique_ptr<InterfaceLowering>>
interfaces;
/// A list of modules for which the header has been created, but the body has
/// not been converted yet.
std::queue<const slang::ast::InstanceBodySymbol *> moduleWorklist;
/// Functions that have already been converted.
DenseMap<const slang::ast::SubroutineSymbol *,
std::unique_ptr<FunctionLowering>>
functions;
/// Classes that have already been converted.
DenseMap<const slang::ast::ClassType *, std::unique_ptr<ClassLowering>>
classes;
/// A table of defined values, such as variables, that may be referred to by
/// name in expressions. The expressions use this table to lookup the MLIR
/// value that was created for a given declaration in the Slang AST node.
using ValueSymbols =
llvm::ScopedHashTable<const slang::ast::ValueSymbol *, Value>;
using ValueSymbolScope = ValueSymbols::ScopeTy;
ValueSymbols valueSymbols;
/// A table of defined global variables that may be referred to by name in
/// expressions.
DenseMap<const slang::ast::ValueSymbol *, moore::GlobalVariableOp>
globalVariables;
/// A list of global variables that still need their initializers to be
/// converted.
SmallVector<const slang::ast::ValueSymbol *> globalVariableWorklist;
/// Collect all hierarchical names used for the per module/instance.
DenseMap<const slang::ast::InstanceBodySymbol *, SmallVector<HierPathInfo>>
hierPaths;
/// It's used to collect the repeat hierarchical names on the same path.
/// Such as `Top.sub.a` and `sub.a`, they are equivalent. The variable "a"
/// will be added to the port list. But we only record once. If we don't do
/// that. We will view the strange IR, such as `module @Sub(out y, out y)`;
DenseSet<StringAttr> sameHierPaths;
/// A stack of assignment left-hand side values. Each assignment will push its
/// lowered left-hand side onto this stack before lowering its right-hand
/// side. This allows expressions to resolve the opaque
/// `LValueReferenceExpression`s in the AST.
SmallVector<Value> lvalueStack;
/// A stack of loop continuation and exit blocks. Each loop will push the
/// relevant info onto this stack, lower its loop body statements, and pop the
/// info off the stack again. Continue and break statements encountered as
/// part of the loop body statements will use this information to branch to
/// the correct block.
SmallVector<LoopFrame> loopStack;
/// A listener called for every variable or net being read. This can be used
/// to collect all variables read as part of an expression or statement, for
/// example to populate the list of observed signals in an implicit event
/// control `@*`.
std::function<void(moore::ReadOp)> rvalueReadCallback;
/// A listener called for every variable or net being assigned. This can be
/// used to collect all variables assigned in a task scope.
std::function<void(mlir::Operation *)> variableAssignCallback;
/// The time scale currently in effect.
slang::TimeScale timeScale;
/// Variable to track the value of the current function's implicit `this`
/// reference
Value currentThisRef = {};
/// Variable that tracks the queue which we are currently converting the index
/// expression for. This is necessary to implement the `$` operator, which
/// returns the index of the last element of the queue.
Value currentQueue = {};
private:
/// Helper function to extract the commonalities in lowering of functions and
/// methods
FunctionLowering *
declareCallableImpl(const slang::ast::SubroutineSymbol &subroutine,
mlir::StringRef qualifiedName,
llvm::SmallVectorImpl<Type> &extraParams);
};
} // namespace ImportVerilog
} // namespace circt
#endif // CONVERSION_IMPORTVERILOG_IMPORTVERILOGINTERNALS_H